]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/misc/guc.c
Remove all the special-case code for INT64_IS_BUSTED, per decision that
[postgresql] / src / backend / utils / misc / guc.c
index 9b33547ed4786b7623c712bacbc92973fd490a19..38d577f87bb9a892a8908bc8f7d3dcc2eafe02bb 100644 (file)
@@ -6,11 +6,11 @@
  * See src/backend/utils/misc/README for more information.
  *
  *
- * Copyright (c) 2000-2008, PostgreSQL Global Development Group
+ * Copyright (c) 2000-2010, PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.433 2008/03/06 16:31:42 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.532 2010/01/07 04:53:35 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 
 #include <ctype.h>
 #include <float.h>
+#include <math.h>
 #include <limits.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include "commands/trigger.h"
 #include "funcapi.h"
 #include "libpq/auth.h"
+#include "libpq/be-fsstubs.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "optimizer/cost.h"
 #include "optimizer/geqo.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
-#include "parser/gramparse.h"
 #include "parser/parse_expr.h"
-#include "parser/parse_relation.h"
 #include "parser/parse_type.h"
+#include "parser/parser.h"
 #include "parser/scansup.h"
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
 #include "postmaster/walwriter.h"
+#include "storage/bufmgr.h"
 #include "storage/fd.h"
-#include "storage/freespace.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
+#include "utils/bytea.h"
 #include "utils/guc_tables.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
@@ -85,7 +87,8 @@
 #endif
 
 /* upper limit for GUC variables measured in kilobytes of memory */
-#if SIZEOF_SIZE_T > 4
+/* note that various places assume the byte size fits in a "long" variable */
+#if SIZEOF_SIZE_T > 4 && SIZEOF_LONG > 4
 #define MAX_KILOBYTES  INT_MAX
 #else
 #define MAX_KILOBYTES  (INT_MAX / 1024)
@@ -112,6 +115,9 @@ extern char *default_tablespace;
 extern char *temp_tablespaces;
 extern bool synchronize_seqscans;
 extern bool fullPageWrites;
+extern int     vacuum_defer_cleanup_age;
+
+int    trace_recovery_messages = LOG;
 
 #ifdef TRACE_SORT
 extern bool trace_sort;
@@ -127,6 +133,8 @@ extern bool optimize_bounded_sort;
 extern char *SSLCipherSuites;
 #endif
 
+static void set_config_sourcefile(const char *name, char *sourcefile,
+                                         int sourceline);
 
 static const char *assign_log_destination(const char *value,
                                           bool doit, GucSource source);
@@ -134,42 +142,26 @@ static const char *assign_log_destination(const char *value,
 #ifdef HAVE_SYSLOG
 static int     syslog_facility = LOG_LOCAL0;
 
-static const char *assign_syslog_facility(const char *facility,
+static bool assign_syslog_facility(int newval,
                                           bool doit, GucSource source);
 static const char *assign_syslog_ident(const char *ident,
                                        bool doit, GucSource source);
 #endif
 
-static const char *assign_defaultxactisolevel(const char *newval, bool doit,
-                                                  GucSource source);
-static const char *assign_session_replication_role(const char *newval, bool doit,
+static bool assign_session_replication_role(int newval, bool doit,
                                                                GucSource source);
-static const char *assign_log_min_messages(const char *newval, bool doit,
-                                               GucSource source);
-static const char *assign_client_min_messages(const char *newval,
-                                                  bool doit, GucSource source);
-static const char *assign_min_error_statement(const char *newval, bool doit,
-                                                  GucSource source);
-static const char *assign_msglvl(int *var, const char *newval, bool doit,
-                         GucSource source);
-static const char *assign_log_error_verbosity(const char *newval, bool doit,
-                                                  GucSource source);
-static const char *assign_log_statement(const char *newval, bool doit,
-                                        GucSource source);
 static const char *show_num_temp_buffers(void);
 static bool assign_phony_autocommit(bool newval, bool doit, GucSource source);
 static const char *assign_custom_variable_classes(const char *newval, bool doit,
                                                           GucSource source);
 static bool assign_debug_assertions(bool newval, bool doit, GucSource source);
+static bool assign_bonjour(bool newval, bool doit, GucSource source);
 static bool assign_ssl(bool newval, bool doit, GucSource source);
 static bool assign_stage_log_stats(bool newval, bool doit, GucSource source);
 static bool assign_log_stats(bool newval, bool doit, GucSource source);
 static bool assign_transaction_read_only(bool newval, bool doit, GucSource source);
 static const char *assign_canonical_path(const char *newval, bool doit, GucSource source);
-static const char *assign_backslash_quote(const char *newval, bool doit, GucSource source);
 static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source);
-static const char *assign_xmlbinary(const char *newval, bool doit, GucSource source);
-static const char *assign_xmloption(const char *newval, bool doit, GucSource source);
 static const char *show_archive_command(void);
 static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source);
 static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source);
@@ -177,8 +169,176 @@ static bool assign_tcp_keepalives_count(int newval, bool doit, GucSource source)
 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 bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
 static bool assign_maxconnections(int newval, bool doit, GucSource source);
+static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
+static bool assign_effective_io_concurrency(int newval, bool doit, GucSource source);
+static const char *assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source);
+static const char *assign_application_name(const char *newval, bool doit, GucSource source);
+
+static char *config_enum_get_options(struct config_enum * record,
+                                               const char *prefix, const char *suffix,
+                                               const char *separator);
+
+
+/*
+ * 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}
+};
+
+/*
+ * We have different sets for client and server message level options because
+ * they sort slightly different (see "log" level)
+ */
+static const struct config_enum_entry client_message_level_options[] = {
+       {"debug", DEBUG2, true},
+       {"debug5", DEBUG5, false},
+       {"debug4", DEBUG4, false},
+       {"debug3", DEBUG3, false},
+       {"debug2", DEBUG2, false},
+       {"debug1", DEBUG1, false},
+       {"log", LOG, false},
+       {"info", INFO, true},
+       {"notice", NOTICE, false},
+       {"warning", WARNING, false},
+       {"error", ERROR, false},
+       {"fatal", FATAL, true},
+       {"panic", PANIC, true},
+       {NULL, 0, false}
+};
+
+static const struct config_enum_entry server_message_level_options[] = {
+       {"debug", DEBUG2, true},
+       {"debug5", DEBUG5, false},
+       {"debug4", DEBUG4, false},
+       {"debug3", DEBUG3, false},
+       {"debug2", DEBUG2, false},
+       {"debug1", DEBUG1, false},
+       {"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}
+};
+
+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}
+};
+
+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}
+};
+
+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}
+};
+
+#ifdef HAVE_SYSLOG
+static const struct config_enum_entry syslog_facility_options[] = {
+       {"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},
+       {NULL, 0}
+};
+#endif
+
+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}
+};
+
+static const struct config_enum_entry xmlbinary_options[] = {
+       {"base64", XMLBINARY_BASE64, false},
+       {"hex", XMLBINARY_HEX, false},
+       {NULL, 0, false}
+};
+
+static const struct config_enum_entry xmloption_options[] = {
+       {"content", XMLOPTION_CONTENT, false},
+       {"document", XMLOPTION_DOCUMENT, false},
+       {NULL, 0, false}
+};
+
+/*
+ * 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 "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}
+};
+
+/*
+ * Options for enum values stored in other modules
+ */
+extern const struct config_enum_entry sync_method_options[];
 
 /*
  * GUC option variables that are exported from this module
@@ -192,8 +352,7 @@ bool                log_duration = false;
 bool           Debug_print_plan = false;
 bool           Debug_print_parse = false;
 bool           Debug_print_rewritten = false;
-bool           Debug_pretty_print = false;
-bool           Explain_pretty_print = true;
+bool           Debug_pretty_print = true;
 
 bool           log_parser_stats = false;
 bool           log_planner_stats = false;
@@ -209,7 +368,7 @@ bool                SQL_inheritance = true;
 bool           Password_encryption = true;
 
 int                    log_min_error_statement = ERROR;
-int                    log_min_messages = NOTICE;
+int                    log_min_messages = WARNING;
 int                    client_min_messages = NOTICE;
 int                    log_min_duration_statement = -1;
 int                    log_temp_files = -1;
@@ -221,6 +380,12 @@ char          *HbaFileName;
 char      *IdentFileName;
 char      *external_pid_file;
 
+char      *pgstat_temp_directory;
+
+char      *default_do_language;
+
+char      *application_name;
+
 int                    tcp_keepalives_idle;
 int                    tcp_keepalives_interval;
 int                    tcp_keepalives_count;
@@ -230,28 +395,18 @@ int                       tcp_keepalives_count;
  * cases provide the value for SHOW to display.  The real state is elsewhere
  * and is kept in sync by assign_hooks.
  */
-static char *client_min_messages_str;
-static char *log_min_messages_str;
-static char *log_error_verbosity_str;
-static char *log_statement_str;
-static char *log_min_error_statement_str;
 static char *log_destination_string;
 
 #ifdef HAVE_SYSLOG
-static char *syslog_facility_str;
 static char *syslog_ident_str;
 #endif
 static bool phony_autocommit;
 static bool session_auth_is_superuser;
 static double phony_random_seed;
-static char *backslash_quote_string;
 static char *client_encoding_string;
 static char *datestyle_string;
-static char *default_iso_level_string;
-static char *session_replication_role_string;
 static char *locale_collate;
 static char *locale_ctype;
-static char *regex_flavor_string;
 static char *server_encoding_string;
 static char *server_version_string;
 static int     server_version_num;
@@ -261,13 +416,15 @@ static char *timezone_abbreviations_string;
 static char *XactIsoLevel_string;
 static char *data_directory;
 static char *custom_variable_classes;
-static char *xmlbinary_string;
-static char *xmloption_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     wal_block_size;
+static int     wal_segment_size;
 static bool integer_datetimes;
+static int     effective_io_concurrency;
 
 /* should be static, but commands/variable.c needs to get at these */
 char      *role_string;
@@ -302,6 +459,7 @@ const char *const GucSource_Names[] =
         /* PGC_S_ARGV */ "command line",
         /* 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",
@@ -328,8 +486,6 @@ const char *const config_group_names[] =
        gettext_noop("Resource Usage"),
        /* RESOURCES_MEM */
        gettext_noop("Resource Usage / Memory"),
-       /* RESOURCES_FSM */
-       gettext_noop("Resource Usage / Free Space Map"),
        /* RESOURCES_KERNEL */
        gettext_noop("Resource Usage / Kernel Resources"),
        /* WAL */
@@ -400,7 +556,8 @@ const char *const config_type_names[] =
         /* PGC_BOOL */ "bool",
         /* PGC_INT */ "integer",
         /* PGC_REAL */ "real",
-        /* PGC_STRING */ "string"
+        /* PGC_STRING */ "string",
+        /* PGC_ENUM */ "enum"
 };
 
 
@@ -508,15 +665,6 @@ static struct config_bool ConfigureNamesBool[] =
                &enable_hashjoin,
                true, NULL, NULL
        },
-       {
-               {"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
-                       gettext_noop("Enables the planner to use constraints to optimize queries."),
-                       gettext_noop("Child table scans will be skipped if their "
-                                          "constraints guarantee that no rows match the query.")
-               },
-               &constraint_exclusion,
-               false, NULL, NULL
-       },
        {
                {"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
                        gettext_noop("Enables genetic query optimization."),
@@ -536,6 +684,14 @@ static struct config_bool ConfigureNamesBool[] =
                &session_auth_is_superuser,
                false, NULL, NULL
        },
+       {
+               {"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
+                       gettext_noop("Enables advertising the server via Bonjour."),
+                       NULL
+               },
+               &enable_bonjour,
+               false, assign_bonjour, NULL
+       },
        {
                {"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY,
                        gettext_noop("Enables SSL connections."),
@@ -589,7 +745,7 @@ static struct config_bool ConfigureNamesBool[] =
                true, NULL, NULL
        },
        {
-               {"silent_mode", PGC_POSTMASTER, LOGGING_WHEN,
+               {"silent_mode", PGC_POSTMASTER, LOGGING_WHERE,
                        gettext_noop("Runs the server silently."),
                        gettext_noop("If this parameter is set, the server will automatically run in the "
                                 "background and any controlling terminals are dissociated.")
@@ -655,7 +811,7 @@ static struct config_bool ConfigureNamesBool[] =
        },
        {
                {"debug_print_parse", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Prints the parse tree to the server log."),
+                       gettext_noop("Logs each query's parse tree."),
                        NULL
                },
                &Debug_print_parse,
@@ -663,7 +819,7 @@ static struct config_bool ConfigureNamesBool[] =
        },
        {
                {"debug_print_rewritten", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Prints the parse tree after rewriting to server log."),
+                       gettext_noop("Logs each query's rewritten parse tree."),
                        NULL
                },
                &Debug_print_rewritten,
@@ -671,7 +827,7 @@ static struct config_bool ConfigureNamesBool[] =
        },
        {
                {"debug_print_plan", PGC_USERSET, LOGGING_WHAT,
-                       gettext_noop("Prints the execution plan to server log."),
+                       gettext_noop("Logs each query's execution plan."),
                        NULL
                },
                &Debug_print_plan,
@@ -683,7 +839,7 @@ static struct config_bool ConfigureNamesBool[] =
                        NULL
                },
                &Debug_pretty_print,
-               false, NULL, NULL
+               true, NULL, NULL
        },
        {
                {"log_parser_stats", PGC_SUSET, STATS_MONITORING,
@@ -729,15 +885,6 @@ static struct config_bool ConfigureNamesBool[] =
        },
 #endif
 
-       {
-               {"explain_pretty_print", PGC_USERSET, CLIENT_CONN_OTHER,
-                       gettext_noop("Uses the indented output format for EXPLAIN VERBOSE."),
-                       NULL
-               },
-               &Explain_pretty_print,
-               true, NULL, NULL
-       },
-
        {
                {"track_activities", PGC_SUSET, STATS_COLLECTOR,
                        gettext_noop("Collects information about executing commands."),
@@ -909,14 +1056,6 @@ static struct config_bool ConfigureNamesBool[] =
                &XactReadOnly,
                false, assign_transaction_read_only, NULL
        },
-       {
-               {"add_missing_from", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Automatically adds missing table references to FROM clauses."),
-                       NULL
-               },
-               &add_missing_from,
-               false, NULL, NULL
-       },
        {
                {"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
                        gettext_noop("Check function bodies during CREATE FUNCTION."),
@@ -1026,7 +1165,7 @@ static struct config_bool ConfigureNamesBool[] =
        },
 
        {
-               {"krb_caseins_users", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+               {"krb_caseins_users", PGC_SIGHUP, CONN_AUTH_SECURITY,
                        gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive."),
                        NULL
                },
@@ -1071,6 +1210,17 @@ static struct config_bool ConfigureNamesBool[] =
                false, NULL, NULL
        },
 
+       {
+               {"recovery_connections", PGC_POSTMASTER, WAL_SETTINGS,
+                       gettext_noop("During recovery, allows connections and queries. "
+                                                " During normal running, causes additional info to be written"
+                                                " to WAL to enable hot standby mode on WAL standby nodes."),
+                       NULL
+               },
+               &XLogRequestRecoveryConnections,
+               true, NULL, NULL
+       },
+
        {
                {"allow_system_table_mods", PGC_POSTMASTER, DEVELOPER_OPTIONS,
                        gettext_noop("Allows modifications of the structure of system tables."),
@@ -1092,6 +1242,16 @@ static struct config_bool ConfigureNamesBool[] =
                false, 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 8.5.")
+               },
+               &lo_compat_privileges,
+               false, NULL, NULL
+       },
+
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL
@@ -1127,7 +1287,7 @@ static struct config_int ConfigureNamesInt[] =
                                "column-specific target set via ALTER TABLE SET STATISTICS.")
                },
                &default_statistics_target,
-               10, 1, 1000, NULL, NULL
+               100, 1, 10000, NULL, NULL
        },
        {
                {"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
@@ -1185,6 +1345,7 @@ static struct config_int ConfigureNamesInt[] =
        },
 
        {
+               /* This is PGC_SIGHUP so all backends have the same value. */
                {"deadlock_timeout", PGC_SIGHUP, LOCK_MANAGEMENT,
                        gettext_noop("Sets the time to wait on a lock before checking for deadlock."),
                        NULL,
@@ -1195,18 +1356,14 @@ static struct config_int ConfigureNamesInt[] =
        },
 
        /*
-        * Note: There is some postprocessing done in PostmasterMain() to make
-        * sure the buffers are at least twice the number of backends, so the
-        * constraints here are partially unused. Similarly, the superuser
-        * reserved number is checked to ensure it is less than the max backends
-        * number.
-        *
-        * MaxBackends is limited to INT_MAX/4 because some places compute
-        * 4*MaxBackends without any overflow check.  This check is made on
+        * Note: MaxBackends is limited to INT_MAX/4 because some places compute
+        * 4*MaxBackends without any overflow check.  This check is made in
         * assign_maxconnections, since MaxBackends is computed as MaxConnections
-        * + autovacuum_max_workers.
+        * plus autovacuum_max_workers plus one (for the autovacuum launcher).
         *
         * Likewise we have to limit NBuffers to INT_MAX/2.
+        *
+        * See also CheckRequiredParameterValues() if this parameter changes
         */
        {
                {"max_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
@@ -1217,6 +1374,15 @@ static struct config_int ConfigureNamesInt[] =
                100, 1, INT_MAX / 4, assign_maxconnections, NULL
        },
 
+       {
+               {"max_standby_delay", PGC_SIGHUP, WAL_SETTINGS,
+                       gettext_noop("Sets the maximum delay to avoid conflict processing on Hot Standby servers."),
+                       NULL
+               },
+               &MaxStandbyDelay,
+               30, -1, INT_MAX, NULL, NULL
+       },
+
        {
                {"superuser_reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
                        gettext_noop("Sets the number of connection slots reserved for superusers."),
@@ -1259,7 +1425,7 @@ static struct config_int ConfigureNamesInt[] =
                {"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 an numeric mode "
+                                                "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).)")
@@ -1277,7 +1443,7 @@ static struct config_int ConfigureNamesInt[] =
                        GUC_UNIT_KB
                },
                &work_mem,
-               1024, 8 * BLCKSZ / 1024, MAX_KILOBYTES, NULL, NULL
+               1024, 64, MAX_KILOBYTES, NULL, NULL
        },
 
        {
@@ -1343,7 +1509,7 @@ static struct config_int ConfigureNamesInt[] =
                        GUC_UNIT_MS
                },
                &VacuumCostDelay,
-               0, 0, 1000, NULL, NULL
+               0, 0, 100, NULL, NULL
        },
 
        {
@@ -1353,7 +1519,7 @@ static struct config_int ConfigureNamesInt[] =
                        GUC_UNIT_MS
                },
                &autovacuum_vac_cost_delay,
-               20, -1, 1000, NULL, NULL
+               20, -1, 100, NULL, NULL
        },
 
        {
@@ -1374,13 +1540,16 @@ static struct config_int ConfigureNamesInt[] =
                1000, 25, INT_MAX, NULL, NULL
        },
 
+       /*
+        * See also CheckRequiredParameterValues() if this parameter changes
+        */
        {
                {"max_prepared_transactions", PGC_POSTMASTER, RESOURCES,
                        gettext_noop("Sets the maximum number of simultaneously prepared transactions."),
                        NULL
                },
                &max_prepared_xacts,
-               5, 0, INT_MAX, NULL, NULL
+               0, 0, INT_MAX / 4, NULL, NULL
        },
 
 #ifdef LOCK_DEBUG
@@ -1420,26 +1589,30 @@ static struct config_int ConfigureNamesInt[] =
                        NULL
                },
                &vacuum_freeze_min_age,
-               100000000, 0, 1000000000, NULL, NULL
+               50000000, 0, 1000000000, NULL, NULL
        },
 
        {
-               {"max_fsm_relations", PGC_POSTMASTER, RESOURCES_FSM,
-                       gettext_noop("Sets the maximum number of tables and indexes for which free space is tracked."),
+               {"vacuum_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Age at which VACUUM should scan whole table to freeze tuples."),
                        NULL
                },
-               &MaxFSMRelations,
-               1000, 100, INT_MAX, NULL, NULL
+               &vacuum_freeze_table_age,
+               150000000, 0, 2000000000, NULL, NULL
        },
+
        {
-               {"max_fsm_pages", PGC_POSTMASTER, RESOURCES_FSM,
-                       gettext_noop("Sets the maximum number of disk pages for which free space is tracked."),
+               {"vacuum_defer_cleanup_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Age by which VACUUM and HOT cleanup should be deferred, if any."),
                        NULL
                },
-               &MaxFSMPages,
-               20000, 1000, INT_MAX, NULL, NULL
+               &vacuum_defer_cleanup_age,
+               0, 0, 1000000, NULL, NULL
        },
 
+       /*
+        * See also CheckRequiredParameterValues() if this parameter changes
+        */
        {
                {"max_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
                        gettext_noop("Sets the maximum number of locks per transaction."),
@@ -1552,7 +1725,7 @@ static struct config_int ConfigureNamesInt[] =
                                                 "(FLT_DIG or DBL_DIG as appropriate).")
                },
                &extra_float_digits,
-               0, -15, 2, NULL, NULL
+               0, -15, 3, NULL, NULL
        },
 
        {
@@ -1596,6 +1769,26 @@ static struct config_int ConfigureNamesInt[] =
                100, 0, 1000, NULL, NULL
        },
 
+       {
+               {"effective_io_concurrency",
+#ifdef USE_PREFETCH
+                       PGC_USERSET,
+#else
+                       PGC_INTERNAL,
+#endif
+                       RESOURCES,
+                       gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem."),
+                       gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array.")
+               },
+               &effective_io_concurrency,
+#ifdef USE_PREFETCH
+               1, 0, 1000,
+#else
+               0, 0, 0,
+#endif
+               assign_effective_io_concurrency, NULL
+       },
+
        {
                {"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
                        gettext_noop("Automatic log file rotation will occur after N minutes."),
@@ -1656,6 +1849,39 @@ static struct config_int ConfigureNamesInt[] =
                BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
        },
 
+       {
+               {"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
+       },
+
+       {
+               {"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
+       },
+
+       {
+               {"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS,
+                       gettext_noop("Shows the number of pages per write ahead log segment."),
+                       NULL,
+                       GUC_UNIT_XBLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+               },
+               &wal_segment_size,
+               (XLOG_SEG_SIZE / XLOG_BLCKSZ),
+               (XLOG_SEG_SIZE / XLOG_BLCKSZ),
+               (XLOG_SEG_SIZE / XLOG_BLCKSZ),
+               NULL, NULL
+       },
+
        {
                {"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
                        gettext_noop("Time to sleep between autovacuum runs."),
@@ -1688,6 +1914,7 @@ static struct config_int ConfigureNamesInt[] =
                        NULL
                },
                &autovacuum_freeze_max_age,
+               /* see pg_resetxlog if you change the upper-limit value */
                200000000, 100000000, 2000000000, NULL, NULL
        },
        {
@@ -1765,7 +1992,7 @@ static struct config_int ConfigureNamesInt[] =
        },
 
        {
-               {"log_temp_files", PGC_USERSET, LOGGING_WHAT,
+               {"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
@@ -1774,6 +2001,15 @@ static struct config_int ConfigureNamesInt[] =
                -1, -1, INT_MAX, NULL, NULL
        },
 
+       {
+               {"track_activity_query_size", PGC_POSTMASTER, RESOURCES_MEM,
+                       gettext_noop("Sets the size reserved for pg_stat_activity.current_query, in bytes."),
+                       NULL,
+               },
+               &pgstat_track_activity_query_size,
+               1024, 100, 102400, NULL, NULL
+       },
+
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
@@ -1829,6 +2065,16 @@ static struct config_real ConfigureNamesReal[] =
                DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, NULL, NULL
        },
 
+       {
+               {"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
+               },
+               &cursor_tuple_fraction,
+               DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0, NULL, NULL
+       },
+
        {
                {"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO,
                        gettext_noop("GEQO: selective pressure within the population."),
@@ -1838,6 +2084,14 @@ static struct config_real ConfigureNamesReal[] =
                DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS,
                MAX_GEQO_SELECTION_BIAS, NULL, NULL
        },
+       {
+               {"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
+                       gettext_noop("GEQO: seed for random path selection."),
+                       NULL
+               },
+               &Geqo_seed,
+               0.0, 0.0, 1.0, NULL, NULL
+       },
 
        {
                {"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES,
@@ -1855,7 +2109,7 @@ static struct config_real ConfigureNamesReal[] =
                        GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
                },
                &phony_random_seed,
-               0.5, 0.0, 1.0, assign_random_seed, show_random_seed
+               0.0, -1.0, 1.0, assign_random_seed, show_random_seed
        },
 
        {
@@ -1902,15 +2156,6 @@ static struct config_string ConfigureNamesString[] =
                "", NULL, show_archive_command
        },
 
-       {
-               {"backslash_quote", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Sets whether \"\\'\" is allowed in string literals."),
-                       gettext_noop("Valid values are ON, OFF, and SAFE_ENCODING.")
-               },
-               &backslash_quote_string,
-               "safe_encoding", assign_backslash_quote, NULL
-       },
-
        {
                {"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
                        gettext_noop("Sets the client's character set encoding."),
@@ -1921,56 +2166,6 @@ static struct config_string ConfigureNamesString[] =
                "SQL_ASCII", assign_client_encoding, NULL
        },
 
-       {
-               {"client_min_messages", PGC_USERSET, LOGGING_WHEN,
-                       gettext_noop("Sets the message levels that are sent to the client."),
-                       gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, "
-                                                "DEBUG1, LOG, NOTICE, WARNING, and ERROR. Each level includes all the "
-                                                "levels that follow it. The later the level, the fewer messages are "
-                                                "sent.")
-               },
-               &client_min_messages_str,
-               "notice", assign_client_min_messages, NULL
-       },
-
-       {
-               {"log_min_messages", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the message levels that are logged."),
-                       gettext_noop("Valid values are DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, "
-                       "INFO, NOTICE, WARNING, ERROR, LOG, FATAL, and PANIC. Each level "
-                                                "includes all the levels that follow it.")
-               },
-               &log_min_messages_str,
-               "notice", assign_log_min_messages, NULL
-       },
-
-       {
-               {"log_error_verbosity", PGC_SUSET, LOGGING_WHEN,
-                       gettext_noop("Sets the verbosity of logged messages."),
-                       gettext_noop("Valid values are \"terse\", \"default\", and \"verbose\".")
-               },
-               &log_error_verbosity_str,
-               "default", assign_log_error_verbosity, NULL
-       },
-       {
-               {"log_statement", PGC_SUSET, LOGGING_WHAT,
-                       gettext_noop("Sets the type of statements logged."),
-                       gettext_noop("Valid values are \"none\", \"ddl\", \"mod\", and \"all\".")
-               },
-               &log_statement_str,
-               "none", assign_log_statement, NULL
-       },
-
-       {
-               {"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("All SQL statements that cause an error of the "
-                                                "specified level or a higher level are logged.")
-               },
-               &log_min_error_statement_str,
-               "error", assign_min_error_statement, NULL
-       },
-
        {
                {"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT,
                        gettext_noop("Controls information prefixed to each log line."),
@@ -2020,26 +2215,6 @@ static struct config_string ConfigureNamesString[] =
                "", assign_temp_tablespaces, NULL
        },
 
-       {
-               {"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the transaction isolation level of each new transaction."),
-                       gettext_noop("Each SQL transaction has an isolation level, which "
-                                                "can be either \"read uncommitted\", \"read committed\", \"repeatable read\", or \"serializable\".")
-               },
-               &default_iso_level_string,
-               "read committed", assign_defaultxactisolevel, NULL
-       },
-
-       {
-               {"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets the session's behavior for triggers and rewrite rules."),
-                       gettext_noop("Each session can be either"
-                                                " \"origin\", \"replica\", or \"local\".")
-               },
-               &session_replication_role_string,
-               "origin", assign_session_replication_role, NULL
-       },
-
        {
                {"dynamic_library_path", PGC_SUSET, CLIENT_CONN_OTHER,
                        gettext_noop("Sets the path for dynamically loadable modules."),
@@ -2054,17 +2229,7 @@ static struct config_string ConfigureNamesString[] =
        },
 
        {
-               {"krb_realm", PGC_POSTMASTER, CONN_AUTH_SECURITY,
-                       gettext_noop("Sets realm to match Kerberos and GSSAPI users against."),
-                       NULL,
-                       GUC_SUPERUSER_ONLY
-               },
-               &pg_krb_realm,
-               NULL, NULL, NULL
-       },
-
-       {
-               {"krb_server_keyfile", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+               {"krb_server_keyfile", PGC_SIGHUP, CONN_AUTH_SECURITY,
                        gettext_noop("Sets the location of the Kerberos server key file."),
                        NULL,
                        GUC_SUPERUSER_ONLY
@@ -2074,7 +2239,7 @@ static struct config_string ConfigureNamesString[] =
        },
 
        {
-               {"krb_srvname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+               {"krb_srvname", PGC_SIGHUP, CONN_AUTH_SECURITY,
                        gettext_noop("Sets the name of the Kerberos service."),
                        NULL
                },
@@ -2082,18 +2247,9 @@ static struct config_string ConfigureNamesString[] =
                PG_KRB_SRVNAM, NULL, NULL
        },
 
-       {
-               {"krb_server_hostname", PGC_POSTMASTER, CONN_AUTH_SECURITY,
-                       gettext_noop("Sets the hostname of the Kerberos server."),
-                       NULL
-               },
-               &pg_krb_server_hostname,
-               NULL, NULL, NULL
-       },
-
        {
                {"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
-                       gettext_noop("Sets the Bonjour broadcast service name."),
+                       gettext_noop("Sets the Bonjour service name."),
                        NULL
                },
                &bonjour_name,
@@ -2178,15 +2334,6 @@ static struct config_string ConfigureNamesString[] =
                "", NULL, NULL
        },
 
-       {
-               {"regex_flavor", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
-                       gettext_noop("Sets the regular expression \"flavor\"."),
-                       gettext_noop("This can be set to advanced, extended, or basic.")
-               },
-               &regex_flavor_string,
-               "advanced", assign_regex_flavor, NULL
-       },
-
        {
                {"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,
                        gettext_noop("Sets the schema search order for names that are not schema-qualified."),
@@ -2224,7 +2371,7 @@ static struct config_string ConfigureNamesString[] =
                {"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_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", assign_role, show_role
@@ -2235,7 +2382,7 @@ static struct config_string ConfigureNamesString[] =
                {"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_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, assign_session_authorization, show_session_authorization
@@ -2273,15 +2420,6 @@ static struct config_string ConfigureNamesString[] =
        },
 
 #ifdef HAVE_SYSLOG
-       {
-               {"syslog_facility", PGC_SIGHUP, LOGGING_WHERE,
-                       gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled."),
-                       gettext_noop("Valid values are LOCAL0, LOCAL1, LOCAL2, LOCAL3, "
-                                                "LOCAL4, LOCAL5, LOCAL6, LOCAL7.")
-               },
-               &syslog_facility_str,
-               "LOCAL0", assign_syslog_facility, NULL
-       },
        {
                {"syslog_ident", PGC_SIGHUP, LOGGING_WHERE,
                        gettext_noop("Sets the program name used to identify PostgreSQL "
@@ -2305,7 +2443,7 @@ static struct config_string ConfigureNamesString[] =
        {
                {"timezone_abbreviations", PGC_USERSET, CLIENT_CONN_LOCALE,
                        gettext_noop("Selects a file of time zone abbreviations."),
-                       NULL,
+                       NULL
                },
                &timezone_abbreviations_string,
                "UNKNOWN", assign_timezone_abbreviations, NULL
@@ -2351,15 +2489,6 @@ static struct config_string ConfigureNamesString[] =
                "localhost", NULL, NULL
        },
 
-       {
-               {"wal_sync_method", PGC_SIGHUP, WAL_SETTINGS,
-                       gettext_noop("Selects the method used for forcing WAL updates to disk."),
-                       NULL
-               },
-               &XLOG_sync_method,
-               XLOG_sync_method_default, assign_xlog_sync_method, NULL
-       },
-
        {
                {"custom_variable_classes", PGC_SIGHUP, CUSTOM_OPTIONS,
                        gettext_noop("Sets the list of known custom variable classes."),
@@ -2421,22 +2550,13 @@ static struct config_string ConfigureNamesString[] =
        },
 
        {
-               {"xmlbinary", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets how binary values are to be encoded in XML."),
-                       gettext_noop("Valid values are BASE64 and HEX.")
-               },
-               &xmlbinary_string,
-               "base64", assign_xmlbinary, NULL
-       },
-
-       {
-               {"xmloption", PGC_USERSET, CLIENT_CONN_STATEMENT,
-                       gettext_noop("Sets whether XML data in implicit parsing and serialization "
-                                                "operations is to be considered as documents or content fragments."),
-                       gettext_noop("Valid values are DOCUMENT and CONTENT.")
+               {"stats_temp_directory", PGC_SIGHUP, STATS_COLLECTOR,
+                       gettext_noop("Writes temporary statistics files to the specified directory."),
+                       NULL,
+                       GUC_SUPERUSER_ONLY
                },
-               &xmloption_string,
-               "content", assign_xmloption, NULL
+               &pgstat_temp_directory,
+               "pg_stat_tmp", assign_pgstat_temp_directory, NULL
        },
 
        {
@@ -2460,6 +2580,25 @@ static struct config_string ConfigureNamesString[] =
        },
 #endif   /* USE_SSL */
 
+       {
+               {"default_do_language", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Sets the language used in DO statement if LANGUAGE is not specified."),
+                       NULL
+               },
+               &default_do_language,
+               "plpgsql", NULL, NULL
+       },
+
+       {
+               {"application_name", PGC_USERSET, LOGGING,
+                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,
+               "", assign_application_name, NULL
+       },
+
        /* End-of-list marker */
        {
                {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
@@ -2467,19 +2606,193 @@ static struct config_string ConfigureNamesString[] =
 };
 
 
-/******** end of options list ********/
+static struct config_enum ConfigureNamesEnum[] =
+{
+       {
+               {"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
+       },
 
+       {
+               {"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
+       },
 
-/*
- * 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
+       {
+               {"client_min_messages", PGC_USERSET, LOGGING_WHEN,
+                       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
+       },
+
+       {
+               {"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.")
+               },
+               &constraint_exclusion,
+               CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options,
+               NULL, NULL
+       },
+
+       {
+               {"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
+       },
+
+       {
+               {"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
+       },
+
+       {
+               {"log_error_verbosity", PGC_SUSET, LOGGING_WHEN,
+                       gettext_noop("Sets the verbosity of logged messages."),
+                       NULL
+               },
+               &Log_error_verbosity,
+               PGERROR_DEFAULT, log_error_verbosity_options, NULL, NULL
+       },
+
+       {
+               {"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
+       },
+
+       {
+               {"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
+       },
+
+       {
+               {"log_statement", PGC_SUSET, LOGGING_WHAT,
+                       gettext_noop("Sets the type of statements logged."),
+                       NULL
+               },
+               &log_statement,
+               LOGSTMT_NONE, log_statement_options, NULL, NULL
+       },
+
+#ifdef HAVE_SYSLOG
+       {
+               {"syslog_facility", PGC_SIGHUP, LOGGING_WHERE,
+                       gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled."),
+                       NULL
+               },
+               &syslog_facility,
+               LOG_LOCAL0, syslog_facility_options, assign_syslog_facility, NULL
+       },
+#endif
+
+       {
+               {"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,
+               assign_session_replication_role, NULL
+       },
+
+       {
+               {"trace_recovery_messages", PGC_SUSET, LOGGING_WHEN,
+                       gettext_noop("Sets the message levels that are logged during recovery."),
+                       gettext_noop("Each level includes all the levels that follow it. The later"
+                                                " the level, the fewer messages are sent.")
+               },
+               &trace_recovery_messages,
+               DEBUG1, server_message_level_options, NULL, NULL
+       },
+
+       {
+               {"track_functions", PGC_SUSET, STATS_COLLECTOR,
+                       gettext_noop("Collects function-level statistics on database activity."),
+                       NULL
+               },
+               &pgstat_track_functions,
+               TRACK_FUNC_OFF, track_function_options, NULL, NULL
+       },
+
+       {
+               {"wal_sync_method", PGC_SIGHUP, WAL_SETTINGS,
+                       gettext_noop("Selects the method used for forcing WAL updates to disk."),
+                       NULL
+               },
+               &sync_method,
+               DEFAULT_SYNC_METHOD, sync_method_options,
+               assign_xlog_sync_method, NULL
+       },
+
+       {
+               {"xmlbinary", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Sets how binary values are to be encoded in XML."),
+                       NULL
+               },
+               &xmlbinary,
+               XMLBINARY_BASE64, xmlbinary_options, NULL, NULL
+       },
+
+       {
+               {"xmloption", PGC_USERSET, CLIENT_CONN_STATEMENT,
+                       gettext_noop("Sets whether XML data in implicit parsing and serialization "
+                                                "operations is to be considered as documents or content fragments."),
+                       NULL
+               },
+               &xmloption,
+               XMLOPTION_CONTENT, xmloption_options, NULL, NULL
+       },
+
+
+       /* End-of-list marker */
+       {
+               {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL
+       }
+};
+
+/******** end of options list ********/
+
+
+/*
+ * 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
 };
 
 
@@ -2504,6 +2817,7 @@ static int        GUCNestLevel = 0;       /* 1 when in main transaction */
 
 static int     guc_var_compare(const void *a, const void *b);
 static int     guc_name_compare(const char *namea, const char *nameb);
+static void InitializeOneGUCOption(struct config_generic * gconf);
 static void push_old_value(struct config_generic * gconf, GucAction action);
 static void ReportGUCOption(struct config_generic * record);
 static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
@@ -2633,6 +2947,10 @@ set_stack_value(struct config_generic * gconf, union config_var_value * val)
                                                         &(val->stringval),
                                                         *((struct config_string *) gconf)->variable);
                        break;
+               case PGC_ENUM:
+                       val->enumval =
+                               *((struct config_enum *) gconf)->variable;
+                       break;
        }
 }
 
@@ -2647,6 +2965,7 @@ discard_stack_value(struct config_generic * gconf, union config_var_value * val)
                case PGC_BOOL:
                case PGC_INT:
                case PGC_REAL:
+               case PGC_ENUM:
                        /* no need to do anything */
                        break;
                case PGC_STRING:
@@ -2714,6 +3033,14 @@ build_guc_variables(void)
                num_vars++;
        }
 
+       for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
+       {
+               struct config_enum *conf = &ConfigureNamesEnum[i];
+
+               conf->gen.vartype = PGC_ENUM;
+               num_vars++;
+       }
+
        /*
         * Create table with 20% slack
         */
@@ -2736,6 +3063,9 @@ build_guc_variables(void)
        for (i = 0; ConfigureNamesString[i].gen.name; i++)
                guc_vars[num_vars++] = &ConfigureNamesString[i].gen;
 
+       for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
+               guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
+
        if (guc_variables)
                free(guc_variables);
        guc_variables = guc_vars;
@@ -2995,98 +3325,7 @@ InitializeGUCOptions(void)
         */
        for (i = 0; i < num_guc_variables; i++)
        {
-               struct config_generic *gconf = guc_variables[i];
-
-               gconf->status = 0;
-               gconf->reset_source = PGC_S_DEFAULT;
-               gconf->source = PGC_S_DEFAULT;
-               gconf->stack = NULL;
-
-               switch (gconf->vartype)
-               {
-                       case PGC_BOOL:
-                               {
-                                       struct config_bool *conf = (struct config_bool *) gconf;
-
-                                       if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->boot_val, true,
-                                                                                                  PGC_S_DEFAULT))
-                                                       elog(FATAL, "failed to initialize %s to %d",
-                                                                conf->gen.name, (int) conf->boot_val);
-                                       *conf->variable = conf->reset_val = conf->boot_val;
-                                       break;
-                               }
-                       case PGC_INT:
-                               {
-                                       struct config_int *conf = (struct config_int *) gconf;
-
-                                       Assert(conf->boot_val >= conf->min);
-                                       Assert(conf->boot_val <= conf->max);
-                                       if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->boot_val, true,
-                                                                                                  PGC_S_DEFAULT))
-                                                       elog(FATAL, "failed to initialize %s to %d",
-                                                                conf->gen.name, conf->boot_val);
-                                       *conf->variable = conf->reset_val = conf->boot_val;
-                                       break;
-                               }
-                       case PGC_REAL:
-                               {
-                                       struct config_real *conf = (struct config_real *) gconf;
-
-                                       Assert(conf->boot_val >= conf->min);
-                                       Assert(conf->boot_val <= conf->max);
-                                       if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->boot_val, true,
-                                                                                                  PGC_S_DEFAULT))
-                                                       elog(FATAL, "failed to initialize %s to %g",
-                                                                conf->gen.name, conf->boot_val);
-                                       *conf->variable = conf->reset_val = conf->boot_val;
-                                       break;
-                               }
-                       case PGC_STRING:
-                               {
-                                       struct config_string *conf = (struct config_string *) gconf;
-                                       char       *str;
-
-                                       *conf->variable = NULL;
-                                       conf->reset_val = NULL;
-
-                                       if (conf->boot_val == NULL)
-                                       {
-                                               /* leave the value NULL, do not call assign hook */
-                                               break;
-                                       }
-
-                                       str = guc_strdup(FATAL, conf->boot_val);
-                                       conf->reset_val = str;
-
-                                       if (conf->assign_hook)
-                                       {
-                                               const char *newstr;
-
-                                               newstr = (*conf->assign_hook) (str, true,
-                                                                                                          PGC_S_DEFAULT);
-                                               if (newstr == NULL)
-                                               {
-                                                       elog(FATAL, "failed to initialize %s to \"%s\"",
-                                                                conf->gen.name, str);
-                                               }
-                                               else if (newstr != str)
-                                               {
-                                                       free(str);
-
-                                                       /*
-                                                        * See notes in set_config_option about casting
-                                                        */
-                                                       str = (char *) newstr;
-                                                       conf->reset_val = str;
-                                               }
-                                       }
-                                       *conf->variable = str;
-                                       break;
-                               }
-               }
+               InitializeOneGUCOption(guc_variables[i]);
        }
 
        guc_dirty = false;
@@ -3142,6 +3381,119 @@ InitializeGUCOptions(void)
        }
 }
 
+/*
+ * Initialize one GUC option variable to its compiled-in default.
+ */
+static void
+InitializeOneGUCOption(struct config_generic * gconf)
+{
+       gconf->status = 0;
+       gconf->reset_source = PGC_S_DEFAULT;
+       gconf->source = PGC_S_DEFAULT;
+       gconf->stack = NULL;
+       gconf->sourcefile = NULL;
+       gconf->sourceline = 0;
+
+       switch (gconf->vartype)
+       {
+               case PGC_BOOL:
+                       {
+                               struct config_bool *conf = (struct config_bool *) gconf;
+
+                               if (conf->assign_hook)
+                                       if (!(*conf->assign_hook) (conf->boot_val, true,
+                                                                                          PGC_S_DEFAULT))
+                                               elog(FATAL, "failed to initialize %s to %d",
+                                                        conf->gen.name, (int) conf->boot_val);
+                               *conf->variable = conf->reset_val = conf->boot_val;
+                               break;
+                       }
+               case PGC_INT:
+                       {
+                               struct config_int *conf = (struct config_int *) gconf;
+
+                               Assert(conf->boot_val >= conf->min);
+                               Assert(conf->boot_val <= conf->max);
+                               if (conf->assign_hook)
+                                       if (!(*conf->assign_hook) (conf->boot_val, true,
+                                                                                          PGC_S_DEFAULT))
+                                               elog(FATAL, "failed to initialize %s to %d",
+                                                        conf->gen.name, conf->boot_val);
+                               *conf->variable = conf->reset_val = conf->boot_val;
+                               break;
+                       }
+               case PGC_REAL:
+                       {
+                               struct config_real *conf = (struct config_real *) gconf;
+
+                               Assert(conf->boot_val >= conf->min);
+                               Assert(conf->boot_val <= conf->max);
+                               if (conf->assign_hook)
+                                       if (!(*conf->assign_hook) (conf->boot_val, true,
+                                                                                          PGC_S_DEFAULT))
+                                               elog(FATAL, "failed to initialize %s to %g",
+                                                        conf->gen.name, conf->boot_val);
+                               *conf->variable = conf->reset_val = conf->boot_val;
+                               break;
+                       }
+               case PGC_STRING:
+                       {
+                               struct config_string *conf = (struct config_string *) gconf;
+                               char       *str;
+
+                               *conf->variable = NULL;
+                               conf->reset_val = NULL;
+
+                               if (conf->boot_val == NULL)
+                               {
+                                       /* leave the value NULL, do not call assign hook */
+                                       break;
+                               }
+
+                               str = guc_strdup(FATAL, conf->boot_val);
+                               conf->reset_val = str;
+
+                               if (conf->assign_hook)
+                               {
+                                       const char *newstr;
+
+                                       newstr = (*conf->assign_hook) (str, true,
+                                                                                                  PGC_S_DEFAULT);
+                                       if (newstr == NULL)
+                                       {
+                                               elog(FATAL, "failed to initialize %s to \"%s\"",
+                                                        conf->gen.name, str);
+                                       }
+                                       else if (newstr != str)
+                                       {
+                                               free(str);
+
+                                               /*
+                                                * See notes in set_config_option about casting
+                                                */
+                                               str = (char *) newstr;
+                                               conf->reset_val = str;
+                                       }
+                               }
+                               *conf->variable = str;
+                               break;
+                       }
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) gconf;
+
+                               if (conf->assign_hook)
+                                       if (!(*conf->assign_hook) (conf->boot_val, true,
+                                                                                          PGC_S_DEFAULT))
+                                               elog(FATAL, "failed to initialize %s to %s",
+                                                        conf->gen.name,
+                                                 config_enum_lookup_by_value(conf, conf->boot_val));
+                               *conf->variable = conf->reset_val = conf->boot_val;
+                               break;
+                       }
+       }
+}
+
 
 /*
  * Select the configuration files and data directory to be used, and
@@ -3327,9 +3679,9 @@ ResetAllOptions(void)
                                        if (conf->assign_hook)
                                                if (!(*conf->assign_hook) (conf->reset_val, true,
                                                                                                   PGC_S_SESSION))
-                                                       elog(ERROR, "failed to reset %s", conf->gen.name);
+                                                       elog(ERROR, "failed to reset %s to %d",
+                                                                conf->gen.name, (int) conf->reset_val);
                                        *conf->variable = conf->reset_val;
-                                       conf->gen.source = conf->gen.reset_source;
                                        break;
                                }
                        case PGC_INT:
@@ -3339,9 +3691,9 @@ ResetAllOptions(void)
                                        if (conf->assign_hook)
                                                if (!(*conf->assign_hook) (conf->reset_val, true,
                                                                                                   PGC_S_SESSION))
-                                                       elog(ERROR, "failed to reset %s", conf->gen.name);
+                                                       elog(ERROR, "failed to reset %s to %d",
+                                                                conf->gen.name, conf->reset_val);
                                        *conf->variable = conf->reset_val;
-                                       conf->gen.source = conf->gen.reset_source;
                                        break;
                                }
                        case PGC_REAL:
@@ -3351,9 +3703,9 @@ ResetAllOptions(void)
                                        if (conf->assign_hook)
                                                if (!(*conf->assign_hook) (conf->reset_val, true,
                                                                                                   PGC_S_SESSION))
-                                                       elog(ERROR, "failed to reset %s", conf->gen.name);
+                                                       elog(ERROR, "failed to reset %s to %g",
+                                                                conf->gen.name, conf->reset_val);
                                        *conf->variable = conf->reset_val;
-                                       conf->gen.source = conf->gen.reset_source;
                                        break;
                                }
                        case PGC_STRING:
@@ -3371,7 +3723,8 @@ ResetAllOptions(void)
                                                newstr = (*conf->assign_hook) (str, true,
                                                                                                           PGC_S_SESSION);
                                                if (newstr == NULL)
-                                                       elog(ERROR, "failed to reset %s", conf->gen.name);
+                                                       elog(ERROR, "failed to reset %s to \"%s\"",
+                                                                conf->gen.name, str);
                                                else if (newstr != str)
                                                {
                                                        /*
@@ -3382,11 +3735,25 @@ ResetAllOptions(void)
                                        }
 
                                        set_string_field(conf, conf->variable, str);
-                                       conf->gen.source = conf->gen.reset_source;
+                                       break;
+                               }
+                       case PGC_ENUM:
+                               {
+                                       struct config_enum *conf = (struct config_enum *) gconf;
+
+                                       if (conf->assign_hook)
+                                               if (!(*conf->assign_hook) (conf->reset_val, true,
+                                                                                                  PGC_S_SESSION))
+                                                       elog(ERROR, "failed to reset %s to %s",
+                                                                conf->gen.name,
+                                                                config_enum_lookup_by_value(conf, conf->reset_val));
+                                       *conf->variable = conf->reset_val;
                                        break;
                                }
                }
 
+               gconf->source = gconf->reset_source;
+
                if (gconf->flags & GUC_REPORT)
                        ReportGUCOption(gconf);
        }
@@ -3650,8 +4017,8 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                                                                if (conf->assign_hook)
                                                                        if (!(*conf->assign_hook) (newval,
                                                                                                           true, PGC_S_OVERRIDE))
-                                                                               elog(LOG, "failed to commit %s",
-                                                                                        conf->gen.name);
+                                                                               elog(LOG, "failed to commit %s as %d",
+                                                                                        conf->gen.name, (int) newval);
                                                                *conf->variable = newval;
                                                                changed = true;
                                                        }
@@ -3667,8 +4034,8 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                                                                if (conf->assign_hook)
                                                                        if (!(*conf->assign_hook) (newval,
                                                                                                           true, PGC_S_OVERRIDE))
-                                                                               elog(LOG, "failed to commit %s",
-                                                                                        conf->gen.name);
+                                                                               elog(LOG, "failed to commit %s as %d",
+                                                                                        conf->gen.name, newval);
                                                                *conf->variable = newval;
                                                                changed = true;
                                                        }
@@ -3684,8 +4051,8 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                                                                if (conf->assign_hook)
                                                                        if (!(*conf->assign_hook) (newval,
                                                                                                           true, PGC_S_OVERRIDE))
-                                                                               elog(LOG, "failed to commit %s",
-                                                                                        conf->gen.name);
+                                                                               elog(LOG, "failed to commit %s as %g",
+                                                                                        conf->gen.name, newval);
                                                                *conf->variable = newval;
                                                                changed = true;
                                                        }
@@ -3705,8 +4072,8 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                                                                        newstr = (*conf->assign_hook) (newval, true,
                                                                                                                         PGC_S_OVERRIDE);
                                                                        if (newstr == NULL)
-                                                                               elog(LOG, "failed to commit %s",
-                                                                                        conf->gen.name);
+                                                                               elog(LOG, "failed to commit %s as \"%s\"",
+                                                                                        conf->gen.name, newval);
                                                                        else if (newstr != newval)
                                                                        {
                                                                                /*
@@ -3734,13 +4101,31 @@ AtEOXact_GUC(bool isCommit, int nestLevel)
                                                        set_string_field(conf, &stack->masked.stringval, NULL);
                                                        break;
                                                }
-                               }
-
-                               gconf->source = newsource;
-                       }
+                                       case PGC_ENUM:
+                                               {
+                                                       struct config_enum *conf = (struct config_enum *) gconf;
+                                                       int                     newval = newvalue.enumval;
 
-                       /* Finish popping the state stack */
-                       gconf->stack = prev;
+                                                       if (*conf->variable != newval)
+                                                       {
+                                                               if (conf->assign_hook)
+                                                                       if (!(*conf->assign_hook) (newval,
+                                                                                                          true, PGC_S_OVERRIDE))
+                                                                               elog(LOG, "failed to commit %s as %s",
+                                                                                        conf->gen.name,
+                                                                                        config_enum_lookup_by_value(conf, newval));
+                                                               *conf->variable = newval;
+                                                               changed = true;
+                                                       }
+                                                       break;
+                                               }
+                               }
+
+                               gconf->source = newsource;
+                       }
+
+                       /* Finish popping the state stack */
+                       gconf->stack = prev;
                        pfree(stack);
 
                        /* Report new value if we changed it */
@@ -3809,74 +4194,6 @@ ReportGUCOption(struct config_generic * record)
        }
 }
 
-
-/*
- * Try to interpret value as boolean value.  Valid values are: true,
- * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof.
- * If the string parses okay, return true, else false.
- * If okay and result is not NULL, return the value in *result.
- */
-static bool
-parse_bool(const char *value, bool *result)
-{
-       size_t          len = strlen(value);
-
-       if (pg_strncasecmp(value, "true", len) == 0)
-       {
-               if (result)
-                       *result = true;
-       }
-       else if (pg_strncasecmp(value, "false", len) == 0)
-       {
-               if (result)
-                       *result = false;
-       }
-
-       else if (pg_strncasecmp(value, "yes", len) == 0)
-       {
-               if (result)
-                       *result = true;
-       }
-       else if (pg_strncasecmp(value, "no", len) == 0)
-       {
-               if (result)
-                       *result = false;
-       }
-
-       /* 'o' is not unique enough */
-       else if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0)
-       {
-               if (result)
-                       *result = true;
-       }
-       else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0)
-       {
-               if (result)
-                       *result = false;
-       }
-
-       else if (pg_strcasecmp(value, "1") == 0)
-       {
-               if (result)
-                       *result = true;
-       }
-       else if (pg_strcasecmp(value, "0") == 0)
-       {
-               if (result)
-                       *result = false;
-       }
-
-       else
-       {
-               if (result)
-                       *result = false;        /* suppress compiler warning */
-               return false;
-       }
-       return true;
-}
-
-
-
 /*
  * Try to parse value as an integer.  The accepted formats are the
  * usual decimal, octal, or hexadecimal formats, optionally followed by
@@ -3887,7 +4204,7 @@ parse_bool(const char *value, bool *result)
  * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable
  *     HINT message, or NULL if no hint provided.
  */
-static bool
+bool
 parse_int(const char *value, int *result, int flags, const char **hintmsg)
 {
        int64           val;
@@ -3923,10 +4240,6 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
                /*
                 * Note: the multiple-switch coding technique here is a bit tedious,
                 * but seems necessary to avoid intermediate-value overflows.
-                *
-                * If INT64_IS_BUSTED (ie, it's really int32) we will fail to detect
-                * overflow due to units conversion, but there are few enough such
-                * machines that it does not seem worth trying to be smarter.
                 */
                if (flags & GUC_UNIT_MEMORY)
                {
@@ -4094,7 +4407,7 @@ parse_int(const char *value, int *result, int flags, const char **hintmsg)
  * If the string parses okay, return true, else false.
  * If okay and result is not NULL, return the value in *result.
  */
-static bool
+bool
 parse_real(const char *value, double *result)
 {
        double          val;
@@ -4120,6 +4433,103 @@ parse_real(const char *value, double *result)
 }
 
 
+/*
+ * Lookup the name for an enum option with the selected value.
+ * Should only ever be called with known-valid values, so throws
+ * an elog(ERROR) if the enum option is not found.
+ *
+ * The returned string is a pointer to static data and not
+ * allocated for modification.
+ */
+const char *
+config_enum_lookup_by_value(struct config_enum * record, int val)
+{
+       const struct config_enum_entry *entry;
+
+       for (entry = record->options; entry && entry->name; entry++)
+       {
+               if (entry->val == val)
+                       return entry->name;
+       }
+
+       elog(ERROR, "could not find enum option %d for %s",
+                val, record->gen.name);
+       return NULL;                            /* silence compiler */
+}
+
+
+/*
+ * Lookup the value for an enum option with the selected name
+ * (case-insensitive).
+ * If the enum option is found, sets the retval value and returns
+ * true. If it's not found, return FALSE and retval is set to 0.
+ */
+bool
+config_enum_lookup_by_name(struct config_enum * record, const char *value,
+                                                  int *retval)
+{
+       const struct config_enum_entry *entry;
+
+       for (entry = record->options; entry && entry->name; entry++)
+       {
+               if (pg_strcasecmp(value, entry->name) == 0)
+               {
+                       *retval = entry->val;
+                       return TRUE;
+               }
+       }
+
+       *retval = 0;
+       return FALSE;
+}
+
+
+/*
+ * Return a list of all available options for an enum, excluding
+ * hidden ones, separated by the given separator.
+ * If prefix is non-NULL, it is added before the first enum value.
+ * If suffix is non-NULL, it is added to the end of the string.
+ */
+static char *
+config_enum_get_options(struct config_enum * record, const char *prefix,
+                                               const char *suffix, const char *separator)
+{
+       const struct config_enum_entry *entry;
+       StringInfoData retstr;
+       int                     seplen;
+
+       initStringInfo(&retstr);
+       appendStringInfoString(&retstr, prefix);
+
+       seplen = strlen(separator);
+       for (entry = record->options; entry && entry->name; entry++)
+       {
+               if (!entry->hidden)
+               {
+                       appendStringInfoString(&retstr, entry->name);
+                       appendBinaryStringInfo(&retstr, separator, seplen);
+               }
+       }
+
+       /*
+        * All the entries may have been hidden, leaving the string empty if no
+        * prefix was given. This indicates a broken GUC setup, since there is no
+        * use for an enum without any values, so we just check to make sure we
+        * don't write to invalid memory instead of actually trying to do
+        * something smart with it.
+        */
+       if (retstr.len >= seplen)
+       {
+               /* Replace final separator */
+               retstr.data[retstr.len - seplen] = '\0';
+               retstr.len -= seplen;
+       }
+
+       appendStringInfoString(&retstr, suffix);
+
+       return retstr.data;
+}
+
 /*
  * Call a GucStringAssignHook function, being careful to free the
  * "newval" string if the hook ereports.
@@ -4192,8 +4602,9 @@ set_config_option(const char *name, const char *value,
                 */
                elevel = IsUnderPostmaster ? DEBUG3 : LOG;
        }
-       else if (source == PGC_S_DATABASE || source == PGC_S_USER)
-               elevel = INFO;
+       else if (source == PGC_S_DATABASE || source == PGC_S_USER ||
+                        source == PGC_S_DATABASE_USER)
+               elevel = WARNING;
        else
                elevel = ERROR;
 
@@ -4246,16 +4657,16 @@ set_config_option(const char *name, const char *value,
                                if (changeVal && !is_newvalue_equal(record, value))
                                        ereport(elevel,
                                                        (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
-                                                        errmsg("parameter \"%s\" cannot be changed after server start; configuration file change ignored",
-                                                                       name)));
+                                          errmsg("parameter \"%s\" cannot be changed without restarting the server",
+                                                         name)));
                                return true;
                        }
                        if (context != PGC_POSTMASTER)
                        {
                                ereport(elevel,
                                                (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
-                                                errmsg("parameter \"%s\" cannot be changed after server start",
-                                                               name)));
+                                          errmsg("parameter \"%s\" cannot be changed without restarting the server",
+                                                         name)));
                                return false;
                        }
                        break;
@@ -4290,7 +4701,8 @@ set_config_option(const char *name, const char *value,
                                if (IsUnderPostmaster)
                                        return true;
                        }
-                       else if (context != PGC_BACKEND && context != PGC_POSTMASTER)
+                       else if (context != PGC_POSTMASTER && context != PGC_BACKEND &&
+                                        source != PGC_S_CLIENT)
                        {
                                ereport(elevel,
                                                (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
@@ -4314,6 +4726,48 @@ set_config_option(const char *name, const char *value,
                        break;
        }
 
+       /*
+        * Disallow changing GUC_NOT_WHILE_SEC_REST values if we are inside a
+        * security restriction context.  We can reject this regardless of
+        * the GUC context or source, mainly because sources that it might be
+        * reasonable to override for won't be seen while inside a function.
+        *
+        * Note: variables marked GUC_NOT_WHILE_SEC_REST should usually be marked
+        * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this.
+        * An exception might be made if the reset value is assumed to be "safe".
+        *
+        * Note: this flag is currently used for "session_authorization" and
+        * "role".  We need to prohibit changing these inside a local userid
+        * context because when we exit it, GUC won't be notified, leaving things
+        * out of sync.  (This could be fixed by forcing a new GUC nesting level,
+        * but that would change behavior in possibly-undesirable ways.)  Also,
+        * we prohibit changing these in a security-restricted operation because
+        * otherwise RESET could be used to regain the session user's privileges.
+        */
+       if (record->flags & GUC_NOT_WHILE_SEC_REST)
+       {
+               if (InLocalUserIdChange())
+               {
+                       /*
+                        * Phrasing of this error message is historical, but it's the
+                        * most common case.
+                        */
+                       ereport(elevel,
+                                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                        errmsg("cannot set parameter \"%s\" within security-definer function",
+                                                       name)));
+                       return false;
+               }
+               if (InSecurityRestrictedOperation())
+               {
+                       ereport(elevel,
+                                       (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                        errmsg("cannot set parameter \"%s\" within security-restricted operation",
+                                                       name)));
+                       return false;
+               }
+       }
+
        /*
         * Should we set reset/stacked values?  (If so, the behavior is not
         * transactional.)      This is done either when we get a default value from
@@ -4370,6 +4824,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4380,32 +4838,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
-                                               {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
+                                               if (stack->source <= source)
                                                {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.boolval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.boolval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4427,7 +4879,7 @@ set_config_option(const char *name, const char *value,
                                                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                                 errmsg("invalid value for parameter \"%s\": \"%s\"",
                                                                name, value),
-                                                                hintmsg ? errhint(hintmsg) : 0));
+                                                                hintmsg ? errhint("%s", _(hintmsg)) : 0));
                                                return false;
                                        }
                                        if (newval < conf->min || newval > conf->max)
@@ -4447,6 +4899,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4457,32 +4913,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
-                                               {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
+                                               if (stack->source <= source)
                                                {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.intval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.intval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4521,6 +4971,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4531,32 +4985,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
-                                               {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
+                                               if (stack->source <= source)
                                                {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.realval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.realval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4610,6 +5058,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook && newval)
                                {
                                        const char *hookresult;
@@ -4647,41 +5099,107 @@ set_config_option(const char *name, const char *value,
                                        }
                                }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       set_string_field(conf, conf->variable, newval);
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
+                               {
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               set_string_field(conf, conf->variable, newval);
-                                               conf->gen.source = source;
+                                               set_string_field(conf, &conf->reset_val, newval);
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
+                                               if (stack->source <= source)
                                                {
-                                                       set_string_field(conf, &conf->reset_val, newval);
-                                                       conf->gen.reset_source = source;
+                                                       set_string_field(conf, &stack->prior.stringval,
+                                                                                        newval);
+                                                       stack->source = source;
                                                }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
+                                       }
+                               }
+                               /* Perhaps we didn't install newval anywhere */
+                               if (newval && !string_field_used(conf, newval))
+                                       free(newval);
+                               break;
+                       }
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) record;
+                               int                     newval;
+
+                               if (value)
+                               {
+                                       if (!config_enum_lookup_by_name(conf, value, &newval))
+                                       {
+                                               char       *hintmsg;
+
+                                               hintmsg = config_enum_get_options(conf,
+                                                                                                               "Available values: ",
+                                                                                                                 ".", ", ");
+
+                                               ereport(elevel,
+                                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                errmsg("invalid value for parameter \"%s\": \"%s\"",
+                                                               name, value),
+                                                                hintmsg ? errhint("%s", _(hintmsg)) : 0));
+
+                                               if (hintmsg)
+                                                       pfree(hintmsg);
+                                               return false;
+                                       }
+                               }
+                               else if (source == PGC_S_DEFAULT)
+                                       newval = conf->boot_val;
+                               else
+                               {
+                                       newval = conf->reset_val;
+                                       source = conf->gen.reset_source;
+                               }
+
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
+                               if (conf->assign_hook)
+                                       if (!(*conf->assign_hook) (newval, changeVal, source))
+                                       {
+                                               ereport(elevel,
+                                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                errmsg("invalid value for parameter \"%s\": \"%s\"",
+                                                               name,
+                                                               config_enum_lookup_by_value(conf, newval))));
+                                               return false;
+                                       }
+
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
+                               {
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
+                                       {
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
+                                       }
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
+                                       {
+                                               if (stack->source <= source)
                                                {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               set_string_field(conf, &stack->prior.stringval,
-                                                                                                newval);
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.enumval = newval;
+                                                       stack->source = source;
                                                }
-                                               /* Perhaps we didn't install newval anywhere */
-                                               if (newval && !string_field_used(conf, newval))
-                                                       free(newval);
                                        }
                                }
-                               else if (newval)
-                                       free(newval);
                                break;
                        }
        }
@@ -4693,10 +5211,40 @@ set_config_option(const char *name, const char *value,
 }
 
 
+/*
+ * Set the fields for source file and line number the setting came from.
+ */
+static void
+set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
+{
+       struct config_generic *record;
+       int                     elevel;
+
+       /*
+        * To avoid cluttering the log, only the postmaster bleats loudly about
+        * problems with the config file.
+        */
+       elevel = IsUnderPostmaster ? DEBUG3 : LOG;
+
+       record = find_option(name, true, elevel);
+       /* should not happen */
+       if (record == NULL)
+               elog(ERROR, "unrecognized configuration parameter \"%s\"", name);
+
+       sourcefile = guc_strdup(elevel, sourcefile);
+       if (record->sourcefile)
+               free(record->sourcefile);
+       record->sourcefile = sourcefile;
+       record->sourceline = sourceline;
+}
+
 /*
  * Set a config option to the given value. See also set_config_option,
  * this is just the wrapper to be called from outside GUC.     NB: this
  * is used only for non-transactional operations.
+ *
+ * Note: there is no support here for setting source file/line, as it
+ * is currently not needed.
  */
 void
 SetConfigOption(const char *name, const char *value,
@@ -4712,11 +5260,15 @@ SetConfigOption(const char *name, const char *value,
  * Fetch the current value of the option `name'. If the option doesn't exist,
  * throw an ereport and don't return.
  *
+ * If restrict_superuser is true, we also enforce that only superusers can
+ * see GUC_SUPERUSER_ONLY variables.  This should only be passed as true
+ * in user-driven calls.
+ *
  * The string is *not* allocated for modification and is really only
  * valid until the next call to configuration related functions.
  */
 const char *
-GetConfigOption(const char *name)
+GetConfigOption(const char *name, bool restrict_superuser)
 {
        struct config_generic *record;
        static char buffer[256];
@@ -4726,7 +5278,9 @@ GetConfigOption(const char *name)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                           errmsg("unrecognized configuration parameter \"%s\"", name)));
-       if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser())
+       if (restrict_superuser &&
+               (record->flags & GUC_SUPERUSER_ONLY) &&
+               !superuser())
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("must be superuser to examine \"%s\"", name)));
@@ -4748,6 +5302,10 @@ GetConfigOption(const char *name)
 
                case PGC_STRING:
                        return *((struct config_string *) record)->variable;
+
+               case PGC_ENUM:
+                       return config_enum_lookup_by_value((struct config_enum *) record,
+                                                                *((struct config_enum *) record)->variable);
        }
        return NULL;
 }
@@ -4792,26 +5350,14 @@ GetConfigOptionResetString(const char *name)
 
                case PGC_STRING:
                        return ((struct config_string *) record)->reset_val;
+
+               case PGC_ENUM:
+                       return config_enum_lookup_by_value((struct config_enum *) record,
+                                                                ((struct config_enum *) record)->reset_val);
        }
        return NULL;
 }
 
-/*
- * Detect whether the given configuration option can only be set by
- * a superuser.
- */
-bool
-IsSuperuserConfigOption(const char *name)
-{
-       struct config_generic *record;
-
-       record = find_option(name, false, ERROR);
-       /* On an unrecognized name, don't error, just return false. */
-       if (record == NULL)
-               return false;
-       return (record->context == PGC_SUSET);
-}
-
 
 /*
  * GUC_complaint_elevel
@@ -4821,7 +5367,7 @@ IsSuperuserConfigOption(const char *name)
  * report (in addition to the generic "invalid value for option FOO" that
  * guc.c will provide).  Note that the result might be ERROR or a lower
  * level, so the caller must be prepared for control to return from ereport,
- * or not.  If control does return, return false/NULL from the hook function.
+ * or not.     If control does return, return false/NULL from the hook function.
  *
  * At some point it'd be nice to replace this with a mechanism that allows
  * the custom message to become the DETAIL line of guc.c's generic message.
@@ -4843,9 +5389,9 @@ GUC_complaint_elevel(GucSource source)
        {
                /*
                 * If we're a postmaster child, this is probably "undo" during
-                * transaction abort, so we don't want to clutter the log.  There's
-                * a small chance of a real problem with an OVERRIDE setting,
-                * though, so suppressing the message entirely wouldn't be desirable.
+                * transaction abort, so we don't want to clutter the log.  There's a
+                * small chance of a real problem with an OVERRIDE setting, though, so
+                * suppressing the message entirely wouldn't be desirable.
                 */
                elevel = IsUnderPostmaster ? DEBUG5 : LOG;
        }
@@ -4899,29 +5445,45 @@ flatten_set_variable_args(const char *name, List *args)
 
        initStringInfo(&buf);
 
+       /*
+        * Each list member may be a plain A_Const node, or an A_Const within a
+        * TypeCast; the latter case is supported only for ConstInterval arguments
+        * (for SET TIME ZONE).
+        */
        foreach(l, args)
        {
-               A_Const    *arg = (A_Const *) lfirst(l);
+               Node       *arg = (Node *) lfirst(l);
                char       *val;
+               TypeName   *typeName = NULL;
+               A_Const    *con;
 
                if (l != list_head(args))
                        appendStringInfo(&buf, ", ");
 
+               if (IsA(arg, TypeCast))
+               {
+                       TypeCast   *tc = (TypeCast *) arg;
+
+                       arg = tc->arg;
+                       typeName = tc->typeName;
+               }
+
                if (!IsA(arg, A_Const))
                        elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
+               con = (A_Const *) arg;
 
-               switch (nodeTag(&arg->val))
+               switch (nodeTag(&con->val))
                {
                        case T_Integer:
-                               appendStringInfo(&buf, "%ld", intVal(&arg->val));
+                               appendStringInfo(&buf, "%ld", intVal(&con->val));
                                break;
                        case T_Float:
                                /* represented as a string, so just copy it */
-                               appendStringInfoString(&buf, strVal(&arg->val));
+                               appendStringInfoString(&buf, strVal(&con->val));
                                break;
                        case T_String:
-                               val = strVal(&arg->val);
-                               if (arg->typename != NULL)
+                               val = strVal(&con->val);
+                               if (typeName != NULL)
                                {
                                        /*
                                         * Must be a ConstInterval argument for TIME ZONE. Coerce
@@ -4933,7 +5495,7 @@ flatten_set_variable_args(const char *name, List *args)
                                        Datum           interval;
                                        char       *intervalout;
 
-                                       typoid = typenameTypeId(NULL, arg->typename, &typmod);
+                                       typoid = typenameTypeId(NULL, typeName, &typmod);
                                        Assert(typoid == INTERVALOID);
 
                                        interval =
@@ -4961,7 +5523,7 @@ flatten_set_variable_args(const char *name, List *args)
                                break;
                        default:
                                elog(ERROR, "unrecognized node type: %d",
-                                        (int) nodeTag(&arg->val));
+                                        (int) nodeTag(&con->val));
                                break;
                }
        }
@@ -5102,7 +5664,6 @@ set_config_by_name(PG_FUNCTION_ARGS)
        char       *value;
        char       *new_value;
        bool            is_local;
-       text       *result_text;
 
        if (PG_ARGISNULL(0))
                ereport(ERROR,
@@ -5110,13 +5671,13 @@ set_config_by_name(PG_FUNCTION_ARGS)
                                 errmsg("SET requires parameter name")));
 
        /* Get the GUC variable name */
-       name = DatumGetCString(DirectFunctionCall1(textout, PG_GETARG_DATUM(0)));
+       name = TextDatumGetCString(PG_GETARG_DATUM(0));
 
        /* Get the desired value or set to NULL for a reset request */
        if (PG_ARGISNULL(1))
                value = NULL;
        else
-               value = DatumGetCString(DirectFunctionCall1(textout, PG_GETARG_DATUM(1)));
+               value = TextDatumGetCString(PG_GETARG_DATUM(1));
 
        /*
         * Get the desired state of is_local. Default to false if provided value
@@ -5139,10 +5700,7 @@ set_config_by_name(PG_FUNCTION_ARGS)
        new_value = GetConfigOptionByName(name, NULL);
 
        /* Convert return string to text */
-       result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(new_value)));
-
-       /* return it */
-       PG_RETURN_TEXT_P(result_text);
+       PG_RETURN_TEXT_P(cstring_to_text(new_value));
 }
 
 
@@ -5155,11 +5713,23 @@ init_custom_variable(const char *name,
                                         const char *short_desc,
                                         const char *long_desc,
                                         GucContext context,
+                                        int flags,
                                         enum config_type type,
                                         size_t sz)
 {
        struct config_generic *gen;
 
+       /*
+        * Only allow custom PGC_POSTMASTER variables to be created during shared
+        * library preload; any later than that, we can't ensure that the value
+        * doesn't change after startup.  This is a fatal elog if it happens; just
+        * erroring out isn't safe because we don't know what the calling loadable
+        * module might already have hooked into.
+        */
+       if (context == PGC_POSTMASTER &&
+               !process_shared_preload_libraries_in_progress)
+               elog(FATAL, "cannot create PGC_POSTMASTER variables after startup");
+
        gen = (struct config_generic *) guc_malloc(ERROR, sz);
        memset(gen, 0, sz);
 
@@ -5168,6 +5738,7 @@ init_custom_variable(const char *name,
        gen->group = CUSTOM_OPTIONS;
        gen->short_desc = short_desc;
        gen->long_desc = long_desc;
+       gen->flags = flags;
        gen->vartype = type;
 
        return gen;
@@ -5184,8 +5755,12 @@ define_custom_variable(struct config_generic * variable)
        const char **nameAddr = &name;
        const char *value;
        struct config_string *pHolder;
+       GucContext      phcontext;
        struct config_generic **res;
 
+       /*
+        * See if there's a placeholder by the same name.
+        */
        res = (struct config_generic **) bsearch((void *) &nameAddr,
                                                                                         (void *) guc_variables,
                                                                                         num_guc_variables,
@@ -5193,7 +5768,11 @@ define_custom_variable(struct config_generic * variable)
                                                                                         guc_var_compare);
        if (res == NULL)
        {
-               /* No placeholder to replace, so just add it */
+               /*
+                * No placeholder to replace, so we can just add it ... but first,
+                * make sure it's initialized to its default value.
+                */
+               InitializeOneGUCOption(variable);
                add_guc_variable(variable, ERROR);
                return;
        }
@@ -5209,6 +5788,13 @@ define_custom_variable(struct config_generic * variable)
        Assert((*res)->vartype == PGC_STRING);
        pHolder = (struct config_string *) (*res);
 
+       /*
+        * First, set the variable to its default value.  We must do this even
+        * though we intend to immediately apply a new value, since it's possible
+        * that the new value is invalid.
+        */
+       InitializeOneGUCOption(variable);
+
        /*
         * Replace the placeholder. We aren't changing the name, so no re-sorting
         * is necessary
@@ -5216,18 +5802,58 @@ define_custom_variable(struct config_generic * variable)
        *res = variable;
 
        /*
-        * Assign the string value stored in the placeholder to the real variable.
-        *
-        * XXX this is not really good enough --- it should be a nontransactional
-        * assignment, since we don't want it to roll back if the current xact
-        * fails later.
+        * Infer context for assignment based on source of existing value. We
+        * can't tell this with exact accuracy, but we can at least do something
+        * reasonable in typical cases.
         */
-       value = *pHolder->variable;
+       switch (pHolder->gen.source)
+       {
+               case PGC_S_DEFAULT:
+               case PGC_S_ENV_VAR:
+               case PGC_S_FILE:
+               case PGC_S_ARGV:
 
-       if (value)
-               set_config_option(name, value,
-                                                 pHolder->gen.context, pHolder->gen.source,
-                                                 GUC_ACTION_SET, true);
+                       /*
+                        * If we got past the check in init_custom_variable, we can safely
+                        * assume that any existing value for a PGC_POSTMASTER variable
+                        * was set in postmaster context.
+                        */
+                       if (variable->context == PGC_POSTMASTER)
+                               phcontext = PGC_POSTMASTER;
+                       else
+                               phcontext = PGC_SIGHUP;
+                       break;
+               case PGC_S_DATABASE:
+               case PGC_S_USER:
+               case PGC_S_DATABASE_USER:
+               case PGC_S_CLIENT:
+               case PGC_S_SESSION:
+               default:
+                       phcontext = PGC_USERSET;
+                       break;
+       }
+
+       /*
+        * Assign the string value stored in the placeholder to the real variable.
+        *
+        * XXX this is not really good enough --- it should be a nontransactional
+        * assignment, since we don't want it to roll back if the current xact
+        * fails later.  (Or do we?)
+        */
+       value = *pHolder->variable;
+
+       if (value)
+       {
+               if (set_config_option(name, value,
+                                                         phcontext, pHolder->gen.source,
+                                                         GUC_ACTION_SET, true))
+               {
+                       /* Also copy over any saved source-location information */
+                       if (pHolder->gen.sourcefile)
+                               set_config_sourcefile(name, pHolder->gen.sourcefile,
+                                                                         pHolder->gen.sourceline);
+               }
+       }
 
        /*
         * Free up as much as we conveniently can of the placeholder structure
@@ -5244,18 +5870,20 @@ DefineCustomBoolVariable(const char *name,
                                                 const char *short_desc,
                                                 const char *long_desc,
                                                 bool *valueAddr,
+                                                bool bootValue,
                                                 GucContext context,
+                                                int flags,
                                                 GucBoolAssignHook assign_hook,
                                                 GucShowHook show_hook)
 {
        struct config_bool *var;
 
        var = (struct config_bool *)
-               init_custom_variable(name, short_desc, long_desc, context,
+               init_custom_variable(name, short_desc, long_desc, context, flags,
                                                         PGC_BOOL, sizeof(struct config_bool));
        var->variable = valueAddr;
-       var->boot_val = *valueAddr;
-       var->reset_val = *valueAddr;
+       var->boot_val = bootValue;
+       var->reset_val = bootValue;
        var->assign_hook = assign_hook;
        var->show_hook = show_hook;
        define_custom_variable(&var->gen);
@@ -5266,20 +5894,22 @@ DefineCustomIntVariable(const char *name,
                                                const char *short_desc,
                                                const char *long_desc,
                                                int *valueAddr,
+                                               int bootValue,
                                                int minValue,
                                                int maxValue,
                                                GucContext context,
+                                               int flags,
                                                GucIntAssignHook assign_hook,
                                                GucShowHook show_hook)
 {
        struct config_int *var;
 
        var = (struct config_int *)
-               init_custom_variable(name, short_desc, long_desc, context,
+               init_custom_variable(name, short_desc, long_desc, context, flags,
                                                         PGC_INT, sizeof(struct config_int));
        var->variable = valueAddr;
-       var->boot_val = *valueAddr;
-       var->reset_val = *valueAddr;
+       var->boot_val = bootValue;
+       var->reset_val = bootValue;
        var->min = minValue;
        var->max = maxValue;
        var->assign_hook = assign_hook;
@@ -5292,20 +5922,22 @@ DefineCustomRealVariable(const char *name,
                                                 const char *short_desc,
                                                 const char *long_desc,
                                                 double *valueAddr,
+                                                double bootValue,
                                                 double minValue,
                                                 double maxValue,
                                                 GucContext context,
+                                                int flags,
                                                 GucRealAssignHook assign_hook,
                                                 GucShowHook show_hook)
 {
        struct config_real *var;
 
        var = (struct config_real *)
-               init_custom_variable(name, short_desc, long_desc, context,
+               init_custom_variable(name, short_desc, long_desc, context, flags,
                                                         PGC_REAL, sizeof(struct config_real));
        var->variable = valueAddr;
-       var->boot_val = *valueAddr;
-       var->reset_val = *valueAddr;
+       var->boot_val = bootValue;
+       var->reset_val = bootValue;
        var->min = minValue;
        var->max = maxValue;
        var->assign_hook = assign_hook;
@@ -5318,17 +5950,19 @@ DefineCustomStringVariable(const char *name,
                                                   const char *short_desc,
                                                   const char *long_desc,
                                                   char **valueAddr,
+                                                  const char *bootValue,
                                                   GucContext context,
+                                                  int flags,
                                                   GucStringAssignHook assign_hook,
                                                   GucShowHook show_hook)
 {
        struct config_string *var;
 
        var = (struct config_string *)
-               init_custom_variable(name, short_desc, long_desc, context,
+               init_custom_variable(name, short_desc, long_desc, context, flags,
                                                         PGC_STRING, sizeof(struct config_string));
        var->variable = valueAddr;
-       var->boot_val = *valueAddr;
+       var->boot_val = bootValue;
        /* we could probably do without strdup, but keep it like normal case */
        if (var->boot_val)
                var->reset_val = guc_strdup(ERROR, var->boot_val);
@@ -5338,24 +5972,49 @@ DefineCustomStringVariable(const char *name,
 }
 
 void
-EmitWarningsOnPlaceholders(const char *className)
+DefineCustomEnumVariable(const char *name,
+                                                const char *short_desc,
+                                                const char *long_desc,
+                                                int *valueAddr,
+                                                int bootValue,
+                                                const struct config_enum_entry * options,
+                                                GucContext context,
+                                                int flags,
+                                                GucEnumAssignHook assign_hook,
+                                                GucShowHook show_hook)
 {
-       struct config_generic **vars = guc_variables;
-       struct config_generic **last = vars + num_guc_variables;
+       struct config_enum *var;
 
-       int                     nameLen = strlen(className);
+       var = (struct config_enum *)
+               init_custom_variable(name, short_desc, long_desc, context, flags,
+                                                        PGC_ENUM, sizeof(struct config_enum));
+       var->variable = valueAddr;
+       var->boot_val = bootValue;
+       var->reset_val = bootValue;
+       var->options = options;
+       var->assign_hook = assign_hook;
+       var->show_hook = show_hook;
+       define_custom_variable(&var->gen);
+}
 
-       while (vars < last)
+void
+EmitWarningsOnPlaceholders(const char *className)
+{
+       int                     classLen = strlen(className);
+       int                     i;
+
+       for (i = 0; i < num_guc_variables; i++)
        {
-               struct config_generic *var = *vars++;
+               struct config_generic *var = guc_variables[i];
 
                if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 &&
-                       strncmp(className, var->name, nameLen) == 0 &&
-                       var->name[nameLen] == GUC_QUALIFIER_SEPARATOR)
+                       strncmp(className, var->name, classLen) == 0 &&
+                       var->name[classLen] == GUC_QUALIFIER_SEPARATOR)
                {
-                       ereport(INFO,
+                       ereport(WARNING,
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                        errmsg("unrecognized configuration parameter \"%s\"", var->name)));
+                                        errmsg("unrecognized configuration parameter \"%s\"",
+                                                       var->name)));
                }
        }
 }
@@ -5388,7 +6047,6 @@ GetPGVariableResultDesc(const char *name)
                                                   TEXTOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
                                                   TEXTOID, -1, 0);
-
        }
        else
        {
@@ -5444,7 +6102,8 @@ ShowAllGUCConfig(DestReceiver *dest)
        int                     i;
        TupOutputState *tstate;
        TupleDesc       tupdesc;
-       char       *values[3];
+       Datum       values[3];
+       bool            isnull[3] = { false, false, false };
 
        /* need a tuple descriptor representing three TEXT columns */
        tupdesc = CreateTemplateTupleDesc(3, false);
@@ -5455,29 +6114,46 @@ ShowAllGUCConfig(DestReceiver *dest)
        TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
                                           TEXTOID, -1, 0);
 
-
        /* prepare for projection of tuples */
        tstate = begin_tup_output_tupdesc(dest, tupdesc);
 
        for (i = 0; i < num_guc_variables; i++)
        {
                struct config_generic *conf = guc_variables[i];
+               char   *setting;
 
                if ((conf->flags & GUC_NO_SHOW_ALL) ||
                        ((conf->flags & GUC_SUPERUSER_ONLY) && !am_superuser))
                        continue;
 
                /* assign to the values array */
-               values[0] = (char *) conf->name;
-               values[1] = _ShowOption(conf, true);
-               values[2] = (char *) conf->short_desc;
+               values[0] = PointerGetDatum(cstring_to_text(conf->name));
+
+               setting = _ShowOption(conf, true);
+               if (setting)
+               {
+                       values[1] = PointerGetDatum(cstring_to_text(setting));
+                       isnull[1] = false;
+               }
+               else
+               {
+                       values[1] = PointerGetDatum(NULL);
+                       isnull[1] = true;
+               }
+
+               values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
 
                /* send it to dest */
-               do_tup_output(tstate, values);
+               do_tup_output(tstate, values, isnull);
 
                /* clean up */
-               if (values[1] != NULL)
-                       pfree(values[1]);
+               pfree(DatumGetPointer(values[0]));
+               if (setting)
+               {
+                       pfree(setting);
+                       pfree(DatumGetPointer(values[1]));
+               }
+               pfree(DatumGetPointer(values[2]));
        }
 
        end_tup_output(tstate);
@@ -5598,11 +6274,22 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
        {
                case PGC_BOOL:
                        {
+                               struct config_bool *lconf = (struct config_bool *) conf;
+
                                /* min_val */
                                values[9] = NULL;
 
                                /* max_val */
                                values[10] = NULL;
+
+                               /* enumvals */
+                               values[11] = NULL;
+
+                               /* boot_val */
+                               values[12] = pstrdup(lconf->boot_val ? "on" : "off");
+
+                               /* reset_val */
+                               values[13] = pstrdup(lconf->reset_val ? "on" : "off");
                        }
                        break;
 
@@ -5617,6 +6304,17 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
                                /* max_val */
                                snprintf(buffer, sizeof(buffer), "%d", lconf->max);
                                values[10] = pstrdup(buffer);
+
+                               /* enumvals */
+                               values[11] = NULL;
+
+                               /* boot_val */
+                               snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
+                               values[12] = pstrdup(buffer);
+
+                               /* reset_val */
+                               snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
+                               values[13] = pstrdup(buffer);
                        }
                        break;
 
@@ -5631,16 +6329,73 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
                                /* max_val */
                                snprintf(buffer, sizeof(buffer), "%g", lconf->max);
                                values[10] = pstrdup(buffer);
+
+                               /* enumvals */
+                               values[11] = NULL;
+
+                               /* boot_val */
+                               snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
+                               values[12] = pstrdup(buffer);
+
+                               /* reset_val */
+                               snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
+                               values[13] = pstrdup(buffer);
                        }
                        break;
 
                case PGC_STRING:
                        {
+                               struct config_string *lconf = (struct config_string *) conf;
+
+                               /* min_val */
+                               values[9] = NULL;
+
+                               /* max_val */
+                               values[10] = NULL;
+
+                               /* enumvals */
+                               values[11] = NULL;
+
+                               /* boot_val */
+                               if (lconf->boot_val == NULL)
+                                       values[12] = NULL;
+                               else
+                                       values[12] = pstrdup(lconf->boot_val);
+
+                               /* reset_val */
+                               if (lconf->reset_val == NULL)
+                                       values[13] = NULL;
+                               else
+                                       values[13] = pstrdup(lconf->reset_val);
+                       }
+                       break;
+
+               case PGC_ENUM:
+                       {
+                               struct config_enum *lconf = (struct config_enum *) conf;
+
                                /* min_val */
                                values[9] = NULL;
 
                                /* max_val */
                                values[10] = NULL;
+
+                               /* enumvals */
+
+                               /*
+                                * NOTE! enumvals with double quotes in them are not
+                                * supported!
+                                */
+                               values[11] = config_enum_get_options((struct config_enum *) conf,
+                                                                                                        "{\"", "\"}", "\",\"");
+
+                               /* boot_val */
+                               values[12] = pstrdup(config_enum_lookup_by_value(lconf,
+                                                                                                                  lconf->boot_val));
+
+                               /* reset_val */
+                               values[13] = pstrdup(config_enum_lookup_by_value(lconf,
+                                                                                                                 lconf->reset_val));
                        }
                        break;
 
@@ -5655,9 +6410,35 @@ GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
 
                                /* max_val */
                                values[10] = NULL;
+
+                               /* enumvals */
+                               values[11] = NULL;
+
+                               /* boot_val */
+                               values[12] = NULL;
+
+                               /* reset_val */
+                               values[13] = NULL;
                        }
                        break;
        }
+
+       /*
+        * If the setting came from a config file, set the source location. For
+        * security reasons, we don't show source file/line number for
+        * non-superusers.
+        */
+       if (conf->source == PGC_S_FILE && superuser())
+       {
+               values[14] = conf->sourcefile;
+               snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
+               values[15] = pstrdup(buffer);
+       }
+       else
+       {
+               values[14] = NULL;
+               values[15] = NULL;
+       }
 }
 
 /*
@@ -5678,26 +6459,22 @@ show_config_by_name(PG_FUNCTION_ARGS)
 {
        char       *varname;
        char       *varval;
-       text       *result_text;
 
        /* Get the GUC variable name */
-       varname = DatumGetCString(DirectFunctionCall1(textout, PG_GETARG_DATUM(0)));
+       varname = TextDatumGetCString(PG_GETARG_DATUM(0));
 
        /* Get the value */
        varval = GetConfigOptionByName(varname, NULL);
 
        /* Convert to text */
-       result_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(varval)));
-
-       /* return it */
-       PG_RETURN_TEXT_P(result_text);
+       PG_RETURN_TEXT_P(cstring_to_text(varval));
 }
 
 /*
  * show_all_settings - equiv to SHOW ALL command but implemented as
  * a Table Function.
  */
-#define NUM_PG_SETTINGS_ATTS   11
+#define NUM_PG_SETTINGS_ATTS   16
 
 Datum
 show_all_settings(PG_FUNCTION_ARGS)
@@ -5747,6 +6524,16 @@ show_all_settings(PG_FUNCTION_ARGS)
                                                   TEXTOID, -1, 0);
                TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
                                                   TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
+                                                  TEXTARRAYOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
+                                                  TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
+                                                  TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
+                                                  TEXTOID, -1, 0);
+               TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
+                                                  INT4OID, -1, 0);
 
                /*
                 * Generate attribute metadata needed later to produce tuples from raw
@@ -5834,10 +6621,15 @@ _ShowOption(struct config_generic * record, bool use_units)
                                        val = (*conf->show_hook) ();
                                else
                                {
-                                       char            unit[4];
-                                       int                     result = *conf->variable;
+                                       /*
+                                        * Use int64 arithmetic to avoid overflows in units
+                                        * conversion.
+                                        */
+                                       int64           result = *conf->variable;
+                                       const char *unit;
 
-                                       if (use_units && result > 0 && (record->flags & GUC_UNIT_MEMORY))
+                                       if (use_units && result > 0 &&
+                                               (record->flags & GUC_UNIT_MEMORY))
                                        {
                                                switch (record->flags & GUC_UNIT_MEMORY)
                                                {
@@ -5852,19 +6644,20 @@ _ShowOption(struct config_generic * record, bool use_units)
                                                if (result % KB_PER_GB == 0)
                                                {
                                                        result /= KB_PER_GB;
-                                                       strcpy(unit, "GB");
+                                                       unit = "GB";
                                                }
                                                else if (result % KB_PER_MB == 0)
                                                {
                                                        result /= KB_PER_MB;
-                                                       strcpy(unit, "MB");
+                                                       unit = "MB";
                                                }
                                                else
                                                {
-                                                       strcpy(unit, "kB");
+                                                       unit = "kB";
                                                }
                                        }
-                                       else if (use_units && result > 0 && (record->flags & GUC_UNIT_TIME))
+                                       else if (use_units && result > 0 &&
+                                                        (record->flags & GUC_UNIT_TIME))
                                        {
                                                switch (record->flags & GUC_UNIT_TIME)
                                                {
@@ -5879,33 +6672,33 @@ _ShowOption(struct config_generic * record, bool use_units)
                                                if (result % MS_PER_D == 0)
                                                {
                                                        result /= MS_PER_D;
-                                                       strcpy(unit, "d");
+                                                       unit = "d";
                                                }
                                                else if (result % MS_PER_H == 0)
                                                {
                                                        result /= MS_PER_H;
-                                                       strcpy(unit, "h");
+                                                       unit = "h";
                                                }
                                                else if (result % MS_PER_MIN == 0)
                                                {
                                                        result /= MS_PER_MIN;
-                                                       strcpy(unit, "min");
+                                                       unit = "min";
                                                }
                                                else if (result % MS_PER_S == 0)
                                                {
                                                        result /= MS_PER_S;
-                                                       strcpy(unit, "s");
+                                                       unit = "s";
                                                }
                                                else
                                                {
-                                                       strcpy(unit, "ms");
+                                                       unit = "ms";
                                                }
                                        }
                                        else
-                                               strcpy(unit, "");
+                                               unit = "";
 
-                                       snprintf(buffer, sizeof(buffer), "%d%s",
-                                                        (int) result, unit);
+                                       snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s",
+                                                        result, unit);
                                        val = buffer;
                                }
                        }
@@ -5939,6 +6732,17 @@ _ShowOption(struct config_generic * record, bool use_units)
                        }
                        break;
 
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) record;
+
+                               if (conf->show_hook)
+                                       val = (*conf->show_hook) ();
+                               else
+                                       val = config_enum_lookup_by_value(conf, *conf->variable);
+                       }
+                       break;
+
                default:
                        /* just to keep compiler quiet */
                        val = "???";
@@ -5995,6 +6799,15 @@ is_newvalue_equal(struct config_generic * record, const char *newvalue)
                                return *conf->variable != NULL &&
                                        strcmp(*conf->variable, newvalue) == 0;
                        }
+
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) record;
+                               int                     newval;
+
+                               return config_enum_lookup_by_name(conf, newvalue, &newval) &&
+                                       *conf->variable == newval;
+                       }
        }
 
        return false;
@@ -6004,19 +6817,82 @@ is_newvalue_equal(struct config_generic * record, const char *newvalue)
 #ifdef EXEC_BACKEND
 
 /*
- *     This routine dumps out all non-default GUC options into a binary
+ *     These routines dump out all non-default GUC options into a binary
  *     file that is read by all exec'ed backends.  The format is:
  *
  *             variable name, string, null terminated
  *             variable value, string, null terminated
  *             variable source, integer
  */
+static void
+write_one_nondefault_variable(FILE *fp, struct config_generic * gconf)
+{
+       if (gconf->source == PGC_S_DEFAULT)
+               return;
+
+       fprintf(fp, "%s", gconf->name);
+       fputc(0, fp);
+
+       switch (gconf->vartype)
+       {
+               case PGC_BOOL:
+                       {
+                               struct config_bool *conf = (struct config_bool *) gconf;
+
+                               if (*conf->variable)
+                                       fprintf(fp, "true");
+                               else
+                                       fprintf(fp, "false");
+                       }
+                       break;
+
+               case PGC_INT:
+                       {
+                               struct config_int *conf = (struct config_int *) gconf;
+
+                               fprintf(fp, "%d", *conf->variable);
+                       }
+                       break;
+
+               case PGC_REAL:
+                       {
+                               struct config_real *conf = (struct config_real *) gconf;
+
+                               /* Could lose precision here? */
+                               fprintf(fp, "%f", *conf->variable);
+                       }
+                       break;
+
+               case PGC_STRING:
+                       {
+                               struct config_string *conf = (struct config_string *) gconf;
+
+                               fprintf(fp, "%s", *conf->variable);
+                       }
+                       break;
+
+               case PGC_ENUM:
+                       {
+                               struct config_enum *conf = (struct config_enum *) gconf;
+
+                               fprintf(fp, "%s",
+                                               config_enum_lookup_by_value(conf, *conf->variable));
+                       }
+                       break;
+       }
+
+       fputc(0, fp);
+
+       fwrite(&gconf->source, sizeof(gconf->source), 1, fp);
+}
+
 void
 write_nondefault_variables(GucContext context)
 {
-       int                     i;
        int                     elevel;
        FILE       *fp;
+       struct config_generic *cvc_conf;
+       int                     i;
 
        Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
 
@@ -6035,58 +6911,20 @@ write_nondefault_variables(GucContext context)
                return;
        }
 
+       /*
+        * custom_variable_classes must be written out first; otherwise we might
+        * reject custom variable values while reading the file.
+        */
+       cvc_conf = find_option("custom_variable_classes", false, ERROR);
+       if (cvc_conf)
+               write_one_nondefault_variable(fp, cvc_conf);
+
        for (i = 0; i < num_guc_variables; i++)
        {
                struct config_generic *gconf = guc_variables[i];
 
-               if (gconf->source != PGC_S_DEFAULT)
-               {
-                       fprintf(fp, "%s", gconf->name);
-                       fputc(0, fp);
-
-                       switch (gconf->vartype)
-                       {
-                               case PGC_BOOL:
-                                       {
-                                               struct config_bool *conf = (struct config_bool *) gconf;
-
-                                               if (*conf->variable == 0)
-                                                       fprintf(fp, "false");
-                                               else
-                                                       fprintf(fp, "true");
-                                       }
-                                       break;
-
-                               case PGC_INT:
-                                       {
-                                               struct config_int *conf = (struct config_int *) gconf;
-
-                                               fprintf(fp, "%d", *conf->variable);
-                                       }
-                                       break;
-
-                               case PGC_REAL:
-                                       {
-                                               struct config_real *conf = (struct config_real *) gconf;
-
-                                               /* Could lose precision here? */
-                                               fprintf(fp, "%f", *conf->variable);
-                                       }
-                                       break;
-
-                               case PGC_STRING:
-                                       {
-                                               struct config_string *conf = (struct config_string *) gconf;
-
-                                               fprintf(fp, "%s", *conf->variable);
-                                       }
-                                       break;
-                       }
-
-                       fputc(0, fp);
-
-                       fwrite(&gconf->source, sizeof(gconf->source), 1, fp);
-               }
+               if (gconf != cvc_conf)
+                       write_one_nondefault_variable(fp, gconf);
        }
 
        if (FreeFile(fp))
@@ -6265,7 +7103,7 @@ ProcessGUCArray(ArrayType *array,
                if (isnull)
                        continue;
 
-               s = DatumGetCString(DirectFunctionCall1(textout, d));
+               s = TextDatumGetCString(d);
 
                ParseLongOption(s, &name, &value);
                if (!value)
@@ -6313,7 +7151,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
 
        newval = palloc(strlen(name) + 1 + strlen(value) + 1);
        sprintf(newval, "%s=%s", name, value);
-       datum = DirectFunctionCall1(textin, CStringGetDatum(newval));
+       datum = CStringGetTextDatum(newval);
 
        if (array)
        {
@@ -6340,7 +7178,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
                                                  &isnull);
                        if (isnull)
                                continue;
-                       current = DatumGetCString(DirectFunctionCall1(textout, d));
+                       current = TextDatumGetCString(d);
                        if (strncmp(current, newval, strlen(name) + 1) == 0)
                        {
                                index = i;
@@ -6410,7 +7248,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
                                          &isnull);
                if (isnull)
                        continue;
-               val = DatumGetCString(DirectFunctionCall1(textout, d));
+               val = TextDatumGetCString(d);
 
                /* ignore entry if it's what we want to delete */
                if (strncmp(val, name, strlen(name)) == 0
@@ -6463,7 +7301,7 @@ assign_log_destination(const char *value, bool doit, GucSource source)
                list_free(elemlist);
                ereport(GUC_complaint_elevel(source),
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                       errmsg("invalid list syntax for parameter \"log_destination\"")));
+                  errmsg("invalid list syntax for parameter \"log_destination\"")));
                return NULL;
        }
 
@@ -6506,38 +7344,14 @@ assign_log_destination(const char *value, bool doit, GucSource source)
 
 #ifdef HAVE_SYSLOG
 
-static const char *
-assign_syslog_facility(const char *facility, bool doit, GucSource source)
+static bool
+assign_syslog_facility(int newval, bool doit, GucSource source)
 {
-       int                     syslog_fac;
-
-       if (pg_strcasecmp(facility, "LOCAL0") == 0)
-               syslog_fac = LOG_LOCAL0;
-       else if (pg_strcasecmp(facility, "LOCAL1") == 0)
-               syslog_fac = LOG_LOCAL1;
-       else if (pg_strcasecmp(facility, "LOCAL2") == 0)
-               syslog_fac = LOG_LOCAL2;
-       else if (pg_strcasecmp(facility, "LOCAL3") == 0)
-               syslog_fac = LOG_LOCAL3;
-       else if (pg_strcasecmp(facility, "LOCAL4") == 0)
-               syslog_fac = LOG_LOCAL4;
-       else if (pg_strcasecmp(facility, "LOCAL5") == 0)
-               syslog_fac = LOG_LOCAL5;
-       else if (pg_strcasecmp(facility, "LOCAL6") == 0)
-               syslog_fac = LOG_LOCAL6;
-       else if (pg_strcasecmp(facility, "LOCAL7") == 0)
-               syslog_fac = LOG_LOCAL7;
-       else
-               return NULL;                    /* reject */
-
        if (doit)
-       {
-               syslog_facility = syslog_fac;
                set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres",
-                                                         syslog_facility);
-       }
+                                                         newval);
 
-       return facility;
+       return true;
 }
 
 static const char *
@@ -6551,207 +7365,19 @@ assign_syslog_ident(const char *ident, bool doit, GucSource source)
 #endif   /* HAVE_SYSLOG */
 
 
-static const char *
-assign_defaultxactisolevel(const char *newval, bool doit, GucSource source)
-{
-       if (pg_strcasecmp(newval, "serializable") == 0)
-       {
-               if (doit)
-                       DefaultXactIsoLevel = XACT_SERIALIZABLE;
-       }
-       else if (pg_strcasecmp(newval, "repeatable read") == 0)
-       {
-               if (doit)
-                       DefaultXactIsoLevel = XACT_REPEATABLE_READ;
-       }
-       else if (pg_strcasecmp(newval, "read committed") == 0)
-       {
-               if (doit)
-                       DefaultXactIsoLevel = XACT_READ_COMMITTED;
-       }
-       else if (pg_strcasecmp(newval, "read uncommitted") == 0)
-       {
-               if (doit)
-                       DefaultXactIsoLevel = XACT_READ_UNCOMMITTED;
-       }
-       else
-               return NULL;
-       return newval;
-}
-
-static const char *
-assign_session_replication_role(const char *newval, bool doit, GucSource source)
+static bool
+assign_session_replication_role(int newval, bool doit, GucSource source)
 {
-       int                     newrole;
-
-       if (pg_strcasecmp(newval, "origin") == 0)
-               newrole = SESSION_REPLICATION_ROLE_ORIGIN;
-       else if (pg_strcasecmp(newval, "replica") == 0)
-               newrole = SESSION_REPLICATION_ROLE_REPLICA;
-       else if (pg_strcasecmp(newval, "local") == 0)
-               newrole = SESSION_REPLICATION_ROLE_LOCAL;
-       else
-               return NULL;
-
        /*
         * Must flush the plan cache when changing replication role; but don't
         * flush unnecessarily.
         */
-       if (doit && SessionReplicationRole != newrole)
+       if (doit && SessionReplicationRole != newval)
        {
                ResetPlanCache();
-               SessionReplicationRole = newrole;
-       }
-
-       return newval;
-}
-
-static const char *
-assign_log_min_messages(const char *newval, bool doit, GucSource source)
-{
-       return (assign_msglvl(&log_min_messages, newval, doit, source));
-}
-
-static const char *
-assign_client_min_messages(const char *newval, bool doit, GucSource source)
-{
-       return (assign_msglvl(&client_min_messages, newval, doit, source));
-}
-
-static const char *
-assign_min_error_statement(const char *newval, bool doit, GucSource source)
-{
-       return (assign_msglvl(&log_min_error_statement, newval, doit, source));
-}
-
-static const char *
-assign_msglvl(int *var, const char *newval, bool doit, GucSource source)
-{
-       if (pg_strcasecmp(newval, "debug") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG2;
-       }
-       else if (pg_strcasecmp(newval, "debug5") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG5;
-       }
-       else if (pg_strcasecmp(newval, "debug4") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG4;
-       }
-       else if (pg_strcasecmp(newval, "debug3") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG3;
-       }
-       else if (pg_strcasecmp(newval, "debug2") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG2;
-       }
-       else if (pg_strcasecmp(newval, "debug1") == 0)
-       {
-               if (doit)
-                       (*var) = DEBUG1;
-       }
-       else if (pg_strcasecmp(newval, "log") == 0)
-       {
-               if (doit)
-                       (*var) = LOG;
-       }
-
-       /*
-        * Client_min_messages always prints 'info', but we allow it as a value
-        * anyway.
-        */
-       else if (pg_strcasecmp(newval, "info") == 0)
-       {
-               if (doit)
-                       (*var) = INFO;
        }
-       else if (pg_strcasecmp(newval, "notice") == 0)
-       {
-               if (doit)
-                       (*var) = NOTICE;
-       }
-       else if (pg_strcasecmp(newval, "warning") == 0)
-       {
-               if (doit)
-                       (*var) = WARNING;
-       }
-       else if (pg_strcasecmp(newval, "error") == 0)
-       {
-               if (doit)
-                       (*var) = ERROR;
-       }
-       /* We allow FATAL/PANIC for client-side messages too. */
-       else if (pg_strcasecmp(newval, "fatal") == 0)
-       {
-               if (doit)
-                       (*var) = FATAL;
-       }
-       else if (pg_strcasecmp(newval, "panic") == 0)
-       {
-               if (doit)
-                       (*var) = PANIC;
-       }
-       else
-               return NULL;                    /* fail */
-       return newval;                          /* OK */
-}
-
-static const char *
-assign_log_error_verbosity(const char *newval, bool doit, GucSource source)
-{
-       if (pg_strcasecmp(newval, "terse") == 0)
-       {
-               if (doit)
-                       Log_error_verbosity = PGERROR_TERSE;
-       }
-       else if (pg_strcasecmp(newval, "default") == 0)
-       {
-               if (doit)
-                       Log_error_verbosity = PGERROR_DEFAULT;
-       }
-       else if (pg_strcasecmp(newval, "verbose") == 0)
-       {
-               if (doit)
-                       Log_error_verbosity = PGERROR_VERBOSE;
-       }
-       else
-               return NULL;                    /* fail */
-       return newval;                          /* OK */
-}
 
-static const char *
-assign_log_statement(const char *newval, bool doit, GucSource source)
-{
-       if (pg_strcasecmp(newval, "none") == 0)
-       {
-               if (doit)
-                       log_statement = LOGSTMT_NONE;
-       }
-       else if (pg_strcasecmp(newval, "ddl") == 0)
-       {
-               if (doit)
-                       log_statement = LOGSTMT_DDL;
-       }
-       else if (pg_strcasecmp(newval, "mod") == 0)
-       {
-               if (doit)
-                       log_statement = LOGSTMT_MOD;
-       }
-       else if (pg_strcasecmp(newval, "all") == 0)
-       {
-               if (doit)
-                       log_statement = LOGSTMT_ALL;
-       }
-       else
-               return NULL;                    /* fail */
-       return newval;                          /* OK */
+       return true;
 }
 
 static const char *
@@ -6814,11 +7440,11 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
                        continue;
                }
 
-               if (hasSpaceAfterToken || !isalnum((unsigned char) c))
+               if (hasSpaceAfterToken || !(isalnum((unsigned char) c) || c == '_'))
                {
                        /*
-                        * Syntax error due to token following space after token or non
-                        * alpha numeric character
+                        * Syntax error due to token following space after token or
+                        * non-identifier character
                         */
                        pfree(buf.data);
                        return NULL;
@@ -6853,6 +7479,21 @@ assign_debug_assertions(bool newval, bool doit, GucSource source)
        return true;
 }
 
+static bool
+assign_bonjour(bool newval, bool doit, GucSource source)
+{
+#ifndef USE_BONJOUR
+       if (newval)
+       {
+               ereport(GUC_complaint_elevel(source),
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("Bonjour is not supported by this build")));
+               return false;
+       }
+#endif
+       return true;
+}
+
 static bool
 assign_ssl(bool newval, bool doit, GucSource source)
 {
@@ -6914,6 +7555,18 @@ assign_transaction_read_only(bool newval, bool doit, GucSource source)
                if (source != PGC_S_OVERRIDE)
                        return false;
        }
+
+       /* Can't go to r/w mode while recovery is still active */
+       if (newval == false && XactReadOnly && RecoveryInProgress())
+       {
+               ereport(GUC_complaint_elevel(source),
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("cannot set transaction read-write mode during recovery")));
+               /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
+               if (source != PGC_S_OVERRIDE)
+                       return false;
+       }
+
        return true;
 }
 
@@ -6931,31 +7584,6 @@ assign_canonical_path(const char *newval, bool doit, GucSource source)
                return newval;
 }
 
-static const char *
-assign_backslash_quote(const char *newval, bool doit, GucSource source)
-{
-       BackslashQuoteType bq;
-       bool            bqbool;
-
-       /*
-        * Although only "on", "off", and "safe_encoding" are documented, we use
-        * parse_bool so we can accept all the likely variants of "on" and "off".
-        */
-       if (pg_strcasecmp(newval, "safe_encoding") == 0)
-               bq = BACKSLASH_QUOTE_SAFE_ENCODING;
-       else if (parse_bool(newval, &bqbool))
-       {
-               bq = bqbool ? BACKSLASH_QUOTE_ON : BACKSLASH_QUOTE_OFF;
-       }
-       else
-               return NULL;                    /* reject */
-
-       if (doit)
-               backslash_quote = bq;
-
-       return newval;
-}
-
 static const char *
 assign_timezone_abbreviations(const char *newval, bool doit, GucSource source)
 {
@@ -7014,42 +7642,6 @@ pg_timezone_abbrev_initialize(void)
        }
 }
 
-static const char *
-assign_xmlbinary(const char *newval, bool doit, GucSource source)
-{
-       XmlBinaryType xb;
-
-       if (pg_strcasecmp(newval, "base64") == 0)
-               xb = XMLBINARY_BASE64;
-       else if (pg_strcasecmp(newval, "hex") == 0)
-               xb = XMLBINARY_HEX;
-       else
-               return NULL;                    /* reject */
-
-       if (doit)
-               xmlbinary = xb;
-
-       return newval;
-}
-
-static const char *
-assign_xmloption(const char *newval, bool doit, GucSource source)
-{
-       XmlOptionType xo;
-
-       if (pg_strcasecmp(newval, "document") == 0)
-               xo = XMLOPTION_DOCUMENT;
-       else if (pg_strcasecmp(newval, "content") == 0)
-               xo = XMLOPTION_CONTENT;
-       else
-               return NULL;                    /* reject */
-
-       if (doit)
-               xmloption = xo;
-
-       return newval;
-}
-
 static const char *
 show_archive_command(void)
 {
@@ -7116,11 +7708,11 @@ show_tcp_keepalives_count(void)
 static bool
 assign_maxconnections(int newval, bool doit, GucSource source)
 {
-       if (newval + autovacuum_max_workers > INT_MAX / 4)
+       if (newval + autovacuum_max_workers + 1 > INT_MAX / 4)
                return false;
 
        if (doit)
-               MaxBackends = newval + autovacuum_max_workers;
+               MaxBackends = newval + autovacuum_max_workers + 1;
 
        return true;
 }
@@ -7128,13 +7720,121 @@ assign_maxconnections(int newval, bool doit, GucSource source)
 static bool
 assign_autovacuum_max_workers(int newval, bool doit, GucSource source)
 {
-       if (newval + MaxConnections > INT_MAX / 4)
+       if (MaxConnections + newval + 1 > INT_MAX / 4)
                return false;
 
        if (doit)
-               MaxBackends = newval + MaxConnections;
+               MaxBackends = MaxConnections + newval + 1;
 
        return true;
 }
 
+static bool
+assign_effective_io_concurrency(int newval, bool doit, GucSource source)
+{
+#ifdef USE_PREFETCH
+       double          new_prefetch_pages = 0.0;
+       int                     i;
+
+       /*----------
+        * The user-visible GUC parameter is the number of drives (spindles),
+        * which we need to translate to a number-of-pages-to-prefetch target.
+        *
+        * The expected number of prefetch pages needed to keep N drives busy is:
+        *
+        * drives |   I/O requests
+        * -------+----------------
+        *              1 |   1
+        *              2 |   2/1 + 2/2 = 3
+        *              3 |   3/1 + 3/2 + 3/3 = 5 1/2
+        *              4 |   4/1 + 4/2 + 4/3 + 4/4 = 8 1/3
+        *              n |   n * H(n)
+        *
+        * This is called the "coupon collector problem" and H(n) is called the
+        * harmonic series.  This could be approximated by n * ln(n), but for
+        * reasonable numbers of drives we might as well just compute the series.
+        *
+        * Alternatively we could set the target to the number of pages necessary
+        * so that the expected number of active spindles is some arbitrary
+        * percentage of the total.  This sounds the same but is actually slightly
+        * different.  The result ends up being ln(1-P)/ln((n-1)/n) where P is
+        * that desired fraction.
+        *
+        * Experimental results show that both of these formulas aren't aggressive
+        * enough, but we don't really have any better proposals.
+        *
+        * Note that if newval = 0 (disabled), we must set target = 0.
+        *----------
+        */
+
+       for (i = 1; i <= newval; i++)
+               new_prefetch_pages += (double) newval / (double) i;
+
+       /* This range check shouldn't fail, but let's be paranoid */
+       if (new_prefetch_pages >= 0.0 && new_prefetch_pages < (double) INT_MAX)
+       {
+               if (doit)
+                       target_prefetch_pages = (int) rint(new_prefetch_pages);
+               return true;
+       }
+       else
+               return false;
+#else
+       return true;
+#endif   /* USE_PREFETCH */
+}
+
+static const char *
+assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source)
+{
+       if (doit)
+       {
+               char       *canon_val = guc_strdup(ERROR, newval);
+               char       *tname;
+               char       *fname;
+
+               canonicalize_path(canon_val);
+
+               tname = guc_malloc(ERROR, strlen(canon_val) + 12);              /* /pgstat.tmp */
+               sprintf(tname, "%s/pgstat.tmp", canon_val);
+               fname = guc_malloc(ERROR, strlen(canon_val) + 13);              /* /pgstat.stat */
+               sprintf(fname, "%s/pgstat.stat", canon_val);
+
+               if (pgstat_stat_tmpname)
+                       free(pgstat_stat_tmpname);
+               pgstat_stat_tmpname = tname;
+               if (pgstat_stat_filename)
+                       free(pgstat_stat_filename);
+               pgstat_stat_filename = fname;
+
+               return canon_val;
+       }
+       else
+               return newval;
+}
+
+static const char *
+assign_application_name(const char *newval, bool doit, GucSource source)
+{
+       if (doit)
+       {
+               /* Only allow clean ASCII chars in the application name */
+               char       *repval = guc_strdup(ERROR, newval);
+               char       *p;
+
+               for (p = repval; *p; p++)
+               {
+                       if (*p < 32 || *p > 126)
+                               *p = '?';
+               }
+
+               /* Update the pg_stat_activity view */
+               pgstat_report_appname(repval);
+
+               return repval;
+       }
+       else
+               return newval;
+}
+
 #include "guc-file.c"