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)

