From f108e6c7e07c4148f097fbfd612cf79db60c5acd Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Mon, 24 Mar 2025 12:46:26 -0500
Subject: [PATCH 1/1] change vacuum_truncate relopt to enum

---
 src/backend/access/common/reloptions.c | 50 ++++++++++++++------------
 src/backend/commands/vacuum.c          |  4 +--
 src/include/access/reloptions.h        |  1 -
 src/include/utils/rel.h                | 11 ++++--
 src/tools/pgindent/typedefs.list       |  1 +
 5 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 645b5c00467..71a44d4cf1e 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -147,15 +147,6 @@ static relopt_bool boolRelOpts[] =
 		},
 		false
 	},
-	{
-		{
-			"vacuum_truncate",
-			"Enables vacuum to truncate empty pages at the end of this table",
-			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
-			ShareUpdateExclusiveLock
-		},
-		true
-	},
 	{
 		{
 			"deduplicate_items",
@@ -524,6 +515,20 @@ static relopt_enum_elt_def viewCheckOptValues[] =
 	{(const char *) NULL}		/* list terminator */
 };
 
+/* values from StdRdOptBool */
+static relopt_enum_elt_def StdRdOptBoolValues[] =
+{
+	{"on", STDRD_OPTION_BOOL_ON},
+	{"off", STDRD_OPTION_BOOL_OFF},
+	{"true", STDRD_OPTION_BOOL_ON},
+	{"false", STDRD_OPTION_BOOL_OFF},
+	{"yes", STDRD_OPTION_BOOL_ON},
+	{"no", STDRD_OPTION_BOOL_OFF},
+	{"1", STDRD_OPTION_BOOL_ON},
+	{"0", STDRD_OPTION_BOOL_OFF},
+	{(const char *) NULL}		/* list terminator */
+};
+
 static relopt_enum enumRelOpts[] =
 {
 	{
@@ -559,6 +564,17 @@ static relopt_enum enumRelOpts[] =
 		VIEW_OPTION_CHECK_OPTION_NOT_SET,
 		gettext_noop("Valid values are \"local\" and \"cascaded\".")
 	},
+	{
+		{
+			"vacuum_truncate",
+			"Enables vacuum to truncate empty pages at the end of this table",
+			RELOPT_KIND_HEAP | RELOPT_KIND_TOAST,
+			ShareUpdateExclusiveLock
+		},
+		StdRdOptBoolValues,
+		STDRD_OPTION_BOOL_NOT_SET,
+		gettext_noop("Valid values are \"on\" and \"off\".")
+	},
 	/* list terminator */
 	{{NULL}}
 };
@@ -1779,17 +1795,6 @@ fillRelOptions(void *rdopts, Size basesize,
 				char	   *itempos = ((char *) rdopts) + elems[j].offset;
 				char	   *string_val;
 
-				/*
-				 * If isset_offset is provided, store whether the reloption is
-				 * set there.
-				 */
-				if (elems[j].isset_offset > 0)
-				{
-					char	   *setpos = ((char *) rdopts) + elems[j].isset_offset;
-
-					*(bool *) setpos = options[i].isset;
-				}
-
 				switch (options[i].gen->type)
 				{
 					case RELOPT_TYPE_BOOL:
@@ -1911,8 +1916,8 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 		offsetof(StdRdOptions, parallel_workers)},
 		{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
 		offsetof(StdRdOptions, vacuum_index_cleanup)},
-		{"vacuum_truncate", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, vacuum_truncate), offsetof(StdRdOptions, vacuum_truncate_set)},
+		{"vacuum_truncate", RELOPT_TYPE_ENUM,
+		offsetof(StdRdOptions, vacuum_truncate)},
 		{"vacuum_max_eager_freeze_failure_rate", RELOPT_TYPE_REAL,
 		offsetof(StdRdOptions, vacuum_max_eager_freeze_failure_rate)}
 	};
@@ -1992,7 +1997,6 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
 		elems[i].optname = opt->option->name;
 		elems[i].opttype = opt->option->type;
 		elems[i].offset = opt->offset;
-		elems[i].isset_offset = 0;	/* not supported for local relopts yet */
 
 		i++;
 	}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index f0a7b87808d..7c725ea4b76 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -2206,9 +2206,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
 	{
 		StdRdOptions *opts = (StdRdOptions *) rel->rd_options;
 
-		if (opts && opts->vacuum_truncate_set)
+		if (opts && opts->vacuum_truncate != STDRD_OPTION_BOOL_NOT_SET)
 		{
-			if (opts->vacuum_truncate)
+			if (opts->vacuum_truncate == STDRD_OPTION_BOOL_ON)
 				params->truncate = VACOPTVALUE_ENABLED;
 			else
 				params->truncate = VACOPTVALUE_DISABLED;
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 146aed47c2d..43445cdcc6c 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -152,7 +152,6 @@ typedef struct
 	const char *optname;		/* option's name */
 	relopt_type opttype;		/* option's datatype */
 	int			offset;			/* offset of field in result struct */
-	int			isset_offset;	/* if > 0, offset of "is set" field */
 } relopt_parse_elt;
 
 /* Local reloption definition */
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index d94fddd7cef..d0c01f69abf 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -334,6 +334,14 @@ typedef enum StdRdOptIndexCleanup
 	STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
 } StdRdOptIndexCleanup;
 
+/* useful for Boolean relopts when we need to determine whether it's set */
+typedef enum StdRdOptBool
+{
+	STDRD_OPTION_BOOL_NOT_SET = 0,
+	STDRD_OPTION_BOOL_ON,
+	STDRD_OPTION_BOOL_OFF,
+} StdRdOptBool;
+
 typedef struct StdRdOptions
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
@@ -343,8 +351,7 @@ typedef struct StdRdOptions
 	bool		user_catalog_table; /* use as an additional catalog relation */
 	int			parallel_workers;	/* max number of parallel workers */
 	StdRdOptIndexCleanup vacuum_index_cleanup;	/* controls index vacuuming */
-	bool		vacuum_truncate;	/* enables vacuum to truncate a relation */
-	bool		vacuum_truncate_set;	/* whether vacuum_truncate is set */
+	StdRdOptBool vacuum_truncate;	/* enables vacuum to truncate a relation */
 
 	/*
 	 * Fraction of pages in a relation that vacuum can eagerly scan and fail
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3fbf5a4c212..ac530fb40e7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2818,6 +2818,7 @@ StatsData
 StatsElem
 StatsExtInfo
 StdAnalyzeData
+StdRdOptBool
 StdRdOptIndexCleanup
 StdRdOptions
 Step
-- 
2.39.5 (Apple Git-154)

