[PATCH] Proof of concept for GUC improvements

Started by David Christensenover 4 years ago18 messages
#1David Christensen
david.christensen@crunchydata.com
1 attachment(s)

-hackers,

Enclosed, find a POC patch that implements "special values" for int GUCs. We have quite a few GUCs
with values that have special meaning atop other settings. I have attempted to identify these and
make it so you can specify a symbol name for these values instead of just relying on the magic
number instead.

For instance, many GUCs have -1 for "disabled", so I've just made it so you can
specify something like:

SET log_min_duration_statement = disabled;

And the raw value will be set to -1 in this case. For the purposes of testing, I have also added a
new GUC "output_special_values" to affect whether `SHOW` or anything that relies on _ShowOption()
can show with the special value instead of just the raw magic value, allowing tools to consume the
original raw value, or provide the output to the user in the nicer format.

This has only been done for ints, and the passthru I did was very quick, so I have probably missed
some options that didn't explicitly have their interpretations in the file and/or I didn't know
about it already. I do not think there are these sorts of values in other non-int GUCs, but there
might be, so a similar approach could be taken to expand things to other config types in the future.

Let me know your thoughts; I personally find this to be useful, and would be a nicer way for some
configs to be displayed in the postgresql.conf file.

Best,

David

Attachments:

0001-POC-use-sentinel-values-for-parsing-outputting-speci.patchtext/x-patchDownload
From 68aef8f20d495bee14bbf27808beadecfb50612a Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Thu, 19 Aug 2021 14:33:15 -0500
Subject: [PATCH] POC: use sentinel values for parsing/outputting "special" int
 GUCs

Some GUCs include specific key values like "-1", etc, which have context beyond the actual value
involved.  Add support for providing synonyms for these values on input/output which make things a
lot easier to understand.

Add a new GUC output_special_values to enable the change of behavior on output; by default we leave
this alone, as there may be tools parsing/using these values as they currently output.

As far as I know, this "magic values" really only exists for ints; we can expand things similarly
for other types if the need arises.

For now, a non-exhaustive pass has been done through the config_int options list to identify
likely/needed values.  This will probably need to be tightened up in the future.

This code supports multiple values; it will stop at the first parsed found value and use that int
value.
---
 src/backend/utils/misc/guc.c      | 374 ++++++++++++++++++++----------
 src/include/utils/guc_tables.h    |   1 +
 src/test/regress/expected/guc.out |  45 ++++
 src/test/regress/sql/guc.sql      |  16 ++
 4 files changed, 308 insertions(+), 128 deletions(-)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a2e0f8de7e..f2f7f55ed7 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -235,6 +235,9 @@ static void assign_recovery_target_lsn(const char *newval, void *extra);
 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
 
+static bool parse_special_int(const struct config_enum_entry *options, const char *value, int *result);
+static bool special_int_to_value(const struct config_enum_entry *options, int value, const char **retval);
+
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
 												 bool applySettings, int elevel);
@@ -565,6 +568,57 @@ extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
 
+/* Some static structs for use in options which have -1 as special values;
+ * example: "disabled" or "inherited". While these are not enums per se, we
+ * are reusing the struct, with the bool field indicating whether to print the
+ * translated values on output */
+
+static const struct config_enum_entry special_auto[] = {
+	{"auto", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled[] = {
+	{"disabled", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled0[] = {
+	{"disabled", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled_all[] = {
+	{"disabled", -1, false},
+	{"all", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_default0[] = {
+	{"default", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_immediate0[] = {
+	{"immediate", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_none0[] = {
+	{"none", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited[] = {
+	{"unlimited", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited0[] = {
+	{"unlimited", 0, false},
+	{NULL, 0, false}
+};
+
 /*
  * GUC option variables that are exported from this module
  */
@@ -592,6 +646,8 @@ bool		check_function_bodies = true;
 bool		default_with_oids = false;
 bool		session_auth_is_superuser;
 
+bool		output_special_values = false;
+
 int			log_min_error_statement = ERROR;
 int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
@@ -2116,6 +2172,15 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"output_special_values", PGC_USERSET, CLIENT_CONN_OTHER,
+			gettext_noop("Whether to display \"special\" values in settings display."),
+		},
+		&output_special_values,
+		false,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -2134,7 +2199,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLogArchiveTimeout,
 		0, 0, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
@@ -2144,7 +2209,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostAuthDelay,
 		0, 0, INT_MAX / 1000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2154,7 +2219,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&default_statistics_target,
 		100, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2167,7 +2232,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&from_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2180,7 +2245,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&join_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2190,7 +2255,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&geqo_threshold,
 		12, 2, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2200,7 +2265,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_effort,
 		DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2210,7 +2275,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_pool_size,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2220,7 +2285,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_generations,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2232,7 +2297,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&DeadlockTimeout,
 		1000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2243,7 +2308,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_archive_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2254,7 +2319,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_streaming_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2265,7 +2330,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&recovery_min_apply_delay,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2276,7 +2341,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_status_interval,
 		10, 0, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2287,7 +2352,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2297,7 +2362,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&MaxConnections,
 		100, 1, MAX_BACKENDS,
-		check_maxconnections, NULL, NULL
+		check_maxconnections, NULL, NULL, NULL
 	},
 
 	{
@@ -2308,7 +2373,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ReservedBackends,
 		3, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2319,7 +2384,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_dynamic_shared_memory,
 		0, 0, (int) Min((size_t) INT_MAX, SIZE_MAX / (1024 * 1024)),
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2334,7 +2399,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&NBuffers,
 		1024, 16, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2345,7 +2410,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&num_temp_buffers,
 		1024, 100, INT_MAX / 2,
-		check_temp_buffers, NULL, NULL
+		check_temp_buffers, NULL, NULL, NULL
 	},
 
 	{
@@ -2355,7 +2420,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostPortNumber,
 		DEF_PGPORT, 1, 65535,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2370,7 +2435,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Unix_socket_permissions,
 		0777, 0000, 0777,
-		NULL, NULL, show_unix_socket_permissions
+		NULL, NULL, show_unix_socket_permissions, NULL
 	},
 
 	{
@@ -2384,7 +2449,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_file_mode,
 		0600, 0000, 0777,
-		NULL, NULL, show_log_file_mode
+		NULL, NULL, show_log_file_mode, NULL
 	},
 
 
@@ -2399,7 +2464,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&data_directory_mode,
 		0700, 0000, 0777,
-		NULL, NULL, show_data_directory_mode
+		NULL, NULL, show_data_directory_mode, NULL
 	},
 
 	{
@@ -2412,7 +2477,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&work_mem,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2423,7 +2488,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&maintenance_work_mem,
 		65536, 1024, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2435,7 +2500,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&logical_decoding_work_mem,
 		65536, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2451,7 +2516,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_stack_depth,
 		100, 100, MAX_KILOBYTES,
-		check_max_stack_depth, assign_max_stack_depth, NULL
+		check_max_stack_depth, assign_max_stack_depth, NULL, NULL
 	},
 
 	{
@@ -2462,7 +2527,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&temp_file_limit,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2472,7 +2537,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageHit,
 		1, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2482,7 +2547,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageMiss,
 		2, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2492,7 +2557,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageDirty,
 		20, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2502,7 +2567,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostLimit,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2512,7 +2577,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_cost_limit,
 		-1, -1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2522,7 +2587,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_files_per_process,
 		1000, 64, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2535,7 +2600,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_prepared_xacts,
 		0, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 #ifdef LOCK_DEBUG
@@ -2547,7 +2612,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_oidmin,
 		FirstNormalObjectId, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
@@ -2557,7 +2622,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_table,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 #endif
 
@@ -2569,7 +2634,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&StatementTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2580,7 +2645,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&LockTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2591,7 +2656,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleInTransactionSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2602,7 +2667,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2612,7 +2677,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_min_age,
 		50000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2622,7 +2687,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2632,7 +2697,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_min_age,
 		5000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2642,7 +2707,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2652,7 +2717,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_defer_cleanup_age,
 		0, 0, 1000000,			/* see ComputeXidHorizons */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2661,7 +2726,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_multixact_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2670,7 +2735,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2685,7 +2750,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2697,7 +2762,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2708,7 +2773,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_relation,
 		-2, INT_MIN, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2719,7 +2784,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_page,
 		2, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2730,7 +2795,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&AuthenticationTimeout,
 		60, 1, 600,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2742,7 +2807,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PreAuthDelay,
 		0, 0, 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2753,7 +2818,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_keep_size_mb,
 		0, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2765,7 +2830,7 @@ static struct config_int ConfigureNamesInt[] =
 		&min_wal_size_mb,
 		DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2777,7 +2842,7 @@ static struct config_int ConfigureNamesInt[] =
 		&max_wal_size_mb,
 		DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, assign_max_wal_size, NULL
+		NULL, assign_max_wal_size, NULL, NULL
 	},
 
 	{
@@ -2788,7 +2853,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointTimeout,
 		300, 30, 86400,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2802,7 +2867,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointWarning,
 		30, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2813,7 +2878,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&checkpoint_flush_after,
 		DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2824,7 +2889,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLOGbuffers,
 		-1, -1, (INT_MAX / XLOG_BLCKSZ),
-		check_wal_buffers, NULL, NULL
+		check_wal_buffers, NULL, NULL, special_auto
 	},
 
 	{
@@ -2835,7 +2900,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterDelay,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2846,7 +2911,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterFlushAfter,
 		(1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_immediate0
 	},
 
 	{
@@ -2857,7 +2922,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_skip_threshold,
 		2048, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2867,7 +2932,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_wal_senders,
 		10, 0, MAX_BACKENDS,
-		check_max_wal_senders, NULL, NULL
+		check_max_wal_senders, NULL, NULL, NULL
 	},
 
 	{
@@ -2878,7 +2943,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_replication_slots,
 		10, 0, MAX_BACKENDS /* XXX? */ ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2891,7 +2956,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_slot_wal_keep_size_mb,
 		-1, -1, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2902,7 +2967,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_sender_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2914,7 +2979,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitDelay,
 		0, 0, 100000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2925,7 +2990,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitSiblings,
 		5, 0, 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2938,7 +3003,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&extra_float_digits,
 		1, -15, 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2951,7 +3016,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_sample,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2963,7 +3028,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_statement,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2975,7 +3040,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_autovacuum_min_duration,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2986,7 +3051,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length,
 		-1, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2997,7 +3062,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length_on_error,
 		0, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3008,7 +3073,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&BgWriterDelay,
 		200, 10, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3018,7 +3083,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_lru_maxpages,
 		100, 0, INT_MAX / 2,	/* Same upper limit as shared_buffers */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3029,7 +3094,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_flush_after,
 		DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3047,7 +3112,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_effective_io_concurrency, NULL, NULL
+		check_effective_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3065,7 +3130,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_maintenance_io_concurrency, NULL, NULL
+		check_maintenance_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3076,7 +3141,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&backend_flush_after,
 		DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3088,7 +3153,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_worker_processes,
 		8, 0, MAX_BACKENDS,
-		check_max_worker_processes, NULL, NULL
+		check_max_worker_processes, NULL, NULL, NULL
 	},
 
 	{
@@ -3100,7 +3165,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_logical_replication_workers,
 		4, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3112,7 +3177,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_sync_workers_per_subscription,
 		2, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3123,7 +3188,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationAge,
 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3134,7 +3199,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationSize,
 		10 * 1024, 0, INT_MAX / 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3145,7 +3210,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_function_args,
 		FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3156,7 +3221,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_index_keys,
 		INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3167,7 +3232,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_identifier_length,
 		NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3178,7 +3243,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&block_size,
 		BLCKSZ, BLCKSZ, BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3189,7 +3254,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&segment_size,
 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3200,7 +3265,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_block_size,
 		XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3212,7 +3277,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_retrieve_retry_interval,
 		5000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3225,7 +3290,7 @@ static struct config_int ConfigureNamesInt[] =
 		DEFAULT_XLOG_SEG_SIZE,
 		WalSegMinSize,
 		WalSegMaxSize,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3236,7 +3301,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_naptime,
 		60, 1, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3245,7 +3310,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3254,7 +3319,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_ins_thresh,
 		1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 	{
 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3263,7 +3328,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_anl_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3278,7 +3343,7 @@ static struct config_int ConfigureNamesInt[] =
 		 * upper-limit value.
 		 */
 		200000000, 100000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3288,7 +3353,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_multixact_freeze_max_age,
 		400000000, 10000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see max_connections */
@@ -3298,7 +3363,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_max_workers,
 		3, 1, MAX_BACKENDS,
-		check_autovacuum_max_workers, NULL, NULL
+		check_autovacuum_max_workers, NULL, NULL, NULL
 	},
 
 	{
@@ -3308,7 +3373,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_maintenance_workers,
 		2, 0, 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3319,7 +3384,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers_per_gather,
 		2, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3330,7 +3395,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers,
 		8, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3341,7 +3406,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_work_mem,
 		-1, -1, MAX_KILOBYTES,
-		check_autovacuum_work_mem, NULL, NULL
+		check_autovacuum_work_mem, NULL, NULL, NULL
 	},
 
 	{
@@ -3352,7 +3417,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&old_snapshot_threshold,
 		-1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 
 	{
@@ -3363,7 +3428,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_idle,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
+		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle, special_default0
 	},
 
 	{
@@ -3374,7 +3439,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_interval,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
+		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval, special_default0
 	},
 
 	{
@@ -3385,7 +3450,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ssl_renegotiation_limit,
 		0, 0, 0,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3397,7 +3462,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_count,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
+		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count, special_default0
 	},
 
 	{
@@ -3408,7 +3473,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&GinFuzzySearchLimit,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3420,7 +3485,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&effective_cache_size,
 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3431,7 +3496,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_table_scan_size,
 		(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3442,7 +3507,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_index_scan_size,
 		(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3454,7 +3519,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&server_version_num,
 		PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3465,7 +3530,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_temp_files,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3476,7 +3541,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&pgstat_track_activity_query_size,
 		1024, 100, 1048576,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3487,7 +3552,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&gin_pending_list_limit,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3498,7 +3563,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_user_timeout,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
+		NULL, assign_tcp_user_timeout, show_tcp_user_timeout, special_default0
 	},
 
 	{
@@ -3532,7 +3597,7 @@ static struct config_int ConfigureNamesInt[] =
 #else							/* not DISCARD_CACHES_ENABLED */
 		0, 0, 0,
 #endif							/* not DISCARD_CACHES_ENABLED */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3543,12 +3608,12 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&client_connection_check_interval,
 		0, 0, INT_MAX,
-		check_client_connection_check_interval, NULL, NULL
+		check_client_connection_check_interval, NULL, NULL, special_disabled0
 	},
 
 	/* End-of-list marker */
 	{
-		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL, NULL
 	}
 };
 
@@ -6911,6 +6976,56 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
 	return true;
 }
 
+
+/*
+ * Lookup special values from an array of chars -> int (case-sensitive).
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false and retval is set to 0.
+ */
+bool
+parse_special_int(const struct config_enum_entry *options, const char *value,
+						   int *retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (pg_strcasecmp(value, entry->name) == 0)
+		{
+			*retval = entry->val;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+/*
+ * Lookup special values from an array of chars -> int (case-sensitive).
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false and retval is set to 0.
+ */
+bool
+special_int_to_value(const struct config_enum_entry *options, int value,
+						   const char **retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (value == entry->val)
+		{
+			*retval = entry->name;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+
 /*
  * Try to parse value as a floating point number in the usual format.
  * Optionally, the value can be followed by a unit name if "flags" indicates
@@ -6974,7 +7089,6 @@ parse_real(const char *value, double *result, int flags, const char **hintmsg)
 	return true;
 }
 
-
 /*
  * Lookup the name for an enum option with the selected value.
  * Should only ever be called with known-valid values, so throws
@@ -7121,8 +7235,8 @@ parse_and_validate_value(struct config_generic *record,
 				struct config_int *conf = (struct config_int *) record;
 				const char *hintmsg;
 
-				if (!parse_int(value, &newval->intval,
-							   conf->gen.flags, &hintmsg))
+				if (!(conf->special && parse_special_int(conf->special, value, &newval->intval)) &&
+					!parse_int(value, &newval->intval, conf->gen.flags, &hintmsg))
 				{
 					ereport(elevel,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -10123,7 +10237,11 @@ _ShowOption(struct config_generic *record, bool use_units)
 			{
 				struct config_int *conf = (struct config_int *) record;
 
-				if (conf->show_hook)
+				/* Special values are prioritized over show hooks */
+				if (output_special_values && conf->special && special_int_to_value(conf->special, *conf->variable, &val))
+					/* if return is true we have no special action to take here but val was set already */
+					;
+				else if (conf->show_hook)
 					val = conf->show_hook();
 				else
 				{
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 6b40f1eeb8..ef2b5aa4c2 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -197,6 +197,7 @@ struct config_int
 	GucIntCheckHook check_hook;
 	GucIntAssignHook assign_hook;
 	GucShowHook show_hook;
+	const struct config_enum_entry *special;
 	/* variable fields, initialized at runtime: */
 	int			reset_val;
 	void	   *reset_extra;
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 59da91ff04..af12c4d1c3 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -813,3 +813,48 @@ set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
 ERROR:  tables declared WITH OIDS are not supported
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index c39c11388d..b6a54e0290 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -311,3 +311,19 @@ reset check_function_bodies;
 set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
+
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
-- 
2.30.1 (Apple Git-130)

#2Vik Fearing
vik@postgresfriends.org
In reply to: David Christensen (#1)
Re: [PATCH] Proof of concept for GUC improvements

On 8/20/21 12:09 AM, David Christensen wrote:

-hackers,

Enclosed, find a POC patch that implements "special values" for int GUCs. We have quite a few GUCs
with values that have special meaning atop other settings. I have attempted to identify these and
make it so you can specify a symbol name for these values instead of just relying on the magic
number instead.

For instance, many GUCs have -1 for "disabled", so I've just made it so you can
specify something like:

SET log_min_duration_statement = disabled;

And the raw value will be set to -1 in this case. For the purposes of testing, I have also added a
new GUC "output_special_values" to affect whether `SHOW` or anything that relies on _ShowOption()
can show with the special value instead of just the raw magic value, allowing tools to consume the
original raw value, or provide the output to the user in the nicer format.

This has only been done for ints, and the passthru I did was very quick, so I have probably missed
some options that didn't explicitly have their interpretations in the file and/or I didn't know
about it already. I do not think there are these sorts of values in other non-int GUCs, but there
might be, so a similar approach could be taken to expand things to other config types in the future.

Let me know your thoughts; I personally find this to be useful, and would be a nicer way for some
configs to be displayed in the postgresql.conf file.

As discussed on IRC, I am in favor of this improvement. (I have not yet
looked at the patch.)
--
Vik Fearing

#3David Christensen
david.christensen@crunchydata.com
In reply to: David Christensen (#1)
Re: [PATCH] Proof of concept for GUC improvements

Hi,
For parse_special_int():

+ * true. If it's not found, return false and retval is set to 0.
...
+   /* don't touch the return value in other case */
+   return false;

It seems the two comments are not consistent with each other (retval is not set in case no entry is found).

For special_int_to_value():

+ * true. If it's not found, return false and retval is set to 0.

First, there is no assignment to retval at the end of the method. Second, retval points to string, so it shouldn't be set to 0.

Cheers

Thanks, I actually noticed on a re-read that the comments didn't
match, but they'll be fixed in the next version. (Will wait to collect
additional feedback.)

Functionality-wise, any thoughts on the overall approach or the specific patch?

Thanks,

David

#4Zhihong Yu
zyu@yugabyte.com
In reply to: David Christensen (#1)
Re: [PATCH] Proof of concept for GUC improvements

On Thu, Aug 19, 2021 at 3:17 PM David Christensen <
david.christensen@crunchydata.com> wrote:

-hackers,

Enclosed, find a POC patch that implements "special values" for int GUCs.
We have quite a few GUCs
with values that have special meaning atop other settings. I have
attempted to identify these and
make it so you can specify a symbol name for these values instead of just
relying on the magic
number instead.

For instance, many GUCs have -1 for "disabled", so I've just made it so
you can
specify something like:

SET log_min_duration_statement = disabled;

And the raw value will be set to -1 in this case. For the purposes of
testing, I have also added a
new GUC "output_special_values" to affect whether `SHOW` or anything that
relies on _ShowOption()
can show with the special value instead of just the raw magic value,
allowing tools to consume the
original raw value, or provide the output to the user in the nicer format.

This has only been done for ints, and the passthru I did was very quick,
so I have probably missed
some options that didn't explicitly have their interpretations in the file
and/or I didn't know
about it already. I do not think there are these sorts of values in other
non-int GUCs, but there
might be, so a similar approach could be taken to expand things to other
config types in the future.

Let me know your thoughts; I personally find this to be useful, and would
be a nicer way for some
configs to be displayed in the postgresql.conf file.

Best,

David

--

Hi,
For parse_special_int():

+ * true. If it's not found, return false and retval is set to 0.
...
+   /* don't touch the return value in other case */
+   return false;

It seems the two comments are not consistent with each other (retval is not
set in case no entry is found).

For special_int_to_value():

+ * true. If it's not found, return false and retval is set to 0.

First, there is no assignment to retval at the end of the method. Second,
retval points to string, so it shouldn't be set to 0.

Cheers

#5David G. Johnston
david.g.johnston@gmail.com
In reply to: David Christensen (#3)
Re: [PATCH] Proof of concept for GUC improvements

On Thu, Aug 19, 2021 at 3:44 PM David Christensen <
david.christensen@crunchydata.com> wrote:

Functionality-wise, any thoughts on the overall approach or the specific
patch?

If this information was exposed only by an addition to pg_settings, and
thus not changeable via a GUC or affecting SHOW, I think it would be more
likely to get accepted. Being more liberal in the accepting of these
values as input seems less problematic so that aspect could just stay. But
the display changes should be done with new outputs, not repurposing
existing ones.

I'm at -0.5 as to whether such a patch would actually be an improvement or
whether the added possibilities would just be confusing and, because it is
all optional, indefinitely so.

David J.

#6Michael Paquier
michael@paquier.xyz
In reply to: David G. Johnston (#5)
Re: [PATCH] Proof of concept for GUC improvements

On Thu, Aug 19, 2021 at 03:58:57PM -0700, David G. Johnston wrote:

I'm at -0.5 as to whether such a patch would actually be an improvement or
whether the added possibilities would just be confusing and, because it is
all optional, indefinitely so.

FWIW, I find this proposition of introducing a set of optional
synonyms to map with some special-case values we have in the
configurations a bit confusing, as that's basically introducing
enum-like options into GUCs that already have a type assigned.

The patch, with its set of options like special_disabled0,
special_disabled_all is not really easy to parse either so that's just
a recipe to make the set of synonyms to grow on an GUC-basis.

What I am wondering, though, is if there are cases in the existing
GUCs, with their existing types, where the situation of a default or
disabled value could be improved, though, to make the overall picture
more consistent.
--
Michael

#7David Christensen
david.christensen@crunchydata.com
In reply to: Michael Paquier (#6)
Re: [PATCH] Proof of concept for GUC improvements

On Fri, Aug 27, 2021 at 1:19 AM Michael Paquier <michael@paquier.xyz> wrote:

On Thu, Aug 19, 2021 at 03:58:57PM -0700, David G. Johnston wrote:

I'm at -0.5 as to whether such a patch would actually be an improvement or
whether the added possibilities would just be confusing and, because it is
all optional, indefinitely so.

FWIW, I find this proposition of introducing a set of optional
synonyms to map with some special-case values we have in the
configurations a bit confusing, as that's basically introducing
enum-like options into GUCs that already have a type assigned.

It does use enum-like mappings, but that is just because I needed to
tie together name + value and just reused the already similar data
structure. That could be changed if the code itself is less
understandable based on the struct names.

The patch, with its set of options like special_disabled0,
special_disabled_all is not really easy to parse either so that's just
a recipe to make the set of synonyms to grow on an GUC-basis.

Yes, when I started out on this, I expected maybe 2-3 different
interpretations at most, with more common overlap. I am not tied to
making *every* GUC support this; maybe we support the special_disabled
or special_disabled0 with differing names.

What I am wondering, though, is if there are cases in the existing
GUCs, with their existing types, where the situation of a default or
disabled value could be improved, though, to make the overall picture
more consistent.

I think this would be possible, although the benefit of what I've
written is that it doesn't change the interpretation of the value
anywhere else, just in GUC parsing (and optionally GUC display). The
parsing was where I felt this improved understanding, I'm less tied to
outputting in the "canonical" way.

#8Aleksander Alekseev
afiskon@gmail.com
In reply to: David Christensen (#7)
Re: [PATCH] Proof of concept for GUC improvements

It looks like this patch rotted a little and needs to be rebased. Please see http://cfbot.cputube.org/

The new status of this patch is: Waiting on Author

#9David Christensen
david.christensen@crunchydata.com
In reply to: David Christensen (#7)
1 attachment(s)
Re: [PATCH] Proof of concept for GUC improvements

Updated version attached with comment fixes and updated for new GUC.

Attachments:

special-guc-values-v2.patchapplication/octet-stream; name=special-guc-values-v2.patchDownload
From 2064ddfea2645dfb0aed4ef82de72e72ca27b728 Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Thu, 19 Aug 2021 14:33:15 -0500
Subject: [PATCH] POC: use sentinel values for parsing/outputting "special" int
 GUCs

Some GUCs include specific key values like "-1", etc, which have context beyond the actual value
involved.  Add support for providing synonyms for these values on input/output which make things a
lot easier to understand.

Add a new GUC output_special_values to enable the change of behavior on output; by default we leave
this alone, as there may be tools parsing/using these values as they currently output.

As far as I know, this "magic values" really only exists for ints; we can expand things similarly
for other types if the need arises.

For now, a non-exhaustive pass has been done through the config_int options list to identify
likely/needed values.  This will probably need to be tightened up in the future.

This code supports multiple values; it will stop at the first parsed found value and use that int
value.
---
 src/backend/utils/misc/guc.c      | 376 ++++++++++++++++++++----------
 src/include/utils/guc_tables.h    |   1 +
 src/test/regress/expected/guc.out |  45 ++++
 src/test/regress/sql/guc.sql      |  16 ++
 4 files changed, 309 insertions(+), 129 deletions(-)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 23236fa4c3..0c37228708 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -235,6 +235,9 @@ static void assign_recovery_target_lsn(const char *newval, void *extra);
 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
 
+static bool parse_special_int(const struct config_enum_entry *options, const char *value, int *result);
+static bool special_int_to_value(const struct config_enum_entry *options, int value, const char **retval);
+
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
 												 bool applySettings, int elevel);
@@ -565,6 +568,57 @@ extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
 
+/* Some static structs for use in options which have -1 as special values;
+ * example: "disabled" or "inherited". While these are not enums per se, we
+ * are reusing the struct, with the bool field indicating whether to print the
+ * translated values on output */
+
+static const struct config_enum_entry special_auto[] = {
+	{"auto", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled[] = {
+	{"disabled", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled0[] = {
+	{"disabled", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled_all[] = {
+	{"disabled", -1, false},
+	{"all", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_default0[] = {
+	{"default", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_immediate0[] = {
+	{"immediate", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_none0[] = {
+	{"none", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited[] = {
+	{"unlimited", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited0[] = {
+	{"unlimited", 0, false},
+	{NULL, 0, false}
+};
+
 /*
  * GUC option variables that are exported from this module
  */
@@ -592,6 +646,8 @@ bool		check_function_bodies = true;
 bool		default_with_oids = false;
 bool		session_auth_is_superuser;
 
+bool		output_special_values = false;
+
 int			log_min_error_statement = ERROR;
 int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
@@ -2117,6 +2173,15 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"output_special_values", PGC_USERSET, CLIENT_CONN_OTHER,
+			gettext_noop("Whether to display \"special\" values in settings display."),
+		},
+		&output_special_values,
+		false,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -2135,7 +2200,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLogArchiveTimeout,
 		0, 0, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
@@ -2145,7 +2210,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostAuthDelay,
 		0, 0, INT_MAX / 1000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2155,7 +2220,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&default_statistics_target,
 		100, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2168,7 +2233,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&from_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2181,7 +2246,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&join_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2191,7 +2256,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&geqo_threshold,
 		12, 2, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2201,7 +2266,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_effort,
 		DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2211,7 +2276,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_pool_size,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2221,7 +2286,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_generations,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2233,7 +2298,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&DeadlockTimeout,
 		1000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2244,7 +2309,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_archive_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2255,7 +2320,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_streaming_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2266,7 +2331,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&recovery_min_apply_delay,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2277,7 +2342,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_status_interval,
 		10, 0, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2288,7 +2353,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2298,7 +2363,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&MaxConnections,
 		100, 1, MAX_BACKENDS,
-		check_maxconnections, NULL, NULL
+		check_maxconnections, NULL, NULL, NULL
 	},
 
 	{
@@ -2309,7 +2374,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ReservedBackends,
 		3, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2320,7 +2385,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_dynamic_shared_memory,
 		0, 0, (int) Min((size_t) INT_MAX, SIZE_MAX / (1024 * 1024)),
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2335,7 +2400,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&NBuffers,
 		16384, 16, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2346,7 +2411,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&shared_memory_size_mb,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2357,7 +2422,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&num_temp_buffers,
 		1024, 100, INT_MAX / 2,
-		check_temp_buffers, NULL, NULL
+		check_temp_buffers, NULL, NULL, NULL
 	},
 
 	{
@@ -2367,7 +2432,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostPortNumber,
 		DEF_PGPORT, 1, 65535,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2382,7 +2447,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Unix_socket_permissions,
 		0777, 0000, 0777,
-		NULL, NULL, show_unix_socket_permissions
+		NULL, NULL, show_unix_socket_permissions, NULL
 	},
 
 	{
@@ -2396,7 +2461,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_file_mode,
 		0600, 0000, 0777,
-		NULL, NULL, show_log_file_mode
+		NULL, NULL, show_log_file_mode, NULL
 	},
 
 
@@ -2411,7 +2476,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&data_directory_mode,
 		0700, 0000, 0777,
-		NULL, NULL, show_data_directory_mode
+		NULL, NULL, show_data_directory_mode, NULL
 	},
 
 	{
@@ -2424,7 +2489,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&work_mem,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2435,7 +2500,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&maintenance_work_mem,
 		65536, 1024, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2447,7 +2512,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&logical_decoding_work_mem,
 		65536, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2463,7 +2528,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_stack_depth,
 		100, 100, MAX_KILOBYTES,
-		check_max_stack_depth, assign_max_stack_depth, NULL
+		check_max_stack_depth, assign_max_stack_depth, NULL, NULL
 	},
 
 	{
@@ -2474,7 +2539,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&temp_file_limit,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2484,7 +2549,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageHit,
 		1, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2494,7 +2559,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageMiss,
 		2, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2504,7 +2569,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageDirty,
 		20, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2514,7 +2579,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostLimit,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2524,7 +2589,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_cost_limit,
 		-1, -1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2534,7 +2599,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_files_per_process,
 		1000, 64, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2547,7 +2612,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_prepared_xacts,
 		0, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 #ifdef LOCK_DEBUG
@@ -2559,7 +2624,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_oidmin,
 		FirstNormalObjectId, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
@@ -2569,7 +2634,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_table,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 #endif
 
@@ -2581,7 +2646,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&StatementTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2592,7 +2657,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&LockTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2603,7 +2668,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleInTransactionSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2614,7 +2679,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2624,7 +2689,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_min_age,
 		50000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2634,7 +2699,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2644,7 +2709,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_min_age,
 		5000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2654,7 +2719,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2664,7 +2729,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_defer_cleanup_age,
 		0, 0, 1000000,			/* see ComputeXidHorizons */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2673,7 +2738,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_multixact_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2682,7 +2747,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2697,7 +2762,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2709,7 +2774,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2720,7 +2785,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_relation,
 		-2, INT_MIN, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2731,7 +2796,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_page,
 		2, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2742,7 +2807,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&AuthenticationTimeout,
 		60, 1, 600,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2754,7 +2819,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PreAuthDelay,
 		0, 0, 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2765,7 +2830,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_keep_size_mb,
 		0, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2777,7 +2842,7 @@ static struct config_int ConfigureNamesInt[] =
 		&min_wal_size_mb,
 		DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2789,7 +2854,7 @@ static struct config_int ConfigureNamesInt[] =
 		&max_wal_size_mb,
 		DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, assign_max_wal_size, NULL
+		NULL, assign_max_wal_size, NULL, NULL
 	},
 
 	{
@@ -2800,7 +2865,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointTimeout,
 		300, 30, 86400,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2814,7 +2879,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointWarning,
 		30, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2825,7 +2890,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&checkpoint_flush_after,
 		DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2836,7 +2901,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLOGbuffers,
 		-1, -1, (INT_MAX / XLOG_BLCKSZ),
-		check_wal_buffers, NULL, NULL
+		check_wal_buffers, NULL, NULL, special_auto
 	},
 
 	{
@@ -2847,7 +2912,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterDelay,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2858,7 +2923,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterFlushAfter,
 		(1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_immediate0
 	},
 
 	{
@@ -2869,7 +2934,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_skip_threshold,
 		2048, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2879,7 +2944,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_wal_senders,
 		10, 0, MAX_BACKENDS,
-		check_max_wal_senders, NULL, NULL
+		check_max_wal_senders, NULL, NULL, NULL
 	},
 
 	{
@@ -2890,7 +2955,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_replication_slots,
 		10, 0, MAX_BACKENDS /* XXX? */ ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2903,7 +2968,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_slot_wal_keep_size_mb,
 		-1, -1, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2914,7 +2979,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_sender_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2926,7 +2991,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitDelay,
 		0, 0, 100000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2937,7 +3002,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitSiblings,
 		5, 0, 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2950,7 +3015,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&extra_float_digits,
 		1, -15, 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2963,7 +3028,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_sample,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2975,7 +3040,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_statement,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2987,7 +3052,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_autovacuum_min_duration,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2998,7 +3063,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length,
 		-1, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3009,7 +3074,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length_on_error,
 		0, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3020,7 +3085,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&BgWriterDelay,
 		200, 10, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3030,7 +3095,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_lru_maxpages,
 		100, 0, INT_MAX / 2,	/* Same upper limit as shared_buffers */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3041,7 +3106,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_flush_after,
 		DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3059,7 +3124,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_effective_io_concurrency, NULL, NULL
+		check_effective_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3077,7 +3142,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_maintenance_io_concurrency, NULL, NULL
+		check_maintenance_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3088,7 +3153,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&backend_flush_after,
 		DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3100,7 +3165,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_worker_processes,
 		8, 0, MAX_BACKENDS,
-		check_max_worker_processes, NULL, NULL
+		check_max_worker_processes, NULL, NULL, NULL
 	},
 
 	{
@@ -3112,7 +3177,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_logical_replication_workers,
 		4, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3124,7 +3189,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_sync_workers_per_subscription,
 		2, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3135,7 +3200,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationAge,
 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3146,7 +3211,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationSize,
 		10 * 1024, 0, INT_MAX / 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3157,7 +3222,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_function_args,
 		FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3168,7 +3233,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_index_keys,
 		INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3179,7 +3244,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_identifier_length,
 		NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3190,7 +3255,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&block_size,
 		BLCKSZ, BLCKSZ, BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3201,7 +3266,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&segment_size,
 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3212,7 +3277,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_block_size,
 		XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3224,7 +3289,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_retrieve_retry_interval,
 		5000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3237,7 +3302,7 @@ static struct config_int ConfigureNamesInt[] =
 		DEFAULT_XLOG_SEG_SIZE,
 		WalSegMinSize,
 		WalSegMaxSize,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3248,7 +3313,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_naptime,
 		60, 1, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3257,7 +3322,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3266,7 +3331,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_ins_thresh,
 		1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 	{
 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3275,7 +3340,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_anl_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3290,7 +3355,7 @@ static struct config_int ConfigureNamesInt[] =
 		 * upper-limit value.
 		 */
 		200000000, 100000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3300,7 +3365,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_multixact_freeze_max_age,
 		400000000, 10000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see max_connections */
@@ -3310,7 +3375,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_max_workers,
 		3, 1, MAX_BACKENDS,
-		check_autovacuum_max_workers, NULL, NULL
+		check_autovacuum_max_workers, NULL, NULL, NULL
 	},
 
 	{
@@ -3320,7 +3385,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_maintenance_workers,
 		2, 0, 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3331,7 +3396,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers_per_gather,
 		2, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3342,7 +3407,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers,
 		8, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3353,7 +3418,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_work_mem,
 		-1, -1, MAX_KILOBYTES,
-		check_autovacuum_work_mem, NULL, NULL
+		check_autovacuum_work_mem, NULL, NULL, NULL
 	},
 
 	{
@@ -3364,7 +3429,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&old_snapshot_threshold,
 		-1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 
 	{
@@ -3375,7 +3440,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_idle,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
+		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle, special_default0
 	},
 
 	{
@@ -3386,7 +3451,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_interval,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
+		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval, special_default0
 	},
 
 	{
@@ -3397,7 +3462,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ssl_renegotiation_limit,
 		0, 0, 0,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3409,7 +3474,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_count,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
+		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count, special_default0
 	},
 
 	{
@@ -3420,7 +3485,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&GinFuzzySearchLimit,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3432,7 +3497,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&effective_cache_size,
 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3443,7 +3508,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_table_scan_size,
 		(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3454,7 +3519,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_index_scan_size,
 		(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3466,7 +3531,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&server_version_num,
 		PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3477,7 +3542,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_temp_files,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3488,7 +3553,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&pgstat_track_activity_query_size,
 		1024, 100, 1048576,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3499,7 +3564,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&gin_pending_list_limit,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3510,7 +3575,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_user_timeout,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
+		NULL, assign_tcp_user_timeout, show_tcp_user_timeout, special_default0
 	},
 
 	{
@@ -3544,7 +3609,7 @@ static struct config_int ConfigureNamesInt[] =
 #else							/* not DISCARD_CACHES_ENABLED */
 		0, 0, 0,
 #endif							/* not DISCARD_CACHES_ENABLED */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3555,12 +3620,12 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&client_connection_check_interval,
 		0, 0, INT_MAX,
-		check_client_connection_check_interval, NULL, NULL
+		check_client_connection_check_interval, NULL, NULL, special_disabled0
 	},
 
 	/* End-of-list marker */
 	{
-		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL, NULL
 	}
 };
 
@@ -6923,6 +6988,56 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
 	return true;
 }
 
+
+/*
+ * Lookup special values from an array of chars -> int (case-sensitive).
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false and leave retval alone.
+ */
+bool
+parse_special_int(const struct config_enum_entry *options, const char *value,
+						   int *retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (pg_strcasecmp(value, entry->name) == 0)
+		{
+			*retval = entry->val;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+/*
+ * Lookup special values by int value and set to static string.
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false.
+ */
+bool
+special_int_to_value(const struct config_enum_entry *options, int value,
+						   const char **retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (value == entry->val)
+		{
+			*retval = entry->name;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+
 /*
  * Try to parse value as a floating point number in the usual format.
  * Optionally, the value can be followed by a unit name if "flags" indicates
@@ -6986,7 +7101,6 @@ parse_real(const char *value, double *result, int flags, const char **hintmsg)
 	return true;
 }
 
-
 /*
  * Lookup the name for an enum option with the selected value.
  * Should only ever be called with known-valid values, so throws
@@ -7133,8 +7247,8 @@ parse_and_validate_value(struct config_generic *record,
 				struct config_int *conf = (struct config_int *) record;
 				const char *hintmsg;
 
-				if (!parse_int(value, &newval->intval,
-							   conf->gen.flags, &hintmsg))
+				if (!(conf->special && parse_special_int(conf->special, value, &newval->intval)) &&
+					!parse_int(value, &newval->intval, conf->gen.flags, &hintmsg))
 				{
 					ereport(elevel,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -10134,7 +10248,11 @@ _ShowOption(struct config_generic *record, bool use_units)
 			{
 				struct config_int *conf = (struct config_int *) record;
 
-				if (conf->show_hook)
+				/* Special values are prioritized over show hooks */
+				if (output_special_values && conf->special && special_int_to_value(conf->special, *conf->variable, &val))
+					/* if return is true we have no special action to take here but val was set already */
+					;
+				else if (conf->show_hook)
 					val = conf->show_hook();
 				else
 				{
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 6b40f1eeb8..ef2b5aa4c2 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -197,6 +197,7 @@ struct config_int
 	GucIntCheckHook check_hook;
 	GucIntAssignHook assign_hook;
 	GucShowHook show_hook;
+	const struct config_enum_entry *special;
 	/* variable fields, initialized at runtime: */
 	int			reset_val;
 	void	   *reset_extra;
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 59da91ff04..af12c4d1c3 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -813,3 +813,48 @@ set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
 ERROR:  tables declared WITH OIDS are not supported
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index c39c11388d..b6a54e0290 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -311,3 +311,19 @@ reset check_function_bodies;
 set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
+
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
-- 
2.30.1 (Apple Git-130)

#10Cary Huang
cary.huang@highgo.ca
In reply to: David Christensen (#9)
Re: [PATCH] Proof of concept for GUC improvements

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: not tested

Hi

I quite like the feature this patch provides, it makes special int values more meaningful to user. I like that you added a configuration to allow the original int value to be outputted or the special value, this adds some flexibility in case returning special value breaks some old applications. I scanned through the GUC list and found that the following parameters can potentially be categorized in the "special_disabled0" group,
just for your reference.

max_prepared_transactions
vacuum_cost_delay
effective_io_concurrency
max_parallel_workers
max_parallel_maintenance_workers
max_parallel_workers_per_gather
max_logical_replication_workers
max_sync_workers_per_subscription
jit_above_cost
jit_inline_above_cost
jit_optimize_above_cost
log_rotation_age
log_rotation_size
log_transaction_sample_rate

Cary Huang
-----------------
HighGo Software Canada
www.highgo.ca

#11Daniel Gustafsson
daniel@yesql.se
In reply to: Cary Huang (#10)
Re: [PATCH] Proof of concept for GUC improvements

On 15 Oct 2021, at 23:54, Cary Huang <cary.huang@highgo.ca> wrote:

I scanned through the GUC list and found that the following parameters can
potentially be categorized in the "special_disabled0" group, just for your
reference.

This patch no longer applies, can you please submit a rebased version? Also,
do you have any thoughts on Cary's suggestion in the above review?

--
Daniel Gustafsson https://vmware.com/

#12David Christensen
david@pgguru.net
In reply to: Daniel Gustafsson (#11)
1 attachment(s)
Re: [PATCH] Proof of concept for GUC improvements

On Nov 3, 2021, at 5:35 AM, Daniel Gustafsson <daniel@yesql.se> wrote:



On 15 Oct 2021, at 23:54, Cary Huang <cary.huang@highgo.ca> wrote:

I scanned through the GUC list and found that the following parameters can
potentially be categorized in the "special_disabled0" group, just for your
reference.

This patch no longer applies, can you please submit a rebased version? Also,
do you have any thoughts on Cary's suggestion in the above review?

Hi, enclosed is a v3, which includes the rebase as well as the additional int GUCs mentioned in Cary’s review. I can add support for Reals (required for the JIT and several other ones), but wanted to get feedback/buy-in on the overall idea first.

Best,

David

Attachments:

special-guc-values-v3.patchapplication/octet-stream; name=special-guc-values-v3.patch; x-apple-part-url=9B35CFF4-BD80-4CB3-BEF6-B67F87EA3902Download
From 5aa187282341bc55b65cb62a9d20bf8f52064d5a Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Thu, 19 Aug 2021 14:33:15 -0500
Subject: [PATCH] POC: use sentinel values for parsing/outputting "special" int
 GUCs

Some GUCs include specific key values like "-1", etc, which have context beyond the actual value
involved.  Add support for providing synonyms for these values on input/output which make things a
lot easier to understand.

Add a new GUC output_special_values to enable the change of behavior on output; by default we leave
this alone, as there may be tools parsing/using these values as they currently output.

As far as I know, this "magic values" really only exists for ints; we can expand things similarly
for other types if the need arises.

For now, a non-exhaustive pass has been done through the config_int options list to identify
likely/needed values.  This will probably need to be tightened up in the future.

This code supports multiple values; it will stop at the first parsed found value and use that int
value.
---
 src/backend/utils/misc/guc.c      | 376 ++++++++++++++++++++----------
 src/include/utils/guc_tables.h    |   1 +
 src/test/regress/expected/guc.out |  45 ++++
 src/test/regress/sql/guc.sql      |  16 ++
 4 files changed, 309 insertions(+), 129 deletions(-)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e91d5a3cfd..1fd0b0ace7 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -236,6 +236,9 @@ static void assign_recovery_target_lsn(const char *newval, void *extra);
 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
 
+static bool parse_special_int(const struct config_enum_entry *options, const char *value, int *result);
+static bool special_int_to_value(const struct config_enum_entry *options, int value, const char **retval);
+
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
 												 bool applySettings, int elevel);
@@ -566,6 +569,57 @@ extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
 
+/* Some static structs for use in options which have -1 as special values;
+ * example: "disabled" or "inherited". While these are not enums per se, we
+ * are reusing the struct, with the bool field indicating whether to print the
+ * translated values on output */
+
+static const struct config_enum_entry special_auto[] = {
+	{"auto", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled[] = {
+	{"disabled", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled0[] = {
+	{"disabled", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled_all[] = {
+	{"disabled", -1, false},
+	{"all", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_default0[] = {
+	{"default", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_immediate0[] = {
+	{"immediate", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_none0[] = {
+	{"none", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited[] = {
+	{"unlimited", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited0[] = {
+	{"unlimited", 0, false},
+	{NULL, 0, false}
+};
+
 /*
  * GUC option variables that are exported from this module
  */
@@ -593,6 +647,8 @@ bool		check_function_bodies = true;
 bool		default_with_oids = false;
 bool		session_auth_is_superuser;
 
+bool		output_special_values = false;
+
 int			log_min_error_statement = ERROR;
 int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
@@ -2119,6 +2175,15 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"output_special_values", PGC_USERSET, CLIENT_CONN_OTHER,
+			gettext_noop("Whether to display \"special\" values in settings display."),
+		},
+		&output_special_values,
+		false,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -2137,7 +2202,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLogArchiveTimeout,
 		0, 0, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
@@ -2147,7 +2212,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostAuthDelay,
 		0, 0, INT_MAX / 1000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2157,7 +2222,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&default_statistics_target,
 		100, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2170,7 +2235,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&from_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2183,7 +2248,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&join_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2193,7 +2258,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&geqo_threshold,
 		12, 2, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2203,7 +2268,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_effort,
 		DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2213,7 +2278,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_pool_size,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2223,7 +2288,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_generations,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2235,7 +2300,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&DeadlockTimeout,
 		1000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2246,7 +2311,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_archive_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2257,7 +2322,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_streaming_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2268,7 +2333,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&recovery_min_apply_delay,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2279,7 +2344,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_status_interval,
 		10, 0, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2290,7 +2355,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2300,7 +2365,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&MaxConnections,
 		100, 1, MAX_BACKENDS,
-		check_maxconnections, NULL, NULL
+		check_maxconnections, NULL, NULL, NULL
 	},
 
 	{
@@ -2311,7 +2376,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ReservedBackends,
 		3, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2322,7 +2387,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_dynamic_shared_memory,
 		0, 0, (int) Min((size_t) INT_MAX, SIZE_MAX / (1024 * 1024)),
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2337,7 +2402,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&NBuffers,
 		16384, 16, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2348,7 +2413,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&shared_memory_size_mb,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2370,7 +2435,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&num_temp_buffers,
 		1024, 100, INT_MAX / 2,
-		check_temp_buffers, NULL, NULL
+		check_temp_buffers, NULL, NULL, NULL
 	},
 
 	{
@@ -2380,7 +2445,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostPortNumber,
 		DEF_PGPORT, 1, 65535,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2395,7 +2460,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Unix_socket_permissions,
 		0777, 0000, 0777,
-		NULL, NULL, show_unix_socket_permissions
+		NULL, NULL, show_unix_socket_permissions, NULL
 	},
 
 	{
@@ -2409,7 +2474,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_file_mode,
 		0600, 0000, 0777,
-		NULL, NULL, show_log_file_mode
+		NULL, NULL, show_log_file_mode, NULL
 	},
 
 
@@ -2424,7 +2489,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&data_directory_mode,
 		0700, 0000, 0777,
-		NULL, NULL, show_data_directory_mode
+		NULL, NULL, show_data_directory_mode, NULL
 	},
 
 	{
@@ -2437,7 +2502,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&work_mem,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2448,7 +2513,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&maintenance_work_mem,
 		65536, 1024, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2460,7 +2525,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&logical_decoding_work_mem,
 		65536, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2476,7 +2541,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_stack_depth,
 		100, 100, MAX_KILOBYTES,
-		check_max_stack_depth, assign_max_stack_depth, NULL
+		check_max_stack_depth, assign_max_stack_depth, NULL, NULL
 	},
 
 	{
@@ -2487,7 +2552,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&temp_file_limit,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2497,7 +2562,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageHit,
 		1, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2507,7 +2572,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageMiss,
 		2, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2517,7 +2582,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageDirty,
 		20, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2527,7 +2592,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostLimit,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2537,7 +2602,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_cost_limit,
 		-1, -1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2547,7 +2612,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_files_per_process,
 		1000, 64, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2560,7 +2625,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_prepared_xacts,
 		0, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 #ifdef LOCK_DEBUG
@@ -2572,7 +2637,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_oidmin,
 		FirstNormalObjectId, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
@@ -2582,7 +2647,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_table,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 #endif
 
@@ -2594,7 +2659,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&StatementTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2605,7 +2670,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&LockTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2616,7 +2681,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleInTransactionSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2627,7 +2692,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2637,7 +2702,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_min_age,
 		50000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2647,7 +2712,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2657,7 +2722,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_min_age,
 		5000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2667,7 +2732,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2677,7 +2742,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_defer_cleanup_age,
 		0, 0, 1000000,			/* see ComputeXidHorizons */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2686,7 +2751,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_multixact_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2695,7 +2760,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2710,7 +2775,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2722,7 +2787,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2733,7 +2798,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_relation,
 		-2, INT_MIN, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2744,7 +2809,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_page,
 		2, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2755,7 +2820,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&AuthenticationTimeout,
 		60, 1, 600,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2767,7 +2832,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PreAuthDelay,
 		0, 0, 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2778,7 +2843,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_keep_size_mb,
 		0, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2790,7 +2855,7 @@ static struct config_int ConfigureNamesInt[] =
 		&min_wal_size_mb,
 		DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2802,7 +2867,7 @@ static struct config_int ConfigureNamesInt[] =
 		&max_wal_size_mb,
 		DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, assign_max_wal_size, NULL
+		NULL, assign_max_wal_size, NULL, NULL
 	},
 
 	{
@@ -2813,7 +2878,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointTimeout,
 		300, 30, 86400,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2827,7 +2892,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointWarning,
 		30, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2838,7 +2903,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&checkpoint_flush_after,
 		DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2849,7 +2914,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLOGbuffers,
 		-1, -1, (INT_MAX / XLOG_BLCKSZ),
-		check_wal_buffers, NULL, NULL
+		check_wal_buffers, NULL, NULL, special_auto
 	},
 
 	{
@@ -2860,7 +2925,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterDelay,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2871,7 +2936,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterFlushAfter,
 		(1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_immediate0
 	},
 
 	{
@@ -2882,7 +2947,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_skip_threshold,
 		2048, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2892,7 +2957,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_wal_senders,
 		10, 0, MAX_BACKENDS,
-		check_max_wal_senders, NULL, NULL
+		check_max_wal_senders, NULL, NULL, NULL
 	},
 
 	{
@@ -2903,7 +2968,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_replication_slots,
 		10, 0, MAX_BACKENDS /* XXX? */ ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2916,7 +2981,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_slot_wal_keep_size_mb,
 		-1, -1, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2927,7 +2992,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_sender_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2939,7 +3004,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitDelay,
 		0, 0, 100000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2950,7 +3015,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitSiblings,
 		5, 0, 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2963,7 +3028,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&extra_float_digits,
 		1, -15, 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2976,7 +3041,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_sample,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2988,7 +3053,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_statement,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3000,7 +3065,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_autovacuum_min_duration,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3011,7 +3076,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length,
 		-1, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3022,7 +3087,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length_on_error,
 		0, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3033,7 +3098,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&BgWriterDelay,
 		200, 10, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3043,7 +3108,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_lru_maxpages,
 		100, 0, INT_MAX / 2,	/* Same upper limit as shared_buffers */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3054,7 +3119,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_flush_after,
 		DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3072,7 +3137,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_effective_io_concurrency, NULL, NULL
+		check_effective_io_concurrency, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3090,7 +3155,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_maintenance_io_concurrency, NULL, NULL
+		check_maintenance_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3101,7 +3166,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&backend_flush_after,
 		DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3113,7 +3178,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_worker_processes,
 		8, 0, MAX_BACKENDS,
-		check_max_worker_processes, NULL, NULL
+		check_max_worker_processes, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3125,7 +3190,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_logical_replication_workers,
 		4, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3137,7 +3202,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_sync_workers_per_subscription,
 		2, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3148,7 +3213,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationAge,
 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3159,7 +3224,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationSize,
 		10 * 1024, 0, INT_MAX / 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3170,7 +3235,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_function_args,
 		FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3181,7 +3246,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_index_keys,
 		INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3192,7 +3257,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_identifier_length,
 		NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3203,7 +3268,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&block_size,
 		BLCKSZ, BLCKSZ, BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3214,7 +3279,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&segment_size,
 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3225,7 +3290,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_block_size,
 		XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3237,7 +3302,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_retrieve_retry_interval,
 		5000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3250,7 +3315,7 @@ static struct config_int ConfigureNamesInt[] =
 		DEFAULT_XLOG_SEG_SIZE,
 		WalSegMinSize,
 		WalSegMaxSize,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3261,7 +3326,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_naptime,
 		60, 1, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3270,7 +3335,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3279,7 +3344,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_ins_thresh,
 		1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 	{
 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3288,7 +3353,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_anl_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3303,7 +3368,7 @@ static struct config_int ConfigureNamesInt[] =
 		 * upper-limit value.
 		 */
 		200000000, 100000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3313,7 +3378,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_multixact_freeze_max_age,
 		400000000, 10000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see max_connections */
@@ -3323,7 +3388,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_max_workers,
 		3, 1, MAX_BACKENDS,
-		check_autovacuum_max_workers, NULL, NULL
+		check_autovacuum_max_workers, NULL, NULL, NULL
 	},
 
 	{
@@ -3333,7 +3398,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_maintenance_workers,
 		2, 0, 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3344,7 +3409,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers_per_gather,
 		2, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3355,7 +3420,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers,
 		8, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3366,7 +3431,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_work_mem,
 		-1, -1, MAX_KILOBYTES,
-		check_autovacuum_work_mem, NULL, NULL
+		check_autovacuum_work_mem, NULL, NULL, NULL
 	},
 
 	{
@@ -3377,7 +3442,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&old_snapshot_threshold,
 		-1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 
 	{
@@ -3388,7 +3453,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_idle,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
+		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle, special_default0
 	},
 
 	{
@@ -3399,7 +3464,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_interval,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
+		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval, special_default0
 	},
 
 	{
@@ -3410,7 +3475,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ssl_renegotiation_limit,
 		0, 0, 0,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3422,7 +3487,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_count,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
+		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count, special_default0
 	},
 
 	{
@@ -3433,7 +3498,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&GinFuzzySearchLimit,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3445,7 +3510,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&effective_cache_size,
 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3456,7 +3521,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_table_scan_size,
 		(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3467,7 +3532,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_index_scan_size,
 		(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3479,7 +3544,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&server_version_num,
 		PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3490,7 +3555,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_temp_files,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3501,7 +3566,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&pgstat_track_activity_query_size,
 		1024, 100, 1048576,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3512,7 +3577,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&gin_pending_list_limit,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3523,7 +3588,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_user_timeout,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
+		NULL, assign_tcp_user_timeout, show_tcp_user_timeout, special_default0
 	},
 
 	{
@@ -3557,7 +3622,7 @@ static struct config_int ConfigureNamesInt[] =
 #else							/* not DISCARD_CACHES_ENABLED */
 		0, 0, 0,
 #endif							/* not DISCARD_CACHES_ENABLED */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3568,7 +3633,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&client_connection_check_interval,
 		0, 0, INT_MAX,
-		check_client_connection_check_interval, NULL, NULL
+		check_client_connection_check_interval, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3585,7 +3650,7 @@ static struct config_int ConfigureNamesInt[] =
 
 	/* End-of-list marker */
 	{
-		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL, NULL
 	}
 };
 
@@ -6948,6 +7013,56 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
 	return true;
 }
 
+
+/*
+ * Lookup special values from an array of chars -> int (case-sensitive).
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false and leave retval alone.
+ */
+bool
+parse_special_int(const struct config_enum_entry *options, const char *value,
+						   int *retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (pg_strcasecmp(value, entry->name) == 0)
+		{
+			*retval = entry->val;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+/*
+ * Lookup special values by int value and set to static string.
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false.
+ */
+bool
+special_int_to_value(const struct config_enum_entry *options, int value,
+						   const char **retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (value == entry->val)
+		{
+			*retval = entry->name;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+
 /*
  * Try to parse value as a floating point number in the usual format.
  * Optionally, the value can be followed by a unit name if "flags" indicates
@@ -7011,7 +7126,6 @@ parse_real(const char *value, double *result, int flags, const char **hintmsg)
 	return true;
 }
 
-
 /*
  * Lookup the name for an enum option with the selected value.
  * Should only ever be called with known-valid values, so throws
@@ -7158,8 +7272,8 @@ parse_and_validate_value(struct config_generic *record,
 				struct config_int *conf = (struct config_int *) record;
 				const char *hintmsg;
 
-				if (!parse_int(value, &newval->intval,
-							   conf->gen.flags, &hintmsg))
+				if (!(conf->special && parse_special_int(conf->special, value, &newval->intval)) &&
+					!parse_int(value, &newval->intval, conf->gen.flags, &hintmsg))
 				{
 					ereport(elevel,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -10159,7 +10273,11 @@ _ShowOption(struct config_generic *record, bool use_units)
 			{
 				struct config_int *conf = (struct config_int *) record;
 
-				if (conf->show_hook)
+				/* Special values are prioritized over show hooks */
+				if (output_special_values && conf->special && special_int_to_value(conf->special, *conf->variable, &val))
+					/* if return is true we have no special action to take here but val was set already */
+					;
+				else if (conf->show_hook)
 					val = conf->show_hook();
 				else
 				{
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 6b40f1eeb8..ef2b5aa4c2 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -197,6 +197,7 @@ struct config_int
 	GucIntCheckHook check_hook;
 	GucIntAssignHook assign_hook;
 	GucShowHook show_hook;
+	const struct config_enum_entry *special;
 	/* variable fields, initialized at runtime: */
 	int			reset_val;
 	void	   *reset_extra;
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 59da91ff04..af12c4d1c3 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -813,3 +813,48 @@ set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
 ERROR:  tables declared WITH OIDS are not supported
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index c39c11388d..b6a54e0290 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -311,3 +311,19 @@ reset check_function_bodies;
 set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
+
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
-- 
2.30.1 (Apple Git-130)

#13Julien Rouhaud
rjuju123@gmail.com
In reply to: David Christensen (#12)
Re: [PATCH] Proof of concept for GUC improvements

Hi,

On Thu, Nov 4, 2021 at 5:50 AM David Christensen <david@pgguru.net> wrote:

Hi, enclosed is a v3 [...]

According to the cfbot, the patch doesn't apply anymore and needs a
rebase: http://cfbot.cputube.org/patch_36_3290.log

43 out of 133 hunks FAILED -- saving rejects to file src/backend/utils/misc/guc.c.rej

I'm switching the patch to Waiting on Author.

#14David Christensen
david@pgguru.net
In reply to: Julien Rouhaud (#13)
1 attachment(s)
Re: [PATCH] Proof of concept for GUC improvements

Hi,

According to the cfbot, the patch doesn't apply anymore and needs a
rebase: http://cfbot.cputube.org/patch_36_3290.log

V4 rebased attached.

Attachments:

special-guc-values-v4.patchapplication/octet-stream; name=special-guc-values-v4.patch; x-apple-part-url=128A4375-B67D-43B0-B84A-878681D9588FDownload
From 3e1e6219c6db94e3c69a8c5cddd6c9ab4b3aa848 Mon Sep 17 00:00:00 2001
From: David Christensen <david.christensen@crunchydata.com>
Date: Thu, 19 Aug 2021 14:33:15 -0500
Subject: [PATCH] POC: use sentinel values for parsing/outputting "special" int
 GUCs

Some GUCs include specific key values like "-1", etc, which have context beyond the actual value
involved.  Add support for providing synonyms for these values on input/output which make things a
lot easier to understand.

Add a new GUC output_special_values to enable the change of behavior on output; by default we leave
this alone, as there may be tools parsing/using these values as they currently output.

As far as I know, this "magic values" really only exists for ints; we can expand things similarly
for other types if the need arises.

For now, a non-exhaustive pass has been done through the config_int options list to identify
likely/needed values.  This will probably need to be tightened up in the future.

This code supports multiple values; it will stop at the first parsed found value and use that int
value.
---
 src/backend/utils/misc/guc.c      | 376 ++++++++++++++++++++----------
 src/include/utils/guc_tables.h    |   1 +
 src/test/regress/expected/guc.out |  45 ++++
 src/test/regress/sql/guc.sql      |  16 ++
 4 files changed, 309 insertions(+), 129 deletions(-)

diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6fc5cbc09a..3f10fef244 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -236,6 +236,9 @@ static void assign_recovery_target_lsn(const char *newval, void *extra);
 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
 
+static bool parse_special_int(const struct config_enum_entry *options, const char *value, int *result);
+static bool special_int_to_value(const struct config_enum_entry *options, int value, const char **retval);
+
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
 												 bool applySettings, int elevel);
@@ -566,6 +569,57 @@ extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
 
+/* Some static structs for use in options which have -1 as special values;
+ * example: "disabled" or "inherited". While these are not enums per se, we
+ * are reusing the struct, with the bool field indicating whether to print the
+ * translated values on output */
+
+static const struct config_enum_entry special_auto[] = {
+	{"auto", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled[] = {
+	{"disabled", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled0[] = {
+	{"disabled", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_disabled_all[] = {
+	{"disabled", -1, false},
+	{"all", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_default0[] = {
+	{"default", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_immediate0[] = {
+	{"immediate", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_none0[] = {
+	{"none", 0, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited[] = {
+	{"unlimited", -1, false},
+	{NULL, 0, false}
+};
+
+static const struct config_enum_entry special_unlimited0[] = {
+	{"unlimited", 0, false},
+	{NULL, 0, false}
+};
+
 /*
  * GUC option variables that are exported from this module
  */
@@ -593,6 +647,8 @@ bool		check_function_bodies = true;
 bool		default_with_oids = false;
 bool		session_auth_is_superuser;
 
+bool		output_special_values = false;
+
 int			log_min_error_statement = ERROR;
 int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
@@ -2120,6 +2176,15 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"output_special_values", PGC_USERSET, CLIENT_CONN_OTHER,
+			gettext_noop("Whether to display \"special\" values in settings display."),
+		},
+		&output_special_values,
+		false,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -2138,7 +2203,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLogArchiveTimeout,
 		0, 0, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
@@ -2149,7 +2214,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostAuthDelay,
 		0, 0, INT_MAX / 1000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 	{
 		{"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2159,7 +2224,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&default_statistics_target,
 		100, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2172,7 +2237,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&from_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -2185,7 +2250,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&join_collapse_limit,
 		8, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2195,7 +2260,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&geqo_threshold,
 		12, 2, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2205,7 +2270,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_effort,
 		DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2215,7 +2280,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_pool_size,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
@@ -2225,7 +2290,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Geqo_generations,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2237,7 +2302,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&DeadlockTimeout,
 		1000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2248,7 +2313,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_archive_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2259,7 +2324,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_standby_streaming_delay,
 		30 * 1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2270,7 +2335,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&recovery_min_apply_delay,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2281,7 +2346,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_status_interval,
 		10, 0, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2292,7 +2357,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_receiver_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2302,7 +2367,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&MaxConnections,
 		100, 1, MAX_BACKENDS,
-		check_maxconnections, NULL, NULL
+		check_maxconnections, NULL, NULL, NULL
 	},
 
 	{
@@ -2313,7 +2378,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ReservedBackends,
 		3, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2324,7 +2389,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_dynamic_shared_memory,
 		0, 0, (int) Min((size_t) INT_MAX, SIZE_MAX / (1024 * 1024)),
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2339,7 +2404,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&NBuffers,
 		16384, 16, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2350,7 +2415,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&shared_memory_size_mb,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2372,7 +2437,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&num_temp_buffers,
 		1024, 100, INT_MAX / 2,
-		check_temp_buffers, NULL, NULL
+		check_temp_buffers, NULL, NULL, NULL
 	},
 
 	{
@@ -2382,7 +2447,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PostPortNumber,
 		DEF_PGPORT, 1, 65535,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2397,7 +2462,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Unix_socket_permissions,
 		0777, 0000, 0777,
-		NULL, NULL, show_unix_socket_permissions
+		NULL, NULL, show_unix_socket_permissions, NULL
 	},
 
 	{
@@ -2411,7 +2476,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_file_mode,
 		0600, 0000, 0777,
-		NULL, NULL, show_log_file_mode
+		NULL, NULL, show_log_file_mode, NULL
 	},
 
 
@@ -2426,7 +2491,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&data_directory_mode,
 		0700, 0000, 0777,
-		NULL, NULL, show_data_directory_mode
+		NULL, NULL, show_data_directory_mode, NULL
 	},
 
 	{
@@ -2439,7 +2504,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&work_mem,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2450,7 +2515,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&maintenance_work_mem,
 		65536, 1024, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2462,7 +2527,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&logical_decoding_work_mem,
 		65536, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2478,7 +2543,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_stack_depth,
 		100, 100, MAX_KILOBYTES,
-		check_max_stack_depth, assign_max_stack_depth, NULL
+		check_max_stack_depth, assign_max_stack_depth, NULL, NULL
 	},
 
 	{
@@ -2489,7 +2554,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&temp_file_limit,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2499,7 +2564,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageHit,
 		1, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2509,7 +2574,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageMiss,
 		2, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2519,7 +2584,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostPageDirty,
 		20, 0, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2529,7 +2594,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&VacuumCostLimit,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2539,7 +2604,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_cost_limit,
 		-1, -1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2549,7 +2614,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_files_per_process,
 		1000, 64, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2562,7 +2627,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_prepared_xacts,
 		0, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 #ifdef LOCK_DEBUG
@@ -2574,7 +2639,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_oidmin,
 		FirstNormalObjectId, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
@@ -2584,7 +2649,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Trace_lock_table,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 #endif
 
@@ -2596,7 +2661,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&StatementTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2607,7 +2672,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&LockTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2618,7 +2683,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleInTransactionSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2629,7 +2694,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&IdleSessionTimeout,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited0
 	},
 
 	{
@@ -2639,7 +2704,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_min_age,
 		50000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2649,7 +2714,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2659,7 +2724,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_min_age,
 		5000000, 0, 1000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2669,7 +2734,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_freeze_table_age,
 		150000000, 0, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2679,7 +2744,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_defer_cleanup_age,
 		0, 0, 1000000,			/* see ComputeXidHorizons */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2688,7 +2753,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"vacuum_multixact_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -2697,7 +2762,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&vacuum_multixact_failsafe_age,
 		1600000000, 0, 2100000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	/*
@@ -2712,7 +2777,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2724,7 +2789,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_xact,
 		64, 10, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2735,7 +2800,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_relation,
 		-2, INT_MIN, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2746,7 +2811,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_predicate_locks_per_page,
 		2, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2757,7 +2822,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&AuthenticationTimeout,
 		60, 1, 600,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2770,7 +2835,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&PreAuthDelay,
 		0, 0, 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2781,7 +2846,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_keep_size_mb,
 		0, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2793,7 +2858,7 @@ static struct config_int ConfigureNamesInt[] =
 		&min_wal_size_mb,
 		DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2805,7 +2870,7 @@ static struct config_int ConfigureNamesInt[] =
 		&max_wal_size_mb,
 		DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
 		2, MAX_KILOBYTES,
-		NULL, assign_max_wal_size, NULL
+		NULL, assign_max_wal_size, NULL, NULL
 	},
 
 	{
@@ -2816,7 +2881,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointTimeout,
 		300, 30, 86400,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2831,7 +2896,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CheckPointWarning,
 		30, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2842,7 +2907,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&checkpoint_flush_after,
 		DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2853,7 +2918,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&XLOGbuffers,
 		-1, -1, (INT_MAX / XLOG_BLCKSZ),
-		check_wal_buffers, NULL, NULL
+		check_wal_buffers, NULL, NULL, special_auto
 	},
 
 	{
@@ -2864,7 +2929,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterDelay,
 		200, 1, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2875,7 +2940,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&WalWriterFlushAfter,
 		(1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_immediate0
 	},
 
 	{
@@ -2886,7 +2951,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_skip_threshold,
 		2048, 0, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2896,7 +2961,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_wal_senders,
 		10, 0, MAX_BACKENDS,
-		check_max_wal_senders, NULL, NULL
+		check_max_wal_senders, NULL, NULL, NULL
 	},
 
 	{
@@ -2907,7 +2972,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_replication_slots,
 		10, 0, MAX_BACKENDS /* XXX? */ ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2920,7 +2985,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_slot_wal_keep_size_mb,
 		-1, -1, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -2931,7 +2996,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_sender_timeout,
 		60 * 1000, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -2943,7 +3008,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitDelay,
 		0, 0, 100000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_none0
 	},
 
 	{
@@ -2954,7 +3019,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&CommitSiblings,
 		5, 0, 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2967,7 +3032,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&extra_float_digits,
 		1, -15, 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -2980,7 +3045,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_sample,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -2992,7 +3057,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_min_duration_statement,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3004,7 +3069,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_autovacuum_min_duration,
 		600000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3016,7 +3081,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length,
 		-1, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3028,7 +3093,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_parameter_max_length_on_error,
 		0, -1, INT_MAX / 2,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_unlimited
 	},
 
 	{
@@ -3039,7 +3104,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&BgWriterDelay,
 		200, 10, 10000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3049,7 +3114,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_lru_maxpages,
 		100, 0, INT_MAX / 2,	/* Same upper limit as shared_buffers */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3060,7 +3125,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&bgwriter_flush_after,
 		DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3078,7 +3143,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_effective_io_concurrency, NULL, NULL
+		check_effective_io_concurrency, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3096,7 +3161,7 @@ static struct config_int ConfigureNamesInt[] =
 		0,
 #endif
 		0, MAX_IO_CONCURRENCY,
-		check_maintenance_io_concurrency, NULL, NULL
+		check_maintenance_io_concurrency, NULL, NULL, NULL
 	},
 
 	{
@@ -3107,7 +3172,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&backend_flush_after,
 		DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3119,7 +3184,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_worker_processes,
 		8, 0, MAX_BACKENDS,
-		check_max_worker_processes, NULL, NULL
+		check_max_worker_processes, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3131,7 +3196,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_logical_replication_workers,
 		4, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3143,7 +3208,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_sync_workers_per_subscription,
 		2, 0, MAX_BACKENDS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3155,7 +3220,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationAge,
 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3167,7 +3232,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&Log_RotationSize,
 		10 * 1024, 0, INT_MAX / 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3178,7 +3243,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_function_args,
 		FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3189,7 +3254,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_index_keys,
 		INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3200,7 +3265,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_identifier_length,
 		NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3211,7 +3276,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&block_size,
 		BLCKSZ, BLCKSZ, BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3222,7 +3287,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&segment_size,
 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3233,7 +3298,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_block_size,
 		XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3245,7 +3310,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&wal_retrieve_retry_interval,
 		5000, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3258,7 +3323,7 @@ static struct config_int ConfigureNamesInt[] =
 		DEFAULT_XLOG_SEG_SIZE,
 		WalSegMinSize,
 		WalSegMaxSize,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3269,7 +3334,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_naptime,
 		60, 1, INT_MAX / 1000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3278,7 +3343,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3287,7 +3352,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_vac_ins_thresh,
 		1000, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 	{
 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
@@ -3296,7 +3361,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_anl_thresh,
 		50, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3308,7 +3373,7 @@ static struct config_int ConfigureNamesInt[] =
 
 		/* see vacuum_failsafe_age if you change the upper-limit value. */
 		200000000, 100000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
@@ -3318,7 +3383,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_multixact_freeze_max_age,
 		400000000, 10000, 2000000000,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 	{
 		/* see max_connections */
@@ -3328,7 +3393,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_max_workers,
 		3, 1, MAX_BACKENDS,
-		check_autovacuum_max_workers, NULL, NULL
+		check_autovacuum_max_workers, NULL, NULL, NULL
 	},
 
 	{
@@ -3338,7 +3403,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_maintenance_workers,
 		2, 0, 1024,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3349,7 +3414,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers_per_gather,
 		2, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3360,7 +3425,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&max_parallel_workers,
 		8, 0, MAX_PARALLEL_WORKER_LIMIT,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3371,7 +3436,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&autovacuum_work_mem,
 		-1, -1, MAX_KILOBYTES,
-		check_autovacuum_work_mem, NULL, NULL
+		check_autovacuum_work_mem, NULL, NULL, NULL
 	},
 
 	{
@@ -3382,7 +3447,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&old_snapshot_threshold,
 		-1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled
 	},
 
 	{
@@ -3393,7 +3458,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_idle,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
+		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle, special_default0
 	},
 
 	{
@@ -3404,7 +3469,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_interval,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
+		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval, special_default0
 	},
 
 	{
@@ -3415,7 +3480,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&ssl_renegotiation_limit,
 		0, 0, 0,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3427,7 +3492,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_keepalives_count,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
+		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count, special_default0
 	},
 
 	{
@@ -3438,7 +3503,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&GinFuzzySearchLimit,
 		0, 0, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3450,7 +3515,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&effective_cache_size,
 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3461,7 +3526,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_table_scan_size,
 		(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3472,7 +3537,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&min_parallel_index_scan_size,
 		(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3484,7 +3549,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&server_version_num,
 		PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3495,7 +3560,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&log_temp_files,
 		-1, -1, INT_MAX,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, special_disabled_all
 	},
 
 	{
@@ -3506,7 +3571,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&pgstat_track_activity_query_size,
 		1024, 100, 1048576,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3517,7 +3582,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&gin_pending_list_limit,
 		4096, 64, MAX_KILOBYTES,
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3528,7 +3593,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&tcp_user_timeout,
 		0, 0, INT_MAX,
-		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
+		NULL, assign_tcp_user_timeout, show_tcp_user_timeout, special_default0
 	},
 
 	{
@@ -3562,7 +3627,7 @@ static struct config_int ConfigureNamesInt[] =
 #else							/* not DISCARD_CACHES_ENABLED */
 		0, 0, 0,
 #endif							/* not DISCARD_CACHES_ENABLED */
-		NULL, NULL, NULL
+		NULL, NULL, NULL, NULL
 	},
 
 	{
@@ -3573,7 +3638,7 @@ static struct config_int ConfigureNamesInt[] =
 		},
 		&client_connection_check_interval,
 		0, 0, INT_MAX,
-		check_client_connection_check_interval, NULL, NULL
+		check_client_connection_check_interval, NULL, NULL, special_disabled0
 	},
 
 	{
@@ -3590,7 +3655,7 @@ static struct config_int ConfigureNamesInt[] =
 
 	/* End-of-list marker */
 	{
-		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL, NULL
 	}
 };
 
@@ -6954,6 +7019,56 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
 	return true;
 }
 
+
+/*
+ * Lookup special values from an array of chars -> int (case-sensitive).
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false and leave retval alone.
+ */
+bool
+parse_special_int(const struct config_enum_entry *options, const char *value,
+						   int *retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (pg_strcasecmp(value, entry->name) == 0)
+		{
+			*retval = entry->val;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+/*
+ * Lookup special values by int value and set to static string.
+ * If the value is found, sets the retval value and returns
+ * true. If it's not found, return false.
+ */
+bool
+special_int_to_value(const struct config_enum_entry *options, int value,
+						   const char **retval)
+{
+	const struct config_enum_entry *entry;
+
+	for (entry = options; entry && entry->name; entry++)
+	{
+		if (value == entry->val)
+		{
+			*retval = entry->name;
+			return true;
+		}
+	}
+
+	/* don't touch the return value in other case */
+	return false;
+}
+
+
 /*
  * Try to parse value as a floating point number in the usual format.
  * Optionally, the value can be followed by a unit name if "flags" indicates
@@ -7017,7 +7132,6 @@ parse_real(const char *value, double *result, int flags, const char **hintmsg)
 	return true;
 }
 
-
 /*
  * Lookup the name for an enum option with the selected value.
  * Should only ever be called with known-valid values, so throws
@@ -7164,8 +7278,8 @@ parse_and_validate_value(struct config_generic *record,
 				struct config_int *conf = (struct config_int *) record;
 				const char *hintmsg;
 
-				if (!parse_int(value, &newval->intval,
-							   conf->gen.flags, &hintmsg))
+				if (!(conf->special && parse_special_int(conf->special, value, &newval->intval)) &&
+					!parse_int(value, &newval->intval, conf->gen.flags, &hintmsg))
 				{
 					ereport(elevel,
 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -10172,7 +10286,11 @@ _ShowOption(struct config_generic *record, bool use_units)
 			{
 				struct config_int *conf = (struct config_int *) record;
 
-				if (conf->show_hook)
+				/* Special values are prioritized over show hooks */
+				if (output_special_values && conf->special && special_int_to_value(conf->special, *conf->variable, &val))
+					/* if return is true we have no special action to take here but val was set already */
+					;
+				else if (conf->show_hook)
 					val = conf->show_hook();
 				else
 				{
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index f7e54a87b7..b37122b046 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -197,6 +197,7 @@ struct config_int
 	GucIntCheckHook check_hook;
 	GucIntAssignHook assign_hook;
 	GucShowHook show_hook;
+	const struct config_enum_entry *special;
 	/* variable fields, initialized at runtime: */
 	int			reset_val;
 	void	   *reset_extra;
diff --git a/src/test/regress/expected/guc.out b/src/test/regress/expected/guc.out
index 59da91ff04..af12c4d1c3 100644
--- a/src/test/regress/expected/guc.out
+++ b/src/test/regress/expected/guc.out
@@ -813,3 +813,48 @@ set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
 ERROR:  tables declared WITH OIDS are not supported
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ disabled
+(1 row)
+
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ 100ms
+(1 row)
+
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+ log_min_duration_statement 
+----------------------------
+ -1
+(1 row)
+
diff --git a/src/test/regress/sql/guc.sql b/src/test/regress/sql/guc.sql
index c39c11388d..b6a54e0290 100644
--- a/src/test/regress/sql/guc.sql
+++ b/src/test/regress/sql/guc.sql
@@ -311,3 +311,19 @@ reset check_function_bodies;
 set default_with_oids to f;
 -- Should not allow to set it to true.
 set default_with_oids to t;
+
+-- tests for output_special_values and special values
+set output_special_values to t;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
+set output_special_values to f;
+set log_min_duration_statement = 100;
+show log_min_duration_statement;
+set log_min_duration_statement = -1;
+show log_min_duration_statement;
+set log_min_duration_statement = disabled;
+show log_min_duration_statement;
-- 
2.32.0 (Apple Git-132)

#15Andres Freund
andres@anarazel.de
In reply to: David Christensen (#14)
Re: [PATCH] Proof of concept for GUC improvements

Hi,

On 2022-01-12 12:57:02 -0600, David Christensen wrote:

Hi,

According to the cfbot, the patch doesn't apply anymore and needs a
rebase: http://cfbot.cputube.org/patch_36_3290.log

V4 rebased attached.

Doesn't apply anymore, again: http://cfbot.cputube.org/patch_37_3290.log

My impression is that there's not a lot of enthusiasm for the concept? If
that's true we maybe ought to mark the CF entry as rejected?

Greetings,

Andres Freund

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#15)
Re: [PATCH] Proof of concept for GUC improvements

Andres Freund <andres@anarazel.de> writes:

My impression is that there's not a lot of enthusiasm for the concept? If
that's true we maybe ought to mark the CF entry as rejected?

Yeah, I'm kind of leaning that way too. I don't see how we can
incorporate the symbolic values into any existing display paths
without breaking applications that expect the old output.
That being the case, it seems like we'd have "two ways to do it"
indefinitely, which would add enough confusion that I'm not
sure there's a net gain. In particular, I foresee novice questions
along the lines of "I set foo to disabled, why is it showing
as zero?".

If we'd done it like this from the beginning, it'd have been
great, but retrofitting it now is a lot less appealing.

regards, tom lane

#17David Christensen
david@pgguru.net
In reply to: Tom Lane (#16)
Re: [PATCH] Proof of concept for GUC improvements

On Mar 21, 2022, at 7:53 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Andres Freund <andres@anarazel.de> writes:

My impression is that there's not a lot of enthusiasm for the concept? If
that's true we maybe ought to mark the CF entry as rejected?

Yeah, I'm kind of leaning that way too. I don't see how we can
incorporate the symbolic values into any existing display paths
without breaking applications that expect the old output.
That being the case, it seems like we'd have "two ways to do it"
indefinitely, which would add enough confusion that I'm not
sure there's a net gain. In particular, I foresee novice questions
along the lines of "I set foo to disabled, why is it showing
as zero?"

Yeah, my main motivation here was about trying to have less special values in the config files, but I guess it would effectively be making everything effectively an enum and still relies on knowing just what the specific magic values are, no not really a net gain in this department.

For the record, I thought this would have a fairly low chance of getting in, was mainly curious what level of effort it would take to get something like this going and get some feedback on the actual idea.

If we'd done it like this from the beginning, it'd have been
great, but retrofitting it now is a lot less appealing.

Yeah, agreed on this. As far as I’m concerned we can reject.

Thanks,

David

#18Andres Freund
andres@anarazel.de
In reply to: David Christensen (#17)
Re: [PATCH] Proof of concept for GUC improvements

On 2022-03-22 13:15:34 -0500, David Christensen wrote:

On Mar 21, 2022, at 7:53 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
If we'd done it like this from the beginning, it'd have been
great, but retrofitting it now is a lot less appealing.

Yeah, agreed on this. As far as I’m concerned we can reject.

Updated CF entry to say so...