Thread

  1. [PATCH v1 3/4] Add alias to be used as "unset" state.

    Nikolay Shaplov <dhyan@nataraj.su> — 2025-08-30T19:34:04Z

    Add `unset_alias` string parameter to trenary reloption definition. This will allow
    user explicitly switch trenary option to "unset" state. Use this feature to
    implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary
    reloptions
    ---
     src/backend/access/common/reloptions.c | 91 +++++++++++---------------
     src/backend/access/gist/gistbuild.c    |  4 +-
     src/backend/commands/vacuum.c          | 11 ++--
     src/include/access/gist_private.h      | 10 +--
     src/include/access/reloptions.h        |  7 +-
     src/include/utils/rel.h                | 10 +--
     src/test/regress/expected/gist.out     |  3 +-
     7 files changed, 54 insertions(+), 82 deletions(-)
    
    diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
    index 24662d277c8..a96abcb056c 100644
    --- a/src/backend/access/common/reloptions.c
    +++ b/src/backend/access/common/reloptions.c
    @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] =
     			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
     			ShareUpdateExclusiveLock
     		},
    +		NULL,
    +		TRENARY_UNSET
    +	},
    +	{
    +		{
    +			"vacuum_index_cleanup",
    +			"Controls index vacuuming and index cleanup",
    +			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
    +			ShareUpdateExclusiveLock
    +		},
    +		"auto",
    +		TRENARY_UNSET
    +	},
    +	{
    +		{
    +			"buffering",
    +			"Enables buffering build for this GiST index",
    +			RELOPT_KIND_GIST,
    +			AccessExclusiveLock
    +		},
    +		"auto",
     		TRENARY_UNSET
     	},
     	/* list terminator */
    @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] =
     	{{NULL}}
     };
     
    -/* values from StdRdOptIndexCleanup */
    -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] =
    -{
    -	{"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO},
    -	{"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
    -	{"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
    -	{"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
    -	{"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
    -	{"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
    -	{"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
    -	{"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON},
    -	{"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF},
    -	{(const char *) NULL}		/* list terminator */
    -};
    -
    -/* values from GistOptBufferingMode */
    -static relopt_enum_elt_def gistBufferingOptValues[] =
    -{
    -	{"auto", GIST_OPTION_BUFFERING_AUTO},
    -	{"on", GIST_OPTION_BUFFERING_ON},
    -	{"off", GIST_OPTION_BUFFERING_OFF},
    -	{(const char *) NULL}		/* list terminator */
    -};
    -
     /* values from ViewOptCheckOption */
     static relopt_enum_elt_def viewCheckOptValues[] =
     {
    @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] =
     
     static relopt_enum enumRelOpts[] =
     {
    -	{
    -		{
    -			"vacuum_index_cleanup",
    -			"Controls index vacuuming and index cleanup",
    -			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
    -			ShareUpdateExclusiveLock
    -		},
    -		StdRdOptIndexCleanupValues,
    -		STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO,
    -		gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
    -	},
    -	{
    -		{
    -			"buffering",
    -			"Enables buffering build for this GiST index",
    -			RELOPT_KIND_GIST,
    -			AccessExclusiveLock
    -		},
    -		gistBufferingOptValues,
    -		GIST_OPTION_BUFFERING_AUTO,
    -		gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
    -	},
     	{
     		{
     			"check_option",
    @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name,
      */
     static relopt_trenary *
     init_trenary_reloption(bits32 kinds, const char *name, const char *desc,
    -					trenary default_val, LOCKMODE lockmode)
    +			trenary default_val, const char* unset_alias, LOCKMODE lockmode)
     {
     	relopt_trenary *newoption;
     
     	newoption = (relopt_trenary *) allocate_reloption(kinds,
     									RELOPT_TYPE_TRENARY, name, desc, lockmode);
     	newoption->default_val = default_val;
    +	newoption->unset_alias = unset_alias;
     
     	return newoption;
     }
    @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc,
      */
     void
     add_trenary_reloption(bits32 kinds, const char *name, const char *desc,
    -				   trenary default_val, LOCKMODE lockmode)
    +			trenary default_val, const char* unset_alias, LOCKMODE lockmode)
     {
     	relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc,
    -												 default_val, lockmode);
    +											default_val, unset_alias, lockmode);
     
     	add_reloption((relopt_gen *) newoption);
     }
    @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc,
     void
     add_local_trenary_reloption(local_relopts *relopts, const char *name,
     							const char *desc, trenary default_val,
    -							int offset)
    +							const char* unset_alias, int offset)
     {
     	relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL,
     												name, desc,
    -												default_val, 0);
    +												default_val, unset_alias, 0);
     
     	add_local_reloption(relopts, (relopt_gen *) newoption, offset);
     }
    @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
     		case RELOPT_TYPE_TRENARY:
     			{
     				bool b;
    +				relopt_trenary *opt = (relopt_trenary *) option->gen;
    +
     				parsed = parse_bool(value, &b);
     				option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE;
    +
    +				if (!parsed && opt->unset_alias)
    +				{
    +					if (pg_strcasecmp(value, opt->unset_alias) == 0)
    +					{
    +						option->values.trenary_val = TRENARY_UNSET;
    +						parsed = true;
    +					}
    +				}
     				if (validate && !parsed)
     					ereport(ERROR,
     							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
     		offsetof(StdRdOptions, user_catalog_table)},
     		{"parallel_workers", RELOPT_TYPE_INT,
     		offsetof(StdRdOptions, parallel_workers)},
    -		{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
    +		{"vacuum_index_cleanup", RELOPT_TYPE_TRENARY,
     		offsetof(StdRdOptions, vacuum_index_cleanup)},
     		{"vacuum_truncate", RELOPT_TYPE_TRENARY,
     		offsetof(StdRdOptions, vacuum_truncate)},
    diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
    index 9b2ec9815f1..bff76dd859e 100644
    --- a/src/backend/access/gist/gistbuild.c
    +++ b/src/backend/access/gist/gistbuild.c
    @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
     	 */
     	if (options)
     	{
    -		if (options->buffering_mode == GIST_OPTION_BUFFERING_ON)
    +		if (options->buffering_mode == TRENARY_TRUE)
     			buildstate.buildMode = GIST_BUFFERING_STATS;
    -		else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF)
    +		else if (options->buffering_mode == TRENARY_FALSE)
     			buildstate.buildMode = GIST_BUFFERING_DISABLED;
     		else					/* must be "auto" */
     			buildstate.buildMode = GIST_BUFFERING_AUTO;
    diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
    index 7b96c7f9a80..779a6078ccb 100644
    --- a/src/backend/commands/vacuum.c
    +++ b/src/backend/commands/vacuum.c
    @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
     	 */
     	if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED)
     	{
    -		StdRdOptIndexCleanup vacuum_index_cleanup;
    +		trenary vacuum_index_cleanup;
     
     		if (rel->rd_options == NULL)
    -			vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
    +			vacuum_index_cleanup = TRENARY_UNSET;
     		else
     			vacuum_index_cleanup =
     				((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup;
     
    -		if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)
    +		if (vacuum_index_cleanup == TRENARY_UNSET)
     			params.index_cleanup = VACOPTVALUE_AUTO;
    -		else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON)
    +		else if (vacuum_index_cleanup == TRENARY_TRUE)
     			params.index_cleanup = VACOPTVALUE_ENABLED;
     		else
     		{
    -			Assert(vacuum_index_cleanup ==
    -				   STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF);
    +			Assert(vacuum_index_cleanup == TRENARY_FALSE);
     			params.index_cleanup = VACOPTVALUE_DISABLED;
     		}
     	}
    diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
    index 39404ec7cdb..527c19b6fdf 100644
    --- a/src/include/access/gist_private.h
    +++ b/src/include/access/gist_private.h
    @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers
     	int			rootlevel;
     } GISTBuildBuffers;
     
    -/* GiSTOptions->buffering_mode values */
    -typedef enum GistOptBufferingMode
    -{
    -	GIST_OPTION_BUFFERING_AUTO,
    -	GIST_OPTION_BUFFERING_ON,
    -	GIST_OPTION_BUFFERING_OFF,
    -} GistOptBufferingMode;
    -
     /*
      * Storage type for GiST's reloptions
      */
    @@ -395,7 +387,7 @@ typedef struct GiSTOptions
     {
     	int32		vl_len_;		/* varlena header (do not touch directly!) */
     	int			fillfactor;		/* page fill factor in percent (0..100) */
    -	GistOptBufferingMode buffering_mode;	/* buffering build mode */
    +	trenary		buffering_mode;	/* buffering build mode */
     } GiSTOptions;
     
     /* gist.c */
    diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
    index 1a6717ed213..5c8eb9e97f9 100644
    --- a/src/include/access/reloptions.h
    +++ b/src/include/access/reloptions.h
    @@ -99,6 +99,7 @@ typedef struct relopt_bool
     typedef struct relopt_rernary
     {
     	relopt_gen	gen;
    +	const char	*unset_alias; /* word that will be treaed as unset value */
     	int 		default_val;
     } relopt_trenary;
     
    @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void);
     extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc,
     							   bool default_val, LOCKMODE lockmode);
     extern void add_trenary_reloption(bits32 kinds, const char *name,
    -					const char *desc, int default_val, LOCKMODE lockmode);
    +					const char *desc, trenary default_val,
    +					const char* unset_alias, LOCKMODE lockmode);
     extern void add_int_reloption(bits32 kinds, const char *name, const char *desc,
     							  int default_val, int min_val, int max_val,
     							  LOCKMODE lockmode);
    @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name,
     									 int offset);
     extern void add_local_trenary_reloption(local_relopts *relopts,
     								const char *name, const char *desc,
    -								trenary default_val, int offset);
    +								trenary default_val, const char* unset_alias,
    +								int offset);
     extern void add_local_int_reloption(local_relopts *relopts, const char *name,
     									const char *desc, int default_val,
     									int min_val, int max_val, int offset);
    diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
    index 08f93bde007..1a1e818bd93 100644
    --- a/src/include/utils/rel.h
    +++ b/src/include/utils/rel.h
    @@ -329,14 +329,6 @@ typedef struct AutoVacOpts
     	float8		analyze_scale_factor;
     } AutoVacOpts;
     
    -/* StdRdOptions->vacuum_index_cleanup values */
    -typedef enum StdRdOptIndexCleanup
    -{
    -	STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0,
    -	STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF,
    -	STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
    -} StdRdOptIndexCleanup;
    -
     typedef struct StdRdOptions
     {
     	int32		vl_len_;		/* varlena header (do not touch directly!) */
    @@ -345,7 +337,7 @@ typedef struct StdRdOptions
     	AutoVacOpts autovacuum;		/* autovacuum-related options */
     	bool		user_catalog_table; /* use as an additional catalog relation */
     	int			parallel_workers;	/* max number of parallel workers */
    -	StdRdOptIndexCleanup vacuum_index_cleanup;	/* controls index vacuuming */
    +	trenary		vacuum_index_cleanup; /* controls index vacuuming */
     	trenary		vacuum_truncate;	/* enables vacuum to truncate a relation */
     
     	/*
    diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out
    index c75bbb23b6e..e7482c0faab 100644
    --- a/src/test/regress/expected/gist.out
    +++ b/src/test/regress/expected/gist.out
    @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au
     drop index gist_pointidx2, gist_pointidx3, gist_pointidx4;
     -- Make sure bad values are refused
     create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value);
    -ERROR:  invalid value for enum option "buffering": invalid_value
    -DETAIL:  Valid values are "on", "off", and "auto".
    +ERROR:  invalid value for trenary option "buffering": invalid_value
     create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9);
     ERROR:  value 9 out of bounds for option "fillfactor"
     DETAIL:  Valid values are between "10" and "100".
    -- 
    2.39.2
    
    
    --nextPart6784952.tM3a2QDmDi
    Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch"
    Content-Transfer-Encoding: 7Bit
    Content-Type: text/x-patch; charset="unicode-2-0-utf-8";
     name="v1-0004-Extra-tests.patch"