Split up guc.c for better build speed and ease of maintenance.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Sep 2022 15:05:07 +0000 (11:05 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Sep 2022 15:11:45 +0000 (11:11 -0400)
guc.c has grown to be one of our largest .c files, making it
a bottleneck for compilation.  It's also acquired a bunch of
knowledge that'd be better kept elsewhere, because of our not
very good habit of putting variable-specific check hooks here.
Hence, split it up along these lines:

* guc.c itself retains just the core GUC housekeeping mechanisms.
* New file guc_funcs.c contains the SET/SHOW interfaces and some
  SQL-accessible functions for GUC manipulation.
* New file guc_tables.c contains the data arrays that define the
  built-in GUC variables, along with some already-exported constant
  tables.
* GUC check/assign/show hook functions are moved to the variable's
  home module, whenever that's clearly identifiable.  A few hard-
  to-classify hooks ended up in commands/variable.c, which was
  already a home for miscellaneous GUC hook functions.

To avoid cluttering a lot more header files with #include "guc.h",
I also invented a new header file utils/guc_hooks.h and put all
the GUC hook functions' declarations there, regardless of their
originating module.  That allowed removal of #include "guc.h"
from some existing headers.  The fallout from that (hopefully
all caught here) demonstrates clearly why such inclusions are
best minimized: there are a lot of files that, for example,
were getting array.h at two or more levels of remove, despite
not having any connection at all to GUCs in themselves.

There is some very minor code beautification here, such as
renaming a couple of inconsistently-named hook functions
and improving some comments.  But mostly this just moves
code from point A to point B and deals with the ensuing
needs for #include adjustments and exporting a few functions
that previously weren't exported.

Patch by me, per a suggestion from Andres Freund; thanks also
to Michael Paquier for the idea to invent guc_funcs.c.

Discussion: https://postgr.es/m/587607.1662836699@sss.pgh.pa.us

59 files changed:
contrib/amcheck/verify_nbtree.c
contrib/ltree/_ltree_gist.c
contrib/ltree/_ltree_op.c
contrib/ltree/lquery_op.c
contrib/ltree/ltree_gist.c
contrib/pg_surgery/heap_surgery.c
contrib/pg_trgm/trgm_op.c
src/backend/access/brin/brin.c
src/backend/access/table/tableamapi.c
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogprefetcher.c
src/backend/access/transam/xlogrecovery.c
src/backend/backup/basebackup.c
src/backend/catalog/aclchk.c
src/backend/catalog/namespace.c
src/backend/catalog/pg_parameter_acl.c
src/backend/commands/cluster.c
src/backend/commands/indexcmds.c
src/backend/commands/tablespace.c
src/backend/commands/trigger.c
src/backend/commands/variable.c
src/backend/libpq/pqcomm.c
src/backend/partitioning/partbounds.c
src/backend/port/sysv_shmem.c
src/backend/port/win32_shmem.c
src/backend/postmaster/autovacuum.c
src/backend/replication/repl_gram.y
src/backend/replication/repl_scanner.l
src/backend/replication/syncrep.c
src/backend/replication/syncrep_gram.y
src/backend/replication/syncrep_scanner.l
src/backend/storage/buffer/localbuf.c
src/backend/storage/ipc/ipci.c
src/backend/storage/lmgr/predicate.c
src/backend/tcop/postgres.c
src/backend/tsearch/dict.c
src/backend/utils/adt/pg_locale.c
src/backend/utils/adt/selfuncs.c
src/backend/utils/adt/varchar.c
src/backend/utils/adt/varlena.c
src/backend/utils/cache/ts_cache.c
src/backend/utils/error/elog.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/Makefile
src/backend/utils/misc/guc.c
src/backend/utils/misc/guc_funcs.c [new file with mode: 0644]
src/backend/utils/misc/guc_tables.c [new file with mode: 0644]
src/include/access/tableam.h
src/include/access/xlog.h
src/include/commands/variable.h [deleted file]
src/include/replication/syncrep.h
src/include/tcop/tcopprot.h
src/include/tsearch/ts_cache.h
src/include/utils/elog.h
src/include/utils/guc.h
src/include/utils/guc_hooks.h [new file with mode: 0644]
src/include/utils/guc_tables.h
src/include/utils/pg_locale.h
src/test/regress/regress.c

index 2beeebb1635313794c8726519f796d2dc3bc79b2..798adc5bc55c6b23be1b017ed4df40a276fea7f0 100644 (file)
@@ -37,6 +37,7 @@
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/smgr.h"
+#include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/snapmgr.h"
 
index 2dc59f8a0f0ae29956b78dade60cfd19dc4b60d9..88d4623621912cdcc2467e47a7e2ed0b4677f744 100644 (file)
@@ -13,6 +13,7 @@
 #include "crc32.h"
 #include "ltree.h"
 #include "port/pg_bitutils.h"
+#include "utils/array.h"
 
 PG_FUNCTION_INFO_V1(_ltree_compress);
 PG_FUNCTION_INFO_V1(_ltree_same);
index 9bb6bcaeffaed80ab5359e094a0ceb828c9604f3..2fdb5ea97bf40a644f161ddbb9f59672bd990b2e 100644 (file)
@@ -10,6 +10,7 @@
 #include <ctype.h>
 
 #include "ltree.h"
+#include "utils/array.h"
 
 PG_FUNCTION_INFO_V1(_ltree_isparent);
 PG_FUNCTION_INFO_V1(_ltree_r_isparent);
index ef86046fc4bc0f1d0d98753817598b9b7ba73ce3..d58033928361b2f251da52e4415b95b7fb0d1c87 100644 (file)
@@ -10,6 +10,7 @@
 #include "catalog/pg_collation.h"
 #include "ltree.h"
 #include "miscadmin.h"
+#include "utils/array.h"
 #include "utils/formatting.h"
 
 PG_FUNCTION_INFO_V1(ltq_regex);
index 36874e9c7263c8ba18eee40d661155b30358f3dd..b582867a938d44f081b7855c21f11b1cadc57ba0 100644 (file)
@@ -10,6 +10,7 @@
 #include "access/stratnum.h"
 #include "crc32.h"
 #include "ltree.h"
+#include "utils/array.h"
 
 #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
 #define ISEQ(a,b)      ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
index 3e641aa6440e8b6ab99d9137d31aafa5f78bfc50..8a2ad9773d04b6a687032f4428088cd029b17677 100644 (file)
@@ -20,6 +20,7 @@
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "utils/acl.h"
+#include "utils/array.h"
 #include "utils/rel.h"
 
 PG_MODULE_MAGIC;
index 2aeaa0ecc50c6f274d9c5b48ec960b1745c46037..154346398afea95aa33b5e3e2a0a815e2fa038a0 100644 (file)
@@ -10,6 +10,7 @@
 #include "miscadmin.h"
 #include "trgm.h"
 #include "tsearch/ts_locale.h"
+#include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/pg_crc.h"
index dcf2d2c4b5081b88459b2a30f4a87a0f7051e034..20b7d65b948fa9249b9f48542f565d4b3ce0a9d3 100644 (file)
@@ -36,6 +36,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
+#include "utils/guc.h"
 #include "utils/index_selfuncs.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
index 873d961bf4868d2c11e5d40a5c86e8709ff70cc0..92d9cf31db79d1c0ed614a3eeb520e1a3b9327ac 100644 (file)
@@ -20,6 +20,7 @@
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "utils/fmgroids.h"
+#include "utils/guc_hooks.h"
 #include "utils/memutils.h"
 #include "utils/syscache.h"
 
index 7a710e6490dbc7e3b24b917fc0f982c74e1530c7..81d339d57d7a278ef3fd65284a6a3965607b8d77 100644 (file)
@@ -97,7 +97,8 @@
 #include "storage/smgr.h"
 #include "storage/spin.h"
 #include "storage/sync.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
+#include "utils/guc_tables.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "utils/relmapper.h"
 #include "utils/snapmgr.h"
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
+#include "utils/varlena.h"
 
 extern uint32 bootstrap_data_checksum_version;
 
@@ -160,6 +162,12 @@ int                        CheckPointSegments;
 static double CheckPointDistanceEstimate = 0;
 static double PrevCheckPointDistance = 0;
 
+/*
+ * Track whether there were any deferred checks for custom resource managers
+ * specified in wal_consistency_checking.
+ */
+static bool check_wal_consistency_checking_deferred = false;
+
 /*
  * GUC support
  */
@@ -4304,6 +4312,172 @@ check_wal_buffers(int *newval, void **extra, GucSource source)
        return true;
 }
 
+/*
+ * GUC check_hook for wal_consistency_checking
+ */
+bool
+check_wal_consistency_checking(char **newval, void **extra, GucSource source)
+{
+       char       *rawstring;
+       List       *elemlist;
+       ListCell   *l;
+       bool            newwalconsistency[RM_MAX_ID + 1];
+
+       /* Initialize the array */
+       MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool));
+
+       /* Need a modifiable copy of string */
+       rawstring = pstrdup(*newval);
+
+       /* Parse string into list of identifiers */
+       if (!SplitIdentifierString(rawstring, ',', &elemlist))
+       {
+               /* syntax error in list */
+               GUC_check_errdetail("List syntax is invalid.");
+               pfree(rawstring);
+               list_free(elemlist);
+               return false;
+       }
+
+       foreach(l, elemlist)
+       {
+               char       *tok = (char *) lfirst(l);
+               int                     rmid;
+
+               /* Check for 'all'. */
+               if (pg_strcasecmp(tok, "all") == 0)
+               {
+                       for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
+                               if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL)
+                                       newwalconsistency[rmid] = true;
+               }
+               else
+               {
+                       /* Check if the token matches any known resource manager. */
+                       bool            found = false;
+
+                       for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
+                       {
+                               if (RmgrIdExists(rmid) && GetRmgr(rmid).rm_mask != NULL &&
+                                       pg_strcasecmp(tok, GetRmgr(rmid).rm_name) == 0)
+                               {
+                                       newwalconsistency[rmid] = true;
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                       {
+                               /*
+                                * During startup, it might be a not-yet-loaded custom
+                                * resource manager.  Defer checking until
+                                * InitializeWalConsistencyChecking().
+                                */
+                               if (!process_shared_preload_libraries_done)
+                               {
+                                       check_wal_consistency_checking_deferred = true;
+                               }
+                               else
+                               {
+                                       GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
+                                       pfree(rawstring);
+                                       list_free(elemlist);
+                                       return false;
+                               }
+                       }
+               }
+       }
+
+       pfree(rawstring);
+       list_free(elemlist);
+
+       /* assign new value */
+       *extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool));
+       memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool));
+       return true;
+}
+
+/*
+ * GUC assign_hook for wal_consistency_checking
+ */
+void
+assign_wal_consistency_checking(const char *newval, void *extra)
+{
+       /*
+        * If some checks were deferred, it's possible that the checks will fail
+        * later during InitializeWalConsistencyChecking(). But in that case, the
+        * postmaster will exit anyway, so it's safe to proceed with the
+        * assignment.
+        *
+        * Any built-in resource managers specified are assigned immediately,
+        * which affects WAL created before shared_preload_libraries are
+        * processed. Any custom resource managers specified won't be assigned
+        * until after shared_preload_libraries are processed, but that's OK
+        * because WAL for a custom resource manager can't be written before the
+        * module is loaded anyway.
+        */
+       wal_consistency_checking = extra;
+}
+
+/*
+ * InitializeWalConsistencyChecking: run after loading custom resource managers
+ *
+ * If any unknown resource managers were specified in the
+ * wal_consistency_checking GUC, processing was deferred.  Now that
+ * shared_preload_libraries have been loaded, process wal_consistency_checking
+ * again.
+ */
+void
+InitializeWalConsistencyChecking(void)
+{
+       Assert(process_shared_preload_libraries_done);
+
+       if (check_wal_consistency_checking_deferred)
+       {
+               struct config_generic *guc;
+
+               guc = find_option("wal_consistency_checking", false, false, ERROR);
+
+               check_wal_consistency_checking_deferred = false;
+
+               set_config_option_ext("wal_consistency_checking",
+                                                         wal_consistency_checking_string,
+                                                         guc->scontext, guc->source, guc->srole,
+                                                         GUC_ACTION_SET, true, ERROR, false);
+
+               /* checking should not be deferred again */
+               Assert(!check_wal_consistency_checking_deferred);
+       }
+}
+
+/*
+ * GUC show_hook for archive_command
+ */
+const char *
+show_archive_command(void)
+{
+       if (XLogArchivingActive())
+               return XLogArchiveCommand;
+       else
+               return "(disabled)";
+}
+
+/*
+ * GUC show_hook for in_hot_standby
+ */
+const char *
+show_in_hot_standby(void)
+{
+       /*
+        * We display the actual state based on shared memory, so that this GUC
+        * reports up-to-date state if examined intra-query.  The underlying
+        * variable (in_hot_standby_guc) changes only when we transmit a new value
+        * to the client.
+        */
+       return RecoveryInProgress() ? "on" : "off";
+}
+
+
 /*
  * Read the control file, set respective GUCs.
  *
index 368aa73ce2052840e70bb56fa7299820757ddd3b..342960263cbe52314276b690470ef2f4260bc904 100644 (file)
@@ -44,7 +44,7 @@
 #include "storage/bufmgr.h"
 #include "storage/shmem.h"
 #include "storage/smgr.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/hsearch.h"
 
 /*
index 9a80084a685801aa7debae33498b8ed428210142..e00ff14d49b569e809c3bf6ff676c0d8f085b221 100644 (file)
@@ -48,6 +48,7 @@
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/startup.h"
+#include "replication/slot.h"
 #include "replication/walreceiver.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
@@ -57,7 +58,9 @@
 #include "storage/procarray.h"
 #include "storage/spin.h"
 #include "utils/builtins.h"
-#include "utils/guc.h"
+#include "utils/datetime.h"
+#include "utils/guc_hooks.h"
+#include "utils/pg_lsn.h"
 #include "utils/ps_status.h"
 #include "utils/pg_rusage.h"
 
@@ -4616,3 +4619,315 @@ RecoveryRequiresIntParameter(const char *param_name, int currValue, int minValue
                                 errhint("You can restart the server after making the necessary configuration changes.")));
        }
 }
+
+
+/*
+ * GUC check_hook for primary_slot_name
+ */
+bool
+check_primary_slot_name(char **newval, void **extra, GucSource source)
+{
+       if (*newval && strcmp(*newval, "") != 0 &&
+               !ReplicationSlotValidateName(*newval, WARNING))
+               return false;
+
+       return true;
+}
+
+/*
+ * Recovery target settings: Only one of the several recovery_target* settings
+ * may be set.  Setting a second one results in an error.  The global variable
+ * recoveryTarget tracks which kind of recovery target was chosen.  Other
+ * variables store the actual target value (for example a string or a xid).
+ * The assign functions of the parameters check whether a competing parameter
+ * was already set.  But we want to allow setting the same parameter multiple
+ * times.  We also want to allow unsetting a parameter and setting a different
+ * one, so we unset recoveryTarget when the parameter is set to an empty
+ * string.
+ *
+ * XXX this code is broken by design.  Throwing an error from a GUC assign
+ * hook breaks fundamental assumptions of guc.c.  So long as all the variables
+ * for which this can happen are PGC_POSTMASTER, the consequences are limited,
+ * since we'd just abort postmaster startup anyway.  Nonetheless it's likely
+ * that we have odd behaviors such as unexpected GUC ordering dependencies.
+ */
+
+static void
+pg_attribute_noreturn()
+error_multiple_recovery_targets(void)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                        errmsg("multiple recovery targets specified"),
+                        errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set.")));
+}
+
+/*
+ * GUC check_hook for recovery_target
+ */
+bool
+check_recovery_target(char **newval, void **extra, GucSource source)
+{
+       if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
+       {
+               GUC_check_errdetail("The only allowed value is \"immediate\".");
+               return false;
+       }
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target
+ */
+void
+assign_recovery_target(const char *newval, void *extra)
+{
+       if (recoveryTarget != RECOVERY_TARGET_UNSET &&
+               recoveryTarget != RECOVERY_TARGET_IMMEDIATE)
+               error_multiple_recovery_targets();
+
+       if (newval && strcmp(newval, "") != 0)
+               recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
+       else
+               recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+/*
+ * GUC check_hook for recovery_target_lsn
+ */
+bool
+check_recovery_target_lsn(char **newval, void **extra, GucSource source)
+{
+       if (strcmp(*newval, "") != 0)
+       {
+               XLogRecPtr      lsn;
+               XLogRecPtr *myextra;
+               bool            have_error = false;
+
+               lsn = pg_lsn_in_internal(*newval, &have_error);
+               if (have_error)
+                       return false;
+
+               myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
+               *myextra = lsn;
+               *extra = (void *) myextra;
+       }
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target_lsn
+ */
+void
+assign_recovery_target_lsn(const char *newval, void *extra)
+{
+       if (recoveryTarget != RECOVERY_TARGET_UNSET &&
+               recoveryTarget != RECOVERY_TARGET_LSN)
+               error_multiple_recovery_targets();
+
+       if (newval && strcmp(newval, "") != 0)
+       {
+               recoveryTarget = RECOVERY_TARGET_LSN;
+               recoveryTargetLSN = *((XLogRecPtr *) extra);
+       }
+       else
+               recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+/*
+ * GUC check_hook for recovery_target_name
+ */
+bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+       /* Use the value of newval directly */
+       if (strlen(*newval) >= MAXFNAMELEN)
+       {
+               GUC_check_errdetail("%s is too long (maximum %d characters).",
+                                                       "recovery_target_name", MAXFNAMELEN - 1);
+               return false;
+       }
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target_name
+ */
+void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+       if (recoveryTarget != RECOVERY_TARGET_UNSET &&
+               recoveryTarget != RECOVERY_TARGET_NAME)
+               error_multiple_recovery_targets();
+
+       if (newval && strcmp(newval, "") != 0)
+       {
+               recoveryTarget = RECOVERY_TARGET_NAME;
+               recoveryTargetName = newval;
+       }
+       else
+               recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+/*
+ * GUC check_hook for recovery_target_time
+ *
+ * The interpretation of the recovery_target_time string can depend on the
+ * time zone setting, so we need to wait until after all GUC processing is
+ * done before we can do the final parsing of the string.  This check function
+ * only does a parsing pass to catch syntax errors, but we store the string
+ * and parse it again when we need to use it.
+ */
+bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+       if (strcmp(*newval, "") != 0)
+       {
+               /* reject some special values */
+               if (strcmp(*newval, "now") == 0 ||
+                       strcmp(*newval, "today") == 0 ||
+                       strcmp(*newval, "tomorrow") == 0 ||
+                       strcmp(*newval, "yesterday") == 0)
+               {
+                       return false;
+               }
+
+               /*
+                * parse timestamp value (see also timestamptz_in())
+                */
+               {
+                       char       *str = *newval;
+                       fsec_t          fsec;
+                       struct pg_tm tt,
+                                          *tm = &tt;
+                       int                     tz;
+                       int                     dtype;
+                       int                     nf;
+                       int                     dterr;
+                       char       *field[MAXDATEFIELDS];
+                       int                     ftype[MAXDATEFIELDS];
+                       char            workbuf[MAXDATELEN + MAXDATEFIELDS];
+                       TimestampTz timestamp;
+
+                       dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
+                                                                 field, ftype, MAXDATEFIELDS, &nf);
+                       if (dterr == 0)
+                               dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
+                       if (dterr != 0)
+                               return false;
+                       if (dtype != DTK_DATE)
+                               return false;
+
+                       if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
+                       {
+                               GUC_check_errdetail("timestamp out of range: \"%s\"", str);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target_time
+ */
+void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+       if (recoveryTarget != RECOVERY_TARGET_UNSET &&
+               recoveryTarget != RECOVERY_TARGET_TIME)
+               error_multiple_recovery_targets();
+
+       if (newval && strcmp(newval, "") != 0)
+               recoveryTarget = RECOVERY_TARGET_TIME;
+       else
+               recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+/*
+ * GUC check_hook for recovery_target_timeline
+ */
+bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+       RecoveryTargetTimeLineGoal rttg;
+       RecoveryTargetTimeLineGoal *myextra;
+
+       if (strcmp(*newval, "current") == 0)
+               rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+       else if (strcmp(*newval, "latest") == 0)
+               rttg = RECOVERY_TARGET_TIMELINE_LATEST;
+       else
+       {
+               rttg = RECOVERY_TARGET_TIMELINE_NUMERIC;
+
+               errno = 0;
+               strtoul(*newval, NULL, 0);
+               if (errno == EINVAL || errno == ERANGE)
+               {
+                       GUC_check_errdetail("recovery_target_timeline is not a valid number.");
+                       return false;
+               }
+       }
+
+       myextra = (RecoveryTargetTimeLineGoal *) guc_malloc(ERROR, sizeof(RecoveryTargetTimeLineGoal));
+       *myextra = rttg;
+       *extra = (void *) myextra;
+
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target_timeline
+ */
+void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+       recoveryTargetTimeLineGoal = *((RecoveryTargetTimeLineGoal *) extra);
+       if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
+               recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
+       else
+               recoveryTargetTLIRequested = 0;
+}
+
+/*
+ * GUC check_hook for recovery_target_xid
+ */
+bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+       if (strcmp(*newval, "") != 0)
+       {
+               TransactionId xid;
+               TransactionId *myextra;
+
+               errno = 0;
+               xid = (TransactionId) strtou64(*newval, NULL, 0);
+               if (errno == EINVAL || errno == ERANGE)
+                       return false;
+
+               myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+               *myextra = xid;
+               *extra = (void *) myextra;
+       }
+       return true;
+}
+
+/*
+ * GUC assign_hook for recovery_target_xid
+ */
+void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+       if (recoveryTarget != RECOVERY_TARGET_UNSET &&
+               recoveryTarget != RECOVERY_TARGET_XID)
+               error_multiple_recovery_targets();
+
+       if (newval && strcmp(newval, "") != 0)
+       {
+               recoveryTarget = RECOVERY_TARGET_XID;
+               recoveryTargetXid = *((TransactionId *) extra);
+       }
+       else
+               recoveryTarget = RECOVERY_TARGET_UNSET;
+}
index 3bf3aa6faabf06e543b6d38906cc3a9f9f4a6356..2bb831a3cd44ee35719aa91149c558c62c922604 100644 (file)
@@ -40,6 +40,7 @@
 #include "storage/ipc.h"
 #include "storage/reinit.h"
 #include "utils/builtins.h"
+#include "utils/guc.h"
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/resowner.h"
index 17ff617fba410a9553d8c087572d15d66fa91ba4..b20974bbebfeab479142fd697b9fd8ab16470d69 100644 (file)
@@ -74,6 +74,7 @@
 #include "utils/aclchk_internal.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
index fafb9349cced32e61b1d026072a14df98bbc21f1..dbb4b008a0bc5c6524b699ee13a317f00867cb2a 100644 (file)
@@ -51,7 +51,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
index 0570e811d1ef7af648183a2eb08d8ef7be1b0da8..37f6217df5591b30ee2d5d6cdee2cbeee83f59de 100644 (file)
@@ -21,6 +21,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_parameter_acl.h"
 #include "utils/builtins.h"
+#include "utils/guc.h"
 #include "utils/pg_locale.h"
 #include "utils/rel.h"
 #include "utils/syscache.h"
index dc35b02910205abd52c1766285571dd48faad77e..1976a373efa60bf8e8173f595fe472bb8912936c 100644 (file)
@@ -49,6 +49,7 @@
 #include "storage/predicate.h"
 #include "utils/acl.h"
 #include "utils/fmgroids.h"
+#include "utils/guc.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
index 9167bab0c55ff6a563e25f5c0c7c06c675dc3fe2..cf98d9e600bd10d83473432cb1b95bbc95a07741 100644 (file)
@@ -57,6 +57,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/guc.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
index f260b484fc4929950930a5e244e5143b810c7ba8..b69ff37dbbdc0ce00a13d0a9b64f2436eb4c68ce 100644 (file)
@@ -79,7 +79,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
index 28c3dcd0f76b2e6840247ad55565780277d05e48..5ad18d2de4b237c217918886e68a411838a6010f 100644 (file)
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/fmgroids.h"
+#include "utils/guc_hooks.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/plancache.h"
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
@@ -6499,6 +6501,20 @@ done:
        table->after_trig_events = qs->events;
 }
 
+/*
+ * GUC assign_hook for session_replication_role
+ */
+void
+assign_session_replication_role(int newval, void *extra)
+{
+       /*
+        * Must flush the plan cache when changing replication role; but don't
+        * flush unnecessarily.
+        */
+       if (SessionReplicationRole != newval)
+               ResetPlanCache();
+}
+
 /*
  * SQL function pg_trigger_depth()
  */
index e5ddcda0b4a0db0a3e1b217179f00e55460bfb94..c795cb7a29ceb01cf23fe72faa5e5de003f9745d 100644 (file)
 #include "access/parallel.h"
 #include "access/xact.h"
 #include "access/xlog.h"
+#include "access/xlogprefetcher.h"
 #include "catalog/pg_authid.h"
-#include "commands/variable.h"
+#include "common/string.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "postmaster/postmaster.h"
+#include "postmaster/syslogger.h"
+#include "storage/bufmgr.h"
 #include "utils/acl.h"
+#include "utils/backend_status.h"
 #include "utils/builtins.h"
+#include "utils/datetime.h"
+#include "utils/guc_hooks.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/timestamp.h"
+#include "utils/tzparser.h"
 #include "utils/varlena.h"
 
 /*
@@ -466,6 +474,56 @@ show_log_timezone(void)
 }
 
 
+/*
+ * TIMEZONE_ABBREVIATIONS
+ */
+
+/*
+ * GUC check_hook for assign_timezone_abbreviations
+ */
+bool
+check_timezone_abbreviations(char **newval, void **extra, GucSource source)
+{
+       /*
+        * The boot_val for timezone_abbreviations is NULL.  When we see that we
+        * just do nothing.  If the value isn't overridden from the config file
+        * then pg_timezone_abbrev_initialize() will eventually replace it with
+        * "Default".  This hack has two purposes: to avoid wasting cycles loading
+        * values that might soon be overridden from the config file, and to avoid
+        * trying to read the timezone abbrev files during InitializeGUCOptions().
+        * The latter doesn't work in an EXEC_BACKEND subprocess because
+        * my_exec_path hasn't been set yet and so we can't locate PGSHAREDIR.
+        */
+       if (*newval == NULL)
+       {
+               Assert(source == PGC_S_DEFAULT);
+               return true;
+       }
+
+       /* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */
+       *extra = load_tzoffsets(*newval);
+
+       /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
+       if (!*extra)
+               return false;
+
+       return true;
+}
+
+/*
+ * GUC assign_hook for assign_timezone_abbreviations
+ */
+void
+assign_timezone_abbreviations(const char *newval, void *extra)
+{
+       /* Do nothing for the boot_val default of NULL */
+       if (!extra)
+               return;
+
+       InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
+}
+
+
 /*
  * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
  *
@@ -522,7 +580,7 @@ check_transaction_read_only(bool *newval, void **extra, GucSource source)
  * As in check_transaction_read_only, allow it if not inside a transaction.
  */
 bool
-check_XactIsoLevel(int *newval, void **extra, GucSource source)
+check_transaction_isolation(int *newval, void **extra, GucSource source)
 {
        int                     newXactIsoLevel = *newval;
 
@@ -933,3 +991,212 @@ show_role(void)
        /* Otherwise we can just use the GUC string */
        return role_string ? role_string : "none";
 }
+
+
+/*
+ * PATH VARIABLES
+ *
+ * check_canonical_path is used for log_directory and some other GUCs where
+ * all we want to do is canonicalize the represented path name.
+ */
+
+bool
+check_canonical_path(char **newval, void **extra, GucSource source)
+{
+       /*
+        * Since canonicalize_path never enlarges the string, we can just modify
+        * newval in-place.  But watch out for NULL, which is the default value
+        * for external_pid_file.
+        */
+       if (*newval)
+               canonicalize_path(*newval);
+       return true;
+}
+
+
+/*
+ * MISCELLANEOUS
+ */
+
+/*
+ * GUC check_hook for application_name
+ */
+bool
+check_application_name(char **newval, void **extra, GucSource source)
+{
+       char       *clean;
+
+       /* Only allow clean ASCII chars in the application name */
+       clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
+       if (!clean)
+               return false;
+
+       clean = guc_strdup(WARNING, clean);
+       if (!clean)
+               return false;
+
+       *newval = clean;
+       return true;
+}
+
+/*
+ * GUC assign_hook for application_name
+ */
+void
+assign_application_name(const char *newval, void *extra)
+{
+       /* Update the pg_stat_activity view */
+       pgstat_report_appname(newval);
+}
+
+/*
+ * GUC check_hook for cluster_name
+ */
+bool
+check_cluster_name(char **newval, void **extra, GucSource source)
+{
+       char       *clean;
+
+       /* Only allow clean ASCII chars in the cluster name */
+       clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
+       if (!clean)
+               return false;
+
+       clean = guc_strdup(WARNING, clean);
+       if (!clean)
+               return false;
+
+       *newval = clean;
+       return true;
+}
+
+/*
+ * GUC assign_hook for maintenance_io_concurrency
+ */
+void
+assign_maintenance_io_concurrency(int newval, void *extra)
+{
+#ifdef USE_PREFETCH
+       /*
+        * Reconfigure recovery prefetching, because a setting it depends on
+        * changed.
+        */
+       maintenance_io_concurrency = newval;
+       if (AmStartupProcess())
+               XLogPrefetchReconfigure();
+#endif
+}
+
+
+/*
+ * These show hooks just exist because we want to show the values in octal.
+ */
+
+/*
+ * GUC show_hook for data_directory_mode
+ */
+const char *
+show_data_directory_mode(void)
+{
+       static char buf[12];
+
+       snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
+       return buf;
+}
+
+/*
+ * GUC show_hook for log_file_mode
+ */
+const char *
+show_log_file_mode(void)
+{
+       static char buf[12];
+
+       snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
+       return buf;
+}
+
+/*
+ * GUC show_hook for unix_socket_permissions
+ */
+const char *
+show_unix_socket_permissions(void)
+{
+       static char buf[12];
+
+       snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
+       return buf;
+}
+
+
+/*
+ * These check hooks do nothing more than reject non-default settings
+ * in builds that don't support them.
+ */
+
+bool
+check_bonjour(bool *newval, void **extra, GucSource source)
+{
+#ifndef USE_BONJOUR
+       if (*newval)
+       {
+               GUC_check_errmsg("Bonjour is not supported by this build");
+               return false;
+       }
+#endif
+       return true;
+}
+
+bool
+check_default_with_oids(bool *newval, void **extra, GucSource source)
+{
+       if (*newval)
+       {
+               /* check the GUC's definition for an explanation */
+               GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
+               GUC_check_errmsg("tables declared WITH OIDS are not supported");
+
+               return false;
+       }
+
+       return true;
+}
+
+bool
+check_effective_io_concurrency(int *newval, void **extra, GucSource source)
+{
+#ifndef USE_PREFETCH
+       if (*newval != 0)
+       {
+               GUC_check_errdetail("effective_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
+               return false;
+       }
+#endif                                                 /* USE_PREFETCH */
+       return true;
+}
+
+bool
+check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
+{
+#ifndef USE_PREFETCH
+       if (*newval != 0)
+       {
+               GUC_check_errdetail("maintenance_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
+               return false;
+       }
+#endif                                                 /* USE_PREFETCH */
+       return true;
+}
+
+bool
+check_ssl(bool *newval, void **extra, GucSource source)
+{
+#ifndef USE_SSL
+       if (*newval)
+       {
+               GUC_check_errmsg("SSL is not supported by this build");
+               return false;
+       }
+#endif
+       return true;
+}
index cba0caced73f0fac421c15de9b533ba8fc3de7fd..ce56ab1d41df6ab0f01091e436851edee7d2215e 100644 (file)
@@ -78,7 +78,7 @@
 #include "miscadmin.h"
 #include "port/pg_bswap.h"
 #include "storage/ipc.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/memutils.h"
 
 /*
@@ -1914,6 +1914,108 @@ pq_settcpusertimeout(int timeout, Port *port)
        return STATUS_OK;
 }
 
+/*
+ * GUC assign_hook for tcp_keepalives_idle
+ */
+void
+assign_tcp_keepalives_idle(int newval, void *extra)
+{
+       /*
+        * The kernel API provides no way to test a value without setting it; and
+        * once we set it we might fail to unset it.  So there seems little point
+        * in fully implementing the check-then-assign GUC API for these
+        * variables.  Instead we just do the assignment on demand.
+        * pq_setkeepalivesidle reports any problems via ereport(LOG).
+        *
+        * This approach means that the GUC value might have little to do with the
+        * actual kernel value, so we use a show_hook that retrieves the kernel
+        * value rather than trusting GUC's copy.
+        */
+       (void) pq_setkeepalivesidle(newval, MyProcPort);
+}
+
+/*
+ * GUC show_hook for tcp_keepalives_idle
+ */
+const char *
+show_tcp_keepalives_idle(void)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       static char nbuf[16];
+
+       snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesidle(MyProcPort));
+       return nbuf;
+}
+
+/*
+ * GUC assign_hook for tcp_keepalives_interval
+ */
+void
+assign_tcp_keepalives_interval(int newval, void *extra)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       (void) pq_setkeepalivesinterval(newval, MyProcPort);
+}
+
+/*
+ * GUC show_hook for tcp_keepalives_interval
+ */
+const char *
+show_tcp_keepalives_interval(void)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       static char nbuf[16];
+
+       snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesinterval(MyProcPort));
+       return nbuf;
+}
+
+/*
+ * GUC assign_hook for tcp_keepalives_count
+ */
+void
+assign_tcp_keepalives_count(int newval, void *extra)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       (void) pq_setkeepalivescount(newval, MyProcPort);
+}
+
+/*
+ * GUC show_hook for tcp_keepalives_count
+ */
+const char *
+show_tcp_keepalives_count(void)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       static char nbuf[16];
+
+       snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivescount(MyProcPort));
+       return nbuf;
+}
+
+/*
+ * GUC assign_hook for tcp_user_timeout
+ */
+void
+assign_tcp_user_timeout(int newval, void *extra)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       (void) pq_settcpusertimeout(newval, MyProcPort);
+}
+
+/*
+ * GUC show_hook for tcp_user_timeout
+ */
+const char *
+show_tcp_user_timeout(void)
+{
+       /* See comments in assign_tcp_keepalives_idle */
+       static char nbuf[16];
+
+       snprintf(nbuf, sizeof(nbuf), "%d", pq_gettcpusertimeout(MyProcPort));
+       return nbuf;
+}
+
 /*
  * Check if the client is still connected.
  */
index 091d6e886b646bfb71521d8d520eb6bec359b53e..57c9b51814c80cdc8b97e7b827abad5a2936b171 100644 (file)
@@ -31,6 +31,7 @@
 #include "partitioning/partbounds.h"
 #include "partitioning/partdesc.h"
 #include "partitioning/partprune.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datum.h"
 #include "utils/fmgroids.h"
index e62d4a618ea4a7a21f4946f712f1c973191cbcac..97ce7b7c497f6a802ebb8631df3cde89ecd6d612 100644 (file)
@@ -34,7 +34,7 @@
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/pidfile.h"
 
 
@@ -570,6 +570,23 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
 #endif                                                 /* MAP_HUGETLB */
 }
 
+/*
+ * GUC check_hook for huge_page_size
+ */
+bool
+check_huge_page_size(int *newval, void **extra, GucSource source)
+{
+#if !(defined(MAP_HUGE_MASK) && defined(MAP_HUGE_SHIFT))
+       /* Recent enough Linux only, for now.  See GetHugePageSize(). */
+       if (*newval != 0)
+       {
+               GUC_check_errdetail("huge_page_size must be 0 on this platform.");
+               return false;
+       }
+#endif
+       return true;
+}
+
 /*
  * Creates an anonymous mmap()ed shared memory segment.
  *
index 6cf69411db1da8b8611afaf2a77b57083358d5f1..d3c9b0f098784d96f08c937906a661d62e9b19e1 100644 (file)
@@ -16,6 +16,8 @@
 #include "storage/dsm.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
+#include "utils/guc_hooks.h"
+
 
 /*
  * Early in a process's life, Windows asynchronously creates threads for the
@@ -619,3 +621,17 @@ GetHugePageSize(Size *hugepagesize, int *mmap_flags)
        if (mmap_flags)
                *mmap_flags = 0;
 }
+
+/*
+ * GUC check_hook for huge_page_size
+ */
+bool
+check_huge_page_size(int *newval, void **extra, GucSource source)
+{
+       if (*newval != 0)
+       {
+               GUC_check_errdetail("huge_page_size must be 0 on this platform.");
+               return false;
+       }
+       return true;
+}
index 9dc6bf9477f16040892d33fd58df79239e208259..1e90b72b7403062b10230e8b2b4736d05207a08a 100644 (file)
@@ -99,6 +99,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/fmgroids.h"
 #include "utils/fmgrprotos.h"
+#include "utils/guc_hooks.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
@@ -3374,3 +3375,29 @@ AutoVacuumShmemInit(void)
        else
                Assert(found);
 }
+
+/*
+ * GUC check_hook for autovacuum_work_mem
+ */
+bool
+check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
+{
+       /*
+        * -1 indicates fallback.
+        *
+        * If we haven't yet changed the boot_val default of -1, just let it be.
+        * Autovacuum will look to maintenance_work_mem instead.
+        */
+       if (*newval == -1)
+               return true;
+
+       /*
+        * We clamp manually-set values to at least 1MB.  Since
+        * maintenance_work_mem is always set to at least this value, do the same
+        * here.
+        */
+       if (*newval < 1024)
+               *newval = 1024;
+
+       return true;
+}
index 8ff6ab362fd06a486bad625685c68b54a6330b73..fe1ec2bc81002c009e584888f34fc6d6b2f4bd7d 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "access/xlogdefs.h"
 #include "nodes/makefuncs.h"
+#include "nodes/parsenodes.h"
 #include "nodes/replnodes.h"
 #include "replication/walsender.h"
 #include "replication/walsender_private.h"
index 23fcb2a11d107f916eaaa904e522b87626dfc094..72ef12225eab5b19cef83a21f751196f2e04770e 100644 (file)
@@ -15,6 +15,7 @@
  */
 #include "postgres.h"
 
+#include "nodes/parsenodes.h"
 #include "utils/builtins.h"
 #include "parser/scansup.h"
 
index ce163b99e95f88360205a2eb0c1c563e46e0b7eb..e360d925b0df5def871925a218c276e2d4cf1b0b 100644 (file)
@@ -84,6 +84,7 @@
 #include "storage/proc.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/guc_hooks.h"
 #include "utils/ps_status.h"
 
 /* User-settable parameters for sync rep */
index c18ddb2e9bc6d64178995e2f83829e77da5e085a..4a8b9f247bde97c744ffb08cdae47575e47c27a9 100644 (file)
@@ -14,6 +14,7 @@
  */
 #include "postgres.h"
 
+#include "nodes/pg_list.h"
 #include "replication/syncrep.h"
 
 /* Result of parsing is returned in one of these two variables */
index bdb1a3391cf0f3b0769722fd71c8dfc4b92c2e96..2f942357f9d17340eb71e3789caa0e8df9b0aa09 100644 (file)
@@ -16,6 +16,7 @@
 #include "postgres.h"
 
 #include "lib/stringinfo.h"
+#include "nodes/pg_list.h"
 
 /*
  * NB: include syncrep_gram.h only AFTER including syncrep.h, because syncrep.h
index 98530078a6db98540a41e1c9bc1a6f9d11b2e261..30d67d1c40d913afd142591701cbcac7e997d41c 100644 (file)
@@ -20,7 +20,7 @@
 #include "executor/instrument.h"
 #include "storage/buf_internals.h"
 #include "storage/bufmgr.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/memutils.h"
 #include "utils/resowner_private.h"
 
@@ -483,6 +483,24 @@ InitLocalBuffers(void)
        NLocBuffer = nbufs;
 }
 
+/*
+ * GUC check_hook for temp_buffers
+ */
+bool
+check_temp_buffers(int *newval, void **extra, GucSource source)
+{
+       /*
+        * Once local buffers have been initialized, it's too late to change this.
+        * However, if this is only a test call, allow it.
+        */
+       if (source != PGC_S_TEST && NLocBuffer && NLocBuffer != *newval)
+       {
+               GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
+               return false;
+       }
+       return true;
+}
+
 /*
  * GetLocalBufferStorage - allocate memory for a local buffer
  *
index 1a6f527051845ff2dac3d46a987ff68943cb3e5e..b204ecdbc3297799b07bc1a928e3b39d90f3258a 100644 (file)
@@ -47,6 +47,7 @@
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
 #include "storage/spin.h"
+#include "utils/guc.h"
 #include "utils/snapmgr.h"
 
 /* GUCs */
index 5136da6ea36b54c7e7f6cf7454fb1afa45ee7a0d..562ac5b4321a7ab84629d766dedbf71f457750bc 100644 (file)
@@ -1685,8 +1685,8 @@ GetSerializableTransactionSnapshot(Snapshot snapshot)
        /*
         * Can't use serializable mode while recovery is still active, as it is,
         * for example, on a hot standby.  We could get here despite the check in
-        * check_XactIsoLevel() if default_transaction_isolation is set to
-        * serializable, so phrase the hint accordingly.
+        * check_transaction_isolation() if default_transaction_isolation is set
+        * to serializable, so phrase the hint accordingly.
         */
        if (RecoveryInProgress())
                ereport(ERROR,
index c6ca3b5b3d495f124c99578cde542a2de69ae998..35eff28bd363de0eacef4119b36919a5a10c4654 100644 (file)
@@ -67,6 +67,7 @@
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
+#include "utils/guc_hooks.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
@@ -3505,6 +3506,58 @@ assign_max_stack_depth(int newval, void *extra)
        max_stack_depth_bytes = newval_bytes;
 }
 
+/*
+ * GUC check_hook for client_connection_check_interval
+ */
+bool
+check_client_connection_check_interval(int *newval, void **extra, GucSource source)
+{
+       if (!WaitEventSetCanReportClosed() && *newval != 0)
+       {
+               GUC_check_errdetail("client_connection_check_interval must be set to 0 on this platform.");
+               return false;
+       }
+       return true;
+}
+
+/*
+ * GUC check_hook for log_parser_stats, log_planner_stats, log_executor_stats
+ *
+ * This function and check_log_stats interact to prevent their variables from
+ * being set in a disallowed combination.  This is a hack that doesn't really
+ * work right; for example it might fail while applying pg_db_role_setting
+ * values even though the final state would have been acceptable.  However,
+ * since these variables are legacy settings with little production usage,
+ * we tolerate that.
+ */
+bool
+check_stage_log_stats(bool *newval, void **extra, GucSource source)
+{
+       if (*newval && log_statement_stats)
+       {
+               GUC_check_errdetail("Cannot enable parameter when \"log_statement_stats\" is true.");
+               return false;
+       }
+       return true;
+}
+
+/*
+ * GUC check_hook for log_statement_stats
+ */
+bool
+check_log_stats(bool *newval, void **extra, GucSource source)
+{
+       if (*newval &&
+               (log_parser_stats || log_planner_stats || log_executor_stats))
+       {
+               GUC_check_errdetail("Cannot enable \"log_statement_stats\" when "
+                                                       "\"log_parser_stats\", \"log_planner_stats\", "
+                                                       "or \"log_executor_stats\" is true.");
+               return false;
+       }
+       return true;
+}
+
 
 /*
  * set_debug_options --- apply "-d N" command line option
index c6ea9f9269465b8a32c8f33d712ea266c887b018..f2c468f84667800b367ba13e286b1df41165d4e3 100644 (file)
@@ -16,6 +16,7 @@
 #include "catalog/pg_type.h"
 #include "tsearch/ts_cache.h"
 #include "tsearch/ts_utils.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 
 
index 1a047a97d74e7fe5b2cad22cd54cf30f7129bf84..2b42d9ccd8b751bcb5cda3a1f4c7803a68bc0a4a 100644 (file)
@@ -60,6 +60,7 @@
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/formatting.h"
+#include "utils/guc_hooks.h"
 #include "utils/hsearch.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
index 50b588e3d0f047d43cc5517f9fb07fda9fade99b..c746759eef4f21a0e4e149f0cfe450cc28a57f52 100644 (file)
 #include "statistics/statistics.h"
 #include "storage/bufmgr.h"
 #include "utils/acl.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datum.h"
index bbeb0a2653a89dccc916268f12c6c2e81585a273..68e2e6f7a719866eacc506e1780f6d1b58951599 100644 (file)
@@ -15,6 +15,7 @@
 #include "postgres.h"
 
 #include "access/detoast.h"
+#include "access/htup_details.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_type.h"
 #include "common/hashfn.h"
index 6ef317e1f93a301934b15b7cd14fc4cd324fbe7d..816c66b7e77a73cdd09bf3242368bd831cbe6006 100644 (file)
@@ -34,6 +34,7 @@
 #include "regex/regex.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
+#include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
index 24808dfbb14aec8e6aba5c7b200f8ec5f284c34a..890832f353c35f25b0bdb8f373644fafec814f53 100644 (file)
@@ -42,6 +42,7 @@
 #include "utils/builtins.h"
 #include "utils/catcache.h"
 #include "utils/fmgroids.h"
+#include "utils/guc_hooks.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -584,7 +585,7 @@ getTSCurrentConfig(bool emitError)
 
 /* GUC check_hook for default_text_search_config */
 bool
-check_TSCurrentConfig(char **newval, void **extra, GucSource source)
+check_default_text_search_config(char **newval, void **extra, GucSource source)
 {
        /*
         * If we aren't inside a transaction, or connected to a database, we
@@ -645,7 +646,7 @@ check_TSCurrentConfig(char **newval, void **extra, GucSource source)
 
 /* GUC assign_hook for default_text_search_config */
 void
-assign_TSCurrentConfig(const char *newval, void *extra)
+assign_default_text_search_config(const char *newval, void *extra)
 {
        /* Just reset the cache to force a lookup on first use */
        TSCurrentConfigCache = InvalidOid;
index cb3c28988980a0f457d1dcdce4f4684713046196..96c694da8fd7bc933e64cd6525902294299ab28b 100644 (file)
 #include "storage/ipc.h"
 #include "storage/proc.h"
 #include "tcop/tcopprot.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
+#include "utils/varlena.h"
 
 
 /* In this module, access gettext() via err_gettext() */
@@ -113,6 +114,9 @@ char           *Log_destination_string = NULL;
 bool           syslog_sequence_numbers = true;
 bool           syslog_split_messages = true;
 
+/* Processed form of backtrace_symbols GUC */
+static char *backtrace_symbol_list;
+
 #ifdef HAVE_SYSLOG
 
 /*
@@ -1957,14 +1961,159 @@ DebugFileOpen(void)
 }
 
 
+/*
+ * GUC check_hook for backtrace_functions
+ *
+ * We split the input string, where commas separate function names
+ * and certain whitespace chars are ignored, into a \0-separated (and
+ * \0\0-terminated) list of function names.  This formulation allows
+ * easy scanning when an error is thrown while avoiding the use of
+ * non-reentrant strtok(), as well as keeping the output data in a
+ * single palloc() chunk.
+ */
+bool
+check_backtrace_functions(char **newval, void **extra, GucSource source)
+{
+       int                     newvallen = strlen(*newval);
+       char       *someval;
+       int                     validlen;
+       int                     i;
+       int                     j;
+
+       /*
+        * Allow characters that can be C identifiers and commas as separators, as
+        * well as some whitespace for readability.
+        */
+       validlen = strspn(*newval,
+                                         "0123456789_"
+                                         "abcdefghijklmnopqrstuvwxyz"
+                                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                         ", \n\t");
+       if (validlen != newvallen)
+       {
+               GUC_check_errdetail("invalid character");
+               return false;
+       }
+
+       if (*newval[0] == '\0')
+       {
+               *extra = NULL;
+               return true;
+       }
+
+       /*
+        * Allocate space for the output and create the copy.  We could discount
+        * whitespace chars to save some memory, but it doesn't seem worth the
+        * trouble.
+        */
+       someval = guc_malloc(ERROR, newvallen + 1 + 1);
+       for (i = 0, j = 0; i < newvallen; i++)
+       {
+               if ((*newval)[i] == ',')
+                       someval[j++] = '\0';    /* next item */
+               else if ((*newval)[i] == ' ' ||
+                                (*newval)[i] == '\n' ||
+                                (*newval)[i] == '\t')
+                       ;                                       /* ignore these */
+               else
+                       someval[j++] = (*newval)[i];    /* copy anything else */
+       }
+
+       /* two \0s end the setting */
+       someval[j] = '\0';
+       someval[j + 1] = '\0';
+
+       *extra = someval;
+       return true;
+}
+
+/*
+ * GUC assign_hook for backtrace_functions
+ */
+void
+assign_backtrace_functions(const char *newval, void *extra)
+{
+       backtrace_symbol_list = (char *) extra;
+}
+
+/*
+ * GUC check_hook for log_destination
+ */
+bool
+check_log_destination(char **newval, void **extra, GucSource source)
+{
+       char       *rawstring;
+       List       *elemlist;
+       ListCell   *l;
+       int                     newlogdest = 0;
+       int                *myextra;
+
+       /* Need a modifiable copy of string */
+       rawstring = pstrdup(*newval);
+
+       /* Parse string into list of identifiers */
+       if (!SplitIdentifierString(rawstring, ',', &elemlist))
+       {
+               /* syntax error in list */
+               GUC_check_errdetail("List syntax is invalid.");
+               pfree(rawstring);
+               list_free(elemlist);
+               return false;
+       }
+
+       foreach(l, elemlist)
+       {
+               char       *tok = (char *) lfirst(l);
+
+               if (pg_strcasecmp(tok, "stderr") == 0)
+                       newlogdest |= LOG_DESTINATION_STDERR;
+               else if (pg_strcasecmp(tok, "csvlog") == 0)
+                       newlogdest |= LOG_DESTINATION_CSVLOG;
+               else if (pg_strcasecmp(tok, "jsonlog") == 0)
+                       newlogdest |= LOG_DESTINATION_JSONLOG;
 #ifdef HAVE_SYSLOG
+               else if (pg_strcasecmp(tok, "syslog") == 0)
+                       newlogdest |= LOG_DESTINATION_SYSLOG;
+#endif
+#ifdef WIN32
+               else if (pg_strcasecmp(tok, "eventlog") == 0)
+                       newlogdest |= LOG_DESTINATION_EVENTLOG;
+#endif
+               else
+               {
+                       GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
+                       pfree(rawstring);
+                       list_free(elemlist);
+                       return false;
+               }
+       }
+
+       pfree(rawstring);
+       list_free(elemlist);
+
+       myextra = (int *) guc_malloc(ERROR, sizeof(int));
+       *myextra = newlogdest;
+       *extra = (void *) myextra;
+
+       return true;
+}
+
+/*
+ * GUC assign_hook for log_destination
+ */
+void
+assign_log_destination(const char *newval, void *extra)
+{
+       Log_destination = *((int *) extra);
+}
 
 /*
- * Set or update the parameters for syslog logging
+ * GUC assign_hook for syslog_ident
  */
 void
-set_syslog_parameters(const char *ident, int facility)
+assign_syslog_ident(const char *newval, void *extra)
 {
+#ifdef HAVE_SYSLOG
        /*
         * guc.c is likely to call us repeatedly with same parameters, so don't
         * thrash the syslog connection unnecessarily.  Also, we do not re-open
@@ -1975,8 +2124,7 @@ set_syslog_parameters(const char *ident, int facility)
         * on guc.c's.  This may be overly paranoid, but it ensures that we cannot
         * accidentally free a string that syslog is still using.
         */
-       if (syslog_ident == NULL || strcmp(syslog_ident, ident) != 0 ||
-               syslog_facility != facility)
+       if (syslog_ident == NULL || strcmp(syslog_ident, newval) != 0)
        {
                if (openlog_done)
                {
@@ -1984,12 +2132,37 @@ set_syslog_parameters(const char *ident, int facility)
                        openlog_done = false;
                }
                free(syslog_ident);
-               syslog_ident = strdup(ident);
+               syslog_ident = strdup(newval);
                /* if the strdup fails, we will cope in write_syslog() */
-               syslog_facility = facility;
        }
+#endif
+       /* Without syslog support, just ignore it */
+}
+
+/*
+ * GUC assign_hook for syslog_facility
+ */
+void
+assign_syslog_facility(int newval, void *extra)
+{
+#ifdef HAVE_SYSLOG
+       /*
+        * As above, don't thrash the syslog connection unnecessarily.
+        */
+       if (syslog_facility != newval)
+       {
+               if (openlog_done)
+               {
+                       closelog();
+                       openlog_done = false;
+               }
+               syslog_facility = newval;
+       }
+#endif
+       /* Without syslog support, just ignore it */
 }
 
+#ifdef HAVE_SYSLOG
 
 /*
  * Write a message line to syslog
index 2b65ef3deb02b9d77b3592419f903a155b9a9338..4a207a739178d801748f07e5072e23b724972bd6 100644 (file)
@@ -58,7 +58,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
-#include "utils/guc.h"
+#include "utils/guc_hooks.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/portal.h"
@@ -563,6 +563,54 @@ InitializeMaxBackends(void)
                elog(ERROR, "too many backends configured");
 }
 
+/*
+ * GUC check_hook for max_connections
+ */
+bool
+check_max_connections(int *newval, void **extra, GucSource source)
+{
+       if (*newval + autovacuum_max_workers + 1 +
+               max_worker_processes + max_wal_senders > MAX_BACKENDS)
+               return false;
+       return true;
+}
+
+/*
+ * GUC check_hook for autovacuum_max_workers
+ */
+bool
+check_autovacuum_max_workers(int *newval, void **extra, GucSource source)
+{
+       if (MaxConnections + *newval + 1 +
+               max_worker_processes + max_wal_senders > MAX_BACKENDS)
+               return false;
+       return true;
+}
+
+/*
+ * GUC check_hook for max_worker_processes
+ */
+bool
+check_max_worker_processes(int *newval, void **extra, GucSource source)
+{
+       if (MaxConnections + autovacuum_max_workers + 1 +
+               *newval + max_wal_senders > MAX_BACKENDS)
+               return false;
+       return true;
+}
+
+/*
+ * GUC check_hook for max_wal_senders
+ */
+bool
+check_max_wal_senders(int *newval, void **extra, GucSource source)
+{
+       if (MaxConnections + autovacuum_max_workers + 1 +
+               max_worker_processes + *newval > MAX_BACKENDS)
+               return false;
+       return true;
+}
+
 /*
  * Early initialization of a backend (either standalone or under postmaster).
  * This happens even before InitPostgres.
index cf7ce9bc83788fabd546df4d8b178231c53c2d70..60973090331c02da1c06ff21ab09608a35355ded 100644 (file)
@@ -17,6 +17,8 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
 OBJS = \
        guc.o \
        guc-file.o \
+       guc_funcs.o \
+       guc_tables.o \
        help_config.o \
        pg_config.o \
        pg_controldata.o \
index ec64b39272b232437202b4ffc423f95312499b15..b11d609bbea7c7a8fb264dfb51936c9c57bac3fb 100644 (file)
@@ -3,6 +3,14 @@
  *
  * Support for grand unified configuration scheme, including SET
  * command, configuration file, and command line options.
+ *
+ * This file contains the generic option processing infrastructure.
+ * guc_funcs.c contains SQL-level functionality, including SET/SHOW
+ * commands and various system-administration SQL functions.
+ * guc_tables.c contains the arrays that define all the built-in
+ * GUC variables.  Code that implements variable-specific behavior
+ * is scattered around the system in check, assign, and show hooks.
+ *
  * See src/backend/utils/misc/README for more information.
  *
  *
  */
 #include "postgres.h"
 
-#include <ctype.h>
-#include <float.h>
-#include <math.h>
 #include <limits.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifndef WIN32
-#include <sys/mman.h>
-#endif
 #include <sys/stat.h>
-#ifdef HAVE_SYSLOG
-#include <syslog.h>
-#endif
 #include <unistd.h>
 
-#include "access/commit_ts.h"
-#include "access/gin.h"
-#include "access/rmgr.h"
-#include "access/tableam.h"
-#include "access/toast_compression.h"
-#include "access/transam.h"
-#include "access/twophase.h"
 #include "access/xact.h"
-#include "access/xlog_internal.h"
-#include "access/xlogprefetcher.h"
-#include "access/xlogrecovery.h"
-#include "catalog/namespace.h"
+#include "access/xlog.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_parameter_acl.h"
-#include "catalog/storage.h"
-#include "commands/async.h"
-#include "commands/prepare.h"
-#include "commands/tablespace.h"
-#include "commands/trigger.h"
-#include "commands/user.h"
-#include "commands/vacuum.h"
-#include "commands/variable.h"
-#include "common/string.h"
-#include "funcapi.h"
 #include "guc_internal.h"
-#include "jit/jit.h"
-#include "libpq/auth.h"
-#include "libpq/libpq.h"
 #include "libpq/pqformat.h"
-#include "miscadmin.h"
-#include "optimizer/cost.h"
-#include "optimizer/geqo.h"
-#include "optimizer/optimizer.h"
-#include "optimizer/paths.h"
-#include "optimizer/planmain.h"
-#include "parser/parse_expr.h"
-#include "parser/parse_type.h"
-#include "parser/parser.h"
 #include "parser/scansup.h"
-#include "pgstat.h"
-#include "postmaster/autovacuum.h"
-#include "postmaster/bgworker_internals.h"
-#include "postmaster/bgwriter.h"
-#include "postmaster/postmaster.h"
-#include "postmaster/startup.h"
-#include "postmaster/syslogger.h"
-#include "postmaster/walwriter.h"
-#include "replication/logicallauncher.h"
-#include "replication/reorderbuffer.h"
-#include "replication/slot.h"
-#include "replication/syncrep.h"
-#include "replication/walreceiver.h"
-#include "replication/walsender.h"
-#include "storage/bufmgr.h"
-#include "storage/dsm_impl.h"
 #include "storage/fd.h"
-#include "storage/large_object.h"
-#include "storage/pg_shmem.h"
-#include "storage/predicate.h"
-#include "storage/proc.h"
-#include "storage/standby.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
 #include "tcop/tcopprot.h"
-#include "tsearch/ts_cache.h"
 #include "utils/acl.h"
 #include "utils/backend_status.h"
 #include "utils/builtins.h"
-#include "utils/bytea.h"
 #include "utils/float.h"
 #include "utils/guc_tables.h"
 #include "utils/memutils.h"
-#include "utils/pg_locale.h"
-#include "utils/pg_lsn.h"
-#include "utils/plancache.h"
-#include "utils/portal.h"
-#include "utils/ps_status.h"
-#include "utils/queryjumble.h"
-#include "utils/rls.h"
-#include "utils/snapmgr.h"
-#include "utils/tzparser.h"
-#include "utils/inval.h"
-#include "utils/varlena.h"
-#include "utils/xml.h"
-
-#ifndef PG_KRB_SRVTAB
-#define PG_KRB_SRVTAB ""
-#endif
+#include "utils/timestamp.h"
+
 
 #define CONFIG_FILENAME "postgresql.conf"
 #define HBA_FILENAME   "pg_hba.conf"
  */
 #define REALTYPE_PRECISION 17
 
-/* XXX these should appear in other modules' header files */
-extern bool Log_disconnections;
-extern int     CommitDelay;
-extern int     CommitSiblings;
-extern char *default_tablespace;
-extern char *temp_tablespaces;
-extern bool ignore_checksum_failure;
-extern bool ignore_invalid_pages;
-extern bool synchronize_seqscans;
-
-#ifdef TRACE_SYNCSCAN
-extern bool trace_syncscan;
-#endif
-#ifdef DEBUG_BOUNDED_SORT
-extern bool optimize_bounded_sort;
-#endif
-
 static int     GUC_check_errcode_value;
 
 static List *reserved_class_prefix = NIL;
@@ -161,725 +73,9 @@ char          *GUC_check_errmsg_string;
 char      *GUC_check_errdetail_string;
 char      *GUC_check_errhint_string;
 
-static void do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) pg_attribute_printf(3, 4);
-
-static void set_config_sourcefile(const char *name, char *sourcefile,
-                                                                 int sourceline);
-static bool call_bool_check_hook(struct config_bool *conf, bool *newval,
-                                                                void **extra, GucSource source, int elevel);
-static bool call_int_check_hook(struct config_int *conf, int *newval,
-                                                               void **extra, GucSource source, int elevel);
-static bool call_real_check_hook(struct config_real *conf, double *newval,
-                                                                void **extra, GucSource source, int elevel);
-static bool call_string_check_hook(struct config_string *conf, char **newval,
-                                                                  void **extra, GucSource source, int elevel);
-static bool call_enum_check_hook(struct config_enum *conf, int *newval,
-                                                                void **extra, GucSource source, int elevel);
-
-static bool check_log_destination(char **newval, void **extra, GucSource source);
-static void assign_log_destination(const char *newval, void *extra);
-
-static bool check_wal_consistency_checking(char **newval, void **extra,
-                                                                                  GucSource source);
-static void assign_wal_consistency_checking(const char *newval, void *extra);
-
-#ifdef HAVE_SYSLOG
-static int     syslog_facility = LOG_LOCAL0;
-#else
-static int     syslog_facility = 0;
-#endif
-
-static void assign_syslog_facility(int newval, void *extra);
-static void assign_syslog_ident(const char *newval, void *extra);
-static void assign_session_replication_role(int newval, void *extra);
-static bool check_temp_buffers(int *newval, void **extra, GucSource source);
-static bool check_bonjour(bool *newval, void **extra, GucSource source);
-static bool check_ssl(bool *newval, void **extra, GucSource source);
-static bool check_stage_log_stats(bool *newval, void **extra, GucSource source);
-static bool check_log_stats(bool *newval, void **extra, GucSource source);
-static bool check_canonical_path(char **newval, void **extra, GucSource source);
-static bool check_timezone_abbreviations(char **newval, void **extra, GucSource source);
-static void assign_timezone_abbreviations(const char *newval, void *extra);
-static void pg_timezone_abbrev_initialize(void);
-static const char *show_archive_command(void);
-static void assign_tcp_keepalives_idle(int newval, void *extra);
-static void assign_tcp_keepalives_interval(int newval, void *extra);
-static void assign_tcp_keepalives_count(int newval, void *extra);
-static void assign_tcp_user_timeout(int newval, void *extra);
-static const char *show_tcp_keepalives_idle(void);
-static const char *show_tcp_keepalives_interval(void);
-static const char *show_tcp_keepalives_count(void);
-static const char *show_tcp_user_timeout(void);
-static bool check_maxconnections(int *newval, void **extra, GucSource source);
-static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
-static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
-static bool check_max_wal_senders(int *newval, void **extra, GucSource source);
-static bool check_autovacuum_work_mem(int *newval, void **extra, GucSource source);
-static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source);
-static bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source);
-static bool check_huge_page_size(int *newval, void **extra, GucSource source);
-static bool check_client_connection_check_interval(int *newval, void **extra, GucSource source);
-static void assign_maintenance_io_concurrency(int newval, void *extra);
-static bool check_application_name(char **newval, void **extra, GucSource source);
-static void assign_application_name(const char *newval, void *extra);
-static bool check_cluster_name(char **newval, void **extra, GucSource source);
-static const char *show_unix_socket_permissions(void);
-static const char *show_log_file_mode(void);
-static const char *show_data_directory_mode(void);
-static const char *show_in_hot_standby(void);
-static bool check_backtrace_functions(char **newval, void **extra, GucSource source);
-static void assign_backtrace_functions(const char *newval, void *extra);
-static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
-static void assign_recovery_target_timeline(const char *newval, void *extra);
-static bool check_recovery_target(char **newval, void **extra, GucSource source);
-static void assign_recovery_target(const char *newval, void *extra);
-static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
-static void assign_recovery_target_xid(const char *newval, void *extra);
-static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
-static void assign_recovery_target_time(const char *newval, void *extra);
-static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
-static void assign_recovery_target_name(const char *newval, void *extra);
-static bool check_recovery_target_lsn(char **newval, void **extra, GucSource source);
-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);
-
-/*
- * Track whether there were any deferred checks for custom resource managers
- * specified in wal_consistency_checking.
- */
-static bool check_wal_consistency_checking_deferred = false;
-
-/*
- * Options for enum values defined in this module.
- *
- * NOTE! Option values may not contain double quotes!
- */
-
-static const struct config_enum_entry bytea_output_options[] = {
-       {"escape", BYTEA_OUTPUT_ESCAPE, false},
-       {"hex", BYTEA_OUTPUT_HEX, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(bytea_output_options) == (BYTEA_OUTPUT_HEX + 2),
-                                "array length mismatch");
-
-/*
- * We have different sets for client and server message level options because
- * they sort slightly different (see "log" level), and because "fatal"/"panic"
- * aren't sensible for client_min_messages.
- */
-static const struct config_enum_entry client_message_level_options[] = {
-       {"debug5", DEBUG5, false},
-       {"debug4", DEBUG4, false},
-       {"debug3", DEBUG3, false},
-       {"debug2", DEBUG2, false},
-       {"debug1", DEBUG1, false},
-       {"debug", DEBUG2, true},
-       {"log", LOG, false},
-       {"info", INFO, true},
-       {"notice", NOTICE, false},
-       {"warning", WARNING, false},
-       {"error", ERROR, false},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry server_message_level_options[] = {
-       {"debug5", DEBUG5, false},
-       {"debug4", DEBUG4, false},
-       {"debug3", DEBUG3, false},
-       {"debug2", DEBUG2, false},
-       {"debug1", DEBUG1, false},
-       {"debug", DEBUG2, true},
-       {"info", INFO, false},
-       {"notice", NOTICE, false},
-       {"warning", WARNING, false},
-       {"error", ERROR, false},
-       {"log", LOG, false},
-       {"fatal", FATAL, false},
-       {"panic", PANIC, false},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry intervalstyle_options[] = {
-       {"postgres", INTSTYLE_POSTGRES, false},
-       {"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
-       {"sql_standard", INTSTYLE_SQL_STANDARD, false},
-       {"iso_8601", INTSTYLE_ISO_8601, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(intervalstyle_options) == (INTSTYLE_ISO_8601 + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry log_error_verbosity_options[] = {
-       {"terse", PGERROR_TERSE, false},
-       {"default", PGERROR_DEFAULT, false},
-       {"verbose", PGERROR_VERBOSE, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry log_statement_options[] = {
-       {"none", LOGSTMT_NONE, false},
-       {"ddl", LOGSTMT_DDL, false},
-       {"mod", LOGSTMT_MOD, false},
-       {"all", LOGSTMT_ALL, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(log_statement_options) == (LOGSTMT_ALL + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry isolation_level_options[] = {
-       {"serializable", XACT_SERIALIZABLE, false},
-       {"repeatable read", XACT_REPEATABLE_READ, false},
-       {"read committed", XACT_READ_COMMITTED, false},
-       {"read uncommitted", XACT_READ_UNCOMMITTED, false},
-       {NULL, 0}
-};
-
-static const struct config_enum_entry session_replication_role_options[] = {
-       {"origin", SESSION_REPLICATION_ROLE_ORIGIN, false},
-       {"replica", SESSION_REPLICATION_ROLE_REPLICA, false},
-       {"local", SESSION_REPLICATION_ROLE_LOCAL, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(session_replication_role_options) == (SESSION_REPLICATION_ROLE_LOCAL + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry syslog_facility_options[] = {
-#ifdef HAVE_SYSLOG
-       {"local0", LOG_LOCAL0, false},
-       {"local1", LOG_LOCAL1, false},
-       {"local2", LOG_LOCAL2, false},
-       {"local3", LOG_LOCAL3, false},
-       {"local4", LOG_LOCAL4, false},
-       {"local5", LOG_LOCAL5, false},
-       {"local6", LOG_LOCAL6, false},
-       {"local7", LOG_LOCAL7, false},
-#else
-       {"none", 0, false},
-#endif
-       {NULL, 0}
-};
-
-static const struct config_enum_entry track_function_options[] = {
-       {"none", TRACK_FUNC_OFF, false},
-       {"pl", TRACK_FUNC_PL, false},
-       {"all", TRACK_FUNC_ALL, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(track_function_options) == (TRACK_FUNC_ALL + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry stats_fetch_consistency[] = {
-       {"none", PGSTAT_FETCH_CONSISTENCY_NONE, false},
-       {"cache", PGSTAT_FETCH_CONSISTENCY_CACHE, false},
-       {"snapshot", PGSTAT_FETCH_CONSISTENCY_SNAPSHOT, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(stats_fetch_consistency) == (PGSTAT_FETCH_CONSISTENCY_SNAPSHOT + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry xmlbinary_options[] = {
-       {"base64", XMLBINARY_BASE64, false},
-       {"hex", XMLBINARY_HEX, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(xmlbinary_options) == (XMLBINARY_HEX + 2),
-                                "array length mismatch");
-
-static const struct config_enum_entry xmloption_options[] = {
-       {"content", XMLOPTION_CONTENT, false},
-       {"document", XMLOPTION_DOCUMENT, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(xmloption_options) == (XMLOPTION_CONTENT + 2),
-                                "array length mismatch");
-
-/*
- * Although only "on", "off", and "safe_encoding" are documented, we
- * accept all the likely variants of "on" and "off".
- */
-static const struct config_enum_entry backslash_quote_options[] = {
-       {"safe_encoding", BACKSLASH_QUOTE_SAFE_ENCODING, false},
-       {"on", BACKSLASH_QUOTE_ON, false},
-       {"off", BACKSLASH_QUOTE_OFF, false},
-       {"true", BACKSLASH_QUOTE_ON, true},
-       {"false", BACKSLASH_QUOTE_OFF, true},
-       {"yes", BACKSLASH_QUOTE_ON, true},
-       {"no", BACKSLASH_QUOTE_OFF, true},
-       {"1", BACKSLASH_QUOTE_ON, true},
-       {"0", BACKSLASH_QUOTE_OFF, true},
-       {NULL, 0, false}
-};
-
-/*
- * Although only "on", "off", and "auto" are documented, we accept
- * all the likely variants of "on" and "off".
- */
-static const struct config_enum_entry compute_query_id_options[] = {
-       {"auto", COMPUTE_QUERY_ID_AUTO, false},
-       {"regress", COMPUTE_QUERY_ID_REGRESS, false},
-       {"on", COMPUTE_QUERY_ID_ON, false},
-       {"off", COMPUTE_QUERY_ID_OFF, false},
-       {"true", COMPUTE_QUERY_ID_ON, true},
-       {"false", COMPUTE_QUERY_ID_OFF, true},
-       {"yes", COMPUTE_QUERY_ID_ON, true},
-       {"no", COMPUTE_QUERY_ID_OFF, true},
-       {"1", COMPUTE_QUERY_ID_ON, true},
-       {"0", COMPUTE_QUERY_ID_OFF, true},
-       {NULL, 0, false}
-};
-
-/*
- * Although only "on", "off", and "partition" are documented, we
- * accept all the likely variants of "on" and "off".
- */
-static const struct config_enum_entry constraint_exclusion_options[] = {
-       {"partition", CONSTRAINT_EXCLUSION_PARTITION, false},
-       {"on", CONSTRAINT_EXCLUSION_ON, false},
-       {"off", CONSTRAINT_EXCLUSION_OFF, false},
-       {"true", CONSTRAINT_EXCLUSION_ON, true},
-       {"false", CONSTRAINT_EXCLUSION_OFF, true},
-       {"yes", CONSTRAINT_EXCLUSION_ON, true},
-       {"no", CONSTRAINT_EXCLUSION_OFF, true},
-       {"1", CONSTRAINT_EXCLUSION_ON, true},
-       {"0", CONSTRAINT_EXCLUSION_OFF, true},
-       {NULL, 0, false}
-};
-
-/*
- * Although only "on", "off", "remote_apply", "remote_write", and "local" are
- * documented, we accept all the likely variants of "on" and "off".
- */
-static const struct config_enum_entry synchronous_commit_options[] = {
-       {"local", SYNCHRONOUS_COMMIT_LOCAL_FLUSH, false},
-       {"remote_write", SYNCHRONOUS_COMMIT_REMOTE_WRITE, false},
-       {"remote_apply", SYNCHRONOUS_COMMIT_REMOTE_APPLY, false},
-       {"on", SYNCHRONOUS_COMMIT_ON, false},
-       {"off", SYNCHRONOUS_COMMIT_OFF, false},
-       {"true", SYNCHRONOUS_COMMIT_ON, true},
-       {"false", SYNCHRONOUS_COMMIT_OFF, true},
-       {"yes", SYNCHRONOUS_COMMIT_ON, true},
-       {"no", SYNCHRONOUS_COMMIT_OFF, true},
-       {"1", SYNCHRONOUS_COMMIT_ON, true},
-       {"0", SYNCHRONOUS_COMMIT_OFF, true},
-       {NULL, 0, false}
-};
-
-/*
- * Although only "on", "off", "try" are documented, we accept all the likely
- * variants of "on" and "off".
- */
-static const struct config_enum_entry huge_pages_options[] = {
-       {"off", HUGE_PAGES_OFF, false},
-       {"on", HUGE_PAGES_ON, false},
-       {"try", HUGE_PAGES_TRY, false},
-       {"true", HUGE_PAGES_ON, true},
-       {"false", HUGE_PAGES_OFF, true},
-       {"yes", HUGE_PAGES_ON, true},
-       {"no", HUGE_PAGES_OFF, true},
-       {"1", HUGE_PAGES_ON, true},
-       {"0", HUGE_PAGES_OFF, true},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry recovery_prefetch_options[] = {
-       {"off", RECOVERY_PREFETCH_OFF, false},
-       {"on", RECOVERY_PREFETCH_ON, false},
-       {"try", RECOVERY_PREFETCH_TRY, false},
-       {"true", RECOVERY_PREFETCH_ON, true},
-       {"false", RECOVERY_PREFETCH_OFF, true},
-       {"yes", RECOVERY_PREFETCH_ON, true},
-       {"no", RECOVERY_PREFETCH_OFF, true},
-       {"1", RECOVERY_PREFETCH_ON, true},
-       {"0", RECOVERY_PREFETCH_OFF, true},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry force_parallel_mode_options[] = {
-       {"off", FORCE_PARALLEL_OFF, false},
-       {"on", FORCE_PARALLEL_ON, false},
-       {"regress", FORCE_PARALLEL_REGRESS, false},
-       {"true", FORCE_PARALLEL_ON, true},
-       {"false", FORCE_PARALLEL_OFF, true},
-       {"yes", FORCE_PARALLEL_ON, true},
-       {"no", FORCE_PARALLEL_OFF, true},
-       {"1", FORCE_PARALLEL_ON, true},
-       {"0", FORCE_PARALLEL_OFF, true},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry plan_cache_mode_options[] = {
-       {"auto", PLAN_CACHE_MODE_AUTO, false},
-       {"force_generic_plan", PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, false},
-       {"force_custom_plan", PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, false},
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry password_encryption_options[] = {
-       {"md5", PASSWORD_TYPE_MD5, false},
-       {"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false},
-       {NULL, 0, false}
-};
-
-const struct config_enum_entry ssl_protocol_versions_info[] = {
-       {"", PG_TLS_ANY, false},
-       {"TLSv1", PG_TLS1_VERSION, false},
-       {"TLSv1.1", PG_TLS1_1_VERSION, false},
-       {"TLSv1.2", PG_TLS1_2_VERSION, false},
-       {"TLSv1.3", PG_TLS1_3_VERSION, false},
-       {NULL, 0, false}
-};
-
-StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2),
-                                "array length mismatch");
-
-static struct config_enum_entry recovery_init_sync_method_options[] = {
-       {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false},
-#ifdef HAVE_SYNCFS
-       {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false},
-#endif
-       {NULL, 0, false}
-};
-
-static struct config_enum_entry shared_memory_options[] = {
-#ifndef WIN32
-       {"sysv", SHMEM_TYPE_SYSV, false},
-#endif
-#ifndef EXEC_BACKEND
-       {"mmap", SHMEM_TYPE_MMAP, false},
-#endif
-#ifdef WIN32
-       {"windows", SHMEM_TYPE_WINDOWS, false},
-#endif
-       {NULL, 0, false}
-};
-
-static struct config_enum_entry default_toast_compression_options[] = {
-       {"pglz", TOAST_PGLZ_COMPRESSION, false},
-#ifdef  USE_LZ4
-       {"lz4", TOAST_LZ4_COMPRESSION, false},
-#endif
-       {NULL, 0, false}
-};
-
-static const struct config_enum_entry wal_compression_options[] = {
-       {"pglz", WAL_COMPRESSION_PGLZ, false},
-#ifdef USE_LZ4
-       {"lz4", WAL_COMPRESSION_LZ4, false},
-#endif
-#ifdef USE_ZSTD
-       {"zstd", WAL_COMPRESSION_ZSTD, false},
-#endif
-       {"on", WAL_COMPRESSION_PGLZ, false},
-       {"off", WAL_COMPRESSION_NONE, false},
-       {"true", WAL_COMPRESSION_PGLZ, true},
-       {"false", WAL_COMPRESSION_NONE, true},
-       {"yes", WAL_COMPRESSION_PGLZ, true},
-       {"no", WAL_COMPRESSION_NONE, true},
-       {"1", WAL_COMPRESSION_PGLZ, true},
-       {"0", WAL_COMPRESSION_NONE, true},
-       {NULL, 0, false}
-};
-
-/*
- * Options for enum values stored in other modules
- */
-extern const struct config_enum_entry wal_level_options[];
-extern const struct config_enum_entry archive_mode_options[];
-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[];
-
-/*
- * GUC option variables that are exported from this module
- */
-bool           log_duration = false;
-bool           Debug_print_plan = false;
-bool           Debug_print_parse = false;
-bool           Debug_print_rewritten = false;
-bool           Debug_pretty_print = true;
-
-bool           log_parser_stats = false;
-bool           log_planner_stats = false;
-bool           log_executor_stats = false;
-bool           log_statement_stats = false;    /* this is sort of all three above
-                                                                                        * together */
-bool           log_btree_build_stats = false;
-char      *event_source;
-
-bool           row_security;
-bool           check_function_bodies = true;
-
-/*
- * This GUC exists solely for backward compatibility, check its definition for
- * details.
- */
-bool           default_with_oids = false;
-bool           session_auth_is_superuser;
-
-int                    log_min_error_statement = ERROR;
-int                    log_min_messages = WARNING;
-int                    client_min_messages = NOTICE;
-int                    log_min_duration_sample = -1;
-int                    log_min_duration_statement = -1;
-int                    log_parameter_max_length = -1;
-int                    log_parameter_max_length_on_error = 0;
-int                    log_temp_files = -1;
-double         log_statement_sample_rate = 1.0;
-double         log_xact_sample_rate = 0;
-int                    trace_recovery_messages = LOG;
-char      *backtrace_functions;
-char      *backtrace_symbol_list;
-
-int                    temp_file_limit = -1;
-
-int                    num_temp_buffers = 1024;
-
-char      *cluster_name = "";
-char      *ConfigFileName;
-char      *HbaFileName;
-char      *IdentFileName;
-char      *external_pid_file;
-
-char      *pgstat_temp_directory;
-
-char      *application_name;
-
-int                    tcp_keepalives_idle;
-int                    tcp_keepalives_interval;
-int                    tcp_keepalives_count;
-int                    tcp_user_timeout;
-
-/*
- * SSL renegotiation was been removed in PostgreSQL 9.5, but we tolerate it
- * being set to zero (meaning never renegotiate) for backward compatibility.
- * This avoids breaking compatibility with clients that have never supported
- * renegotiation and therefore always try to zero it.
- */
-int                    ssl_renegotiation_limit;
-
-/*
- * This really belongs in pg_shmem.c, but is defined here so that it doesn't
- * need to be duplicated in all the different implementations of pg_shmem.c.
- */
-int                    huge_pages;
-int                    huge_page_size;
-
-/*
- * These variables are all dummies that don't do anything, except in some
- * cases provide the value for SHOW to display.  The real state is elsewhere
- * and is kept in sync by assign_hooks.
- */
-static char *syslog_ident_str;
-static double phony_random_seed;
-static char *client_encoding_string;
-static char *datestyle_string;
-static char *locale_collate;
-static char *locale_ctype;
-static char *server_encoding_string;
-static char *server_version_string;
-static int     server_version_num;
-static char *timezone_string;
-static char *log_timezone_string;
-static char *timezone_abbreviations_string;
-static char *data_directory;
-static char *session_authorization_string;
-static int     max_function_args;
-static int     max_index_keys;
-static int     max_identifier_length;
-static int     block_size;
-static int     segment_size;
-static int     shared_memory_size_mb;
-static int     shared_memory_size_in_huge_pages;
-static int     wal_block_size;
-static bool data_checksums;
-static bool integer_datetimes;
-static bool assert_enabled;
-static bool in_hot_standby;
-static char *recovery_target_timeline_string;
-static char *recovery_target_string;
-static char *recovery_target_xid_string;
-static char *recovery_target_name_string;
-static char *recovery_target_lsn_string;
-
-
-/* should be static, but commands/variable.c needs to get at this */
-char      *role_string;
-
-
-/*
- * Displayable names for context types (enum GucContext)
- *
- * Note: these strings are deliberately not localized.
- */
-const char *const GucContext_Names[] =
-{
-        /* PGC_INTERNAL */ "internal",
-        /* PGC_POSTMASTER */ "postmaster",
-        /* PGC_SIGHUP */ "sighup",
-        /* PGC_SU_BACKEND */ "superuser-backend",
-        /* PGC_BACKEND */ "backend",
-        /* PGC_SUSET */ "superuser",
-        /* PGC_USERSET */ "user"
-};
-
-StaticAssertDecl(lengthof(GucContext_Names) == (PGC_USERSET + 1),
-                                "array length mismatch");
-
-/*
- * Displayable names for source types (enum GucSource)
- *
- * Note: these strings are deliberately not localized.
- */
-const char *const GucSource_Names[] =
-{
-        /* PGC_S_DEFAULT */ "default",
-        /* PGC_S_DYNAMIC_DEFAULT */ "default",
-        /* PGC_S_ENV_VAR */ "environment variable",
-        /* PGC_S_FILE */ "configuration file",
-        /* PGC_S_ARGV */ "command line",
-        /* PGC_S_GLOBAL */ "global",
-        /* PGC_S_DATABASE */ "database",
-        /* PGC_S_USER */ "user",
-        /* PGC_S_DATABASE_USER */ "database user",
-        /* PGC_S_CLIENT */ "client",
-        /* PGC_S_OVERRIDE */ "override",
-        /* PGC_S_INTERACTIVE */ "interactive",
-        /* PGC_S_TEST */ "test",
-        /* PGC_S_SESSION */ "session"
-};
-
-StaticAssertDecl(lengthof(GucSource_Names) == (PGC_S_SESSION + 1),
-                                "array length mismatch");
-
-/*
- * Displayable names for the groupings defined in enum config_group
- */
-const char *const config_group_names[] =
-{
-       /* UNGROUPED */
-       gettext_noop("Ungrouped"),
-       /* FILE_LOCATIONS */
-       gettext_noop("File Locations"),
-       /* CONN_AUTH_SETTINGS */
-       gettext_noop("Connections and Authentication / Connection Settings"),
-       /* CONN_AUTH_TCP */
-       gettext_noop("Connections and Authentication / TCP Settings"),
-       /* CONN_AUTH_AUTH */
-       gettext_noop("Connections and Authentication / Authentication"),
-       /* CONN_AUTH_SSL */
-       gettext_noop("Connections and Authentication / SSL"),
-       /* RESOURCES_MEM */
-       gettext_noop("Resource Usage / Memory"),
-       /* RESOURCES_DISK */
-       gettext_noop("Resource Usage / Disk"),
-       /* RESOURCES_KERNEL */
-       gettext_noop("Resource Usage / Kernel Resources"),
-       /* RESOURCES_VACUUM_DELAY */
-       gettext_noop("Resource Usage / Cost-Based Vacuum Delay"),
-       /* RESOURCES_BGWRITER */
-       gettext_noop("Resource Usage / Background Writer"),
-       /* RESOURCES_ASYNCHRONOUS */
-       gettext_noop("Resource Usage / Asynchronous Behavior"),
-       /* WAL_SETTINGS */
-       gettext_noop("Write-Ahead Log / Settings"),
-       /* WAL_CHECKPOINTS */
-       gettext_noop("Write-Ahead Log / Checkpoints"),
-       /* WAL_ARCHIVING */
-       gettext_noop("Write-Ahead Log / Archiving"),
-       /* WAL_RECOVERY */
-       gettext_noop("Write-Ahead Log / Recovery"),
-       /* WAL_ARCHIVE_RECOVERY */
-       gettext_noop("Write-Ahead Log / Archive Recovery"),
-       /* WAL_RECOVERY_TARGET */
-       gettext_noop("Write-Ahead Log / Recovery Target"),
-       /* REPLICATION_SENDING */
-       gettext_noop("Replication / Sending Servers"),
-       /* REPLICATION_PRIMARY */
-       gettext_noop("Replication / Primary Server"),
-       /* REPLICATION_STANDBY */
-       gettext_noop("Replication / Standby Servers"),
-       /* REPLICATION_SUBSCRIBERS */
-       gettext_noop("Replication / Subscribers"),
-       /* QUERY_TUNING_METHOD */
-       gettext_noop("Query Tuning / Planner Method Configuration"),
-       /* QUERY_TUNING_COST */
-       gettext_noop("Query Tuning / Planner Cost Constants"),
-       /* QUERY_TUNING_GEQO */
-       gettext_noop("Query Tuning / Genetic Query Optimizer"),
-       /* QUERY_TUNING_OTHER */
-       gettext_noop("Query Tuning / Other Planner Options"),
-       /* LOGGING_WHERE */
-       gettext_noop("Reporting and Logging / Where to Log"),
-       /* LOGGING_WHEN */
-       gettext_noop("Reporting and Logging / When to Log"),
-       /* LOGGING_WHAT */
-       gettext_noop("Reporting and Logging / What to Log"),
-       /* PROCESS_TITLE */
-       gettext_noop("Reporting and Logging / Process Title"),
-       /* STATS_MONITORING */
-       gettext_noop("Statistics / Monitoring"),
-       /* STATS_CUMULATIVE */
-       gettext_noop("Statistics / Cumulative Query and Index Statistics"),
-       /* AUTOVACUUM */
-       gettext_noop("Autovacuum"),
-       /* CLIENT_CONN_STATEMENT */
-       gettext_noop("Client Connection Defaults / Statement Behavior"),
-       /* CLIENT_CONN_LOCALE */
-       gettext_noop("Client Connection Defaults / Locale and Formatting"),
-       /* CLIENT_CONN_PRELOAD */
-       gettext_noop("Client Connection Defaults / Shared Library Preloading"),
-       /* CLIENT_CONN_OTHER */
-       gettext_noop("Client Connection Defaults / Other Defaults"),
-       /* LOCK_MANAGEMENT */
-       gettext_noop("Lock Management"),
-       /* COMPAT_OPTIONS_PREVIOUS */
-       gettext_noop("Version and Platform Compatibility / Previous PostgreSQL Versions"),
-       /* COMPAT_OPTIONS_CLIENT */
-       gettext_noop("Version and Platform Compatibility / Other Platforms and Clients"),
-       /* ERROR_HANDLING */
-       gettext_noop("Error Handling"),
-       /* PRESET_OPTIONS */
-       gettext_noop("Preset Options"),
-       /* CUSTOM_OPTIONS */
-       gettext_noop("Customized Options"),
-       /* DEVELOPER_OPTIONS */
-       gettext_noop("Developer Options"),
-       /* help_config wants this array to be null-terminated */
-       NULL
-};
-
-StaticAssertDecl(lengthof(config_group_names) == (DEVELOPER_OPTIONS + 2),
-                                "array length mismatch");
-
-/*
- * Displayable names for GUC variable types (enum config_type)
- *
- * Note: these strings are deliberately not localized.
- */
-const char *const config_type_names[] =
-{
-        /* PGC_BOOL */ "bool",
-        /* PGC_INT */ "integer",
-        /* PGC_REAL */ "real",
-        /* PGC_STRING */ "string",
-        /* PGC_ENUM */ "enum"
-};
+/* Kluge: for speed, we examine this GUC variable's value directly */
+extern bool in_hot_standby_guc;
 
-StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
-                                "array length mismatch");
 
 /*
  * Unit conversion tables.
@@ -980,12372 +176,6248 @@ static const unit_conversion time_unit_conversion_table[] =
 };
 
 /*
- * Contents of GUC tables
- *
- * See src/backend/utils/misc/README for design notes.
- *
- * TO ADD AN OPTION:
- *
- * 1. Declare a global variable of type bool, int, double, or char*
- *       and make use of it.
- *
- * 2. Decide at what times it's safe to set the option. See guc.h for
- *       details.
- *
- * 3. Decide on a name, a default value, upper and lower bounds (if
- *       applicable), etc.
- *
- * 4. Add a record below.
- *
- * 5. Add it to src/backend/utils/misc/postgresql.conf.sample, if
- *       appropriate.
- *
- * 6. Don't forget to document the option (at least in config.sgml).
- *
- * 7. If it's a new GUC_LIST_QUOTE option, you must add it to
- *       variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c.
+ * To allow continued support of obsolete names for GUC variables, we apply
+ * the following mappings to any unrecognized name.  Note that an old name
+ * should be mapped to a new one only if the new variable has very similar
+ * semantics to the old.
  */
+static const char *const map_old_guc_names[] = {
+       "sort_mem", "work_mem",
+       "vacuum_mem", "maintenance_work_mem",
+       NULL
+};
 
 
-/******** option records follow ********/
+/*
+ * Actual lookup of variables is done through this single, sorted array.
+ */
+static struct config_generic **guc_variables;
 
-static struct config_bool ConfigureNamesBool[] =
-{
-       {
-               {"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of sequential-scan plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_seqscan,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of index-scan plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_indexscan,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_indexonlyscan", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of index-only-scan plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_indexonlyscan,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of bitmap-scan plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_bitmapscan,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of TID scan plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_tidscan,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of explicit sort steps."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_sort,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_incremental_sort", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of incremental sort steps."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_incremental_sort,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of hashed aggregation plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_hashagg,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_material", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of materialization."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_material,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_memoize", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of memoization."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_memoize,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of nested-loop join plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_nestloop,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of merge join plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_mergejoin,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of hash join plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_hashjoin,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_gathermerge", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of gather merge plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_gathermerge,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_partitionwise_join", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables partitionwise join."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_partitionwise_join,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_partitionwise_aggregate", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables partitionwise aggregation and grouping."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_partitionwise_aggregate,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_parallel_append", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of parallel append plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_parallel_append,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_parallel_hash", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of parallel hash plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_parallel_hash,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_partition_pruning", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables plan-time and execution-time partition pruning."),
-                       gettext_noop("Allows the query planner and executor to compare partition "
-                                                "bounds to conditions in the query to determine which "
-                                                "partitions must be scanned."),
-                       GUC_EXPLAIN
-               },
-               &enable_partition_pruning,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_async_append", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enables the planner's use of async append plans."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_async_append,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"enable_group_by_reordering", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enable reordering of GROUP BY key."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &enable_group_by_reordering,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("Enables genetic query optimization."),
-                       gettext_noop("This algorithm attempts to do planning without "
-                                                "exhaustive searching."),
-                       GUC_EXPLAIN
-               },
-               &enable_geqo,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               /* Not for general use --- used by SET SESSION AUTHORIZATION */
-               {"is_superuser", PGC_INTERNAL, UNGROUPED,
-                       gettext_noop("Shows whether the current user is a superuser."),
-                       NULL,
-                       GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &session_auth_is_superuser,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Enables advertising the server via Bonjour."),
-                       NULL
-               },
-               &enable_bonjour,
-               false,
-               check_bonjour, NULL, NULL
-       },
-       {
-               {"track_commit_timestamp", PGC_POSTMASTER, REPLICATION_SENDING,
-                       gettext_noop("Collects transaction commit time."),
-                       NULL
-               },
-               &track_commit_timestamp,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"ssl", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Enables SSL connections."),
-                       NULL
-               },
-               &EnableSSL,
-               false,
-               check_ssl, NULL, NULL
-       },
-       {
-               {"ssl_passphrase_command_supports_reload", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Controls whether ssl_passphrase_command is called during server reload."),
-                       NULL
-               },
-               &ssl_passphrase_command_supports_reload,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"ssl_prefer_server_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Give priority to server ciphersuite order."),
-                       NULL
-               },
-               &SSLPreferServerCiphers,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"fsync", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Forces synchronization of updates to disk."),
-                       gettext_noop("The server will use the fsync() system call in several places to make "
-                                                "sure that updates are physically written to disk. This insures "
-                                                "that a database cluster will recover to a consistent state after "
-                                                "an operating system or hardware crash.")
-               },
-               &enableFsync,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"ignore_checksum_failure", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Continues processing after a checksum failure."),
-                       gettext_noop("Detection of a checksum failure normally causes PostgreSQL to "
-                                                "report an error, aborting the current transaction. Setting "
-                                                "ignore_checksum_failure to true causes the system to ignore the failure "
-                                                "(but still report a warning), and continue processing. This "
-                                                "behavior could cause crashes or other serious problems. Only "
-                                                "has an effect if checksums are enabled."),
-                       GUC_NOT_IN_SAMPLE
-               },
-               &ignore_checksum_failure,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"zero_damaged_pages", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Continues processing past damaged page headers."),
-                       gettext_noop("Detection of a damaged page header normally causes PostgreSQL to "
-                                                "report an error, aborting the current transaction. Setting "
-                                                "zero_damaged_pages to true causes the system to instead report a "
-                                                "warning, zero out the damaged page, and continue processing. This "
-                                                "behavior will destroy data, namely all the rows on the damaged page."),
-                       GUC_NOT_IN_SAMPLE
-               },
-               &zero_damaged_pages,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"ignore_invalid_pages", PGC_POSTMASTER, DEVELOPER_OPTIONS,
-                       gettext_noop("Continues recovery after an invalid pages failure."),
-                       gettext_noop("Detection of WAL records having references to "
-                                                "invalid pages during recovery causes PostgreSQL to "
-                                                "raise a PANIC-level error, aborting the recovery. "
-                                                "Setting ignore_invalid_pages to true causes "
-                                                "the system to ignore invalid page references "
-                                                "in WAL records (but still report a warning), "
-                                                "and continue recovery. This behavior may cause "
-                                                "crashes, data loss, propagate or hide corruption, "
-                                                "or other serious problems. Only has an effect "
-                                                "during recovery or in standby mode."),
-                       GUC_NOT_IN_SAMPLE
-               },
-               &ignore_invalid_pages,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"full_page_writes", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Writes full pages to WAL when first modified after a checkpoint."),
-                       gettext_noop("A page write in process during an operating system crash might be "
-                                                "only partially written to disk.  During recovery, the row changes "
-                                                "stored in WAL are not enough to recover.  This option writes "
-                                                "pages when first modified after a checkpoint to WAL so full recovery "
-                                                "is possible.")
-               },
-               &fullPageWrites,
-               true,
-               NULL, NULL, NULL
-       },
+/* Current number of variables contained in the vector */
+static int     num_guc_variables;
 
-       {
-               {"wal_log_hints", PGC_POSTMASTER, WAL_SETTINGS,
-                       gettext_noop("Writes full pages to WAL when first modified after a checkpoint, even for a non-critical modification."),
-                       NULL
-               },
-               &wal_log_hints,
-               false,
-               NULL, NULL, NULL
-       },
+/* Vector capacity */
+static int     size_guc_variables;
 
-       {
-               {"wal_init_zero", PGC_SUSET, WAL_SETTINGS,
-                       gettext_noop("Writes zeroes to new WAL files before first use."),
-                       NULL
-               },
-               &wal_init_zero,
-               true,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"wal_recycle", PGC_SUSET, WAL_SETTINGS,
-                       gettext_noop("Recycles WAL files by renaming them."),
-                       NULL
-               },
-               &wal_recycle,
-               true,
-               NULL, NULL, NULL
-       },
+static bool guc_dirty;                 /* true if need to do commit/abort work */
 
-       {
-               {"log_checkpoints", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Logs each checkpoint."),
-                       NULL
-               },
-               &log_checkpoints,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_connections", PGC_SU_BACKEND, LOGGING_WHAT,
-                       gettext_noop("Logs each successful connection."),
-                       NULL
-               },
-               &Log_connections,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_disconnections", PGC_SU_BACKEND, LOGGING_WHAT,
-                       gettext_noop("Logs end of a session, including duration."),
-                       NULL
-               },
-               &Log_disconnections,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_replication_commands", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Logs each replication command."),
-                       NULL
-               },
-               &log_replication_commands,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_assertions", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows whether the running server has assertion checks enabled."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &assert_enabled,
-#ifdef USE_ASSERT_CHECKING
-               true,
-#else
-               false,
-#endif
-               NULL, NULL, NULL
-       },
+static bool reporting_enabled; /* true to enable GUC_REPORT */
 
-       {
-               {"exit_on_error", PGC_USERSET, ERROR_HANDLING_OPTIONS,
-                       gettext_noop("Terminate session on any error."),
-                       NULL
-               },
-               &ExitOnAnyError,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"restart_after_crash", PGC_SIGHUP, ERROR_HANDLING_OPTIONS,
-                       gettext_noop("Reinitialize server after backend crash."),
-                       NULL
-               },
-               &restart_after_crash,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"remove_temp_files_after_crash", PGC_SIGHUP, DEVELOPER_OPTIONS,
-                       gettext_noop("Remove temporary files after backend crash."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &remove_temp_files_after_crash,
-               true,
-               NULL, NULL, NULL
-       },
+static bool report_needed;             /* true if any GUC_REPORT reports are needed */
 
-       {
-               {"log_duration", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Logs the duration of each completed SQL statement."),
-                       NULL
-               },
-               &log_duration,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_print_parse", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Logs each query's parse tree."),
-                       NULL
-               },
-               &Debug_print_parse,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_print_rewritten", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Logs each query's rewritten parse tree."),
-                       NULL
-               },
-               &Debug_print_rewritten,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_print_plan", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Logs each query's execution plan."),
-                       NULL
-               },
-               &Debug_print_plan,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_pretty_print", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Indents parse and plan tree displays."),
-                       NULL
-               },
-               &Debug_pretty_print,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_parser_stats", PGC_SUSET, STATS_MONITORING,
-                       gettext_noop("Writes parser performance statistics to the server log."),
-                       NULL
-               },
-               &log_parser_stats,
-               false,
-               check_stage_log_stats, NULL, NULL
-       },
-       {
-               {"log_planner_stats", PGC_SUSET, STATS_MONITORING,
-                       gettext_noop("Writes planner performance statistics to the server log."),
-                       NULL
-               },
-               &log_planner_stats,
-               false,
-               check_stage_log_stats, NULL, NULL
-       },
-       {
-               {"log_executor_stats", PGC_SUSET, STATS_MONITORING,
-                       gettext_noop("Writes executor performance statistics to the server log."),
-                       NULL
-               },
-               &log_executor_stats,
-               false,
-               check_stage_log_stats, NULL, NULL
-       },
-       {
-               {"log_statement_stats", PGC_SUSET, STATS_MONITORING,
-                       gettext_noop("Writes cumulative performance statistics to the server log."),
-                       NULL
-               },
-               &log_statement_stats,
-               false,
-               check_log_stats, NULL, NULL
-       },
-#ifdef BTREE_BUILD_STATS
-       {
-               {"log_btree_build_stats", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Logs system resource usage statistics (memory and CPU) on various B-tree operations."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &log_btree_build_stats,
-               false,
-               NULL, NULL, NULL
-       },
-#endif
+static int     GUCNestLevel = 0;       /* 1 when in main transaction */
 
-       {
-               {"track_activities", PGC_SUSET, STATS_CUMULATIVE,
-                       gettext_noop("Collects information about executing commands."),
-                       gettext_noop("Enables the collection of information on the currently "
-                                                "executing command of each session, along with "
-                                                "the time at which that command began execution.")
-               },
-               &pgstat_track_activities,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"track_counts", PGC_SUSET, STATS_CUMULATIVE,
-                       gettext_noop("Collects statistics on database activity."),
-                       NULL
-               },
-               &pgstat_track_counts,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"track_io_timing", PGC_SUSET, STATS_CUMULATIVE,
-                       gettext_noop("Collects timing statistics for database I/O activity."),
-                       NULL
-               },
-               &track_io_timing,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"track_wal_io_timing", PGC_SUSET, STATS_CUMULATIVE,
-                       gettext_noop("Collects timing statistics for WAL I/O activity."),
-                       NULL
-               },
-               &track_wal_io_timing,
-               false,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"update_process_title", PGC_SUSET, PROCESS_TITLE,
-                       gettext_noop("Updates the process title to show the active SQL command."),
-                       gettext_noop("Enables updating of the process title every time a new SQL command is received by the server.")
-               },
-               &update_process_title,
-#ifdef WIN32
-               false,
-#else
-               true,
-#endif
-               NULL, NULL, NULL
-       },
+static int     guc_var_compare(const void *a, const void *b);
+static void InitializeGUCOptionsFromEnvironment(void);
+static void InitializeOneGUCOption(struct config_generic *gconf);
+static void pg_timezone_abbrev_initialize(void);
+static void push_old_value(struct config_generic *gconf, GucAction action);
+static void ReportGUCOption(struct config_generic *record);
+static void set_config_sourcefile(const char *name, char *sourcefile,
+                                                                 int sourceline);
+static void reapply_stacked_values(struct config_generic *variable,
+                                                                  struct config_string *pHolder,
+                                                                  GucStack *stack,
+                                                                  const char *curvalue,
+                                                                  GucContext curscontext, GucSource cursource,
+                                                                  Oid cursrole);
+static bool validate_option_array_item(const char *name, const char *value,
+                                                                          bool skipIfNoPermissions);
+static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p);
+static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
+                                                                         const char *name, const char *value);
+static bool valid_custom_variable_name(const char *name);
+static void do_serialize(char **destptr, Size *maxbytes,
+                                                const char *fmt,...) pg_attribute_printf(3, 4);
+static bool call_bool_check_hook(struct config_bool *conf, bool *newval,
+                                                                void **extra, GucSource source, int elevel);
+static bool call_int_check_hook(struct config_int *conf, int *newval,
+                                                               void **extra, GucSource source, int elevel);
+static bool call_real_check_hook(struct config_real *conf, double *newval,
+                                                                void **extra, GucSource source, int elevel);
+static bool call_string_check_hook(struct config_string *conf, char **newval,
+                                                                  void **extra, GucSource source, int elevel);
+static bool call_enum_check_hook(struct config_enum *conf, int *newval,
+                                                                void **extra, GucSource source, int elevel);
 
-       {
-               {"autovacuum", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Starts the autovacuum subprocess."),
-                       NULL
-               },
-               &autovacuum_start_daemon,
-               true,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_notify,
-               false,
-               NULL, NULL, NULL
-       },
-
-#ifdef LOCK_DEBUG
-       {
-               {"trace_locks", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Emits information about lock usage."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_locks,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"trace_userlocks", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Emits information about user lock usage."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_userlocks,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"trace_lwlocks", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Emits information about lightweight lock usage."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_lwlocks,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"debug_deadlocks", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Dumps information about all current locks when a deadlock timeout occurs."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Debug_deadlocks,
-               false,
-               NULL, NULL, NULL
-       },
-#endif
+/*
+ * This function handles both actual config file (re)loads and execution of
+ * show_all_file_settings() (i.e., the pg_file_settings view).  In the latter
+ * case we don't apply any of the settings, but we make all the usual validity
+ * checks, and we return the ConfigVariable list so that it can be printed out
+ * by show_all_file_settings().
+ */
+ConfigVariable *
+ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel)
+{
+       bool            error = false;
+       bool            applying = false;
+       const char *ConfFileWithError;
+       ConfigVariable *item,
+                          *head,
+                          *tail;
+       int                     i;
 
+       /* Parse the main config file into a list of option names and values */
+       ConfFileWithError = ConfigFileName;
+       head = tail = NULL;
+
+       if (!ParseConfigFile(ConfigFileName, true,
+                                                NULL, 0, 0, elevel,
+                                                &head, &tail))
        {
-               {"log_lock_waits", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Logs long lock waits."),
-                       NULL
-               },
-               &log_lock_waits,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_recovery_conflict_waits", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Logs standby recovery conflict waits."),
-                       NULL
-               },
-               &log_recovery_conflict_waits,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_hostname", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Logs the host name in the connection logs."),
-                       gettext_noop("By default, connection logs only show the IP address "
-                                                "of the connecting host. If you want them to show the host name you "
-                                                "can turn this on, but depending on your host name resolution "
-                                                "setup it might impose a non-negligible performance penalty.")
-               },
-               &log_hostname,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT,
-                       gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."),
-                       gettext_noop("When turned on, expressions of the form expr = NULL "
-                                                "(or NULL = expr) are treated as expr IS NULL, that is, they "
-                                                "return true if expr evaluates to the null value, and false "
-                                                "otherwise. The correct behavior of expr = NULL is to always "
-                                                "return null (unknown).")
-               },
-               &Transform_null_equals,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"db_user_namespace", PGC_SIGHUP, CONN_AUTH_AUTH,
-                       gettext_noop("Enables per-database user names."),
-                       NULL
-               },
-               &Db_user_namespace,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"default_transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the default read-only status of new transactions."),
-                       NULL,
-                       GUC_REPORT
-               },
-               &DefaultXactReadOnly,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the current transaction's read-only status."),
-                       NULL,
-                       GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &XactReadOnly,
-               false,
-               check_transaction_read_only, NULL, NULL
-       },
-       {
-               {"default_transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the default deferrable status of new transactions."),
-                       NULL
-               },
-               &DefaultXactDeferrable,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures."),
-                       NULL,
-                       GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &XactDeferrable,
-               false,
-               check_transaction_deferrable, NULL, NULL
-       },
-       {
-               {"row_security", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Enable row security."),
-                       gettext_noop("When enabled, row security will be applied to all users.")
-               },
-               &row_security,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Check routine bodies during CREATE FUNCTION and CREATE PROCEDURE."),
-                       NULL
-               },
-               &check_function_bodies,
-               true,
-               NULL, NULL, NULL
-       },
-       {
-               {"array_nulls", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Enable input of NULL elements in arrays."),
-                       gettext_noop("When turned on, unquoted NULL in an array input "
-                                                "value means a null value; "
-                                                "otherwise it is taken literally.")
-               },
-               &Array_nulls,
-               true,
-               NULL, NULL, NULL
-       },
+               /* Syntax error(s) detected in the file, so bail out */
+               error = true;
+               goto bail_out;
+       }
 
        /*
-        * WITH OIDS support, and consequently default_with_oids, was removed in
-        * PostgreSQL 12, but we tolerate the parameter being set to false to
-        * avoid unnecessarily breaking older dump files.
+        * Parse the PG_AUTOCONF_FILENAME file, if present, after the main file to
+        * replace any parameters set by ALTER SYSTEM command.  Because this file
+        * is in the data directory, we can't read it until the DataDir has been
+        * set.
         */
+       if (DataDir)
        {
-               {"default_with_oids", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("WITH OIDS is no longer supported; this can only be false."),
-                       NULL,
-                       GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE
-               },
-               &default_with_oids,
-               false,
-               check_default_with_oids, NULL, NULL
-       },
-       {
-               {"logging_collector", PGC_POSTMASTER, LOGGING_WHERE,
-                       gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files."),
-                       NULL
-               },
-               &Logging_collector,
-               false,
-               NULL, NULL, NULL
-       },
-       {
-               {"log_truncate_on_rotation", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Truncate existing log files of same name during log rotation."),
-                       NULL
-               },
-               &Log_truncate_on_rotation,
-               false,
-               NULL, NULL, NULL
-       },
-
-#ifdef TRACE_SORT
-       {
-               {"trace_sort", PGC_USERSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Emit information about resource usage in sorting."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &trace_sort,
-               false,
-               NULL, NULL, NULL
-       },
-#endif
-
-#ifdef TRACE_SYNCSCAN
-       /* this is undocumented because not exposed in a standard build */
-       {
-               {"trace_syncscan", PGC_USERSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Generate debugging output for synchronized scanning."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &trace_syncscan,
-               false,
-               NULL, NULL, NULL
-       },
-#endif
-
-#ifdef DEBUG_BOUNDED_SORT
-       /* this is undocumented because not exposed in a standard build */
-       {
+               if (!ParseConfigFile(PG_AUTOCONF_FILENAME, false,
+                                                        NULL, 0, 0, elevel,
+                                                        &head, &tail))
                {
-                       "optimize_bounded_sort", PGC_USERSET, QUERY_TUNING_METHOD,
-                       gettext_noop("Enable bounded sorting using heap sort."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_EXPLAIN
-               },
-               &optimize_bounded_sort,
-               true,
-               NULL, NULL, NULL
-       },
-#endif
-
-#ifdef WAL_DEBUG
-       {
-               {"wal_debug", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Emit WAL-related debugging output."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &XLOG_DEBUG,
-               false,
-               NULL, NULL, NULL
-       },
-#endif
-
-       {
-               {"integer_datetimes", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows whether datetimes are integer based."),
-                       NULL,
-                       GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &integer_datetimes,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"krb_caseins_users", PGC_SIGHUP, CONN_AUTH_AUTH,
-                       gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive."),
-                       NULL
-               },
-               &pg_krb_caseins_users,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"escape_string_warning", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Warn about backslash escapes in ordinary string literals."),
-                       NULL
-               },
-               &escape_string_warning,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"standard_conforming_strings", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Causes '...' strings to treat backslashes literally."),
-                       NULL,
-                       GUC_REPORT
-               },
-               &standard_conforming_strings,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"synchronize_seqscans", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Enable synchronized sequential scans."),
-                       NULL
-               },
-               &synchronize_seqscans,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"recovery_target_inclusive", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets whether to include or exclude transaction with recovery target."),
-                       NULL
-               },
-               &recoveryTargetInclusive,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
-                       gettext_noop("Allows connections and queries during recovery."),
-                       NULL
-               },
-               &EnableHotStandby,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"hot_standby_feedback", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Allows feedback from a hot standby to the primary that will avoid query conflicts."),
-                       NULL
-               },
-               &hot_standby_feedback,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"in_hot_standby", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows whether hot standby is currently active."),
-                       NULL,
-                       GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &in_hot_standby,
-               false,
-               NULL, NULL, show_in_hot_standby
-       },
-
-       {
-               {"allow_system_table_mods", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Allows modifications of the structure of system tables."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &allowSystemTableMods,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"ignore_system_indexes", PGC_BACKEND, DEVELOPER_OPTIONS,
-                       gettext_noop("Disables reading from system indexes."),
-                       gettext_noop("It does not prevent updating the indexes, so it is safe "
-                                                "to use.  The worst consequence is slowness."),
-                       GUC_NOT_IN_SAMPLE
-               },
-               &IgnoreSystemIndexes,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"allow_in_place_tablespaces", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Allows tablespaces directly inside pg_tblspc, for testing."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &allow_in_place_tablespaces,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Enables backward compatibility mode for privilege checks on large objects."),
-                       gettext_noop("Skips privilege checks when reading or modifying large objects, "
-                                                "for compatibility with PostgreSQL releases prior to 9.0.")
-               },
-               &lo_compat_privileges,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"quote_all_identifiers", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("When generating SQL fragments, quote all identifiers."),
-                       NULL,
-               },
-               &quote_all_identifiers,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"data_checksums", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows whether data checksums are turned on for this cluster."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
-               },
-               &data_checksums,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"syslog_sequence_numbers", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Add sequence number to syslog messages to avoid duplicate suppression."),
-                       NULL
-               },
-               &syslog_sequence_numbers,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"syslog_split_messages", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Split messages sent to syslog by lines and to fit into 1024 bytes."),
-                       NULL
-               },
-               &syslog_split_messages,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"parallel_leader_participation", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Controls whether Gather and Gather Merge also run subplans."),
-                       gettext_noop("Should gather nodes also run subplans or just gather tuples?"),
-                       GUC_EXPLAIN
-               },
-               &parallel_leader_participation,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"jit", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Allow JIT compilation."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &jit_enabled,
-               true,
-               NULL, NULL, NULL
-       },
-
+                       /* Syntax error(s) detected in the file, so bail out */
+                       error = true;
+                       ConfFileWithError = PG_AUTOCONF_FILENAME;
+                       goto bail_out;
+               }
+       }
+       else
        {
-               {"jit_debugging_support", PGC_SU_BACKEND, DEVELOPER_OPTIONS,
-                       gettext_noop("Register JIT-compiled functions with debugger."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &jit_debugging_support,
-               false,
-
                /*
-                * This is not guaranteed to be available, but given it's a developer
-                * oriented option, it doesn't seem worth adding code checking
-                * availability.
+                * If DataDir is not set, the PG_AUTOCONF_FILENAME file cannot be
+                * read.  In this case, we don't want to accept any settings but
+                * data_directory from postgresql.conf, because they might be
+                * overwritten with settings in the PG_AUTOCONF_FILENAME file which
+                * will be read later. OTOH, since data_directory isn't allowed in the
+                * PG_AUTOCONF_FILENAME file, it will never be overwritten later.
                 */
-               NULL, NULL, NULL
-       },
-
-       {
-               {"jit_dump_bitcode", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Write out LLVM bitcode to facilitate JIT debugging."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &jit_dump_bitcode,
-               false,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"jit_expressions", PGC_USERSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Allow JIT compilation of expressions."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &jit_expressions,
-               true,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"jit_profiling_support", PGC_SU_BACKEND, DEVELOPER_OPTIONS,
-                       gettext_noop("Register JIT-compiled functions with perf profiler."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &jit_profiling_support,
-               false,
+               ConfigVariable *newlist = NULL;
 
                /*
-                * This is not guaranteed to be available, but given it's a developer
-                * oriented option, it doesn't seem worth adding code checking
-                * availability.
+                * Prune all items except the last "data_directory" from the list.
                 */
-               NULL, NULL, NULL
-       },
-
-       {
-               {"jit_tuple_deforming", PGC_USERSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Allow JIT compilation of tuple deforming."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &jit_tuple_deforming,
-               true,
-               NULL, NULL, NULL
-       },
+               for (item = head; item; item = item->next)
+               {
+                       if (!item->ignore &&
+                               strcmp(item->name, "data_directory") == 0)
+                               newlist = item;
+               }
 
-       {
-               {"data_sync_retry", PGC_POSTMASTER, ERROR_HANDLING_OPTIONS,
-                       gettext_noop("Whether to continue running after a failure to sync data files."),
-               },
-               &data_sync_retry,
-               false,
-               NULL, NULL, NULL
-       },
+               if (newlist)
+                       newlist->next = NULL;
+               head = tail = newlist;
 
-       {
-               {"wal_receiver_create_temp_slot", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets whether a WAL receiver should create a temporary replication slot if no permanent slot is configured."),
-               },
-               &wal_receiver_create_temp_slot,
-               false,
-               NULL, NULL, NULL
-       },
-
-       /* End-of-list marker */
-       {
-               {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
+               /*
+                * Quick exit if data_directory is not present in file.
+                *
+                * We need not do any further processing, in particular we don't set
+                * PgReloadTime; that will be set soon by subsequent full loading of
+                * the config file.
+                */
+               if (head == NULL)
+                       goto bail_out;
        }
-};
-
-
-static struct config_int ConfigureNamesInt[] =
-{
-       {
-               {"archive_timeout", PGC_SIGHUP, WAL_ARCHIVING,
-                       gettext_noop("Sets the amount of time to wait before forcing a "
-                                                "switch to the next WAL file."),
-                       NULL,
-                       GUC_UNIT_S
-               },
-               &XLogArchiveTimeout,
-               0, 0, INT_MAX / 2,
-               NULL, NULL, NULL
-       },
-       {
-               {"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
-                       gettext_noop("Sets the amount of time to wait after "
-                                                "authentication on connection startup."),
-                       gettext_noop("This allows attaching a debugger to the process."),
-                       GUC_NOT_IN_SAMPLE | GUC_UNIT_S
-               },
-               &PostAuthDelay,
-               0, 0, INT_MAX / 1000000,
-               NULL, NULL, NULL
-       },
-       {
-               {"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Sets the default statistics target."),
-                       gettext_noop("This applies to table columns that have not had a "
-                                                "column-specific target set via ALTER TABLE SET STATISTICS.")
-               },
-               &default_statistics_target,
-               100, 1, 10000,
-               NULL, NULL, NULL
-       },
-       {
-               {"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Sets the FROM-list size beyond which subqueries "
-                                                "are not collapsed."),
-                       gettext_noop("The planner will merge subqueries into upper "
-                                                "queries if the resulting FROM list would have no more than "
-                                                "this many items."),
-                       GUC_EXPLAIN
-               },
-               &from_collapse_limit,
-               8, 1, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Sets the FROM-list size beyond which JOIN "
-                                                "constructs are not flattened."),
-                       gettext_noop("The planner will flatten explicit JOIN "
-                                                "constructs into lists of FROM items whenever a "
-                                                "list of no more than this many items would result."),
-                       GUC_EXPLAIN
-               },
-               &join_collapse_limit,
-               8, 1, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("Sets the threshold of FROM items beyond which GEQO is used."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &geqo_threshold,
-               12, 2, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("GEQO: effort is used to set the default for other GEQO parameters."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &Geqo_effort,
-               DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("GEQO: number of individuals in the population."),
-                       gettext_noop("Zero selects a suitable default value."),
-                       GUC_EXPLAIN
-               },
-               &Geqo_pool_size,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("GEQO: number of iterations of the algorithm."),
-                       gettext_noop("Zero selects a suitable default value."),
-                       GUC_EXPLAIN
-               },
-               &Geqo_generations,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               /* This is PGC_SUSET to prevent hiding from log_lock_waits. */
-               {"deadlock_timeout", PGC_SUSET, LOCK_MANAGEMENT,
-                       gettext_noop("Sets the time to wait on a lock before checking for deadlock."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &DeadlockTimeout,
-               1000, 1, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"max_standby_archive_delay", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing archived WAL data."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &max_standby_archive_delay,
-               30 * 1000, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"max_standby_streaming_delay", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing streamed WAL data."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &max_standby_streaming_delay,
-               30 * 1000, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"recovery_min_apply_delay", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the minimum delay for applying changes during recovery."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &recovery_min_apply_delay,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"wal_receiver_status_interval", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server."),
-                       NULL,
-                       GUC_UNIT_S
-               },
-               &wal_receiver_status_interval,
-               10, 0, INT_MAX / 1000,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"wal_receiver_timeout", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the maximum wait time to receive data from the sending server."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &wal_receiver_timeout,
-               60 * 1000, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"max_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the maximum number of concurrent connections."),
-                       NULL
-               },
-               &MaxConnections,
-               100, 1, MAX_BACKENDS,
-               check_maxconnections, NULL, NULL
-       },
 
+       /*
+        * Mark all extant GUC variables as not present in the config file. We
+        * need this so that we can tell below which ones have been removed from
+        * the file since we last processed it.
+        */
+       for (i = 0; i < num_guc_variables; i++)
        {
-               /* see max_connections */
-               {"superuser_reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the number of connection slots reserved for superusers."),
-                       NULL
-               },
-               &ReservedBackends,
-               3, 0, MAX_BACKENDS,
-               NULL, NULL, NULL
-       },
+               struct config_generic *gconf = guc_variables[i];
 
-       {
-               {"min_dynamic_shared_memory", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("Amount of dynamic shared memory reserved at startup."),
-                       NULL,
-                       GUC_UNIT_MB
-               },
-               &min_dynamic_shared_memory,
-               0, 0, (int) Min((size_t) INT_MAX, SIZE_MAX / (1024 * 1024)),
-               NULL, NULL, NULL
-       },
+               gconf->status &= ~GUC_IS_IN_FILE;
+       }
 
        /*
-        * We sometimes multiply the number of shared buffers by two without
-        * checking for overflow, so we mustn't allow more than INT_MAX / 2.
+        * Check if all the supplied option names are valid, as an additional
+        * quasi-syntactic check on the validity of the config file.  It is
+        * important that the postmaster and all backends agree on the results of
+        * this phase, else we will have strange inconsistencies about which
+        * processes accept a config file update and which don't.  Hence, unknown
+        * custom variable names have to be accepted without complaint.  For the
+        * same reason, we don't attempt to validate the options' values here.
+        *
+        * In addition, the GUC_IS_IN_FILE flag is set on each existing GUC
+        * variable mentioned in the file; and we detect duplicate entries in the
+        * file and mark the earlier occurrences as ignorable.
         */
+       for (item = head; item; item = item->next)
        {
-               {"shared_buffers", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("Sets the number of shared memory buffers used by the server."),
-                       NULL,
-                       GUC_UNIT_BLOCKS
-               },
-               &NBuffers,
-               16384, 16, INT_MAX / 2,
-               NULL, NULL, NULL
-       },
+               struct config_generic *record;
 
-       {
-               {"shared_memory_size", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the size of the server's main shared memory area (rounded up to the nearest MB)."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_UNIT_MB | GUC_RUNTIME_COMPUTED
-               },
-               &shared_memory_size_mb,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+               /* Ignore anything already marked as ignorable */
+               if (item->ignore)
+                       continue;
 
-       {
-               {"shared_memory_size_in_huge_pages", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the number of huge pages needed for the main shared memory area."),
-                       gettext_noop("-1 indicates that the value could not be determined."),
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
-               },
-               &shared_memory_size_in_huge_pages,
-               -1, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
+               /*
+                * Try to find the variable; but do not create a custom placeholder if
+                * it's not there already.
+                */
+               record = find_option(item->name, false, true, elevel);
 
-       {
-               {"temp_buffers", PGC_USERSET, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum number of temporary buffers used by each session."),
-                       NULL,
-                       GUC_UNIT_BLOCKS | GUC_EXPLAIN
-               },
-               &num_temp_buffers,
-               1024, 100, INT_MAX / 2,
-               check_temp_buffers, NULL, NULL
-       },
+               if (record)
+               {
+                       /* If it's already marked, then this is a duplicate entry */
+                       if (record->status & GUC_IS_IN_FILE)
+                       {
+                               /*
+                                * Mark the earlier occurrence(s) as dead/ignorable.  We could
+                                * avoid the O(N^2) behavior here with some additional state,
+                                * but it seems unlikely to be worth the trouble.
+                                */
+                               ConfigVariable *pitem;
 
-       {
-               {"port", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the TCP port the server listens on."),
-                       NULL
-               },
-               &PostPortNumber,
-               DEF_PGPORT, 1, 65535,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"unix_socket_permissions", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the access permissions of the Unix-domain socket."),
-                       gettext_noop("Unix-domain sockets use the usual Unix file system "
-                                                "permission set. The parameter value is expected "
-                                                "to be a numeric mode specification in the form "
-                                                "accepted by the chmod and umask system calls. "
-                                                "(To use the customary octal format the number must "
-                                                "start with a 0 (zero).)")
-               },
-               &Unix_socket_permissions,
-               0777, 0000, 0777,
-               NULL, NULL, show_unix_socket_permissions
-       },
-
-       {
-               {"log_file_mode", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the file permissions for log files."),
-                       gettext_noop("The parameter value is expected "
-                                                "to be a numeric mode specification in the form "
-                                                "accepted by the chmod and umask system calls. "
-                                                "(To use the customary octal format the number must "
-                                                "start with a 0 (zero).)")
-               },
-               &Log_file_mode,
-               0600, 0000, 0777,
-               NULL, NULL, show_log_file_mode
-       },
-
-
-       {
-               {"data_directory_mode", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the mode of the data directory."),
-                       gettext_noop("The parameter value is a numeric mode specification "
-                                                "in the form accepted by the chmod and umask system "
-                                                "calls. (To use the customary octal format the number "
-                                                "must start with a 0 (zero).)"),
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
-               },
-               &data_directory_mode,
-               0700, 0000, 0777,
-               NULL, NULL, show_data_directory_mode
-       },
-
-       {
-               {"work_mem", PGC_USERSET, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum memory to be used for query workspaces."),
-                       gettext_noop("This much memory can be used by each internal "
-                                                "sort operation and hash table before switching to "
-                                                "temporary disk files."),
-                       GUC_UNIT_KB | GUC_EXPLAIN
-               },
-               &work_mem,
-               4096, 64, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"maintenance_work_mem", PGC_USERSET, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum memory to be used for maintenance operations."),
-                       gettext_noop("This includes operations such as VACUUM and CREATE INDEX."),
-                       GUC_UNIT_KB
-               },
-               &maintenance_work_mem,
-               65536, 1024, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"logical_decoding_work_mem", PGC_USERSET, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum memory to be used for logical decoding."),
-                       gettext_noop("This much memory can be used by each internal "
-                                                "reorder buffer before spilling to disk."),
-                       GUC_UNIT_KB
-               },
-               &logical_decoding_work_mem,
-               65536, 64, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+                               for (pitem = head; pitem != item; pitem = pitem->next)
+                               {
+                                       if (!pitem->ignore &&
+                                               strcmp(pitem->name, item->name) == 0)
+                                               pitem->ignore = true;
+                               }
+                       }
+                       /* Now mark it as present in file */
+                       record->status |= GUC_IS_IN_FILE;
+               }
+               else if (!valid_custom_variable_name(item->name))
+               {
+                       /* Invalid non-custom variable, so complain */
+                       ereport(elevel,
+                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                        errmsg("unrecognized configuration parameter \"%s\" in file \"%s\" line %d",
+                                                       item->name,
+                                                       item->filename, item->sourceline)));
+                       item->errmsg = pstrdup("unrecognized configuration parameter");
+                       error = true;
+                       ConfFileWithError = item->filename;
+               }
+       }
 
        /*
-        * We use the hopefully-safely-small value of 100kB as the compiled-in
-        * default for max_stack_depth.  InitializeGUCOptions will increase it if
-        * possible, depending on the actual platform-specific stack limit.
+        * If we've detected any errors so far, we don't want to risk applying any
+        * changes.
         */
-       {
-               {"max_stack_depth", PGC_SUSET, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum stack depth, in kilobytes."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &max_stack_depth,
-               100, 100, MAX_KILOBYTES,
-               check_max_stack_depth, assign_max_stack_depth, NULL
-       },
-
-       {
-               {"temp_file_limit", PGC_SUSET, RESOURCES_DISK,
-                       gettext_noop("Limits the total size of all temporary files used by each process."),
-                       gettext_noop("-1 means no limit."),
-                       GUC_UNIT_KB
-               },
-               &temp_file_limit,
-               -1, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"vacuum_cost_page_hit", PGC_USERSET, RESOURCES_VACUUM_DELAY,
-                       gettext_noop("Vacuum cost for a page found in the buffer cache."),
-                       NULL
-               },
-               &VacuumCostPageHit,
-               1, 0, 10000,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"vacuum_cost_page_miss", PGC_USERSET, RESOURCES_VACUUM_DELAY,
-                       gettext_noop("Vacuum cost for a page not found in the buffer cache."),
-                       NULL
-               },
-               &VacuumCostPageMiss,
-               2, 0, 10000,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"vacuum_cost_page_dirty", PGC_USERSET, RESOURCES_VACUUM_DELAY,
-                       gettext_noop("Vacuum cost for a page dirtied by vacuum."),
-                       NULL
-               },
-               &VacuumCostPageDirty,
-               20, 0, 10000,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"vacuum_cost_limit", PGC_USERSET, RESOURCES_VACUUM_DELAY,
-                       gettext_noop("Vacuum cost amount available before napping."),
-                       NULL
-               },
-               &VacuumCostLimit,
-               200, 1, 10000,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_vacuum_cost_limit", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Vacuum cost amount available before napping, for autovacuum."),
-                       NULL
-               },
-               &autovacuum_vac_cost_limit,
-               -1, -1, 10000,
-               NULL, NULL, NULL
-       },
+       if (error)
+               goto bail_out;
 
-       {
-               {"max_files_per_process", PGC_POSTMASTER, RESOURCES_KERNEL,
-                       gettext_noop("Sets the maximum number of simultaneously open files for each server process."),
-                       NULL
-               },
-               &max_files_per_process,
-               1000, 64, INT_MAX,
-               NULL, NULL, NULL
-       },
+       /* Otherwise, set flag that we're beginning to apply changes */
+       applying = true;
 
        /*
-        * See also CheckRequiredParameterValues() if this parameter changes
+        * Check for variables having been removed from the config file, and
+        * revert their reset values (and perhaps also effective values) to the
+        * boot-time defaults.  If such a variable can't be changed after startup,
+        * report that and continue.
         */
+       for (i = 0; i < num_guc_variables; i++)
        {
-               {"max_prepared_transactions", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum number of simultaneously prepared transactions."),
-                       NULL
-               },
-               &max_prepared_xacts,
-               0, 0, MAX_BACKENDS,
-               NULL, NULL, NULL
-       },
-
-#ifdef LOCK_DEBUG
-       {
-               {"trace_lock_oidmin", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Sets the minimum OID of tables for tracking locks."),
-                       gettext_noop("Is used to avoid output on system tables."),
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_lock_oidmin,
-               FirstNormalObjectId, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Sets the OID of the table with unconditionally lock tracing."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &Trace_lock_table,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-#endif
-
-       {
-               {"statement_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the maximum allowed duration of any statement."),
-                       gettext_noop("A value of 0 turns off the timeout."),
-                       GUC_UNIT_MS
-               },
-               &StatementTimeout,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"lock_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the maximum allowed duration of any wait for a lock."),
-                       gettext_noop("A value of 0 turns off the timeout."),
-                       GUC_UNIT_MS
-               },
-               &LockTimeout,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the maximum allowed idle time between queries, when in a transaction."),
-                       gettext_noop("A value of 0 turns off the timeout."),
-                       GUC_UNIT_MS
-               },
-               &IdleInTransactionSessionTimeout,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"idle_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the maximum allowed idle time between queries, when not in a transaction."),
-                       gettext_noop("A value of 0 turns off the timeout."),
-                       GUC_UNIT_MS
-               },
-               &IdleSessionTimeout,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+               struct config_generic *gconf = guc_variables[i];
+               GucStack   *stack;
 
-       {
-               {"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Minimum age at which VACUUM should freeze a table row."),
-                       NULL
-               },
-               &vacuum_freeze_min_age,
-               50000000, 0, 1000000000,
-               NULL, NULL, NULL
-       },
+               if (gconf->reset_source != PGC_S_FILE ||
+                       (gconf->status & GUC_IS_IN_FILE))
+                       continue;
+               if (gconf->context < PGC_SIGHUP)
+               {
+                       /* The removal can't be effective without a restart */
+                       gconf->status |= GUC_PENDING_RESTART;
+                       ereport(elevel,
+                                       (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+                                        errmsg("parameter \"%s\" cannot be changed without restarting the server",
+                                                       gconf->name)));
+                       record_config_file_error(psprintf("parameter \"%s\" cannot be changed without restarting the server",
+                                                                                         gconf->name),
+                                                                        NULL, 0,
+                                                                        &head, &tail);
+                       error = true;
+                       continue;
+               }
 
-       {
-               {"vacuum_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Age at which VACUUM should scan whole table to freeze tuples."),
-                       NULL
-               },
-               &vacuum_freeze_table_age,
-               150000000, 0, 2000000000,
-               NULL, NULL, NULL
-       },
+               /* No more to do if we're just doing show_all_file_settings() */
+               if (!applySettings)
+                       continue;
 
-       {
-               {"vacuum_multixact_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Minimum age at which VACUUM should freeze a MultiXactId in a table row."),
-                       NULL
-               },
-               &vacuum_multixact_freeze_min_age,
-               5000000, 0, 1000000000,
-               NULL, NULL, NULL
-       },
+               /*
+                * Reset any "file" sources to "default", else set_config_option will
+                * not override those settings.
+                */
+               if (gconf->reset_source == PGC_S_FILE)
+                       gconf->reset_source = PGC_S_DEFAULT;
+               if (gconf->source == PGC_S_FILE)
+                       gconf->source = PGC_S_DEFAULT;
+               for (stack = gconf->stack; stack; stack = stack->prev)
+               {
+                       if (stack->source == PGC_S_FILE)
+                               stack->source = PGC_S_DEFAULT;
+               }
 
-       {
-               {"vacuum_multixact_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Multixact age at which VACUUM should scan whole table to freeze tuples."),
-                       NULL
-               },
-               &vacuum_multixact_freeze_table_age,
-               150000000, 0, 2000000000,
-               NULL, NULL, NULL
-       },
+               /* Now we can re-apply the wired-in default (i.e., the boot_val) */
+               if (set_config_option(gconf->name, NULL,
+                                                         context, PGC_S_DEFAULT,
+                                                         GUC_ACTION_SET, true, 0, false) > 0)
+               {
+                       /* Log the change if appropriate */
+                       if (context == PGC_SIGHUP)
+                               ereport(elevel,
+                                               (errmsg("parameter \"%s\" removed from configuration file, reset to default",
+                                                               gconf->name)));
+               }
+       }
 
+       /*
+        * Restore any variables determined by environment variables or
+        * dynamically-computed defaults.  This is a no-op except in the case
+        * where one of these had been in the config file and is now removed.
+        *
+        * In particular, we *must not* do this during the postmaster's initial
+        * loading of the file, since the timezone functions in particular should
+        * be run only after initialization is complete.
+        *
+        * XXX this is an unmaintainable crock, because we have to know how to set
+        * (or at least what to call to set) every non-PGC_INTERNAL variable that
+        * could potentially have PGC_S_DYNAMIC_DEFAULT or PGC_S_ENV_VAR source.
+        */
+       if (context == PGC_SIGHUP && applySettings)
        {
-               {"vacuum_defer_cleanup_age", PGC_SIGHUP, REPLICATION_PRIMARY,
-                       gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any."),
-                       NULL
-               },
-               &vacuum_defer_cleanup_age,
-               0, 0, 1000000,                  /* see ComputeXidHorizons */
-               NULL, NULL, NULL
-       },
-       {
-               {"vacuum_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Age at which VACUUM should trigger failsafe to avoid a wraparound outage."),
-                       NULL
-               },
-               &vacuum_failsafe_age,
-               1600000000, 0, 2100000000,
-               NULL, NULL, NULL
-       },
-       {
-               {"vacuum_multixact_failsafe_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Multixact age at which VACUUM should trigger failsafe to avoid a wraparound outage."),
-                       NULL
-               },
-               &vacuum_multixact_failsafe_age,
-               1600000000, 0, 2100000000,
-               NULL, NULL, NULL
-       },
+               InitializeGUCOptionsFromEnvironment();
+               pg_timezone_abbrev_initialize();
+               /* this selects SQL_ASCII in processes not connected to a database */
+               SetConfigOption("client_encoding", GetDatabaseEncodingName(),
+                                               PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT);
+       }
 
        /*
-        * See also CheckRequiredParameterValues() if this parameter changes
+        * Now apply the values from the config file.
         */
+       for (item = head; item; item = item->next)
        {
-               {"max_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
-                       gettext_noop("Sets the maximum number of locks per transaction."),
-                       gettext_noop("The shared lock table is sized on the assumption that "
-                                                "at most max_locks_per_transaction * max_connections distinct "
-                                                "objects will need to be locked at any one time.")
-               },
-               &max_locks_per_xact,
-               64, 10, INT_MAX,
-               NULL, NULL, NULL
-       },
+               char       *pre_value = NULL;
+               int                     scres;
 
-       {
-               {"max_pred_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
-                       gettext_noop("Sets the maximum number of predicate locks per transaction."),
-                       gettext_noop("The shared predicate lock table is sized on the assumption that "
-                                                "at most max_pred_locks_per_transaction * max_connections distinct "
-                                                "objects will need to be locked at any one time.")
-               },
-               &max_predicate_locks_per_xact,
-               64, 10, INT_MAX,
-               NULL, NULL, NULL
-       },
+               /* Ignore anything marked as ignorable */
+               if (item->ignore)
+                       continue;
 
-       {
-               {"max_pred_locks_per_relation", PGC_SIGHUP, LOCK_MANAGEMENT,
-                       gettext_noop("Sets the maximum number of predicate-locked pages and tuples per relation."),
-                       gettext_noop("If more than this total of pages and tuples in the same relation are locked "
-                                                "by a connection, those locks are replaced by a relation-level lock.")
-               },
-               &max_predicate_locks_per_relation,
-               -2, INT_MIN, INT_MAX,
-               NULL, NULL, NULL
-       },
+               /* In SIGHUP cases in the postmaster, we want to report changes */
+               if (context == PGC_SIGHUP && applySettings && !IsUnderPostmaster)
+               {
+                       const char *preval = GetConfigOption(item->name, true, false);
 
-       {
-               {"max_pred_locks_per_page", PGC_SIGHUP, LOCK_MANAGEMENT,
-                       gettext_noop("Sets the maximum number of predicate-locked tuples per page."),
-                       gettext_noop("If more than this number of tuples on the same page are locked "
-                                                "by a connection, those locks are replaced by a page-level lock.")
-               },
-               &max_predicate_locks_per_page,
-               2, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+                       /* If option doesn't exist yet or is NULL, treat as empty string */
+                       if (!preval)
+                               preval = "";
+                       /* must dup, else might have dangling pointer below */
+                       pre_value = pstrdup(preval);
+               }
 
-       {
-               {"authentication_timeout", PGC_SIGHUP, CONN_AUTH_AUTH,
-                       gettext_noop("Sets the maximum allowed time to complete client authentication."),
-                       NULL,
-                       GUC_UNIT_S
-               },
-               &AuthenticationTimeout,
-               60, 1, 600,
-               NULL, NULL, NULL
-       },
+               scres = set_config_option(item->name, item->value,
+                                                                 context, PGC_S_FILE,
+                                                                 GUC_ACTION_SET, applySettings, 0, false);
+               if (scres > 0)
+               {
+                       /* variable was updated, so log the change if appropriate */
+                       if (pre_value)
+                       {
+                               const char *post_value = GetConfigOption(item->name, true, false);
 
-       {
-               /* Not for general use */
-               {"pre_auth_delay", PGC_SIGHUP, DEVELOPER_OPTIONS,
-                       gettext_noop("Sets the amount of time to wait before "
-                                                "authentication on connection startup."),
-                       gettext_noop("This allows attaching a debugger to the process."),
-                       GUC_NOT_IN_SAMPLE | GUC_UNIT_S
-               },
-               &PreAuthDelay,
-               0, 0, 60,
-               NULL, NULL, NULL
-       },
+                               if (!post_value)
+                                       post_value = "";
+                               if (strcmp(pre_value, post_value) != 0)
+                                       ereport(elevel,
+                                                       (errmsg("parameter \"%s\" changed to \"%s\"",
+                                                                       item->name, item->value)));
+                       }
+                       item->applied = true;
+               }
+               else if (scres == 0)
+               {
+                       error = true;
+                       item->errmsg = pstrdup("setting could not be applied");
+                       ConfFileWithError = item->filename;
+               }
+               else
+               {
+                       /* no error, but variable's active value was not changed */
+                       item->applied = true;
+               }
 
-       {
-               {"wal_decode_buffer_size", PGC_POSTMASTER, WAL_RECOVERY,
-                       gettext_noop("Buffer size for reading ahead in the WAL during recovery."),
-                       gettext_noop("This controls the maximum distance we can read ahead in the WAL to prefetch referenced data blocks."),
-                       GUC_UNIT_BYTE
-               },
-               &wal_decode_buffer_size,
-               512 * 1024, 64 * 1024, MaxAllocSize,
-               NULL, NULL, NULL
-       },
+               /*
+                * We should update source location unless there was an error, since
+                * even if the active value didn't change, the reset value might have.
+                * (In the postmaster, there won't be a difference, but it does matter
+                * in backends.)
+                */
+               if (scres != 0 && applySettings)
+                       set_config_sourcefile(item->name, item->filename,
+                                                                 item->sourceline);
 
-       {
-               {"wal_keep_size", PGC_SIGHUP, REPLICATION_SENDING,
-                       gettext_noop("Sets the size of WAL files held for standby servers."),
-                       NULL,
-                       GUC_UNIT_MB
-               },
-               &wal_keep_size_mb,
-               0, 0, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+               if (pre_value)
+                       pfree(pre_value);
+       }
 
-       {
-               {"min_wal_size", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Sets the minimum size to shrink the WAL to."),
-                       NULL,
-                       GUC_UNIT_MB
-               },
-               &min_wal_size_mb,
-               DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
-               2, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+       /* Remember when we last successfully loaded the config file. */
+       if (applySettings)
+               PgReloadTime = GetCurrentTimestamp();
 
+bail_out:
+       if (error && applySettings)
        {
-               {"max_wal_size", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Sets the WAL size that triggers a checkpoint."),
-                       NULL,
-                       GUC_UNIT_MB
-               },
-               &max_wal_size_mb,
-               DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
-               2, MAX_KILOBYTES,
-               NULL, assign_max_wal_size, NULL
-       },
+               /* During postmaster startup, any error is fatal */
+               if (context == PGC_POSTMASTER)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("configuration file \"%s\" contains errors",
+                                                       ConfFileWithError)));
+               else if (applying)
+                       ereport(elevel,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("configuration file \"%s\" contains errors; unaffected changes were applied",
+                                                       ConfFileWithError)));
+               else
+                       ereport(elevel,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("configuration file \"%s\" contains errors; no changes were applied",
+                                                       ConfFileWithError)));
+       }
 
-       {
-               {"checkpoint_timeout", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Sets the maximum time between automatic WAL checkpoints."),
-                       NULL,
-                       GUC_UNIT_S
-               },
-               &CheckPointTimeout,
-               300, 30, 86400,
-               NULL, NULL, NULL
-       },
+       /* Successful or otherwise, return the collected data list */
+       return head;
+}
 
-       {
-               {"checkpoint_warning", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Sets the maximum time before warning if checkpoints "
-                                                "triggered by WAL volume happen too frequently."),
-                       gettext_noop("Write a message to the server log if checkpoints "
-                                                "caused by the filling of WAL segment files happen more "
-                                                "frequently than this amount of time. "
-                                                "Zero turns off the warning."),
-                       GUC_UNIT_S
-               },
-               &CheckPointWarning,
-               30, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+/*
+ * Some infrastructure for checking malloc/strdup/realloc calls
+ */
+void *
+guc_malloc(int elevel, size_t size)
+{
+       void       *data;
 
-       {
-               {"checkpoint_flush_after", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
-                       NULL,
-                       GUC_UNIT_BLOCKS
-               },
-               &checkpoint_flush_after,
-               DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-               NULL, NULL, NULL
-       },
+       /* Avoid unportable behavior of malloc(0) */
+       if (size == 0)
+               size = 1;
+       data = malloc(size);
+       if (data == NULL)
+               ereport(elevel,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+       return data;
+}
 
-       {
-               {"wal_buffers", PGC_POSTMASTER, WAL_SETTINGS,
-                       gettext_noop("Sets the number of disk-page buffers in shared memory for WAL."),
-                       NULL,
-                       GUC_UNIT_XBLOCKS
-               },
-               &XLOGbuffers,
-               -1, -1, (INT_MAX / XLOG_BLCKSZ),
-               check_wal_buffers, NULL, NULL
-       },
+void *
+guc_realloc(int elevel, void *old, size_t size)
+{
+       void       *data;
 
-       {
-               {"wal_writer_delay", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Time between WAL flushes performed in the WAL writer."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &WalWriterDelay,
-               200, 1, 10000,
-               NULL, NULL, NULL
-       },
+       /* Avoid unportable behavior of realloc(NULL, 0) */
+       if (old == NULL && size == 0)
+               size = 1;
+       data = realloc(old, size);
+       if (data == NULL)
+               ereport(elevel,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+       return data;
+}
 
-       {
-               {"wal_writer_flush_after", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Amount of WAL written out by WAL writer that triggers a flush."),
-                       NULL,
-                       GUC_UNIT_XBLOCKS
-               },
-               &WalWriterFlushAfter,
-               (1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+char *
+guc_strdup(int elevel, const char *src)
+{
+       char       *data;
 
-       {
-               {"wal_skip_threshold", PGC_USERSET, WAL_SETTINGS,
-                       gettext_noop("Minimum size of new file to fsync instead of writing WAL."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &wal_skip_threshold,
-               2048, 0, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+       data = strdup(src);
+       if (data == NULL)
+               ereport(elevel,
+                               (errcode(ERRCODE_OUT_OF_MEMORY),
+                                errmsg("out of memory")));
+       return data;
+}
 
-       {
-               {"max_wal_senders", PGC_POSTMASTER, REPLICATION_SENDING,
-                       gettext_noop("Sets the maximum number of simultaneously running WAL sender processes."),
-                       NULL
-               },
-               &max_wal_senders,
-               10, 0, MAX_BACKENDS,
-               check_max_wal_senders, NULL, NULL
-       },
 
-       {
-               /* see max_wal_senders */
-               {"max_replication_slots", PGC_POSTMASTER, REPLICATION_SENDING,
-                       gettext_noop("Sets the maximum number of simultaneously defined replication slots."),
-                       NULL
-               },
-               &max_replication_slots,
-               10, 0, MAX_BACKENDS /* XXX? */ ,
-               NULL, NULL, NULL
-       },
+/*
+ * Detect whether strval is referenced anywhere in a GUC string item
+ */
+static bool
+string_field_used(struct config_string *conf, char *strval)
+{
+       GucStack   *stack;
 
+       if (strval == *(conf->variable) ||
+               strval == conf->reset_val ||
+               strval == conf->boot_val)
+               return true;
+       for (stack = conf->gen.stack; stack; stack = stack->prev)
        {
-               {"max_slot_wal_keep_size", PGC_SIGHUP, REPLICATION_SENDING,
-                       gettext_noop("Sets the maximum WAL size that can be reserved by replication slots."),
-                       gettext_noop("Replication slots will be marked as failed, and segments released "
-                                                "for deletion or recycling, if this much space is occupied by WAL "
-                                                "on disk."),
-                       GUC_UNIT_MB
-               },
-               &max_slot_wal_keep_size_mb,
-               -1, -1, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+               if (strval == stack->prior.val.stringval ||
+                       strval == stack->masked.val.stringval)
+                       return true;
+       }
+       return false;
+}
 
-       {
-               {"wal_sender_timeout", PGC_USERSET, REPLICATION_SENDING,
-                       gettext_noop("Sets the maximum time to wait for WAL replication."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &wal_sender_timeout,
-               60 * 1000, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+/*
+ * Support for assigning to a field of a string GUC item.  Free the prior
+ * value if it's not referenced anywhere else in the item (including stacked
+ * states).
+ */
+static void
+set_string_field(struct config_string *conf, char **field, char *newval)
+{
+       char       *oldval = *field;
 
-       {
-               {"commit_delay", PGC_SUSET, WAL_SETTINGS,
-                       gettext_noop("Sets the delay in microseconds between transaction commit and "
-                                                "flushing WAL to disk."),
-                       NULL
-                       /* we have no microseconds designation, so can't supply units here */
-               },
-               &CommitDelay,
-               0, 0, 100000,
-               NULL, NULL, NULL
-       },
+       /* Do the assignment */
+       *field = newval;
 
-       {
-               {"commit_siblings", PGC_USERSET, WAL_SETTINGS,
-                       gettext_noop("Sets the minimum number of concurrent open transactions "
-                                                "required before performing commit_delay."),
-                       NULL
-               },
-               &CommitSiblings,
-               5, 0, 1000,
-               NULL, NULL, NULL
-       },
+       /* Free old value if it's not NULL and isn't referenced anymore */
+       if (oldval && !string_field_used(conf, oldval))
+               free(oldval);
+}
 
-       {
-               {"extra_float_digits", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the number of digits displayed for floating-point values."),
-                       gettext_noop("This affects real, double precision, and geometric data types. "
-                                                "A zero or negative parameter value is added to the standard "
-                                                "number of digits (FLT_DIG or DBL_DIG as appropriate). "
-                                                "Any value greater than zero selects precise output mode.")
-               },
-               &extra_float_digits,
-               1, -15, 3,
-               NULL, NULL, NULL
-       },
+/*
+ * Detect whether an "extra" struct is referenced anywhere in a GUC item
+ */
+static bool
+extra_field_used(struct config_generic *gconf, void *extra)
+{
+       GucStack   *stack;
 
+       if (extra == gconf->extra)
+               return true;
+       switch (gconf->vartype)
        {
-               {"log_min_duration_sample", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the minimum execution time above which "
-                                                "a sample of statements will be logged."
-                                                " Sampling is determined by log_statement_sample_rate."),
-                       gettext_noop("Zero logs a sample of all queries. -1 turns this feature off."),
-                       GUC_UNIT_MS
-               },
-               &log_min_duration_sample,
-               -1, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
-
+               case PGC_BOOL:
+                       if (extra == ((struct config_bool *) gconf)->reset_extra)
+                               return true;
+                       break;
+               case PGC_INT:
+                       if (extra == ((struct config_int *) gconf)->reset_extra)
+                               return true;
+                       break;
+               case PGC_REAL:
+                       if (extra == ((struct config_real *) gconf)->reset_extra)
+                               return true;
+                       break;
+               case PGC_STRING:
+                       if (extra == ((struct config_string *) gconf)->reset_extra)
+                               return true;
+                       break;
+               case PGC_ENUM:
+                       if (extra == ((struct config_enum *) gconf)->reset_extra)
+                               return true;
+                       break;
+       }
+       for (stack = gconf->stack; stack; stack = stack->prev)
        {
-               {"log_min_duration_statement", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the minimum execution time above which "
-                                                "all statements will be logged."),
-                       gettext_noop("Zero prints all queries. -1 turns this feature off."),
-                       GUC_UNIT_MS
-               },
-               &log_min_duration_statement,
-               -1, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
+               if (extra == stack->prior.extra ||
+                       extra == stack->masked.extra)
+                       return true;
+       }
 
-       {
-               {"log_autovacuum_min_duration", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Sets the minimum execution time above which "
-                                                "autovacuum actions will be logged."),
-                       gettext_noop("Zero prints all actions. -1 turns autovacuum logging off."),
-                       GUC_UNIT_MS
-               },
-               &Log_autovacuum_min_duration,
-               600000, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
+       return false;
+}
 
-       {
-               {"log_parameter_max_length", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Sets the maximum length in bytes of data logged for bind "
-                                                "parameter values when logging statements."),
-                       gettext_noop("-1 to print values in full."),
-                       GUC_UNIT_BYTE
-               },
-               &log_parameter_max_length,
-               -1, -1, INT_MAX / 2,
-               NULL, NULL, NULL
-       },
+/*
+ * Support for assigning to an "extra" field of a GUC item.  Free the prior
+ * value if it's not referenced anywhere else in the item (including stacked
+ * states).
+ */
+static void
+set_extra_field(struct config_generic *gconf, void **field, void *newval)
+{
+       void       *oldval = *field;
 
-       {
-               {"log_parameter_max_length_on_error", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Sets the maximum length in bytes of data logged for bind "
-                                                "parameter values when logging statements, on error."),
-                       gettext_noop("-1 to print values in full."),
-                       GUC_UNIT_BYTE
-               },
-               &log_parameter_max_length_on_error,
-               0, -1, INT_MAX / 2,
-               NULL, NULL, NULL
-       },
+       /* Do the assignment */
+       *field = newval;
 
-       {
-               {"bgwriter_delay", PGC_SIGHUP, RESOURCES_BGWRITER,
-                       gettext_noop("Background writer sleep time between rounds."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &BgWriterDelay,
-               200, 10, 10000,
-               NULL, NULL, NULL
-       },
+       /* Free old value if it's not NULL and isn't referenced anymore */
+       if (oldval && !extra_field_used(gconf, oldval))
+               free(oldval);
+}
 
+/*
+ * Support for copying a variable's active value into a stack entry.
+ * The "extra" field associated with the active value is copied, too.
+ *
+ * NB: be sure stringval and extra fields of a new stack entry are
+ * initialized to NULL before this is used, else we'll try to free() them.
+ */
+static void
+set_stack_value(struct config_generic *gconf, config_var_value *val)
+{
+       switch (gconf->vartype)
        {
-               {"bgwriter_lru_maxpages", PGC_SIGHUP, RESOURCES_BGWRITER,
-                       gettext_noop("Background writer maximum number of LRU pages to flush per round."),
-                       NULL
-               },
-               &bgwriter_lru_maxpages,
-               100, 0, INT_MAX / 2,    /* Same upper limit as shared_buffers */
-               NULL, NULL, NULL
-       },
+               case PGC_BOOL:
+                       val->val.boolval =
+                               *((struct config_bool *) gconf)->variable;
+                       break;
+               case PGC_INT:
+                       val->val.intval =
+                               *((struct config_int *) gconf)->variable;
+                       break;
+               case PGC_REAL:
+                       val->val.realval =
+                               *((struct config_real *) gconf)->variable;
+                       break;
+               case PGC_STRING:
+                       set_string_field((struct config_string *) gconf,
+                                                        &(val->val.stringval),
+                                                        *((struct config_string *) gconf)->variable);
+                       break;
+               case PGC_ENUM:
+                       val->val.enumval =
+                               *((struct config_enum *) gconf)->variable;
+                       break;
+       }
+       set_extra_field(gconf, &(val->extra), gconf->extra);
+}
 
+/*
+ * Support for discarding a no-longer-needed value in a stack entry.
+ * The "extra" field associated with the stack entry is cleared, too.
+ */
+static void
+discard_stack_value(struct config_generic *gconf, config_var_value *val)
+{
+       switch (gconf->vartype)
        {
-               {"bgwriter_flush_after", PGC_SIGHUP, RESOURCES_BGWRITER,
-                       gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
-                       NULL,
-                       GUC_UNIT_BLOCKS
-               },
-               &bgwriter_flush_after,
-               DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-               NULL, NULL, NULL
-       },
+               case PGC_BOOL:
+               case PGC_INT:
+               case PGC_REAL:
+               case PGC_ENUM:
+                       /* no need to do anything */
+                       break;
+               case PGC_STRING:
+                       set_string_field((struct config_string *) gconf,
+                                                        &(val->val.stringval),
+                                                        NULL);
+                       break;
+       }
+       set_extra_field(gconf, &(val->extra), NULL);
+}
 
-       {
-               {"effective_io_concurrency",
-                       PGC_USERSET,
-                       RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &effective_io_concurrency,
-#ifdef USE_PREFETCH
-               1,
-#else
-               0,
-#endif
-               0, MAX_IO_CONCURRENCY,
-               check_effective_io_concurrency, NULL, NULL
-       },
 
-       {
-               {"maintenance_io_concurrency",
-                       PGC_USERSET,
-                       RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("A variant of effective_io_concurrency that is used for maintenance work."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &maintenance_io_concurrency,
-#ifdef USE_PREFETCH
-               10,
-#else
-               0,
-#endif
-               0, MAX_IO_CONCURRENCY,
-               check_maintenance_io_concurrency, assign_maintenance_io_concurrency,
-               NULL
-       },
+/*
+ * Fetch the sorted array pointer (exported for help_config.c's use ONLY)
+ */
+struct config_generic **
+get_guc_variables(void)
+{
+       return guc_variables;
+}
 
-       {
-               {"backend_flush_after", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
-                       NULL,
-                       GUC_UNIT_BLOCKS
-               },
-               &backend_flush_after,
-               DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"max_worker_processes",
-                       PGC_POSTMASTER,
-                       RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Maximum number of concurrent worker processes."),
-                       NULL,
-               },
-               &max_worker_processes,
-               8, 0, MAX_BACKENDS,
-               check_max_worker_processes, NULL, NULL
-       },
+/*
+ * Build the sorted array.  This is split out so that it could be
+ * re-executed after startup (e.g., we could allow loadable modules to
+ * add vars, and then we'd need to re-sort).
+ */
+void
+build_guc_variables(void)
+{
+       int                     size_vars;
+       int                     num_vars = 0;
+       struct config_generic **guc_vars;
+       int                     i;
 
+       for (i = 0; ConfigureNamesBool[i].gen.name; i++)
        {
-               {"max_logical_replication_workers",
-                       PGC_POSTMASTER,
-                       REPLICATION_SUBSCRIBERS,
-                       gettext_noop("Maximum number of logical replication worker processes."),
-                       NULL,
-               },
-               &max_logical_replication_workers,
-               4, 0, MAX_BACKENDS,
-               NULL, NULL, NULL
-       },
+               struct config_bool *conf = &ConfigureNamesBool[i];
 
-       {
-               {"max_sync_workers_per_subscription",
-                       PGC_SIGHUP,
-                       REPLICATION_SUBSCRIBERS,
-                       gettext_noop("Maximum number of table synchronization workers per subscription."),
-                       NULL,
-               },
-               &max_sync_workers_per_subscription,
-               2, 0, MAX_BACKENDS,
-               NULL, NULL, NULL
-       },
+               /* Rather than requiring vartype to be filled in by hand, do this: */
+               conf->gen.vartype = PGC_BOOL;
+               num_vars++;
+       }
 
+       for (i = 0; ConfigureNamesInt[i].gen.name; i++)
        {
-               {"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the amount of time to wait before forcing "
-                                                "log file rotation."),
-                       NULL,
-                       GUC_UNIT_MIN
-               },
-               &Log_RotationAge,
-               HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
-               NULL, NULL, NULL
-       },
+               struct config_int *conf = &ConfigureNamesInt[i];
 
-       {
-               {"log_rotation_size", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the maximum size a log file can reach before "
-                                                "being rotated."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &Log_RotationSize,
-               10 * 1024, 0, INT_MAX / 1024,
-               NULL, NULL, NULL
-       },
+               conf->gen.vartype = PGC_INT;
+               num_vars++;
+       }
 
+       for (i = 0; ConfigureNamesReal[i].gen.name; i++)
        {
-               {"max_function_args", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the maximum number of function arguments."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &max_function_args,
-               FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
-               NULL, NULL, NULL
-       },
+               struct config_real *conf = &ConfigureNamesReal[i];
 
-       {
-               {"max_index_keys", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the maximum number of index keys."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &max_index_keys,
-               INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
-               NULL, NULL, NULL
-       },
+               conf->gen.vartype = PGC_REAL;
+               num_vars++;
+       }
 
+       for (i = 0; ConfigureNamesString[i].gen.name; i++)
        {
-               {"max_identifier_length", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the maximum identifier length."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &max_identifier_length,
-               NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
-               NULL, NULL, NULL
-       },
+               struct config_string *conf = &ConfigureNamesString[i];
 
-       {
-               {"block_size", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the size of a disk block."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &block_size,
-               BLCKSZ, BLCKSZ, BLCKSZ,
-               NULL, NULL, NULL
-       },
+               conf->gen.vartype = PGC_STRING;
+               num_vars++;
+       }
 
+       for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
        {
-               {"segment_size", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the number of pages per disk file."),
-                       NULL,
-                       GUC_UNIT_BLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &segment_size,
-               RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
-               NULL, NULL, NULL
-       },
+               struct config_enum *conf = &ConfigureNamesEnum[i];
 
-       {
-               {"wal_block_size", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the block size in the write ahead log."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &wal_block_size,
-               XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
-               NULL, NULL, NULL
-       },
+               conf->gen.vartype = PGC_ENUM;
+               num_vars++;
+       }
 
-       {
-               {"wal_retrieve_retry_interval", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the time to wait before retrying to retrieve WAL "
-                                                "after a failed attempt."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &wal_retrieve_retry_interval,
-               5000, 1, INT_MAX,
-               NULL, NULL, NULL
-       },
+       /*
+        * Create table with 20% slack
+        */
+       size_vars = num_vars + num_vars / 4;
 
-       {
-               {"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the size of write ahead log segments."),
-                       NULL,
-                       GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_RUNTIME_COMPUTED
-               },
-               &wal_segment_size,
-               DEFAULT_XLOG_SEG_SIZE,
-               WalSegMinSize,
-               WalSegMaxSize,
-               NULL, NULL, NULL
-       },
+       guc_vars = (struct config_generic **)
+               guc_malloc(FATAL, size_vars * sizeof(struct config_generic *));
 
-       {
-               {"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Time to sleep between autovacuum runs."),
-                       NULL,
-                       GUC_UNIT_S
-               },
-               &autovacuum_naptime,
-               60, 1, INT_MAX / 1000,
-               NULL, NULL, NULL
-       },
-       {
-               {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
-                       NULL
-               },
-               &autovacuum_vac_thresh,
-               50, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
-                       NULL
-               },
-               &autovacuum_vac_ins_thresh,
-               1000, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
-                       NULL
-               },
-               &autovacuum_anl_thresh,
-               50, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               /* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
-               {"autovacuum_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
-                       gettext_noop("Age at which to autovacuum a table to prevent transaction ID wraparound."),
-                       NULL
-               },
-               &autovacuum_freeze_max_age,
-
-               /* see vacuum_failsafe_age if you change the upper-limit value. */
-               200000000, 100000, 2000000000,
-               NULL, NULL, NULL
-       },
-       {
-               /* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
-               {"autovacuum_multixact_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
-                       gettext_noop("Multixact age at which to autovacuum a table to prevent multixact wraparound."),
-                       NULL
-               },
-               &autovacuum_multixact_freeze_max_age,
-               400000000, 10000, 2000000000,
-               NULL, NULL, NULL
-       },
-       {
-               /* see max_connections */
-               {"autovacuum_max_workers", PGC_POSTMASTER, AUTOVACUUM,
-                       gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
-                       NULL
-               },
-               &autovacuum_max_workers,
-               3, 1, MAX_BACKENDS,
-               check_autovacuum_max_workers, NULL, NULL
-       },
+       num_vars = 0;
 
-       {
-               {"max_parallel_maintenance_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Sets the maximum number of parallel processes per maintenance operation."),
-                       NULL
-               },
-               &max_parallel_maintenance_workers,
-               2, 0, 1024,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"max_parallel_workers_per_gather", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Sets the maximum number of parallel processes per executor node."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &max_parallel_workers_per_gather,
-               2, 0, MAX_PARALLEL_WORKER_LIMIT,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Sets the maximum number of parallel workers that can be active at one time."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &max_parallel_workers,
-               8, 0, MAX_PARALLEL_WORKER_LIMIT,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_work_mem", PGC_SIGHUP, RESOURCES_MEM,
-                       gettext_noop("Sets the maximum memory to be used by each autovacuum worker process."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &autovacuum_work_mem,
-               -1, -1, MAX_KILOBYTES,
-               check_autovacuum_work_mem, NULL, NULL
-       },
-
-       {
-               {"old_snapshot_threshold", PGC_POSTMASTER, RESOURCES_ASYNCHRONOUS,
-                       gettext_noop("Time before a snapshot is too old to read pages changed after the snapshot was taken."),
-                       gettext_noop("A value of -1 disables this feature."),
-                       GUC_UNIT_MIN
-               },
-               &old_snapshot_threshold,
-               -1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
-               NULL, NULL, NULL
-       },
+       for (i = 0; ConfigureNamesBool[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesBool[i].gen;
 
-       {
-               {"tcp_keepalives_idle", PGC_USERSET, CONN_AUTH_TCP,
-                       gettext_noop("Time between issuing TCP keepalives."),
-                       gettext_noop("A value of 0 uses the system default."),
-                       GUC_UNIT_S
-               },
-               &tcp_keepalives_idle,
-               0, 0, INT_MAX,
-               NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
-       },
+       for (i = 0; ConfigureNamesInt[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesInt[i].gen;
 
-       {
-               {"tcp_keepalives_interval", PGC_USERSET, CONN_AUTH_TCP,
-                       gettext_noop("Time between TCP keepalive retransmits."),
-                       gettext_noop("A value of 0 uses the system default."),
-                       GUC_UNIT_S
-               },
-               &tcp_keepalives_interval,
-               0, 0, INT_MAX,
-               NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
-       },
+       for (i = 0; ConfigureNamesReal[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesReal[i].gen;
 
-       {
-               {"ssl_renegotiation_limit", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("SSL renegotiation is no longer supported; this can only be 0."),
-                       NULL,
-                       GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE,
-               },
-               &ssl_renegotiation_limit,
-               0, 0, 0,
-               NULL, NULL, NULL
-       },
+       for (i = 0; ConfigureNamesString[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesString[i].gen;
 
-       {
-               {"tcp_keepalives_count", PGC_USERSET, CONN_AUTH_TCP,
-                       gettext_noop("Maximum number of TCP keepalive retransmits."),
-                       gettext_noop("This controls the number of consecutive keepalive retransmits that can be "
-                                                "lost before a connection is considered dead. A value of 0 uses the "
-                                                "system default."),
-               },
-               &tcp_keepalives_count,
-               0, 0, INT_MAX,
-               NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
-       },
+       for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
 
-       {
-               {"gin_fuzzy_search_limit", PGC_USERSET, CLIENT_CONN_OTHER,
-                       gettext_noop("Sets the maximum allowed result for exact search by GIN."),
-                       NULL,
-                       0
-               },
-               &GinFuzzySearchLimit,
-               0, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
+       free(guc_variables);
+       guc_variables = guc_vars;
+       num_guc_variables = num_vars;
+       size_guc_variables = size_vars;
+       qsort((void *) guc_variables, num_guc_variables,
+                 sizeof(struct config_generic *), guc_var_compare);
+}
 
+/*
+ * Add a new GUC variable to the list of known variables. The
+ * list is expanded if needed.
+ */
+static bool
+add_guc_variable(struct config_generic *var, int elevel)
+{
+       if (num_guc_variables + 1 >= size_guc_variables)
        {
-               {"effective_cache_size", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's assumption about the total size of the data caches."),
-                       gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. "
-                                                "This is measured in disk pages, which are normally 8 kB each."),
-                       GUC_UNIT_BLOCKS | GUC_EXPLAIN,
-               },
-               &effective_cache_size,
-               DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
-               NULL, NULL, NULL
-       },
+               /*
+                * Increase the vector by 25%
+                */
+               int                     size_vars = size_guc_variables + size_guc_variables / 4;
+               struct config_generic **guc_vars;
 
-       {
-               {"min_parallel_table_scan_size", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the minimum amount of table data for a parallel scan."),
-                       gettext_noop("If the planner estimates that it will read a number of table pages too small to reach this limit, a parallel scan will not be considered."),
-                       GUC_UNIT_BLOCKS | GUC_EXPLAIN,
-               },
-               &min_parallel_table_scan_size,
-               (8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-               NULL, NULL, NULL
-       },
+               if (size_vars == 0)
+               {
+                       size_vars = 100;
+                       guc_vars = (struct config_generic **)
+                               guc_malloc(elevel, size_vars * sizeof(struct config_generic *));
+               }
+               else
+               {
+                       guc_vars = (struct config_generic **)
+                               guc_realloc(elevel, guc_variables, size_vars * sizeof(struct config_generic *));
+               }
 
-       {
-               {"min_parallel_index_scan_size", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the minimum amount of index data for a parallel scan."),
-                       gettext_noop("If the planner estimates that it will read a number of index pages too small to reach this limit, a parallel scan will not be considered."),
-                       GUC_UNIT_BLOCKS | GUC_EXPLAIN,
-               },
-               &min_parallel_index_scan_size,
-               (512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
-               NULL, NULL, NULL
-       },
+               if (guc_vars == NULL)
+                       return false;           /* out of memory */
 
-       {
-               /* Can't be set in postgresql.conf */
-               {"server_version_num", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the server version as an integer."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &server_version_num,
-               PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
-               NULL, NULL, NULL
-       },
+               guc_variables = guc_vars;
+               size_guc_variables = size_vars;
+       }
+       guc_variables[num_guc_variables++] = var;
+       qsort((void *) guc_variables, num_guc_variables,
+                 sizeof(struct config_generic *), guc_var_compare);
+       return true;
+}
 
-       {
-               {"log_temp_files", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Log the use of temporary files larger than this number of kilobytes."),
-                       gettext_noop("Zero logs all files. The default is -1 (turning this feature off)."),
-                       GUC_UNIT_KB
-               },
-               &log_temp_files,
-               -1, -1, INT_MAX,
-               NULL, NULL, NULL
-       },
+/*
+ * Decide whether a proposed custom variable name is allowed.
+ *
+ * It must be two or more identifiers separated by dots, where the rules
+ * for what is an identifier agree with scan.l.  (If you change this rule,
+ * adjust the errdetail in find_option().)
+ */
+static bool
+valid_custom_variable_name(const char *name)
+{
+       bool            saw_sep = false;
+       bool            name_start = true;
 
+       for (const char *p = name; *p; p++)
        {
-               {"track_activity_query_size", PGC_POSTMASTER, STATS_CUMULATIVE,
-                       gettext_noop("Sets the size reserved for pg_stat_activity.query, in bytes."),
-                       NULL,
-                       GUC_UNIT_BYTE
-               },
-               &pgstat_track_activity_query_size,
-               1024, 100, 1048576,
-               NULL, NULL, NULL
-       },
+               if (*p == GUC_QUALIFIER_SEPARATOR)
+               {
+                       if (name_start)
+                               return false;   /* empty name component */
+                       saw_sep = true;
+                       name_start = true;
+               }
+               else if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                               "abcdefghijklmnopqrstuvwxyz_", *p) != NULL ||
+                                IS_HIGHBIT_SET(*p))
+               {
+                       /* okay as first or non-first character */
+                       name_start = false;
+               }
+               else if (!name_start && strchr("0123456789$", *p) != NULL)
+                        /* okay as non-first character */ ;
+               else
+                       return false;
+       }
+       if (name_start)
+               return false;                   /* empty name component */
+       /* OK if we found at least one separator */
+       return saw_sep;
+}
 
-       {
-               {"gin_pending_list_limit", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the maximum size of the pending list for GIN index."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &gin_pending_list_limit,
-               4096, 64, MAX_KILOBYTES,
-               NULL, NULL, NULL
-       },
+/*
+ * Create and add a placeholder variable for a custom variable name.
+ */
+static struct config_generic *
+add_placeholder_variable(const char *name, int elevel)
+{
+       size_t          sz = sizeof(struct config_string) + sizeof(char *);
+       struct config_string *var;
+       struct config_generic *gen;
 
-       {
-               {"tcp_user_timeout", PGC_USERSET, CONN_AUTH_TCP,
-                       gettext_noop("TCP user timeout."),
-                       gettext_noop("A value of 0 uses the system default."),
-                       GUC_UNIT_MS
-               },
-               &tcp_user_timeout,
-               0, 0, INT_MAX,
-               NULL, assign_tcp_user_timeout, show_tcp_user_timeout
-       },
+       var = (struct config_string *) guc_malloc(elevel, sz);
+       if (var == NULL)
+               return NULL;
+       memset(var, 0, sz);
+       gen = &var->gen;
 
+       gen->name = guc_strdup(elevel, name);
+       if (gen->name == NULL)
        {
-               {"huge_page_size", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("The size of huge page that should be requested."),
-                       NULL,
-                       GUC_UNIT_KB
-               },
-               &huge_page_size,
-               0, 0, INT_MAX,
-               check_huge_page_size, NULL, NULL
-       },
+               free(var);
+               return NULL;
+       }
 
-       {
-               {"debug_discard_caches", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Aggressively flush system caches for debugging purposes."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &debug_discard_caches,
-#ifdef DISCARD_CACHES_ENABLED
-               /* Set default based on older compile-time-only cache clobber macros */
-#if defined(CLOBBER_CACHE_RECURSIVELY)
-               3,
-#elif defined(CLOBBER_CACHE_ALWAYS)
-               1,
-#else
-               0,
-#endif
-               0, 5,
-#else                                                  /* not DISCARD_CACHES_ENABLED */
-               0, 0, 0,
-#endif                                                 /* not DISCARD_CACHES_ENABLED */
-               NULL, NULL, NULL
-       },
+       gen->context = PGC_USERSET;
+       gen->group = CUSTOM_OPTIONS;
+       gen->short_desc = "GUC placeholder variable";
+       gen->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER;
+       gen->vartype = PGC_STRING;
 
-       {
-               {"client_connection_check_interval", PGC_USERSET, CONN_AUTH_TCP,
-                       gettext_noop("Sets the time interval between checks for disconnection while running queries."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &client_connection_check_interval,
-               0, 0, INT_MAX,
-               check_client_connection_check_interval, NULL, NULL
-       },
+       /*
+        * The char* is allocated at the end of the struct since we have no
+        * 'static' place to point to.  Note that the current value, as well as
+        * the boot and reset values, start out NULL.
+        */
+       var->variable = (char **) (var + 1);
 
+       if (!add_guc_variable((struct config_generic *) var, elevel))
        {
-               {"log_startup_progress_interval", PGC_SIGHUP, LOGGING_WHEN,
-                       gettext_noop("Time between progress updates for "
-                                                "long-running startup operations."),
-                       gettext_noop("0 turns this feature off."),
-                       GUC_UNIT_MS,
-               },
-               &log_startup_progress_interval,
-               10000, 0, INT_MAX,
-               NULL, NULL, NULL
-       },
-
-       /* End-of-list marker */
-       {
-               {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
+               free(unconstify(char *, gen->name));
+               free(var);
+               return NULL;
        }
-};
 
+       return gen;
+}
 
-static struct config_real ConfigureNamesReal[] =
+/*
+ * Look up option "name".  If it exists, return a pointer to its record.
+ * Otherwise, if create_placeholders is true and name is a valid-looking
+ * custom variable name, we'll create and return a placeholder record.
+ * Otherwise, if skip_errors is true, then we silently return NULL for
+ * an unrecognized or invalid name.  Otherwise, the error is reported at
+ * error level elevel (and we return NULL if that's less than ERROR).
+ *
+ * Note: internal errors, primarily out-of-memory, draw an elevel-level
+ * report and NULL return regardless of skip_errors.  Hence, callers must
+ * handle a NULL return whenever elevel < ERROR, but they should not need
+ * to emit any additional error message.  (In practice, internal errors
+ * can only happen when create_placeholders is true, so callers passing
+ * false need not think terribly hard about this.)
+ */
+struct config_generic *
+find_option(const char *name, bool create_placeholders, bool skip_errors,
+                       int elevel)
 {
-       {
-               {"seq_page_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of a "
-                                                "sequentially fetched disk page."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &seq_page_cost,
-               DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"random_page_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of a "
-                                                "nonsequentially fetched disk page."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &random_page_cost,
-               DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"cpu_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of "
-                                                "processing each tuple (row)."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &cpu_tuple_cost,
-               DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"cpu_index_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of "
-                                                "processing each index entry during an index scan."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &cpu_index_tuple_cost,
-               DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"cpu_operator_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of "
-                                                "processing each operator or function call."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &cpu_operator_cost,
-               DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"parallel_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of "
-                                                "passing each tuple (row) from worker to leader backend."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &parallel_tuple_cost,
-               DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
-       {
-               {"parallel_setup_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Sets the planner's estimate of the cost of "
-                                                "starting up worker processes for parallel query."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &parallel_setup_cost,
-               DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX,
-               NULL, NULL, NULL
-       },
+       const char **key = &name;
+       struct config_generic **res;
+       int                     i;
 
-       {
-               {"jit_above_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Perform JIT compilation if query is more expensive."),
-                       gettext_noop("-1 disables JIT compilation."),
-                       GUC_EXPLAIN
-               },
-               &jit_above_cost,
-               100000, -1, DBL_MAX,
-               NULL, NULL, NULL
-       },
+       Assert(name);
 
-       {
-               {"jit_optimize_above_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Optimize JIT-compiled functions if query is more expensive."),
-                       gettext_noop("-1 disables optimization."),
-                       GUC_EXPLAIN
-               },
-               &jit_optimize_above_cost,
-               500000, -1, DBL_MAX,
-               NULL, NULL, NULL
-       },
+       /*
+        * By equating const char ** with struct config_generic *, we are assuming
+        * the name field is first in config_generic.
+        */
+       res = (struct config_generic **) bsearch((void *) &key,
+                                                                                        (void *) guc_variables,
+                                                                                        num_guc_variables,
+                                                                                        sizeof(struct config_generic *),
+                                                                                        guc_var_compare);
+       if (res)
+               return *res;
 
+       /*
+        * See if the name is an obsolete name for a variable.  We assume that the
+        * set of supported old names is short enough that a brute-force search is
+        * the best way.
+        */
+       for (i = 0; map_old_guc_names[i] != NULL; i += 2)
        {
-               {"jit_inline_above_cost", PGC_USERSET, QUERY_TUNING_COST,
-                       gettext_noop("Perform JIT inlining if query is more expensive."),
-                       gettext_noop("-1 disables inlining."),
-                       GUC_EXPLAIN
-               },
-               &jit_inline_above_cost,
-               500000, -1, DBL_MAX,
-               NULL, NULL, NULL
-       },
+               if (guc_name_compare(name, map_old_guc_names[i]) == 0)
+                       return find_option(map_old_guc_names[i + 1], false,
+                                                          skip_errors, elevel);
+       }
 
+       if (create_placeholders)
        {
-               {"cursor_tuple_fraction", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Sets the planner's estimate of the fraction of "
-                                                "a cursor's rows that will be retrieved."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &cursor_tuple_fraction,
-               DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0,
-               NULL, NULL, NULL
-       },
+               /*
+                * Check if the name is valid, and if so, add a placeholder.  If it
+                * doesn't contain a separator, don't assume that it was meant to be a
+                * placeholder.
+                */
+               const char *sep = strchr(name, GUC_QUALIFIER_SEPARATOR);
 
-       {
-               {"recursive_worktable_factor", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Sets the planner's estimate of the average size "
-                                                "of a recursive query's working table."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &recursive_worktable_factor,
-               DEFAULT_RECURSIVE_WORKTABLE_FACTOR, 0.001, 1000000.0,
-               NULL, NULL, NULL
-       },
+               if (sep != NULL)
+               {
+                       size_t          classLen = sep - name;
+                       ListCell   *lc;
 
-       {
-               {"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("GEQO: selective pressure within the population."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &Geqo_selection_bias,
-               DEFAULT_GEQO_SELECTION_BIAS,
-               MIN_GEQO_SELECTION_BIAS, MAX_GEQO_SELECTION_BIAS,
-               NULL, NULL, NULL
-       },
-       {
-               {"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
-                       gettext_noop("GEQO: seed for random path selection."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &Geqo_seed,
-               0.0, 0.0, 1.0,
-               NULL, NULL, NULL
-       },
+                       /* The name must be syntactically acceptable ... */
+                       if (!valid_custom_variable_name(name))
+                       {
+                               if (!skip_errors)
+                                       ereport(elevel,
+                                                       (errcode(ERRCODE_INVALID_NAME),
+                                                        errmsg("invalid configuration parameter name \"%s\"",
+                                                                       name),
+                                                        errdetail("Custom parameter names must be two or more simple identifiers separated by dots.")));
+                               return NULL;
+                       }
+                       /* ... and it must not match any previously-reserved prefix */
+                       foreach(lc, reserved_class_prefix)
+                       {
+                               const char *rcprefix = lfirst(lc);
 
-       {
-               {"hash_mem_multiplier", PGC_USERSET, RESOURCES_MEM,
-                       gettext_noop("Multiple of work_mem to use for hash tables."),
-                       NULL,
-                       GUC_EXPLAIN
-               },
-               &hash_mem_multiplier,
-               2.0, 1.0, 1000.0,
-               NULL, NULL, NULL
-       },
+                               if (strlen(rcprefix) == classLen &&
+                                       strncmp(name, rcprefix, classLen) == 0)
+                               {
+                                       if (!skip_errors)
+                                               ereport(elevel,
+                                                               (errcode(ERRCODE_INVALID_NAME),
+                                                                errmsg("invalid configuration parameter name \"%s\"",
+                                                                               name),
+                                                                errdetail("\"%s\" is a reserved prefix.",
+                                                                                  rcprefix)));
+                                       return NULL;
+                               }
+                       }
+                       /* OK, create it */
+                       return add_placeholder_variable(name, elevel);
+               }
+       }
 
-       {
-               {"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES_BGWRITER,
-                       gettext_noop("Multiple of the average buffer usage to free per round."),
-                       NULL
-               },
-               &bgwriter_lru_multiplier,
-               2.0, 0.0, 10.0,
-               NULL, NULL, NULL
-       },
+       /* Unknown name */
+       if (!skip_errors)
+               ereport(elevel,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("unrecognized configuration parameter \"%s\"",
+                                               name)));
+       return NULL;
+}
 
-       {
-               {"seed", PGC_USERSET, UNGROUPED,
-                       gettext_noop("Sets the seed for random-number generation."),
-                       NULL,
-                       GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &phony_random_seed,
-               0.0, -1.0, 1.0,
-               check_random_seed, assign_random_seed, show_random_seed
-       },
 
-       {
-               {"vacuum_cost_delay", PGC_USERSET, RESOURCES_VACUUM_DELAY,
-                       gettext_noop("Vacuum cost delay in milliseconds."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &VacuumCostDelay,
-               0, 0, 100,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."),
-                       NULL,
-                       GUC_UNIT_MS
-               },
-               &autovacuum_vac_cost_delay,
-               2, -1, 100,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_vacuum_scale_factor", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples."),
-                       NULL
-               },
-               &autovacuum_vac_scale,
-               0.2, 0.0, 100.0,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_vacuum_insert_scale_factor", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Number of tuple inserts prior to vacuum as a fraction of reltuples."),
-                       NULL
-               },
-               &autovacuum_vac_ins_scale,
-               0.2, 0.0, 100.0,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM,
-                       gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples."),
-                       NULL
-               },
-               &autovacuum_anl_scale,
-               0.1, 0.0, 100.0,
-               NULL, NULL, NULL
-       },
+/*
+ * comparator for qsorting and bsearching guc_variables array
+ */
+static int
+guc_var_compare(const void *a, const void *b)
+{
+       const struct config_generic *confa = *(struct config_generic *const *) a;
+       const struct config_generic *confb = *(struct config_generic *const *) b;
 
-       {
-               {"checkpoint_completion_target", PGC_SIGHUP, WAL_CHECKPOINTS,
-                       gettext_noop("Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval."),
-                       NULL
-               },
-               &CheckPointCompletionTarget,
-               0.9, 0.0, 1.0,
-               NULL, NULL, NULL
-       },
+       return guc_name_compare(confa->name, confb->name);
+}
 
+/*
+ * the bare comparison function for GUC names
+ */
+int
+guc_name_compare(const char *namea, const char *nameb)
+{
+       /*
+        * The temptation to use strcasecmp() here must be resisted, because the
+        * array ordering has to remain stable across setlocale() calls. So, build
+        * our own with a simple ASCII-only downcasing.
+        */
+       while (*namea && *nameb)
        {
-               {"log_statement_sample_rate", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Fraction of statements exceeding log_min_duration_sample to be logged."),
-                       gettext_noop("Use a value between 0.0 (never log) and 1.0 (always log).")
-               },
-               &log_statement_sample_rate,
-               1.0, 0.0, 1.0,
-               NULL, NULL, NULL
-       },
+               char            cha = *namea++;
+               char            chb = *nameb++;
 
-       {
-               {"log_transaction_sample_rate", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the fraction of transactions from which to log all statements."),
-                       gettext_noop("Use a value between 0.0 (never log) and 1.0 (log all "
-                                                "statements for all transactions).")
-               },
-               &log_xact_sample_rate,
-               0.0, 0.0, 1.0,
-               NULL, NULL, NULL
-       },
-
-       /* End-of-list marker */
-       {
-               {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL
+               if (cha >= 'A' && cha <= 'Z')
+                       cha += 'a' - 'A';
+               if (chb >= 'A' && chb <= 'Z')
+                       chb += 'a' - 'A';
+               if (cha != chb)
+                       return cha - chb;
        }
-};
+       if (*namea)
+               return 1;                               /* a is longer */
+       if (*nameb)
+               return -1;                              /* b is longer */
+       return 0;
+}
 
 
-static struct config_string ConfigureNamesString[] =
+/*
+ * Convert a GUC name to the form that should be used in pg_parameter_acl.
+ *
+ * We need to canonicalize entries since, for example, case should not be
+ * significant.  In addition, we apply the map_old_guc_names[] mapping so that
+ * any obsolete names will be converted when stored in a new PG version.
+ * Note however that this function does not verify legality of the name.
+ *
+ * The result is a palloc'd string.
+ */
+char *
+convert_GUC_name_for_parameter_acl(const char *name)
 {
-       {
-               {"archive_command", PGC_SIGHUP, WAL_ARCHIVING,
-                       gettext_noop("Sets the shell command that will be called to archive a WAL file."),
-                       gettext_noop("This is used only if \"archive_library\" is not set.")
-               },
-               &XLogArchiveCommand,
-               "",
-               NULL, NULL, show_archive_command
-       },
-
-       {
-               {"archive_library", PGC_SIGHUP, WAL_ARCHIVING,
-                       gettext_noop("Sets the library that will be called to archive a WAL file."),
-                       gettext_noop("An empty string indicates that \"archive_command\" should be used.")
-               },
-               &XLogArchiveLibrary,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
-                       gettext_noop("Sets the shell command that will be called to retrieve an archived WAL file."),
-                       NULL
-               },
-               &recoveryRestoreCommand,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
-                       gettext_noop("Sets the shell command that will be executed at every restart point."),
-                       NULL
-               },
-               &archiveCleanupCommand,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
-                       gettext_noop("Sets the shell command that will be executed once at the end of recovery."),
-                       NULL
-               },
-               &recoveryEndCommand,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Specifies the timeline to recover into."),
-                       NULL
-               },
-               &recovery_target_timeline_string,
-               "latest",
-               check_recovery_target_timeline, assign_recovery_target_timeline, NULL
-       },
-
-       {
-               {"recovery_target", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Set to \"immediate\" to end recovery as soon as a consistent state is reached."),
-                       NULL
-               },
-               &recovery_target_string,
-               "",
-               check_recovery_target, assign_recovery_target, NULL
-       },
-       {
-               {"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets the transaction ID up to which recovery will proceed."),
-                       NULL
-               },
-               &recovery_target_xid_string,
-               "",
-               check_recovery_target_xid, assign_recovery_target_xid, NULL
-       },
-       {
-               {"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets the time stamp up to which recovery will proceed."),
-                       NULL
-               },
-               &recovery_target_time_string,
-               "",
-               check_recovery_target_time, assign_recovery_target_time, NULL
-       },
-       {
-               {"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets the named restore point up to which recovery will proceed."),
-                       NULL
-               },
-               &recovery_target_name_string,
-               "",
-               check_recovery_target_name, assign_recovery_target_name, NULL
-       },
-       {
-               {"recovery_target_lsn", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets the LSN of the write-ahead log location up to which recovery will proceed."),
-                       NULL
-               },
-               &recovery_target_lsn_string,
-               "",
-               check_recovery_target_lsn, assign_recovery_target_lsn, NULL
-       },
-
-       {
-               {"promote_trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Specifies a file name whose presence ends recovery in the standby."),
-                       NULL
-               },
-               &PromoteTriggerFile,
-               "",
-               NULL, NULL, NULL
-       },
+       char       *result;
 
+       /* Apply old-GUC-name mapping. */
+       for (int i = 0; map_old_guc_names[i] != NULL; i += 2)
        {
-               {"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the connection string to be used to connect to the sending server."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &PrimaryConnInfo,
-               "",
-               NULL, NULL, NULL
-       },
+               if (guc_name_compare(name, map_old_guc_names[i]) == 0)
+               {
+                       name = map_old_guc_names[i + 1];
+                       break;
+               }
+       }
 
+       /* Apply case-folding that matches guc_name_compare(). */
+       result = pstrdup(name);
+       for (char *ptr = result; *ptr != '\0'; ptr++)
        {
-               {"primary_slot_name", PGC_SIGHUP, REPLICATION_STANDBY,
-                       gettext_noop("Sets the name of the replication slot to use on the sending server."),
-                       NULL
-               },
-               &PrimarySlotName,
-               "",
-               check_primary_slot_name, NULL, NULL
-       },
+               char            ch = *ptr;
 
-       {
-               {"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the client's character set encoding."),
-                       NULL,
-                       GUC_IS_NAME | GUC_REPORT
-               },
-               &client_encoding_string,
-               "SQL_ASCII",
-               check_client_encoding, assign_client_encoding, NULL
-       },
+               if (ch >= 'A' && ch <= 'Z')
+               {
+                       ch += 'a' - 'A';
+                       *ptr = ch;
+               }
+       }
 
-       {
-               {"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Controls information prefixed to each log line."),
-                       gettext_noop("If blank, no prefix is used.")
-               },
-               &Log_line_prefix,
-               "%m [%p] ",
-               NULL, NULL, NULL
-       },
+       return result;
+}
 
-       {
-               {"log_timezone", PGC_SIGHUP, LOGGING_WHAT,
-                       gettext_noop("Sets the time zone to use in log messages."),
-                       NULL
-               },
-               &log_timezone_string,
-               "GMT",
-               check_log_timezone, assign_log_timezone, show_log_timezone
-       },
+/*
+ * Check whether we should allow creation of a pg_parameter_acl entry
+ * for the given name.  (This can be applied either before or after
+ * canonicalizing it.)
+ */
+bool
+check_GUC_name_for_parameter_acl(const char *name)
+{
+       /* OK if the GUC exists. */
+       if (find_option(name, false, true, DEBUG1) != NULL)
+               return true;
+       /* Otherwise, it'd better be a valid custom GUC name. */
+       if (valid_custom_variable_name(name))
+               return true;
+       return false;
+}
 
-       {
-               {"DateStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the display format for date and time values."),
-                       gettext_noop("Also controls interpretation of ambiguous "
-                                                "date inputs."),
-                       GUC_LIST_INPUT | GUC_REPORT
-               },
-               &datestyle_string,
-               "ISO, MDY",
-               check_datestyle, assign_datestyle, NULL
-       },
 
-       {
-               {"default_table_access_method", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the default table access method for new tables."),
-                       NULL,
-                       GUC_IS_NAME
-               },
-               &default_table_access_method,
-               DEFAULT_TABLE_ACCESS_METHOD,
-               check_default_table_access_method, NULL, NULL
-       },
+/*
+ * Initialize GUC options during program startup.
+ *
+ * Note that we cannot read the config file yet, since we have not yet
+ * processed command-line switches.
+ */
+void
+InitializeGUCOptions(void)
+{
+       int                     i;
 
-       {
-               {"default_tablespace", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the default tablespace to create tables and indexes in."),
-                       gettext_noop("An empty string selects the database's default tablespace."),
-                       GUC_IS_NAME
-               },
-               &default_tablespace,
-               "",
-               check_default_tablespace, NULL, NULL
-       },
+       /*
+        * Before log_line_prefix could possibly receive a nonempty setting, make
+        * sure that timezone processing is minimally alive (see elog.c).
+        */
+       pg_timezone_initialize();
 
-       {
-               {"temp_tablespaces", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the tablespace(s) to use for temporary tables and sort files."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE
-               },
-               &temp_tablespaces,
-               "",
-               check_temp_tablespaces, assign_temp_tablespaces, NULL
-       },
+       /*
+        * Build sorted array of all GUC variables.
+        */
+       build_guc_variables();
 
+       /*
+        * Load all variables with their compiled-in defaults, and initialize
+        * status fields as needed.
+        */
+       for (i = 0; i < num_guc_variables; i++)
        {
-               {"dynamic_library_path", PGC_SUSET, CLIENT_CONN_OTHER,
-                       gettext_noop("Sets the path for dynamically loadable modules."),
-                       gettext_noop("If a dynamically loadable module needs to be opened and "
-                                                "the specified name does not have a directory component (i.e., the "
-                                                "name does not contain a slash), the system will search this path for "
-                                                "the specified file."),
-                       GUC_SUPERUSER_ONLY
-               },
-               &Dynamic_library_path,
-               "$libdir",
-               NULL, NULL, NULL
-       },
+               InitializeOneGUCOption(guc_variables[i]);
+       }
 
-       {
-               {"krb_server_keyfile", PGC_SIGHUP, CONN_AUTH_AUTH,
-                       gettext_noop("Sets the location of the Kerberos server key file."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &pg_krb_server_keyfile,
-               PG_KRB_SRVTAB,
-               NULL, NULL, NULL
-       },
+       guc_dirty = false;
 
-       {
-               {"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the Bonjour service name."),
-                       NULL
-               },
-               &bonjour_name,
-               "",
-               NULL, NULL, NULL
-       },
+       reporting_enabled = false;
 
-       /* See main.c about why defaults for LC_foo are not all alike */
+       /*
+        * Prevent any attempt to override the transaction modes from
+        * non-interactive sources.
+        */
+       SetConfigOption("transaction_isolation", "read committed",
+                                       PGC_POSTMASTER, PGC_S_OVERRIDE);
+       SetConfigOption("transaction_read_only", "no",
+                                       PGC_POSTMASTER, PGC_S_OVERRIDE);
+       SetConfigOption("transaction_deferrable", "no",
+                                       PGC_POSTMASTER, PGC_S_OVERRIDE);
 
-       {
-               {"lc_collate", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the collation order locale."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &locale_collate,
-               "C",
-               NULL, NULL, NULL
-       },
+       /*
+        * For historical reasons, some GUC parameters can receive defaults from
+        * environment variables.  Process those settings.
+        */
+       InitializeGUCOptionsFromEnvironment();
+}
 
-       {
-               {"lc_ctype", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the character classification and case conversion locale."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &locale_ctype,
-               "C",
-               NULL, NULL, NULL
-       },
+/*
+ * Assign any GUC values that can come from the server's environment.
+ *
+ * This is called from InitializeGUCOptions, and also from ProcessConfigFile
+ * to deal with the possibility that a setting has been removed from
+ * postgresql.conf and should now get a value from the environment.
+ * (The latter is a kludge that should probably go away someday; if so,
+ * fold this back into InitializeGUCOptions.)
+ */
+static void
+InitializeGUCOptionsFromEnvironment(void)
+{
+       char       *env;
+       long            stack_rlimit;
 
-       {
-               {"lc_messages", PGC_SUSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the language in which messages are displayed."),
-                       NULL
-               },
-               &locale_messages,
-               "",
-               check_locale_messages, assign_locale_messages, NULL
-       },
+       env = getenv("PGPORT");
+       if (env != NULL)
+               SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
 
-       {
-               {"lc_monetary", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the locale for formatting monetary amounts."),
-                       NULL
-               },
-               &locale_monetary,
-               "C",
-               check_locale_monetary, assign_locale_monetary, NULL
-       },
+       env = getenv("PGDATESTYLE");
+       if (env != NULL)
+               SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
 
-       {
-               {"lc_numeric", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the locale for formatting numbers."),
-                       NULL
-               },
-               &locale_numeric,
-               "C",
-               check_locale_numeric, assign_locale_numeric, NULL
-       },
+       env = getenv("PGCLIENTENCODING");
+       if (env != NULL)
+               SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
 
+       /*
+        * rlimit isn't exactly an "environment variable", but it behaves about
+        * the same.  If we can identify the platform stack depth rlimit, increase
+        * default stack depth setting up to whatever is safe (but at most 2MB).
+        * Report the value's source as PGC_S_DYNAMIC_DEFAULT if it's 2MB, or as
+        * PGC_S_ENV_VAR if it's reflecting the rlimit limit.
+        */
+       stack_rlimit = get_stack_depth_rlimit();
+       if (stack_rlimit > 0)
        {
-               {"lc_time", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the locale for formatting date and time values."),
-                       NULL
-               },
-               &locale_time,
-               "C",
-               check_locale_time, assign_locale_time, NULL
-       },
+               long            new_limit = (stack_rlimit - STACK_DEPTH_SLOP) / 1024L;
 
-       {
-               {"session_preload_libraries", PGC_SUSET, CLIENT_CONN_PRELOAD,
-                       gettext_noop("Lists shared libraries to preload into each backend."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
-               },
-               &session_preload_libraries_string,
-               "",
-               NULL, NULL, NULL
-       },
+               if (new_limit > 100)
+               {
+                       GucSource       source;
+                       char            limbuf[16];
 
-       {
-               {"shared_preload_libraries", PGC_POSTMASTER, CLIENT_CONN_PRELOAD,
-                       gettext_noop("Lists shared libraries to preload into server."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
-               },
-               &shared_preload_libraries_string,
-               "",
-               NULL, NULL, NULL
-       },
+                       if (new_limit < 2048)
+                               source = PGC_S_ENV_VAR;
+                       else
+                       {
+                               new_limit = 2048;
+                               source = PGC_S_DYNAMIC_DEFAULT;
+                       }
+                       snprintf(limbuf, sizeof(limbuf), "%ld", new_limit);
+                       SetConfigOption("max_stack_depth", limbuf,
+                                                       PGC_POSTMASTER, source);
+               }
+       }
+}
 
-       {
-               {"local_preload_libraries", PGC_USERSET, CLIENT_CONN_PRELOAD,
-                       gettext_noop("Lists unprivileged shared libraries to preload into each backend."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE
-               },
-               &local_preload_libraries_string,
-               "",
-               NULL, NULL, NULL
-       },
+/*
+ * Initialize one GUC option variable to its compiled-in default.
+ *
+ * Note: the reason for calling check_hooks is not that we think the boot_val
+ * might fail, but that the hooks might wish to compute an "extra" struct.
+ */
+static void
+InitializeOneGUCOption(struct config_generic *gconf)
+{
+       gconf->status = 0;
+       gconf->source = PGC_S_DEFAULT;
+       gconf->reset_source = PGC_S_DEFAULT;
+       gconf->scontext = PGC_INTERNAL;
+       gconf->reset_scontext = PGC_INTERNAL;
+       gconf->srole = BOOTSTRAP_SUPERUSERID;
+       gconf->reset_srole = BOOTSTRAP_SUPERUSERID;
+       gconf->stack = NULL;
+       gconf->extra = NULL;
+       gconf->last_reported = NULL;
+       gconf->sourcefile = NULL;
+       gconf->sourceline = 0;
 
+       switch (gconf->vartype)
        {
-               {"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the schema search order for names that are not schema-qualified."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN
-               },
-               &namespace_search_path,
-               "\"$user\", public",
-               check_search_path, assign_search_path, NULL
-       },
+               case PGC_BOOL:
+                       {
+                               struct config_bool *conf = (struct config_bool *) gconf;
+                               bool            newval = conf->boot_val;
+                               void       *extra = NULL;
 
-       {
-               /* Can't be set in postgresql.conf */
-               {"server_encoding", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the server (database) character set encoding."),
-                       NULL,
-                       GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &server_encoding_string,
-               "SQL_ASCII",
-               NULL, NULL, NULL
-       },
+                               if (!call_bool_check_hook(conf, &newval, &extra,
+                                                                                 PGC_S_DEFAULT, LOG))
+                                       elog(FATAL, "failed to initialize %s to %d",
+                                                conf->gen.name, (int) newval);
+                               if (conf->assign_hook)
+                                       conf->assign_hook(newval, extra);
+                               *conf->variable = conf->reset_val = newval;
+                               conf->gen.extra = conf->reset_extra = extra;
+                               break;
+                       }
+               case PGC_INT:
+                       {
+                               struct config_int *conf = (struct config_int *) gconf;
+                               int                     newval = conf->boot_val;
+                               void       *extra = NULL;
 
-       {
-               /* Can't be set in postgresql.conf */
-               {"server_version", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the server version."),
-                       NULL,
-                       GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &server_version_string,
-               PG_VERSION,
-               NULL, NULL, NULL
-       },
+                               Assert(newval >= conf->min);
+                               Assert(newval <= conf->max);
+                               if (!call_int_check_hook(conf, &newval, &extra,
+                                                                                PGC_S_DEFAULT, LOG))
+                                       elog(FATAL, "failed to initialize %s to %d",
+                                                conf->gen.name, newval);
+                               if (conf->assign_hook)
+                                       conf->assign_hook(newval, extra);
+                               *conf->variable = conf->reset_val = newval;
+                               conf->gen.extra = conf->reset_extra = extra;
+                               break;
+                       }
+               case PGC_REAL:
+                       {
+                               struct config_real *conf = (struct config_real *) gconf;
+                               double          newval = conf->boot_val;
+                               void       *extra = NULL;
 
-       {
-               /* Not for general use --- used by SET ROLE */
-               {"role", PGC_USERSET, UNGROUPED,
-                       gettext_noop("Sets the current role."),
-                       NULL,
-                       GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST
-               },
-               &role_string,
-               "none",
-               check_role, assign_role, show_role
-       },
+                               Assert(newval >= conf->min);
+                               Assert(newval <= conf->max);
+                               if (!call_real_check_hook(conf, &newval, &extra,
+                                                                                 PGC_S_DEFAULT, LOG))
+                                       elog(FATAL, "failed to initialize %s to %g",
+                                                conf->gen.name, newval);
+                               if (conf->assign_hook)
+                                       conf->assign_hook(newval, extra);
+                               *conf->variable = conf->reset_val = newval;
+                               conf->gen.extra = conf->reset_extra = extra;
+                               break;
+                       }
+               case PGC_STRING:
+                       {
+                               struct config_string *conf = (struct config_string *) gconf;
+                               char       *newval;
+                               void       *extra = NULL;
 
-       {
-               /* Not for general use --- used by SET SESSION AUTHORIZATION */
-               {"session_authorization", PGC_USERSET, UNGROUPED,
-                       gettext_noop("Sets the session user name."),
-                       NULL,
-                       GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST
-               },
-               &session_authorization_string,
-               NULL,
-               check_session_authorization, assign_session_authorization, NULL
-       },
+                               /* non-NULL boot_val must always get strdup'd */
+                               if (conf->boot_val != NULL)
+                                       newval = guc_strdup(FATAL, conf->boot_val);
+                               else
+                                       newval = NULL;
 
-       {
-               {"log_destination", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the destination for server log output."),
-                       gettext_noop("Valid values are combinations of \"stderr\", "
-                                                "\"syslog\", \"csvlog\", \"jsonlog\", and \"eventlog\", "
-                                                "depending on the platform."),
-                       GUC_LIST_INPUT
-               },
-               &Log_destination_string,
-               "stderr",
-               check_log_destination, assign_log_destination, NULL
-       },
-       {
-               {"log_directory", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the destination directory for log files."),
-                       gettext_noop("Can be specified as relative to the data directory "
-                                                "or as absolute path."),
-                       GUC_SUPERUSER_ONLY
-               },
-               &Log_directory,
-               "log",
-               check_canonical_path, NULL, NULL
-       },
-       {
-               {"log_filename", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the file name pattern for log files."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &Log_filename,
-               "postgresql-%Y-%m-%d_%H%M%S.log",
-               NULL, NULL, NULL
-       },
+                               if (!call_string_check_hook(conf, &newval, &extra,
+                                                                                       PGC_S_DEFAULT, LOG))
+                                       elog(FATAL, "failed to initialize %s to \"%s\"",
+                                                conf->gen.name, newval ? newval : "");
+                               if (conf->assign_hook)
+                                       conf->assign_hook(newval, extra);
+                               *conf->variable = conf->reset_val = newval;
+                               conf->gen.extra = conf->reset_extra = extra;
+                               break;
+                       }
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) gconf;
+                               int                     newval = conf->boot_val;
+                               void       *extra = NULL;
 
-       {
-               {"syslog_ident", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the program name used to identify PostgreSQL "
-                                                "messages in syslog."),
-                       NULL
-               },
-               &syslog_ident_str,
-               "postgres",
-               NULL, assign_syslog_ident, NULL
-       },
+                               if (!call_enum_check_hook(conf, &newval, &extra,
+                                                                                 PGC_S_DEFAULT, LOG))
+                                       elog(FATAL, "failed to initialize %s to %d",
+                                                conf->gen.name, newval);
+                               if (conf->assign_hook)
+                                       conf->assign_hook(newval, extra);
+                               *conf->variable = conf->reset_val = newval;
+                               conf->gen.extra = conf->reset_extra = extra;
+                               break;
+                       }
+       }
+}
 
-       {
-               {"event_source", PGC_POSTMASTER, LOGGING_WHERE,
-                       gettext_noop("Sets the application name used to identify "
-                                                "PostgreSQL messages in the event log."),
-                       NULL
-               },
-               &event_source,
-               DEFAULT_EVENT_SOURCE,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"TimeZone", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the time zone for displaying and interpreting time stamps."),
-                       NULL,
-                       GUC_REPORT
-               },
-               &timezone_string,
-               "GMT",
-               check_timezone, assign_timezone, show_timezone
-       },
-       {
-               {"timezone_abbreviations", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Selects a file of time zone abbreviations."),
-                       NULL
-               },
-               &timezone_abbreviations_string,
-               NULL,
-               check_timezone_abbreviations, assign_timezone_abbreviations, NULL
-       },
+/*
+ * Select the configuration files and data directory to be used, and
+ * do the initial read of postgresql.conf.
+ *
+ * This is called after processing command-line switches.
+ *             userDoption is the -D switch value if any (NULL if unspecified).
+ *             progname is just for use in error messages.
+ *
+ * Returns true on success; on failure, prints a suitable error message
+ * to stderr and returns false.
+ */
+bool
+SelectConfigFiles(const char *userDoption, const char *progname)
+{
+       char       *configdir;
+       char       *fname;
+       struct stat stat_buf;
+       struct config_string *data_directory_rec;
 
-       {
-               {"unix_socket_group", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the owning group of the Unix-domain socket."),
-                       gettext_noop("The owning user of the socket is always the user "
-                                                "that starts the server.")
-               },
-               &Unix_socket_group,
-               "",
-               NULL, NULL, NULL
-       },
+       /* configdir is -D option, or $PGDATA if no -D */
+       if (userDoption)
+               configdir = make_absolute_path(userDoption);
+       else
+               configdir = make_absolute_path(getenv("PGDATA"));
 
+       if (configdir && stat(configdir, &stat_buf) != 0)
        {
-               {"unix_socket_directories", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the directories where Unix-domain sockets will be created."),
-                       NULL,
-                       GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
-               },
-               &Unix_socket_directories,
-               DEFAULT_PGSOCKET_DIR,
-               NULL, NULL, NULL
-       },
+               write_stderr("%s: could not access directory \"%s\": %s\n",
+                                        progname,
+                                        configdir,
+                                        strerror(errno));
+               if (errno == ENOENT)
+                       write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n");
+               return false;
+       }
 
+       /*
+        * Find the configuration file: if config_file was specified on the
+        * command line, use it, else use configdir/postgresql.conf.  In any case
+        * ensure the result is an absolute path, so that it will be interpreted
+        * the same way by future backends.
+        */
+       if (ConfigFileName)
+               fname = make_absolute_path(ConfigFileName);
+       else if (configdir)
        {
-               {"listen_addresses", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the host name or IP address(es) to listen to."),
-                       NULL,
-                       GUC_LIST_INPUT
-               },
-               &ListenAddresses,
-               "localhost",
-               NULL, NULL, NULL
-       },
-
+               fname = guc_malloc(FATAL,
+                                                  strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
+               sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
+       }
+       else
        {
-               /*
-                * Can't be set by ALTER SYSTEM as it can lead to recursive definition
-                * of data_directory.
-                */
-               {"data_directory", PGC_POSTMASTER, FILE_LOCATIONS,
-                       gettext_noop("Sets the server's data directory."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE
-               },
-               &data_directory,
-               NULL,
-               NULL, NULL, NULL
-       },
+               write_stderr("%s does not know where to find the server configuration file.\n"
+                                        "You must specify the --config-file or -D invocation "
+                                        "option or set the PGDATA environment variable.\n",
+                                        progname);
+               return false;
+       }
 
-       {
-               {"config_file", PGC_POSTMASTER, FILE_LOCATIONS,
-                       gettext_noop("Sets the server's main configuration file."),
-                       NULL,
-                       GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY
-               },
-               &ConfigFileName,
-               NULL,
-               NULL, NULL, NULL
-       },
+       /*
+        * Set the ConfigFileName GUC variable to its final value, ensuring that
+        * it can't be overridden later.
+        */
+       SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
+       free(fname);
 
+       /*
+        * Now read the config file for the first time.
+        */
+       if (stat(ConfigFileName, &stat_buf) != 0)
        {
-               {"hba_file", PGC_POSTMASTER, FILE_LOCATIONS,
-                       gettext_noop("Sets the server's \"hba\" configuration file."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &HbaFileName,
-               NULL,
-               NULL, NULL, NULL
-       },
+               write_stderr("%s: could not access the server configuration file \"%s\": %s\n",
+                                        progname, ConfigFileName, strerror(errno));
+               free(configdir);
+               return false;
+       }
 
-       {
-               {"ident_file", PGC_POSTMASTER, FILE_LOCATIONS,
-                       gettext_noop("Sets the server's \"ident\" configuration file."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &IdentFileName,
-               NULL,
-               NULL, NULL, NULL
-       },
+       /*
+        * Read the configuration file for the first time.  This time only the
+        * data_directory parameter is picked up to determine the data directory,
+        * so that we can read the PG_AUTOCONF_FILENAME file next time.
+        */
+       ProcessConfigFile(PGC_POSTMASTER);
 
+       /*
+        * If the data_directory GUC variable has been set, use that as DataDir;
+        * otherwise use configdir if set; else punt.
+        *
+        * Note: SetDataDir will copy and absolute-ize its argument, so we don't
+        * have to.
+        */
+       data_directory_rec = (struct config_string *)
+               find_option("data_directory", false, false, PANIC);
+       if (*data_directory_rec->variable)
+               SetDataDir(*data_directory_rec->variable);
+       else if (configdir)
+               SetDataDir(configdir);
+       else
        {
-               {"external_pid_file", PGC_POSTMASTER, FILE_LOCATIONS,
-                       gettext_noop("Writes the postmaster PID to the specified file."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &external_pid_file,
-               NULL,
-               check_canonical_path, NULL, NULL
-       },
+               write_stderr("%s does not know where to find the database system data.\n"
+                                        "This can be specified as \"data_directory\" in \"%s\", "
+                                        "or by the -D invocation option, or by the "
+                                        "PGDATA environment variable.\n",
+                                        progname, ConfigFileName);
+               return false;
+       }
 
-       {
-               {"ssl_library", PGC_INTERNAL, PRESET_OPTIONS,
-                       gettext_noop("Shows the name of the SSL library."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &ssl_library,
-#ifdef USE_SSL
-               "OpenSSL",
-#else
-               "",
-#endif
-               NULL, NULL, NULL
-       },
+       /*
+        * Reflect the final DataDir value back into the data_directory GUC var.
+        * (If you are wondering why we don't just make them a single variable,
+        * it's because the EXEC_BACKEND case needs DataDir to be transmitted to
+        * child backends specially.  XXX is that still true?  Given that we now
+        * chdir to DataDir, EXEC_BACKEND can read the config file without knowing
+        * DataDir in advance.)
+        */
+       SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
 
-       {
-               {"ssl_cert_file", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL server certificate file."),
-                       NULL
-               },
-               &ssl_cert_file,
-               "server.crt",
-               NULL, NULL, NULL
-       },
+       /*
+        * Now read the config file a second time, allowing any settings in the
+        * PG_AUTOCONF_FILENAME file to take effect.  (This is pretty ugly, but
+        * since we have to determine the DataDir before we can find the autoconf
+        * file, the alternatives seem worse.)
+        */
+       ProcessConfigFile(PGC_POSTMASTER);
 
-       {
-               {"ssl_key_file", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL server private key file."),
-                       NULL
-               },
-               &ssl_key_file,
-               "server.key",
-               NULL, NULL, NULL
-       },
+       /*
+        * If timezone_abbreviations wasn't set in the configuration file, install
+        * the default value.  We do it this way because we can't safely install a
+        * "real" value until my_exec_path is set, which may not have happened
+        * when InitializeGUCOptions runs, so the bootstrap default value cannot
+        * be the real desired default.
+        */
+       pg_timezone_abbrev_initialize();
 
+       /*
+        * Figure out where pg_hba.conf is, and make sure the path is absolute.
+        */
+       if (HbaFileName)
+               fname = make_absolute_path(HbaFileName);
+       else if (configdir)
        {
-               {"ssl_ca_file", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL certificate authority file."),
-                       NULL
-               },
-               &ssl_ca_file,
-               "",
-               NULL, NULL, NULL
-       },
-
+               fname = guc_malloc(FATAL,
+                                                  strlen(configdir) + strlen(HBA_FILENAME) + 2);
+               sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
+       }
+       else
        {
-               {"ssl_crl_file", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL certificate revocation list file."),
-                       NULL
-               },
-               &ssl_crl_file,
-               "",
-               NULL, NULL, NULL
-       },
+               write_stderr("%s does not know where to find the \"hba\" configuration file.\n"
+                                        "This can be specified as \"hba_file\" in \"%s\", "
+                                        "or by the -D invocation option, or by the "
+                                        "PGDATA environment variable.\n",
+                                        progname, ConfigFileName);
+               return false;
+       }
+       SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
+       free(fname);
 
+       /*
+        * Likewise for pg_ident.conf.
+        */
+       if (IdentFileName)
+               fname = make_absolute_path(IdentFileName);
+       else if (configdir)
        {
-               {"ssl_crl_dir", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL certificate revocation list directory."),
-                       NULL
-               },
-               &ssl_crl_dir,
-               "",
-               NULL, NULL, NULL
-       },
-
+               fname = guc_malloc(FATAL,
+                                                  strlen(configdir) + strlen(IDENT_FILENAME) + 2);
+               sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
+       }
+       else
        {
-               {"synchronous_standby_names", PGC_SIGHUP, REPLICATION_PRIMARY,
-                       gettext_noop("Number of synchronous standbys and list of names of potential synchronous ones."),
-                       NULL,
-                       GUC_LIST_INPUT
-               },
-               &SyncRepStandbyNames,
-               "",
-               check_synchronous_standby_names, assign_synchronous_standby_names, NULL
-       },
+               write_stderr("%s does not know where to find the \"ident\" configuration file.\n"
+                                        "This can be specified as \"ident_file\" in \"%s\", "
+                                        "or by the -D invocation option, or by the "
+                                        "PGDATA environment variable.\n",
+                                        progname, ConfigFileName);
+               return false;
+       }
+       SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
+       free(fname);
 
-       {
-               {"default_text_search_config", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets default text search configuration."),
-                       NULL
-               },
-               &TSCurrentConfig,
-               "pg_catalog.simple",
-               check_TSCurrentConfig, assign_TSCurrentConfig, NULL
-       },
-
-       {
-               {"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Sets the list of allowed SSL ciphers."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &SSLCipherSuites,
-#ifdef USE_OPENSSL
-               "HIGH:MEDIUM:+3DES:!aNULL",
-#else
-               "none",
-#endif
-               NULL, NULL, NULL
-       },
-
-       {
-               {"ssl_ecdh_curve", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Sets the curve to use for ECDH."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &SSLECDHCurve,
-#ifdef USE_SSL
-               "prime256v1",
-#else
-               "none",
-#endif
-               NULL, NULL, NULL
-       },
-
-       {
-               {"ssl_dh_params_file", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Location of the SSL DH parameters file."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &ssl_dh_params_file,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"ssl_passphrase_command", PGC_SIGHUP, CONN_AUTH_SSL,
-                       gettext_noop("Command to obtain passphrases for SSL."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &ssl_passphrase_command,
-               "",
-               NULL, NULL, NULL
-       },
-
-       {
-               {"application_name", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Sets the application name to be reported in statistics and logs."),
-                       NULL,
-                       GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE
-               },
-               &application_name,
-               "",
-               check_application_name, assign_application_name, NULL
-       },
-
-       {
-               {"cluster_name", PGC_POSTMASTER, PROCESS_TITLE,
-                       gettext_noop("Sets the name of the cluster, which is included in the process title."),
-                       NULL,
-                       GUC_IS_NAME
-               },
-               &cluster_name,
-               "",
-               check_cluster_name, NULL, NULL
-       },
-
-       {
-               {"wal_consistency_checking", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Sets the WAL resource managers for which WAL consistency checks are done."),
-                       gettext_noop("Full-page images will be logged for all data blocks and cross-checked against the results of WAL replay."),
-                       GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE
-               },
-               &wal_consistency_checking_string,
-               "",
-               check_wal_consistency_checking, assign_wal_consistency_checking, NULL
-       },
+       free(configdir);
 
-       {
-               {"jit_provider", PGC_POSTMASTER, CLIENT_CONN_PRELOAD,
-                       gettext_noop("JIT provider to use."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &jit_provider,
-               "llvmjit",
-               NULL, NULL, NULL
-       },
+       return true;
+}
 
-       {
-               {"backtrace_functions", PGC_SUSET, DEVELOPER_OPTIONS,
-                       gettext_noop("Log backtrace for errors in these functions."),
-                       NULL,
-                       GUC_NOT_IN_SAMPLE
-               },
-               &backtrace_functions,
-               "",
-               check_backtrace_functions, assign_backtrace_functions, NULL
-       },
-
-       /* End-of-list marker */
-       {
-               {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
-       }
-};
+/*
+ * pg_timezone_abbrev_initialize --- set default value if not done already
+ *
+ * This is called after initial loading of postgresql.conf.  If no
+ * timezone_abbreviations setting was found therein, select default.
+ * If a non-default value is already installed, nothing will happen.
+ *
+ * This can also be called from ProcessConfigFile to establish the default
+ * value after a postgresql.conf entry for it is removed.
+ */
+static void
+pg_timezone_abbrev_initialize(void)
+{
+       SetConfigOption("timezone_abbreviations", "Default",
+                                       PGC_POSTMASTER, PGC_S_DYNAMIC_DEFAULT);
+}
 
 
-static struct config_enum ConfigureNamesEnum[] =
+/*
+ * Reset all options to their saved default values (implements RESET ALL)
+ */
+void
+ResetAllOptions(void)
 {
-       {
-               {"backslash_quote", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Sets whether \"\\'\" is allowed in string literals."),
-                       NULL
-               },
-               &backslash_quote,
-               BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the output format for bytea."),
-                       NULL
-               },
-               &bytea_output,
-               BYTEA_OUTPUT_HEX, bytea_output_options,
-               NULL, NULL, NULL
-       },
+       int                     i;
 
+       for (i = 0; i < num_guc_variables; i++)
        {
-               {"client_min_messages", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the message levels that are sent to the client."),
-                       gettext_noop("Each level includes all the levels that follow it. The later"
-                                                " the level, the fewer messages are sent.")
-               },
-               &client_min_messages,
-               NOTICE, client_message_level_options,
-               NULL, NULL, NULL
-       },
+               struct config_generic *gconf = guc_variables[i];
 
-       {
-               {"compute_query_id", PGC_SUSET, STATS_MONITORING,
-                       gettext_noop("Enables in-core computation of query identifiers."),
-                       NULL
-               },
-               &compute_query_id,
-               COMPUTE_QUERY_ID_AUTO, compute_query_id_options,
-               NULL, NULL, NULL
-       },
+               /* Don't reset non-SET-able values */
+               if (gconf->context != PGC_SUSET &&
+                       gconf->context != PGC_USERSET)
+                       continue;
+               /* Don't reset if special exclusion from RESET ALL */
+               if (gconf->flags & GUC_NO_RESET_ALL)
+                       continue;
+               /* No need to reset if wasn't SET */
+               if (gconf->source <= PGC_S_OVERRIDE)
+                       continue;
 
-       {
-               {"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Enables the planner to use constraints to optimize queries."),
-                       gettext_noop("Table scans will be skipped if their constraints"
-                                                " guarantee that no rows match the query."),
-                       GUC_EXPLAIN
-               },
-               &constraint_exclusion,
-               CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options,
-               NULL, NULL, NULL
-       },
+               /* Save old value to support transaction abort */
+               push_old_value(gconf, GUC_ACTION_SET);
 
-       {
-               {"default_toast_compression", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the default compression method for compressible values."),
-                       NULL
-               },
-               &default_toast_compression,
-               TOAST_PGLZ_COMPRESSION,
-               default_toast_compression_options,
-               NULL, NULL, NULL
-       },
+               switch (gconf->vartype)
+               {
+                       case PGC_BOOL:
+                               {
+                                       struct config_bool *conf = (struct config_bool *) gconf;
 
-       {
-               {"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the transaction isolation level of each new transaction."),
-                       NULL
-               },
-               &DefaultXactIsoLevel,
-               XACT_READ_COMMITTED, isolation_level_options,
-               NULL, NULL, NULL
-       },
+                                       if (conf->assign_hook)
+                                               conf->assign_hook(conf->reset_val,
+                                                                                 conf->reset_extra);
+                                       *conf->variable = conf->reset_val;
+                                       set_extra_field(&conf->gen, &conf->gen.extra,
+                                                                       conf->reset_extra);
+                                       break;
+                               }
+                       case PGC_INT:
+                               {
+                                       struct config_int *conf = (struct config_int *) gconf;
 
-       {
-               {"transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the current transaction's isolation level."),
-                       NULL,
-                       GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
-               },
-               &XactIsoLevel,
-               XACT_READ_COMMITTED, isolation_level_options,
-               check_XactIsoLevel, NULL, NULL
-       },
+                                       if (conf->assign_hook)
+                                               conf->assign_hook(conf->reset_val,
+                                                                                 conf->reset_extra);
+                                       *conf->variable = conf->reset_val;
+                                       set_extra_field(&conf->gen, &conf->gen.extra,
+                                                                       conf->reset_extra);
+                                       break;
+                               }
+                       case PGC_REAL:
+                               {
+                                       struct config_real *conf = (struct config_real *) gconf;
 
-       {
-               {"IntervalStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
-                       gettext_noop("Sets the display format for interval values."),
-                       NULL,
-                       GUC_REPORT
-               },
-               &IntervalStyle,
-               INTSTYLE_POSTGRES, intervalstyle_options,
-               NULL, NULL, NULL
-       },
+                                       if (conf->assign_hook)
+                                               conf->assign_hook(conf->reset_val,
+                                                                                 conf->reset_extra);
+                                       *conf->variable = conf->reset_val;
+                                       set_extra_field(&conf->gen, &conf->gen.extra,
+                                                                       conf->reset_extra);
+                                       break;
+                               }
+                       case PGC_STRING:
+                               {
+                                       struct config_string *conf = (struct config_string *) gconf;
 
-       {
-               {"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Sets the verbosity of logged messages."),
-                       NULL
-               },
-               &Log_error_verbosity,
-               PGERROR_DEFAULT, log_error_verbosity_options,
-               NULL, NULL, NULL
-       },
+                                       if (conf->assign_hook)
+                                               conf->assign_hook(conf->reset_val,
+                                                                                 conf->reset_extra);
+                                       set_string_field(conf, conf->variable, conf->reset_val);
+                                       set_extra_field(&conf->gen, &conf->gen.extra,
+                                                                       conf->reset_extra);
+                                       break;
+                               }
+                       case PGC_ENUM:
+                               {
+                                       struct config_enum *conf = (struct config_enum *) gconf;
 
-       {
-               {"log_min_messages", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the message levels that are logged."),
-                       gettext_noop("Each level includes all the levels that follow it. The later"
-                                                " the level, the fewer messages are sent.")
-               },
-               &log_min_messages,
-               WARNING, server_message_level_options,
-               NULL, NULL, NULL
-       },
+                                       if (conf->assign_hook)
+                                               conf->assign_hook(conf->reset_val,
+                                                                                 conf->reset_extra);
+                                       *conf->variable = conf->reset_val;
+                                       set_extra_field(&conf->gen, &conf->gen.extra,
+                                                                       conf->reset_extra);
+                                       break;
+                               }
+               }
 
-       {
-               {"log_min_error_statement", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Causes all statements generating error at or above this level to be logged."),
-                       gettext_noop("Each level includes all the levels that follow it. The later"
-                                                " the level, the fewer messages are sent.")
-               },
-               &log_min_error_statement,
-               ERROR, server_message_level_options,
-               NULL, NULL, NULL
-       },
+               gconf->source = gconf->reset_source;
+               gconf->scontext = gconf->reset_scontext;
+               gconf->srole = gconf->reset_srole;
 
-       {
-               {"log_statement", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Sets the type of statements logged."),
-                       NULL
-               },
-               &log_statement,
-               LOGSTMT_NONE, log_statement_options,
-               NULL, NULL, NULL
-       },
+               if (gconf->flags & GUC_REPORT)
+               {
+                       gconf->status |= GUC_NEEDS_REPORT;
+                       report_needed = true;
+               }
+       }
+}
 
-       {
-               {"syslog_facility", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled."),
-                       NULL
-               },
-               &syslog_facility,
-#ifdef HAVE_SYSLOG
-               LOG_LOCAL0,
-#else
-               0,
-#endif
-               syslog_facility_options,
-               NULL, assign_syslog_facility, NULL
-       },
 
-       {
-               {"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the session's behavior for triggers and rewrite rules."),
-                       NULL
-               },
-               &SessionReplicationRole,
-               SESSION_REPLICATION_ROLE_ORIGIN, session_replication_role_options,
-               NULL, assign_session_replication_role, NULL
-       },
+/*
+ * push_old_value
+ *             Push previous state during transactional assignment to a GUC variable.
+ */
+static void
+push_old_value(struct config_generic *gconf, GucAction action)
+{
+       GucStack   *stack;
 
-       {
-               {"synchronous_commit", PGC_USERSET, WAL_SETTINGS,
-                       gettext_noop("Sets the current transaction's synchronization level."),
-                       NULL
-               },
-               &synchronous_commit,
-               SYNCHRONOUS_COMMIT_ON, synchronous_commit_options,
-               NULL, assign_synchronous_commit, NULL
-       },
+       /* If we're not inside a nest level, do nothing */
+       if (GUCNestLevel == 0)
+               return;
 
+       /* Do we already have a stack entry of the current nest level? */
+       stack = gconf->stack;
+       if (stack && stack->nest_level >= GUCNestLevel)
        {
-               {"archive_mode", PGC_POSTMASTER, WAL_ARCHIVING,
-                       gettext_noop("Allows archiving of WAL files using archive_command."),
-                       NULL
-               },
-               &XLogArchiveMode,
-               ARCHIVE_MODE_OFF, archive_mode_options,
-               NULL, NULL, NULL
-       },
+               /* Yes, so adjust its state if necessary */
+               Assert(stack->nest_level == GUCNestLevel);
+               switch (action)
+               {
+                       case GUC_ACTION_SET:
+                               /* SET overrides any prior action at same nest level */
+                               if (stack->state == GUC_SET_LOCAL)
+                               {
+                                       /* must discard old masked value */
+                                       discard_stack_value(gconf, &stack->masked);
+                               }
+                               stack->state = GUC_SET;
+                               break;
+                       case GUC_ACTION_LOCAL:
+                               if (stack->state == GUC_SET)
+                               {
+                                       /* SET followed by SET LOCAL, remember SET's value */
+                                       stack->masked_scontext = gconf->scontext;
+                                       stack->masked_srole = gconf->srole;
+                                       set_stack_value(gconf, &stack->masked);
+                                       stack->state = GUC_SET_LOCAL;
+                               }
+                               /* in all other cases, no change to stack entry */
+                               break;
+                       case GUC_ACTION_SAVE:
+                               /* Could only have a prior SAVE of same variable */
+                               Assert(stack->state == GUC_SAVE);
+                               break;
+               }
+               Assert(guc_dirty);              /* must be set already */
+               return;
+       }
 
-       {
-               {"recovery_target_action", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
-                       gettext_noop("Sets the action to perform upon reaching the recovery target."),
-                       NULL
-               },
-               &recoveryTargetAction,
-               RECOVERY_TARGET_ACTION_PAUSE, recovery_target_action_options,
-               NULL, NULL, NULL
-       },
+       /*
+        * Push a new stack entry
+        *
+        * We keep all the stack entries in TopTransactionContext for simplicity.
+        */
+       stack = (GucStack *) MemoryContextAllocZero(TopTransactionContext,
+                                                                                               sizeof(GucStack));
 
+       stack->prev = gconf->stack;
+       stack->nest_level = GUCNestLevel;
+       switch (action)
        {
-               {"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
-                       gettext_noop("Enables logging of recovery-related debugging information."),
-                       gettext_noop("Each level includes all the levels that follow it. The later"
-                                                " the level, the fewer messages are sent."),
-                       GUC_NOT_IN_SAMPLE,
-               },
-               &trace_recovery_messages,
-
-               /*
-                * client_message_level_options allows too many values, really, but
-                * it's not worth having a separate options array for this.
-                */
-               LOG, client_message_level_options,
-               NULL, NULL, NULL
-       },
+               case GUC_ACTION_SET:
+                       stack->state = GUC_SET;
+                       break;
+               case GUC_ACTION_LOCAL:
+                       stack->state = GUC_LOCAL;
+                       break;
+               case GUC_ACTION_SAVE:
+                       stack->state = GUC_SAVE;
+                       break;
+       }
+       stack->source = gconf->source;
+       stack->scontext = gconf->scontext;
+       stack->srole = gconf->srole;
+       set_stack_value(gconf, &stack->prior);
 
-       {
-               {"track_functions", PGC_SUSET, STATS_CUMULATIVE,
-                       gettext_noop("Collects function-level statistics on database activity."),
-                       NULL
-               },
-               &pgstat_track_functions,
-               TRACK_FUNC_OFF, track_function_options,
-               NULL, NULL, NULL
-       },
+       gconf->stack = stack;
 
+       /* Ensure we remember to pop at end of xact */
+       guc_dirty = true;
+}
 
-       {
-               {"stats_fetch_consistency", PGC_USERSET, STATS_CUMULATIVE,
-                       gettext_noop("Sets the consistency of accesses to statistics data."),
-                       NULL
-               },
-               &pgstat_fetch_consistency,
-               PGSTAT_FETCH_CONSISTENCY_CACHE, stats_fetch_consistency,
-               NULL, NULL, NULL
-       },
 
-       {
-               {"wal_compression", PGC_SUSET, WAL_SETTINGS,
-                       gettext_noop("Compresses full-page writes written in WAL file with specified method."),
-                       NULL
-               },
-               &wal_compression,
-               WAL_COMPRESSION_NONE, wal_compression_options,
-               NULL, NULL, NULL
-       },
+/*
+ * Do GUC processing at main transaction start.
+ */
+void
+AtStart_GUC(void)
+{
+       /*
+        * The nest level should be 0 between transactions; if it isn't, somebody
+        * didn't call AtEOXact_GUC, or called it with the wrong nestLevel.  We
+        * throw a warning but make no other effort to clean up.
+        */
+       if (GUCNestLevel != 0)
+               elog(WARNING, "GUC nest level = %d at transaction start",
+                        GUCNestLevel);
+       GUCNestLevel = 1;
+}
 
-       {
-               {"wal_level", PGC_POSTMASTER, WAL_SETTINGS,
-                       gettext_noop("Sets the level of information written to the WAL."),
-                       NULL
-               },
-               &wal_level,
-               WAL_LEVEL_REPLICA, wal_level_options,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"dynamic_shared_memory_type", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("Selects the dynamic shared memory implementation used."),
-                       NULL
-               },
-               &dynamic_shared_memory_type,
-               DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE, dynamic_shared_memory_options,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"shared_memory_type", PGC_POSTMASTER, RESOURCES_MEM,
-                       gettext_noop("Selects the shared memory implementation used for the main shared memory region."),
-                       NULL
-               },
-               &shared_memory_type,
-               DEFAULT_SHARED_MEMORY_TYPE, shared_memory_options,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"wal_sync_method", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Selects the method used for forcing WAL updates to disk."),
-                       NULL
-               },
-               &sync_method,
-  &nbs