X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fbackend%2Futils%2Fmisc%2Fguc.c;h=c5782e2de2f9dbb92dfb3cdb62540f068be397f7;hb=f7ea6beaf4ca02b8e6dc576255e35a5b86035cb9;hp=0bf1845599558c98a863c24b6c8e145fef8b5df0;hpb=a8a8a3e0965201df88bdfdff08f50e5c06c552b7;p=pg-rex%2Fsyncrep.git diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 0bf1845599..c5782e2de2 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -104,7 +104,7 @@ * backend ID as a 3-byte signed integer. Even if that limitation were * removed, we still could not exceed INT_MAX/4 because some places compute * 4*MaxBackends without any overflow check. This is rechecked in - * assign_maxconnections, since MaxBackends is computed as MaxConnections + * check_maxconnections, since MaxBackends is computed as MaxConnections * plus autovacuum_max_workers plus one (for the autovacuum launcher). */ #define MAX_BACKENDS 0x7fffff @@ -143,11 +143,29 @@ extern bool trace_syncscan; extern bool optimize_bounded_sort; #endif +static int GUC_check_errcode_value; + +/* global variables for check hook support */ +char *GUC_check_errmsg_string; +char *GUC_check_errdetail_string; +char *GUC_check_errhint_string; + + 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); +static bool call_bool_check_hook(struct config_bool * conf, bool *newval, + void **extra, GucSource source, int elevel); +static bool call_int_check_hook(struct config_int * conf, int *newval, + void **extra, GucSource source, int elevel); +static bool call_real_check_hook(struct config_real * conf, double *newval, + void **extra, GucSource source, int elevel); +static bool call_string_check_hook(struct config_string * conf, char **newval, + void **extra, GucSource source, int elevel); +static bool call_enum_check_hook(struct config_enum * conf, int *newval, + void **extra, GucSource source, int elevel); + +static bool check_log_destination(char **newval, void **extra, GucSource source); +static void assign_log_destination(const char *newval, void *extra); #ifdef HAVE_SYSLOG static int syslog_facility = LOG_LOCAL0; @@ -155,36 +173,36 @@ static int syslog_facility = LOG_LOCAL0; static int syslog_facility = 0; #endif -static bool assign_syslog_facility(int newval, - bool doit, GucSource source); -static const char *assign_syslog_ident(const char *ident, - bool doit, GucSource source); - -static bool assign_session_replication_role(int 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 const char *assign_canonical_path(const char *newval, bool doit, GucSource source); -static const char *assign_timezone_abbreviations(const char *newval, bool doit, GucSource source); +static void assign_syslog_facility(int newval, void *extra); +static void assign_syslog_ident(const char *newval, void *extra); +static void assign_session_replication_role(int newval, void *extra); +static bool check_temp_buffers(int *newval, void **extra, GucSource source); +static bool check_phony_autocommit(bool *newval, void **extra, GucSource source); +static bool check_custom_variable_classes(char **newval, void **extra, GucSource source); +static bool check_debug_assertions(bool *newval, void **extra, GucSource source); +static bool check_bonjour(bool *newval, void **extra, GucSource source); +static bool check_ssl(bool *newval, void **extra, GucSource source); +static bool check_stage_log_stats(bool *newval, void **extra, GucSource source); +static bool check_log_stats(bool *newval, void **extra, GucSource source); +static bool check_canonical_path(char **newval, void **extra, GucSource source); +static bool check_timezone_abbreviations(char **newval, void **extra, GucSource source); +static void assign_timezone_abbreviations(const char *newval, void *extra); static 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); -static bool assign_tcp_keepalives_count(int newval, bool doit, GucSource source); +static void assign_tcp_keepalives_idle(int newval, void *extra); +static void assign_tcp_keepalives_interval(int newval, void *extra); +static void assign_tcp_keepalives_count(int newval, void *extra); static 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_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 bool check_maxconnections(int *newval, void **extra, GucSource source); +static void assign_maxconnections(int newval, void *extra); +static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source); +static void assign_autovacuum_max_workers(int newval, void *extra); +static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source); +static void assign_effective_io_concurrency(int newval, void *extra); +static void assign_pgstat_temp_directory(const char *newval, void *extra); +static bool check_application_name(char **newval, void **extra, GucSource source); +static void assign_application_name(const char *newval, void *extra); static const char *show_unix_socket_permissions(void); static const char *show_log_file_mode(void); @@ -351,6 +369,23 @@ static const struct config_enum_entry constraint_exclusion_options[] = { }; /* + * Although only "on", "off", and "local" are documented, we + * accept all the likely variants of "on" and "off". + */ +static const struct config_enum_entry synchronous_commit_options[] = { + {"local", SYNCHRONOUS_COMMIT_LOCAL_FLUSH, false}, + {"on", SYNCHRONOUS_COMMIT_ON, false}, + {"off", SYNCHRONOUS_COMMIT_OFF, false}, + {"true", SYNCHRONOUS_COMMIT_ON, true}, + {"false", SYNCHRONOUS_COMMIT_OFF, true}, + {"yes", SYNCHRONOUS_COMMIT_ON, true}, + {"no", SYNCHRONOUS_COMMIT_OFF, true}, + {"1", SYNCHRONOUS_COMMIT_ON, true}, + {"0", SYNCHRONOUS_COMMIT_OFF, true}, + {NULL, 0, false} +}; + +/* * Options for enum values stored in other modules */ extern const struct config_enum_entry wal_level_options[]; @@ -390,7 +425,7 @@ int log_min_duration_statement = -1; int log_temp_files = -1; int trace_recovery_messages = LOG; -int num_temp_buffers = 1000; +int num_temp_buffers = 1024; char *data_directory; char *ConfigFileName; @@ -427,6 +462,8 @@ static int server_version_num; static char *timezone_string; static char *log_timezone_string; static char *timezone_abbreviations_string; +static char *XactIsoLevel_string; +static char *session_authorization_string; static char *custom_variable_classes; static int max_function_args; static int max_index_keys; @@ -438,10 +475,8 @@ 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 */ +/* should be static, but commands/variable.c needs to get at this */ char *role_string; -char *session_authorization_string; -char *XactIsoLevel_string; /* @@ -467,6 +502,7 @@ const char *const GucContext_Names[] = const char *const GucSource_Names[] = { /* PGC_S_DEFAULT */ "default", + /* PGC_S_DYNAMIC_DEFAULT */ "default", /* PGC_S_ENV_VAR */ "environment variable", /* PGC_S_FILE */ "configuration file", /* PGC_S_ARGV */ "command line", @@ -626,7 +662,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_seqscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -634,7 +671,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_indexscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -642,7 +680,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_bitmapscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -650,7 +689,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_tidscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD, @@ -658,7 +698,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_sort, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD, @@ -666,7 +707,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_hashagg, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_material", PGC_USERSET, QUERY_TUNING_METHOD, @@ -674,7 +716,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_material, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD, @@ -682,7 +725,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_nestloop, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD, @@ -690,7 +734,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_mergejoin, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD, @@ -698,7 +743,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_hashjoin, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"geqo", PGC_USERSET, QUERY_TUNING_GEQO, @@ -707,7 +753,8 @@ static struct config_bool ConfigureNamesBool[] = "exhaustive searching.") }, &enable_geqo, - true, NULL, NULL + true, + NULL, NULL, NULL }, { /* Not for general use --- used by SET SESSION AUTHORIZATION */ @@ -717,7 +764,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &session_auth_is_superuser, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS, @@ -725,7 +773,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_bonjour, - false, assign_bonjour, NULL + false, + check_bonjour, NULL, NULL }, { {"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY, @@ -733,7 +782,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &EnableSSL, - false, assign_ssl, NULL + false, + check_ssl, NULL, NULL }, { {"fsync", PGC_SIGHUP, WAL_SETTINGS, @@ -744,23 +794,8 @@ static struct config_bool ConfigureNamesBool[] = "an operating system or hardware crash.") }, &enableFsync, - true, NULL, NULL - }, - { - {"synchronous_commit", PGC_USERSET, WAL_SETTINGS, - gettext_noop("Sets immediate fsync at commit."), - NULL - }, - &XactSyncCommit, - true, NULL, NULL - }, - { - {"synchronous_replication", PGC_USERSET, WAL_REPLICATION, - gettext_noop("Requests synchronous replication."), - NULL - }, - &sync_rep_mode, - false, NULL, NULL + true, + NULL, NULL, NULL }, { {"zero_damaged_pages", PGC_SUSET, DEVELOPER_OPTIONS, @@ -773,7 +808,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &zero_damaged_pages, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"full_page_writes", PGC_SIGHUP, WAL_SETTINGS, @@ -785,16 +821,8 @@ static struct config_bool ConfigureNamesBool[] = "is possible.") }, &fullPageWrites, - true, NULL, NULL - }, - { - {"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.") - }, - &SilentMode, - false, NULL, NULL + true, + NULL, NULL, NULL }, { {"log_checkpoints", PGC_SIGHUP, LOGGING_WHAT, @@ -802,7 +830,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_checkpoints, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_connections", PGC_BACKEND, LOGGING_WHAT, @@ -810,7 +839,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_connections, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_disconnections", PGC_BACKEND, LOGGING_WHAT, @@ -818,7 +848,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_disconnections, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_assertions", PGC_USERSET, DEVELOPER_OPTIONS, @@ -832,7 +863,7 @@ static struct config_bool ConfigureNamesBool[] = #else false, #endif - assign_debug_assertions, NULL + check_debug_assertions, NULL, NULL }, { @@ -841,7 +872,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &ExitOnAnyError, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"restart_after_crash", PGC_SIGHUP, ERROR_HANDLING_OPTIONS, @@ -849,7 +881,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &restart_after_crash, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -858,7 +891,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_duration, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_parse", PGC_USERSET, LOGGING_WHAT, @@ -866,7 +900,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_parse, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_rewritten", PGC_USERSET, LOGGING_WHAT, @@ -874,7 +909,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_rewritten, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_plan", PGC_USERSET, LOGGING_WHAT, @@ -882,7 +918,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_plan, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_pretty_print", PGC_USERSET, LOGGING_WHAT, @@ -890,7 +927,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_pretty_print, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"log_parser_stats", PGC_SUSET, STATS_MONITORING, @@ -898,7 +936,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_parser_stats, - false, assign_stage_log_stats, NULL + false, + check_stage_log_stats, NULL, NULL }, { {"log_planner_stats", PGC_SUSET, STATS_MONITORING, @@ -906,7 +945,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_planner_stats, - false, assign_stage_log_stats, NULL + false, + check_stage_log_stats, NULL, NULL }, { {"log_executor_stats", PGC_SUSET, STATS_MONITORING, @@ -914,7 +954,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_executor_stats, - false, assign_stage_log_stats, NULL + false, + check_stage_log_stats, NULL, NULL }, { {"log_statement_stats", PGC_SUSET, STATS_MONITORING, @@ -922,7 +963,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_statement_stats, - false, assign_log_stats, NULL + false, + check_log_stats, NULL, NULL }, #ifdef BTREE_BUILD_STATS { @@ -932,7 +974,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &log_btree_build_stats, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -944,7 +987,8 @@ static struct config_bool ConfigureNamesBool[] = "the time at which that command began execution.") }, &pgstat_track_activities, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"track_counts", PGC_SUSET, STATS_COLLECTOR, @@ -952,7 +996,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &pgstat_track_counts, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -961,7 +1006,8 @@ static struct config_bool ConfigureNamesBool[] = gettext_noop("Enables updating of the process title every time a new SQL command is received by the server.") }, &update_process_title, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -970,7 +1016,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &autovacuum_start_daemon, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -980,7 +1027,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Trace_notify, - false, NULL, NULL + false, + NULL, NULL, NULL }, #ifdef LOCK_DEBUG @@ -991,7 +1039,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Trace_locks, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"trace_userlocks", PGC_SUSET, DEVELOPER_OPTIONS, @@ -1000,7 +1049,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Trace_userlocks, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"trace_lwlocks", PGC_SUSET, DEVELOPER_OPTIONS, @@ -1009,7 +1059,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Trace_lwlocks, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_deadlocks", PGC_SUSET, DEVELOPER_OPTIONS, @@ -1018,7 +1069,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Debug_deadlocks, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1028,7 +1080,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_lock_waits, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1040,7 +1093,8 @@ static struct config_bool ConfigureNamesBool[] = "setup it might impose a non-negligible performance penalty.") }, &log_hostname, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"sql_inheritance", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, @@ -1048,7 +1102,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &SQL_inheritance, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY, @@ -1058,7 +1113,8 @@ static struct config_bool ConfigureNamesBool[] = "this parameter determines whether the password is to be encrypted.") }, &Password_encryption, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT, @@ -1070,7 +1126,8 @@ static struct config_bool ConfigureNamesBool[] = "return null (unknown).") }, &Transform_null_equals, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"db_user_namespace", PGC_SIGHUP, CONN_AUTH_SECURITY, @@ -1078,7 +1135,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Db_user_namespace, - false, NULL, NULL + false, + NULL, NULL, NULL }, { /* only here for backwards compatibility */ @@ -1088,7 +1146,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE }, &phony_autocommit, - true, assign_phony_autocommit, NULL + true, + check_phony_autocommit, NULL, NULL }, { {"default_transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1096,7 +1155,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &DefaultXactReadOnly, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1105,7 +1165,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &XactReadOnly, - false, assign_transaction_read_only, NULL + false, + check_transaction_read_only, NULL, NULL }, { {"default_transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1113,7 +1174,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &DefaultXactDeferrable, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1122,7 +1184,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &XactDeferrable, - false, assign_transaction_deferrable, NULL + false, + check_transaction_deferrable, NULL, NULL }, { {"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1130,7 +1193,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &check_function_bodies, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"array_nulls", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, @@ -1140,7 +1204,8 @@ static struct config_bool ConfigureNamesBool[] = "otherwise it is taken literally.") }, &Array_nulls, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"default_with_oids", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, @@ -1148,7 +1213,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &default_with_oids, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"logging_collector", PGC_POSTMASTER, LOGGING_WHERE, @@ -1156,7 +1222,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Logging_collector, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_truncate_on_rotation", PGC_SIGHUP, LOGGING_WHERE, @@ -1164,7 +1231,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_truncate_on_rotation, - false, NULL, NULL + false, + NULL, NULL, NULL }, #ifdef TRACE_SORT @@ -1175,7 +1243,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &trace_sort, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1188,7 +1257,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &trace_syncscan, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1202,7 +1272,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &optimize_bounded_sort, - true, NULL, NULL + true, + NULL, NULL, NULL }, #endif @@ -1214,7 +1285,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &XLOG_DEBUG, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1226,10 +1298,11 @@ static struct config_bool ConfigureNamesBool[] = }, &integer_datetimes, #ifdef HAVE_INT64_TIMESTAMP - true, NULL, NULL + true, #else - false, NULL, NULL + false, #endif + NULL, NULL, NULL }, { @@ -1238,7 +1311,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &pg_krb_caseins_users, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1247,7 +1321,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &escape_string_warning, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1257,7 +1332,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_REPORT }, &standard_conforming_strings, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1266,7 +1342,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &synchronize_seqscans, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1275,7 +1352,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &XLogArchiveMode, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1284,7 +1362,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &EnableHotStandby, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1293,7 +1372,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &hot_standby_feedback, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1303,7 +1383,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &allowSystemTableMods, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1314,7 +1395,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &IgnoreSystemIndexes, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1324,7 +1406,8 @@ static struct config_bool ConfigureNamesBool[] = "for compatibility with PostgreSQL releases prior to 9.0.") }, &lo_compat_privileges, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1333,12 +1416,13 @@ static struct config_bool ConfigureNamesBool[] = NULL, }, "e_all_identifiers, - false, NULL, NULL + false, + NULL, NULL, NULL }, /* End-of-list marker */ { - {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL + {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL } }; @@ -1353,7 +1437,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &XLogArchiveTimeout, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { {"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS, @@ -1362,7 +1447,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_UNIT_S }, &PostAuthDelay, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { {"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER, @@ -1371,7 +1457,8 @@ static struct config_int ConfigureNamesInt[] = "column-specific target set via ALTER TABLE SET STATISTICS.") }, &default_statistics_target, - 100, 1, 10000, NULL, NULL + 100, 1, 10000, + NULL, NULL, NULL }, { {"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER, @@ -1382,7 +1469,8 @@ static struct config_int ConfigureNamesInt[] = "this many items.") }, &from_collapse_limit, - 8, 1, INT_MAX, NULL, NULL + 8, 1, INT_MAX, + NULL, NULL, NULL }, { {"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER, @@ -1393,7 +1481,8 @@ static struct config_int ConfigureNamesInt[] = "list of no more than this many items would result.") }, &join_collapse_limit, - 8, 1, INT_MAX, NULL, NULL + 8, 1, INT_MAX, + NULL, NULL, NULL }, { {"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO, @@ -1401,7 +1490,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &geqo_threshold, - 12, 2, INT_MAX, NULL, NULL + 12, 2, INT_MAX, + NULL, NULL, NULL }, { {"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO, @@ -1409,7 +1499,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &Geqo_effort, - DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT, NULL, NULL + DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT, + NULL, NULL, NULL }, { {"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO, @@ -1417,7 +1508,8 @@ static struct config_int ConfigureNamesInt[] = gettext_noop("Zero selects a suitable default value.") }, &Geqo_pool_size, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { {"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO, @@ -1425,18 +1517,20 @@ static struct config_int ConfigureNamesInt[] = gettext_noop("Zero selects a suitable default value.") }, &Geqo_generations, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { - /* This is PGC_SIGHUP so all backends have the same value. */ - {"deadlock_timeout", PGC_SIGHUP, LOCK_MANAGEMENT, + /* This is PGC_SUSET to prevent hiding from log_lock_waits. */ + {"deadlock_timeout", PGC_SUSET, LOCK_MANAGEMENT, gettext_noop("Sets the time to wait on a lock before checking for deadlock."), NULL, GUC_UNIT_MS }, &DeadlockTimeout, - 1000, 1, INT_MAX / 1000, NULL, NULL + 1000, 1, INT_MAX, + NULL, NULL, NULL }, { @@ -1446,7 +1540,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &max_standby_archive_delay, - 30 * 1000, -1, INT_MAX / 1000, NULL, NULL + 30 * 1000, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1456,7 +1551,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &max_standby_streaming_delay, - 30 * 1000, -1, INT_MAX / 1000, NULL, NULL + 30 * 1000, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1466,7 +1562,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &wal_receiver_status_interval, - 10, 0, INT_MAX/1000, NULL, NULL + 10, 0, INT_MAX / 1000, + NULL, NULL, NULL }, { @@ -1475,7 +1572,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &MaxConnections, - 100, 1, MAX_BACKENDS, assign_maxconnections, NULL + 100, 1, MAX_BACKENDS, + check_maxconnections, assign_maxconnections, NULL }, { @@ -1484,7 +1582,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &ReservedBackends, - 3, 0, MAX_BACKENDS, NULL, NULL + 3, 0, MAX_BACKENDS, + NULL, NULL, NULL }, /* @@ -1498,7 +1597,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS }, &NBuffers, - 1024, 16, INT_MAX / 2, NULL, NULL + 1024, 16, INT_MAX / 2, + NULL, NULL, NULL }, { @@ -1508,7 +1608,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS }, &num_temp_buffers, - 1024, 100, INT_MAX / 2, NULL, show_num_temp_buffers + 1024, 100, INT_MAX / 2, + check_temp_buffers, NULL, NULL }, { @@ -1517,7 +1618,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &PostPortNumber, - DEF_PGPORT, 1, 65535, NULL, NULL + DEF_PGPORT, 1, 65535, + NULL, NULL, NULL }, { @@ -1531,7 +1633,8 @@ static struct config_int ConfigureNamesInt[] = "start with a 0 (zero).)") }, &Unix_socket_permissions, - 0777, 0000, 0777, NULL, show_unix_socket_permissions + 0777, 0000, 0777, + NULL, NULL, show_unix_socket_permissions }, { @@ -1544,7 +1647,8 @@ static struct config_int ConfigureNamesInt[] = "start with a 0 (zero).)") }, &Log_file_mode, - 0600, 0000, 0777, NULL, show_log_file_mode + 0600, 0000, 0777, + NULL, NULL, show_log_file_mode }, { @@ -1556,7 +1660,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &work_mem, - 1024, 64, MAX_KILOBYTES, NULL, NULL + 1024, 64, MAX_KILOBYTES, + NULL, NULL, NULL }, { @@ -1566,7 +1671,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &maintenance_work_mem, - 16384, 1024, MAX_KILOBYTES, NULL, NULL + 16384, 1024, MAX_KILOBYTES, + NULL, NULL, NULL }, /* @@ -1581,7 +1687,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &max_stack_depth, - 100, 100, MAX_KILOBYTES, assign_max_stack_depth, NULL + 100, 100, MAX_KILOBYTES, + check_max_stack_depth, assign_max_stack_depth, NULL }, { @@ -1590,7 +1697,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageHit, - 1, 0, 10000, NULL, NULL + 1, 0, 10000, + NULL, NULL, NULL }, { @@ -1599,7 +1707,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageMiss, - 10, 0, 10000, NULL, NULL + 10, 0, 10000, + NULL, NULL, NULL }, { @@ -1608,7 +1717,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageDirty, - 20, 0, 10000, NULL, NULL + 20, 0, 10000, + NULL, NULL, NULL }, { @@ -1617,7 +1727,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostLimit, - 200, 1, 10000, NULL, NULL + 200, 1, 10000, + NULL, NULL, NULL }, { @@ -1627,7 +1738,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &VacuumCostDelay, - 0, 0, 100, NULL, NULL + 0, 0, 100, + NULL, NULL, NULL }, { @@ -1637,7 +1749,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &autovacuum_vac_cost_delay, - 20, -1, 100, NULL, NULL + 20, -1, 100, + NULL, NULL, NULL }, { @@ -1646,7 +1759,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &autovacuum_vac_cost_limit, - -1, -1, 10000, NULL, NULL + -1, -1, 10000, + NULL, NULL, NULL }, { @@ -1655,7 +1769,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_files_per_process, - 1000, 25, INT_MAX, NULL, NULL + 1000, 25, INT_MAX, + NULL, NULL, NULL }, /* @@ -1667,7 +1782,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_prepared_xacts, - 0, 0, MAX_BACKENDS, NULL, NULL + 0, 0, MAX_BACKENDS, + NULL, NULL, NULL }, #ifdef LOCK_DEBUG @@ -1678,7 +1794,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE }, &Trace_lock_oidmin, - FirstNormalObjectId, 0, INT_MAX, NULL, NULL + FirstNormalObjectId, 0, INT_MAX, + NULL, NULL, NULL }, { {"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS, @@ -1687,7 +1804,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE }, &Trace_lock_table, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, #endif @@ -1698,7 +1816,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &StatementTimeout, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1707,7 +1826,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_freeze_min_age, - 50000000, 0, 1000000000, NULL, NULL + 50000000, 0, 1000000000, + NULL, NULL, NULL }, { @@ -1716,7 +1836,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_freeze_table_age, - 150000000, 0, 2000000000, NULL, NULL + 150000000, 0, 2000000000, + NULL, NULL, NULL }, { @@ -1725,7 +1846,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_defer_cleanup_age, - 0, 0, 1000000, NULL, NULL + 0, 0, 1000000, + NULL, NULL, NULL }, /* @@ -1739,18 +1861,20 @@ static struct config_int ConfigureNamesInt[] = "objects will need to be locked at any one time.") }, &max_locks_per_xact, - 64, 10, INT_MAX, NULL, NULL + 64, 10, INT_MAX, + NULL, NULL, NULL }, { {"max_pred_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT, gettext_noop("Sets the maximum number of predicate locks per transaction."), gettext_noop("The shared predicate lock table is sized on the assumption that " - "at most max_pred_locks_per_transaction * max_connections distinct " + "at most max_pred_locks_per_transaction * max_connections distinct " "objects will need to be locked at any one time.") }, &max_predicate_locks_per_xact, - 64, 10, INT_MAX, NULL, NULL + 64, 10, INT_MAX, + NULL, NULL, NULL }, { @@ -1760,7 +1884,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &AuthenticationTimeout, - 60, 1, 600, NULL, NULL + 60, 1, 600, + NULL, NULL, NULL }, { @@ -1771,7 +1896,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_UNIT_S }, &PreAuthDelay, - 0, 0, 60, NULL, NULL + 0, 0, 60, + NULL, NULL, NULL }, { @@ -1780,7 +1906,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &wal_keep_segments, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1789,7 +1916,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CheckPointSegments, - 3, 1, INT_MAX, NULL, NULL + 3, 1, INT_MAX, + NULL, NULL, NULL }, { @@ -1799,7 +1927,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &CheckPointTimeout, - 300, 30, 3600, NULL, NULL + 300, 30, 3600, + NULL, NULL, NULL }, { @@ -1812,7 +1941,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &CheckPointWarning, - 30, 0, INT_MAX, NULL, NULL + 30, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1822,7 +1952,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_XBLOCKS }, &XLOGbuffers, - -1, -1, INT_MAX, NULL, NULL + -1, -1, INT_MAX, + check_wal_buffers, NULL, NULL }, { @@ -1832,7 +1963,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &WalWriterDelay, - 200, 1, 10000, NULL, NULL + 200, 1, 10000, + NULL, NULL, NULL }, { @@ -1842,7 +1974,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_wal_senders, - 0, 0, MAX_BACKENDS, NULL, NULL + 0, 0, MAX_BACKENDS, + NULL, NULL, NULL }, { @@ -1852,7 +1985,19 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &WalSndDelay, - 1000, 1, 10000, NULL, NULL + 1000, 1, 10000, + NULL, NULL, NULL + }, + + { + {"replication_timeout", PGC_SIGHUP, WAL_REPLICATION, + gettext_noop("Sets the maximum time to wait for WAL replication."), + NULL, + GUC_UNIT_MS + }, + &replication_timeout, + 60 * 1000, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1862,7 +2007,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CommitDelay, - 0, 0, 100000, NULL, NULL + 0, 0, 100000, + NULL, NULL, NULL }, { @@ -1872,7 +2018,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CommitSiblings, - 5, 0, 1000, NULL, NULL + 5, 0, 1000, + NULL, NULL, NULL }, { @@ -1883,7 +2030,8 @@ static struct config_int ConfigureNamesInt[] = "(FLT_DIG or DBL_DIG as appropriate).") }, &extra_float_digits, - 0, -15, 3, NULL, NULL + 0, -15, 3, + NULL, NULL, NULL }, { @@ -1894,7 +2042,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &log_min_duration_statement, - -1, -1, INT_MAX / 1000, NULL, NULL + -1, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1905,7 +2054,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &Log_autovacuum_min_duration, - -1, -1, INT_MAX / 1000, NULL, NULL + -1, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1915,7 +2065,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &BgWriterDelay, - 200, 10, 10000, NULL, NULL + 200, 10, 10000, + NULL, NULL, NULL }, { @@ -1924,7 +2075,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &bgwriter_lru_maxpages, - 100, 0, 1000, NULL, NULL + 100, 0, 1000, + NULL, NULL, NULL }, { @@ -1944,7 +2096,7 @@ static struct config_int ConfigureNamesInt[] = #else 0, 0, 0, #endif - assign_effective_io_concurrency, NULL + check_effective_io_concurrency, assign_effective_io_concurrency, NULL }, { @@ -1954,7 +2106,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MIN }, &Log_RotationAge, - HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / MINS_PER_HOUR, NULL, NULL + HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / MINS_PER_HOUR, + NULL, NULL, NULL }, { @@ -1964,7 +2117,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &Log_RotationSize, - 10 * 1024, 0, INT_MAX / 1024, NULL, NULL + 10 * 1024, 0, INT_MAX / 1024, + NULL, NULL, NULL }, { @@ -1974,7 +2128,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &max_function_args, - FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS, NULL, NULL + FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS, + NULL, NULL, NULL }, { @@ -1984,7 +2139,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &max_index_keys, - INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS, NULL, NULL + INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS, + NULL, NULL, NULL }, { @@ -1994,7 +2150,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &max_identifier_length, - NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1, NULL, NULL + NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1, + NULL, NULL, NULL }, { @@ -2004,7 +2161,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &block_size, - BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL + BLCKSZ, BLCKSZ, BLCKSZ, + NULL, NULL, NULL }, { @@ -2014,7 +2172,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &segment_size, - RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE, NULL, NULL + RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE, + NULL, NULL, NULL }, { @@ -2024,7 +2183,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &wal_block_size, - XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ, NULL, NULL + XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ, + NULL, NULL, NULL }, { @@ -2037,7 +2197,7 @@ static struct config_int ConfigureNamesInt[] = (XLOG_SEG_SIZE / XLOG_BLCKSZ), (XLOG_SEG_SIZE / XLOG_BLCKSZ), (XLOG_SEG_SIZE / XLOG_BLCKSZ), - NULL, NULL + NULL, NULL, NULL }, { @@ -2047,7 +2207,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &autovacuum_naptime, - 60, 1, INT_MAX / 1000, NULL, NULL + 60, 1, INT_MAX / 1000, + NULL, NULL, NULL }, { {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM, @@ -2055,7 +2216,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &autovacuum_vac_thresh, - 50, 0, INT_MAX, NULL, NULL + 50, 0, INT_MAX, + NULL, NULL, NULL }, { {"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM, @@ -2063,7 +2225,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &autovacuum_anl_thresh, - 50, 0, INT_MAX, NULL, NULL + 50, 0, INT_MAX, + NULL, NULL, NULL }, { /* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */ @@ -2073,7 +2236,8 @@ static struct config_int ConfigureNamesInt[] = }, &autovacuum_freeze_max_age, /* see pg_resetxlog if you change the upper-limit value */ - 200000000, 100000000, 2000000000, NULL, NULL + 200000000, 100000000, 2000000000, + NULL, NULL, NULL }, { /* see max_connections */ @@ -2082,7 +2246,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &autovacuum_max_workers, - 3, 1, MAX_BACKENDS, assign_autovacuum_max_workers, NULL + 3, 1, MAX_BACKENDS, + check_autovacuum_max_workers, assign_autovacuum_max_workers, NULL }, { @@ -2092,7 +2257,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &tcp_keepalives_idle, - 0, 0, INT_MAX, assign_tcp_keepalives_idle, show_tcp_keepalives_idle + 0, 0, INT_MAX, + NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle }, { @@ -2102,7 +2268,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &tcp_keepalives_interval, - 0, 0, INT_MAX, assign_tcp_keepalives_interval, show_tcp_keepalives_interval + 0, 0, INT_MAX, + NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval }, { @@ -2112,7 +2279,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB, }, &ssl_renegotiation_limit, - 512 * 1024, 0, MAX_KILOBYTES, NULL, NULL + 512 * 1024, 0, MAX_KILOBYTES, + NULL, NULL, NULL }, { @@ -2123,7 +2291,8 @@ static struct config_int ConfigureNamesInt[] = "system default."), }, &tcp_keepalives_count, - 0, 0, INT_MAX, assign_tcp_keepalives_count, show_tcp_keepalives_count + 0, 0, INT_MAX, + NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count }, { @@ -2133,7 +2302,8 @@ static struct config_int ConfigureNamesInt[] = 0 }, &GinFuzzySearchLimit, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -2145,7 +2315,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_BLOCKS, }, &effective_cache_size, - DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, NULL, NULL + DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, + NULL, NULL, NULL }, { @@ -2156,7 +2327,8 @@ static struct config_int ConfigureNamesInt[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &server_version_num, - PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM, NULL, NULL + PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM, + NULL, NULL, NULL }, { @@ -2166,7 +2338,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &log_temp_files, - -1, -1, INT_MAX, NULL, NULL + -1, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -2175,12 +2348,13 @@ static struct config_int ConfigureNamesInt[] = NULL, }, &pgstat_track_activity_query_size, - 1024, 100, 102400, NULL, NULL + 1024, 100, 102400, + NULL, NULL, NULL }, /* End-of-list marker */ { - {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL + {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL } }; @@ -2194,7 +2368,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &seq_page_cost, - DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX, NULL, NULL + DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX, + NULL, NULL, NULL }, { {"random_page_cost", PGC_USERSET, QUERY_TUNING_COST, @@ -2203,7 +2378,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &random_page_cost, - DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, NULL, NULL + DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, + NULL, NULL, NULL }, { {"cpu_tuple_cost", PGC_USERSET, QUERY_TUNING_COST, @@ -2212,7 +2388,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &cpu_tuple_cost, - DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, NULL, NULL + DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, + NULL, NULL, NULL }, { {"cpu_index_tuple_cost", PGC_USERSET, QUERY_TUNING_COST, @@ -2221,7 +2398,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &cpu_index_tuple_cost, - DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, NULL, NULL + DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, + NULL, NULL, NULL }, { {"cpu_operator_cost", PGC_USERSET, QUERY_TUNING_COST, @@ -2230,7 +2408,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &cpu_operator_cost, - DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, NULL, NULL + DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, + NULL, NULL, NULL }, { @@ -2240,7 +2419,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &cursor_tuple_fraction, - DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0, NULL, NULL + DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0, + NULL, NULL, NULL }, { @@ -2249,8 +2429,9 @@ static struct config_real ConfigureNamesReal[] = NULL }, &Geqo_selection_bias, - DEFAULT_GEQO_SELECTION_BIAS, MIN_GEQO_SELECTION_BIAS, - MAX_GEQO_SELECTION_BIAS, NULL, NULL + DEFAULT_GEQO_SELECTION_BIAS, + MIN_GEQO_SELECTION_BIAS, MAX_GEQO_SELECTION_BIAS, + NULL, NULL, NULL }, { {"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO, @@ -2258,7 +2439,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &Geqo_seed, - 0.0, 0.0, 1.0, NULL, NULL + 0.0, 0.0, 1.0, + NULL, NULL, NULL }, { @@ -2267,7 +2449,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &bgwriter_lru_multiplier, - 2.0, 0.0, 10.0, NULL, NULL + 2.0, 0.0, 10.0, + NULL, NULL, NULL }, { @@ -2277,7 +2460,8 @@ 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.0, -1.0, 1.0, assign_random_seed, show_random_seed + 0.0, -1.0, 1.0, + check_random_seed, assign_random_seed, show_random_seed }, { @@ -2286,7 +2470,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &autovacuum_vac_scale, - 0.2, 0.0, 100.0, NULL, NULL + 0.2, 0.0, 100.0, + NULL, NULL, NULL }, { {"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM, @@ -2294,7 +2479,8 @@ static struct config_real ConfigureNamesReal[] = NULL }, &autovacuum_anl_scale, - 0.1, 0.0, 100.0, NULL, NULL + 0.1, 0.0, 100.0, + NULL, NULL, NULL }, { @@ -2303,12 +2489,13 @@ static struct config_real ConfigureNamesReal[] = NULL }, &CheckPointCompletionTarget, - 0.5, 0.0, 1.0, NULL, NULL + 0.5, 0.0, 1.0, + NULL, NULL, NULL }, /* End-of-list marker */ { - {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL + {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL } }; @@ -2321,7 +2508,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &XLogArchiveCommand, - "", NULL, show_archive_command + "", + NULL, NULL, show_archive_command }, { @@ -2331,7 +2519,8 @@ static struct config_string ConfigureNamesString[] = GUC_IS_NAME | GUC_REPORT }, &client_encoding_string, - "SQL_ASCII", assign_client_encoding, NULL + "SQL_ASCII", + check_client_encoding, assign_client_encoding, NULL }, { @@ -2340,7 +2529,8 @@ static struct config_string ConfigureNamesString[] = gettext_noop("If blank, no prefix is used.") }, &Log_line_prefix, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2349,7 +2539,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &log_timezone_string, - "UNKNOWN", assign_log_timezone, show_log_timezone + NULL, + check_log_timezone, assign_log_timezone, show_log_timezone }, { @@ -2360,7 +2551,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_REPORT }, &datestyle_string, - "ISO, MDY", assign_datestyle, NULL + "ISO, MDY", + check_datestyle, assign_datestyle, NULL }, { @@ -2370,7 +2562,8 @@ static struct config_string ConfigureNamesString[] = GUC_IS_NAME }, &default_tablespace, - "", assign_default_tablespace, NULL + "", + check_default_tablespace, NULL, NULL }, { @@ -2380,7 +2573,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &temp_tablespaces, - "", assign_temp_tablespaces, NULL + "", + check_temp_tablespaces, assign_temp_tablespaces, NULL }, { @@ -2393,7 +2587,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &Dynamic_library_path, - "$libdir", NULL, NULL + "$libdir", + NULL, NULL, NULL }, { @@ -2403,7 +2598,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &pg_krb_server_keyfile, - PG_KRB_SRVTAB, NULL, NULL + PG_KRB_SRVTAB, + NULL, NULL, NULL }, { @@ -2412,7 +2608,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &pg_krb_srvnam, - PG_KRB_SRVNAM, NULL, NULL + PG_KRB_SRVNAM, + NULL, NULL, NULL }, { @@ -2421,7 +2618,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &bonjour_name, - "", NULL, NULL + "", + NULL, NULL, NULL }, /* See main.c about why defaults for LC_foo are not all alike */ @@ -2433,7 +2631,8 @@ static struct config_string ConfigureNamesString[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &locale_collate, - "C", NULL, NULL + "C", + NULL, NULL, NULL }, { @@ -2443,7 +2642,8 @@ static struct config_string ConfigureNamesString[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &locale_ctype, - "C", NULL, NULL + "C", + NULL, NULL, NULL }, { @@ -2452,7 +2652,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_messages, - "", locale_messages_assign, NULL + "", + check_locale_messages, assign_locale_messages, NULL }, { @@ -2461,7 +2662,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_monetary, - "C", locale_monetary_assign, NULL + "C", + check_locale_monetary, assign_locale_monetary, NULL }, { @@ -2470,7 +2672,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_numeric, - "C", locale_numeric_assign, NULL + "C", + check_locale_numeric, assign_locale_numeric, NULL }, { @@ -2479,7 +2682,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_time, - "C", locale_time_assign, NULL + "C", + check_locale_time, assign_locale_time, NULL }, { @@ -2489,7 +2693,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY }, &shared_preload_libraries_string, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2499,7 +2704,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &local_preload_libraries_string, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2509,7 +2715,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &namespace_search_path, - "\"$user\",public", assign_search_path, NULL + "\"$user\",public", + check_search_path, assign_search_path, NULL }, { @@ -2520,7 +2727,8 @@ static struct config_string ConfigureNamesString[] = GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &server_encoding_string, - "SQL_ASCII", NULL, NULL + "SQL_ASCII", + NULL, NULL, NULL }, { @@ -2531,7 +2739,8 @@ static struct config_string ConfigureNamesString[] = GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &server_version_string, - PG_VERSION, NULL, NULL + PG_VERSION, + NULL, NULL, NULL }, { @@ -2542,7 +2751,8 @@ static struct config_string ConfigureNamesString[] = 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 + "none", + check_role, assign_role, show_role }, { @@ -2553,7 +2763,8 @@ static struct config_string ConfigureNamesString[] = 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 + NULL, + check_session_authorization, assign_session_authorization, NULL }, { @@ -2565,7 +2776,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT }, &log_destination_string, - "stderr", assign_log_destination, NULL + "stderr", + check_log_destination, assign_log_destination, NULL }, { {"log_directory", PGC_SIGHUP, LOGGING_WHERE, @@ -2575,7 +2787,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &Log_directory, - "pg_log", assign_canonical_path, NULL + "pg_log", + check_canonical_path, NULL, NULL }, { {"log_filename", PGC_SIGHUP, LOGGING_WHERE, @@ -2584,7 +2797,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &Log_filename, - "postgresql-%Y-%m-%d_%H%M%S.log", NULL, NULL + "postgresql-%Y-%m-%d_%H%M%S.log", + NULL, NULL, NULL }, { @@ -2594,7 +2808,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &syslog_ident_str, - "postgres", assign_syslog_ident, NULL + "postgres", + NULL, assign_syslog_ident, NULL }, { @@ -2604,7 +2819,8 @@ static struct config_string ConfigureNamesString[] = GUC_REPORT }, &timezone_string, - "UNKNOWN", assign_timezone, show_timezone + NULL, + check_timezone, assign_timezone, show_timezone }, { {"timezone_abbreviations", PGC_USERSET, CLIENT_CONN_LOCALE, @@ -2612,7 +2828,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &timezone_abbreviations_string, - "UNKNOWN", assign_timezone_abbreviations, NULL + NULL, + check_timezone_abbreviations, assign_timezone_abbreviations, NULL }, { @@ -2622,7 +2839,8 @@ static struct config_string ConfigureNamesString[] = GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &XactIsoLevel_string, - NULL, assign_XactIsoLevel, show_XactIsoLevel + "default", + check_XactIsoLevel, assign_XactIsoLevel, show_XactIsoLevel }, { @@ -2632,7 +2850,8 @@ static struct config_string ConfigureNamesString[] = "that starts the server.") }, &Unix_socket_group, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2642,7 +2861,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &UnixSocketDir, - "", assign_canonical_path, NULL + "", + check_canonical_path, NULL, NULL }, { @@ -2652,7 +2872,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT }, &ListenAddresses, - "localhost", NULL, NULL + "localhost", + NULL, NULL, NULL }, { @@ -2662,7 +2883,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &custom_variable_classes, - NULL, assign_custom_variable_classes, NULL + NULL, + check_custom_variable_classes, NULL, NULL }, { @@ -2672,6 +2894,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &data_directory, + NULL, NULL, NULL, NULL }, @@ -2682,6 +2905,7 @@ static struct config_string ConfigureNamesString[] = GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY }, &ConfigFileName, + NULL, NULL, NULL, NULL }, @@ -2692,6 +2916,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &HbaFileName, + NULL, NULL, NULL, NULL }, @@ -2702,6 +2927,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &IdentFileName, + NULL, NULL, NULL, NULL }, @@ -2712,7 +2938,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &external_pid_file, - NULL, assign_canonical_path, NULL + NULL, + check_canonical_path, NULL, NULL }, { @@ -2722,17 +2949,19 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &pgstat_temp_directory, - "pg_stat_tmp", assign_pgstat_temp_directory, NULL + "pg_stat_tmp", + check_canonical_path, assign_pgstat_temp_directory, NULL }, { {"synchronous_standby_names", PGC_SIGHUP, WAL_REPLICATION, - gettext_noop("List of potential standby names to synchronise with."), + gettext_noop("List of potential standby names to synchronize with."), NULL, GUC_LIST_INPUT }, &SyncRepStandbyNames, - "", assign_synchronous_standby_names, NULL + "", + check_synchronous_standby_names, NULL, NULL }, { @@ -2741,7 +2970,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &TSCurrentConfig, - "pg_catalog.simple", assignTSCurrentConfig, NULL + "pg_catalog.simple", + check_TSCurrentConfig, assign_TSCurrentConfig, NULL }, { @@ -2756,7 +2986,7 @@ static struct config_string ConfigureNamesString[] = #else "none", #endif - NULL, NULL + NULL, NULL, NULL }, { @@ -2766,12 +2996,13 @@ static struct config_string ConfigureNamesString[] = GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE }, &application_name, - "", assign_application_name, NULL + "", + check_application_name, assign_application_name, NULL }, /* End-of-list marker */ { - {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL + {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL } }; @@ -2784,7 +3015,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &backslash_quote, - BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options, NULL, NULL + BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options, + NULL, NULL, NULL }, { @@ -2793,7 +3025,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &bytea_output, - BYTEA_OUTPUT_HEX, bytea_output_options, NULL, NULL + BYTEA_OUTPUT_HEX, bytea_output_options, + NULL, NULL, NULL }, { @@ -2803,7 +3036,8 @@ static struct config_enum ConfigureNamesEnum[] = " the level, the fewer messages are sent.") }, &client_min_messages, - NOTICE, client_message_level_options, NULL, NULL + NOTICE, client_message_level_options, + NULL, NULL, NULL }, { @@ -2814,7 +3048,7 @@ static struct config_enum ConfigureNamesEnum[] = }, &constraint_exclusion, CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options, - NULL, NULL + NULL, NULL, NULL }, { @@ -2823,7 +3057,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &DefaultXactIsoLevel, - XACT_READ_COMMITTED, isolation_level_options, NULL, NULL + XACT_READ_COMMITTED, isolation_level_options, + NULL, NULL, NULL }, { @@ -2833,7 +3068,8 @@ static struct config_enum ConfigureNamesEnum[] = GUC_REPORT }, &IntervalStyle, - INTSTYLE_POSTGRES, intervalstyle_options, NULL, NULL + INTSTYLE_POSTGRES, intervalstyle_options, + NULL, NULL, NULL }, { @@ -2842,7 +3078,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &Log_error_verbosity, - PGERROR_DEFAULT, log_error_verbosity_options, NULL, NULL + PGERROR_DEFAULT, log_error_verbosity_options, + NULL, NULL, NULL }, { @@ -2852,7 +3089,8 @@ static struct config_enum ConfigureNamesEnum[] = " the level, the fewer messages are sent.") }, &log_min_messages, - WARNING, server_message_level_options, NULL, NULL + WARNING, server_message_level_options, + NULL, NULL, NULL }, { @@ -2862,7 +3100,8 @@ static struct config_enum ConfigureNamesEnum[] = " the level, the fewer messages are sent.") }, &log_min_error_statement, - ERROR, server_message_level_options, NULL, NULL + ERROR, server_message_level_options, + NULL, NULL, NULL }, { @@ -2871,7 +3110,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &log_statement, - LOGSTMT_NONE, log_statement_options, NULL, NULL + LOGSTMT_NONE, log_statement_options, + NULL, NULL, NULL }, { @@ -2885,7 +3125,8 @@ static struct config_enum ConfigureNamesEnum[] = #else 0, #endif - syslog_facility_options, assign_syslog_facility, NULL + syslog_facility_options, + NULL, assign_syslog_facility, NULL }, { @@ -2895,7 +3136,17 @@ static struct config_enum ConfigureNamesEnum[] = }, &SessionReplicationRole, SESSION_REPLICATION_ROLE_ORIGIN, session_replication_role_options, - assign_session_replication_role, NULL + NULL, assign_session_replication_role, NULL + }, + + { + {"synchronous_commit", PGC_USERSET, WAL_SETTINGS, + gettext_noop("Sets the current transaction's synchronization level."), + NULL + }, + &synchronous_commit, + SYNCHRONOUS_COMMIT_ON, synchronous_commit_options, + NULL, NULL, NULL }, { @@ -2905,11 +3156,13 @@ static struct config_enum ConfigureNamesEnum[] = " the level, the fewer messages are sent.") }, &trace_recovery_messages, + /* - * client_message_level_options allows too many values, really, - * but it's not worth having a separate options array for this. + * client_message_level_options allows too many values, really, but + * it's not worth having a separate options array for this. */ - LOG, client_message_level_options, NULL, NULL + LOG, client_message_level_options, + NULL, NULL, NULL }, { @@ -2918,7 +3171,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &pgstat_track_functions, - TRACK_FUNC_OFF, track_function_options, NULL, NULL + TRACK_FUNC_OFF, track_function_options, + NULL, NULL, NULL }, { @@ -2927,7 +3181,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &wal_level, - WAL_LEVEL_MINIMAL, wal_level_options, NULL + WAL_LEVEL_MINIMAL, wal_level_options, + NULL, NULL, NULL }, { @@ -2937,7 +3192,7 @@ static struct config_enum ConfigureNamesEnum[] = }, &sync_method, DEFAULT_SYNC_METHOD, sync_method_options, - assign_xlog_sync_method, NULL + NULL, assign_xlog_sync_method, NULL }, { @@ -2946,7 +3201,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &xmlbinary, - XMLBINARY_BASE64, xmlbinary_options, NULL, NULL + XMLBINARY_BASE64, xmlbinary_options, + NULL, NULL, NULL }, { @@ -2956,13 +3212,14 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &xmloption, - XMLOPTION_CONTENT, xmloption_options, NULL, NULL + XMLOPTION_CONTENT, xmloption_options, + NULL, NULL, NULL }, /* End-of-list marker */ { - {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL + {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL } }; @@ -3003,13 +3260,13 @@ 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 InitializeGUCOptionsFromEnvironment(void); 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); static void ShowAllGUCConfig(DestReceiver *dest); static char *_ShowOption(struct config_generic * record, bool use_units); -static bool is_newvalue_equal(struct config_generic * record, const char *newvalue); static bool validate_option_array_item(const char *name, const char *value, bool skipIfNoPermissions); @@ -3058,6 +3315,27 @@ guc_strdup(int elevel, const char *src) /* + * Detect whether strval is referenced anywhere in a GUC string item + */ +static bool +string_field_used(struct config_string * conf, char *strval) +{ + GucStack *stack; + + if (strval == *(conf->variable) || + strval == conf->reset_val || + strval == conf->boot_val) + return true; + for (stack = conf->gen.stack; stack; stack = stack->prev) + { + if (strval == stack->prior.val.stringval || + strval == stack->masked.val.stringval) + return true; + } + return false; +} + +/* * Support for assigning to a field of a string GUC item. Free the prior * value if it's not referenced anywhere else in the item (including stacked * states). @@ -3066,87 +3344,119 @@ static void set_string_field(struct config_string * conf, char **field, char *newval) { char *oldval = *field; - GucStack *stack; /* Do the assignment */ *field = newval; - /* Exit if any duplicate references, or if old value was NULL anyway */ - if (oldval == NULL || - oldval == *(conf->variable) || - oldval == conf->reset_val || - oldval == conf->boot_val) - return; - for (stack = conf->gen.stack; stack; stack = stack->prev) - { - if (oldval == stack->prior.stringval || - oldval == stack->masked.stringval) - return; - } - - /* Not used anymore, so free it */ - free(oldval); + /* Free old value if it's not NULL and isn't referenced anymore */ + if (oldval && !string_field_used(conf, oldval)) + free(oldval); } /* - * Detect whether strval is referenced anywhere in a GUC string item + * Detect whether an "extra" struct is referenced anywhere in a GUC item */ static bool -string_field_used(struct config_string * conf, char *strval) +extra_field_used(struct config_generic * gconf, void *extra) { GucStack *stack; - if (strval == *(conf->variable) || - strval == conf->reset_val || - strval == conf->boot_val) + if (extra == gconf->extra) return true; - for (stack = conf->gen.stack; stack; stack = stack->prev) + switch (gconf->vartype) { - if (strval == stack->prior.stringval || - strval == stack->masked.stringval) + case PGC_BOOL: + if (extra == ((struct config_bool *) gconf)->reset_extra) + return true; + break; + case PGC_INT: + if (extra == ((struct config_int *) gconf)->reset_extra) + return true; + break; + case PGC_REAL: + if (extra == ((struct config_real *) gconf)->reset_extra) + return true; + break; + case PGC_STRING: + if (extra == ((struct config_string *) gconf)->reset_extra) + return true; + break; + case PGC_ENUM: + if (extra == ((struct config_enum *) gconf)->reset_extra) + return true; + break; + } + for (stack = gconf->stack; stack; stack = stack->prev) + { + if (extra == stack->prior.extra || + extra == stack->masked.extra) return true; } + return false; } /* - * Support for copying a variable's active value into a stack entry + * Support for assigning to an "extra" field of a GUC item. Free the prior + * value if it's not referenced anywhere else in the item (including stacked + * states). + */ +static void +set_extra_field(struct config_generic * gconf, void **field, void *newval) +{ + void *oldval = *field; + + /* Do the assignment */ + *field = newval; + + /* Free old value if it's not NULL and isn't referenced anymore */ + if (oldval && !extra_field_used(gconf, oldval)) + free(oldval); +} + +/* + * Support for copying a variable's active value into a stack entry. + * The "extra" field associated with the active value is copied, too. + * + * NB: be sure stringval and extra fields of a new stack entry are + * initialized to NULL before this is used, else we'll try to free() them. */ static void -set_stack_value(struct config_generic * gconf, union config_var_value * val) +set_stack_value(struct config_generic * gconf, config_var_value *val) { switch (gconf->vartype) { case PGC_BOOL: - val->boolval = + val->val.boolval = *((struct config_bool *) gconf)->variable; break; case PGC_INT: - val->intval = + val->val.intval = *((struct config_int *) gconf)->variable; break; case PGC_REAL: - val->realval = + val->val.realval = *((struct config_real *) gconf)->variable; break; case PGC_STRING: - /* we assume stringval is NULL if not valid */ set_string_field((struct config_string *) gconf, - &(val->stringval), + &(val->val.stringval), *((struct config_string *) gconf)->variable); break; case PGC_ENUM: - val->enumval = + val->val.enumval = *((struct config_enum *) gconf)->variable; break; } + set_extra_field(gconf, &(val->extra), gconf->extra); } /* - * Support for discarding a no-longer-needed value in a stack entry + * Support for discarding a no-longer-needed value in a stack entry. + * The "extra" field associated with the stack entry is cleared, too. */ static void -discard_stack_value(struct config_generic * gconf, union config_var_value * val) +discard_stack_value(struct config_generic * gconf, config_var_value *val) { switch (gconf->vartype) { @@ -3158,10 +3468,11 @@ discard_stack_value(struct config_generic * gconf, union config_var_value * val) break; case PGC_STRING: set_string_field((struct config_string *) gconf, - &(val->stringval), + &(val->val.stringval), NULL); break; } + set_extra_field(gconf, &(val->extra), NULL); } @@ -3493,8 +3804,6 @@ void InitializeGUCOptions(void) { int i; - char *env; - long stack_rlimit; /* * Before log_line_prefix could possibly receive a nonempty setting, make @@ -3533,9 +3842,25 @@ InitializeGUCOptions(void) /* * For historical reasons, some GUC parameters can receive defaults from - * environment variables. Process those settings. NB: if you add or - * remove anything here, see also ProcessConfigFile(). + * environment variables. Process those settings. */ + InitializeGUCOptionsFromEnvironment(); +} + +/* + * Assign any GUC values that can come from the server's environment. + * + * This is called from InitializeGUCOptions, and also from ProcessConfigFile + * to deal with the possibility that a setting has been removed from + * postgresql.conf and should now get a value from the environment. + * (The latter is a kludge that should probably go away someday; if so, + * fold this back into InitializeGUCOptions.) + */ +static void +InitializeGUCOptionsFromEnvironment(void) +{ + char *env; + long stack_rlimit; env = getenv("PGPORT"); if (env != NULL) @@ -3573,6 +3898,9 @@ InitializeGUCOptions(void) /* * Initialize one GUC option variable to its compiled-in default. + * + * Note: the reason for calling check_hooks is not that we think the boot_val + * might fail, but that the hooks might wish to compute an "extra" struct. */ static void InitializeOneGUCOption(struct config_generic * gconf) @@ -3581,6 +3909,7 @@ InitializeOneGUCOption(struct config_generic * gconf) gconf->reset_source = PGC_S_DEFAULT; gconf->source = PGC_S_DEFAULT; gconf->stack = NULL; + gconf->extra = NULL; gconf->sourcefile = NULL; gconf->sourceline = 0; @@ -3589,96 +3918,91 @@ InitializeOneGUCOption(struct config_generic * gconf) case PGC_BOOL: { struct config_bool *conf = (struct config_bool *) gconf; + bool newval = conf->boot_val; + void *extra = NULL; + if (!call_bool_check_hook(conf, &newval, &extra, + PGC_S_DEFAULT, LOG)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, (int) newval); if (conf->assign_hook) - 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; + (*conf->assign_hook) (newval, extra); + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; break; } case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; - - Assert(conf->boot_val >= conf->min); - Assert(conf->boot_val <= conf->max); + int newval = conf->boot_val; + void *extra = NULL; + + Assert(newval >= conf->min); + Assert(newval <= conf->max); + if (!call_int_check_hook(conf, &newval, &extra, + PGC_S_DEFAULT, LOG)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, newval); if (conf->assign_hook) - 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; + (*conf->assign_hook) (newval, extra); + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; break; } case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; - - Assert(conf->boot_val >= conf->min); - Assert(conf->boot_val <= conf->max); + double newval = conf->boot_val; + void *extra = NULL; + + Assert(newval >= conf->min); + Assert(newval <= conf->max); + if (!call_real_check_hook(conf, &newval, &extra, + PGC_S_DEFAULT, LOG)) + elog(FATAL, "failed to initialize %s to %g", + conf->gen.name, newval); if (conf->assign_hook) - 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; + (*conf->assign_hook) (newval, extra); + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; break; } case PGC_STRING: { struct config_string *conf = (struct config_string *) gconf; - char *str; - - *conf->variable = NULL; - conf->reset_val = NULL; - - if (conf->boot_val == NULL) - { - /* leave the value NULL, do not call assign hook */ - break; - } + char *newval; + void *extra = NULL; - str = guc_strdup(FATAL, conf->boot_val); - conf->reset_val = str; + /* non-NULL boot_val must always get strdup'd */ + if (conf->boot_val != NULL) + newval = guc_strdup(FATAL, conf->boot_val); + else + newval = NULL; + if (!call_string_check_hook(conf, &newval, &extra, + PGC_S_DEFAULT, LOG)) + elog(FATAL, "failed to initialize %s to \"%s\"", + conf->gen.name, newval ? newval : ""); if (conf->assign_hook) - { - 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; + (*conf->assign_hook) (newval, extra); + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; break; } case PGC_ENUM: { struct config_enum *conf = (struct config_enum *) gconf; + int newval = conf->boot_val; + void *extra = NULL; + if (!call_enum_check_hook(conf, &newval, &extra, + PGC_S_DEFAULT, LOG)) + elog(FATAL, "failed to initialize %s to %d", + conf->gen.name, newval); if (conf->assign_hook) - 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; + (*conf->assign_hook) (newval, extra); + *conf->variable = conf->reset_val = newval; + conf->gen.extra = conf->reset_extra = extra; break; } } @@ -3867,11 +4191,11 @@ ResetAllOptions(void) struct config_bool *conf = (struct config_bool *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, - PGC_S_SESSION)) - elog(ERROR, "failed to reset %s to %d", - conf->gen.name, (int) conf->reset_val); + (*conf->assign_hook) (conf->reset_val, + conf->reset_extra); *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); break; } case PGC_INT: @@ -3879,11 +4203,11 @@ ResetAllOptions(void) struct config_int *conf = (struct config_int *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, - PGC_S_SESSION)) - elog(ERROR, "failed to reset %s to %d", - conf->gen.name, conf->reset_val); + (*conf->assign_hook) (conf->reset_val, + conf->reset_extra); *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); break; } case PGC_REAL: @@ -3891,40 +4215,23 @@ ResetAllOptions(void) struct config_real *conf = (struct config_real *) gconf; if (conf->assign_hook) - if (!(*conf->assign_hook) (conf->reset_val, true, - PGC_S_SESSION)) - elog(ERROR, "failed to reset %s to %g", - conf->gen.name, conf->reset_val); + (*conf->assign_hook) (conf->reset_val, + conf->reset_extra); *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); break; } case PGC_STRING: { struct config_string *conf = (struct config_string *) gconf; - char *str; - - /* We need not strdup here */ - str = conf->reset_val; - - if (conf->assign_hook && str) - { - const char *newstr; - - newstr = (*conf->assign_hook) (str, true, - PGC_S_SESSION); - if (newstr == NULL) - elog(ERROR, "failed to reset %s to \"%s\"", - conf->gen.name, str); - else if (newstr != str) - { - /* - * See notes in set_config_option about casting - */ - str = (char *) newstr; - } - } - set_string_field(conf, conf->variable, str); + if (conf->assign_hook) + (*conf->assign_hook) (conf->reset_val, + conf->reset_extra); + set_string_field(conf, conf->variable, conf->reset_val); + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); break; } case PGC_ENUM: @@ -3932,12 +4239,11 @@ ResetAllOptions(void) 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->assign_hook) (conf->reset_val, + conf->reset_extra); *conf->variable = conf->reset_val; + set_extra_field(&conf->gen, &conf->gen.extra, + conf->reset_extra); break; } } @@ -4188,7 +4494,7 @@ AtEOXact_GUC(bool isCommit, int nestLevel) if (restorePrior || restoreMasked) { /* Perform appropriate restoration of the stacked value */ - union config_var_value newvalue; + config_var_value newvalue; GucSource newsource; if (restoreMasked) @@ -4207,16 +4513,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) case PGC_BOOL: { struct config_bool *conf = (struct config_bool *) gconf; - bool newval = newvalue.boolval; + bool newval = newvalue.val.boolval; + void *newextra = newvalue.extra; - if (*conf->variable != newval) + if (*conf->variable != newval || + conf->gen.extra != newextra) { if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, - true, PGC_S_OVERRIDE)) - elog(LOG, "failed to commit %s as %d", - conf->gen.name, (int) newval); + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); changed = true; } break; @@ -4224,16 +4531,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) case PGC_INT: { struct config_int *conf = (struct config_int *) gconf; - int newval = newvalue.intval; + int newval = newvalue.val.intval; + void *newextra = newvalue.extra; - if (*conf->variable != newval) + if (*conf->variable != newval || + conf->gen.extra != newextra) { if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, - true, PGC_S_OVERRIDE)) - elog(LOG, "failed to commit %s as %d", - conf->gen.name, newval); + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); changed = true; } break; @@ -4241,16 +4549,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) case PGC_REAL: { struct config_real *conf = (struct config_real *) gconf; - double newval = newvalue.realval; + double newval = newvalue.val.realval; + void *newextra = newvalue.extra; - if (*conf->variable != newval) + if (*conf->variable != newval || + conf->gen.extra != newextra) { if (conf->assign_hook) - if (!(*conf->assign_hook) (newval, - true, PGC_S_OVERRIDE)) - elog(LOG, "failed to commit %s as %g", - conf->gen.name, newval); + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); changed = true; } break; @@ -4258,33 +4567,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) case PGC_STRING: { struct config_string *conf = (struct config_string *) gconf; - char *newval = newvalue.stringval; + char *newval = newvalue.val.stringval; + void *newextra = newvalue.extra; - if (*conf->variable != newval) + if (*conf->variable != newval || + conf->gen.extra != newextra) { - if (conf->assign_hook && newval) - { - const char *newstr; - - newstr = (*conf->assign_hook) (newval, true, - PGC_S_OVERRIDE); - if (newstr == NULL) - elog(LOG, "failed to commit %s as \"%s\"", - conf->gen.name, newval); - else if (newstr != newval) - { - /* - * If newval should now be freed, - * it'll be taken care of below. - * - * See notes in set_config_option - * about casting - */ - newval = (char *) newstr; - } - } - + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); set_string_field(conf, conf->variable, newval); + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); changed = true; } @@ -4294,30 +4587,36 @@ AtEOXact_GUC(bool isCommit, int nestLevel) * we have type-specific code anyway, might as * well inline it. */ - set_string_field(conf, &stack->prior.stringval, NULL); - set_string_field(conf, &stack->masked.stringval, NULL); + set_string_field(conf, &stack->prior.val.stringval, NULL); + set_string_field(conf, &stack->masked.val.stringval, NULL); break; } case PGC_ENUM: { struct config_enum *conf = (struct config_enum *) gconf; - int newval = newvalue.enumval; + int newval = newvalue.val.enumval; + void *newextra = newvalue.extra; - if (*conf->variable != newval) + if (*conf->variable != newval || + conf->gen.extra != newextra) { 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->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); changed = true; } break; } } + /* + * Release stacked extra values if not used anymore. + */ + set_extra_field(gconf, &(stack->prior.extra), NULL); + set_extra_field(gconf, &(stack->masked.extra), NULL); + gconf->source = newsource; } @@ -4727,33 +5026,6 @@ config_enum_get_options(struct config_enum * record, const char *prefix, return retstr.data; } -/* - * Call a GucStringAssignHook function, being careful to free the - * "newval" string if the hook ereports. - * - * This is split out of set_config_option just to avoid the "volatile" - * qualifiers that would otherwise have to be plastered all over. - */ -static const char * -call_string_assign_hook(GucStringAssignHook assign_hook, - char *newval, bool doit, GucSource source) -{ - const char *result; - - PG_TRY(); - { - result = (*assign_hook) (newval, doit, source); - } - PG_CATCH(); - { - free(newval); - PG_RE_THROW(); - } - PG_END_TRY(); - - return result; -} - /* * Sets option `name' to given value. The value should be a string @@ -4789,6 +5061,7 @@ set_config_option(const char *name, const char *value, { struct config_generic *record; int elevel; + bool prohibitValueChange = false; bool makeDefault; if (context == PGC_SIGHUP || source == PGC_S_DEFAULT) @@ -4825,15 +5098,21 @@ set_config_option(const char *name, const char *value, /* * Check if the option can be set at this time. See guc.h for the precise - * rules. Note that we don't want to throw errors if we're in the SIGHUP - * context. In that case we just ignore the attempt and return true. + * rules. */ switch (record->context) { case PGC_INTERNAL: if (context == PGC_SIGHUP) + { + /* + * Historically we've just silently ignored attempts to set + * PGC_INTERNAL variables from the config file. Maybe it'd be + * better to use the prohibitValueChange logic for this? + */ return true; - if (context != PGC_INTERNAL) + } + else if (context != PGC_INTERNAL) { ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), @@ -4846,19 +5125,23 @@ set_config_option(const char *name, const char *value, if (context == PGC_SIGHUP) { /* - * We are reading a PGC_POSTMASTER var from postgresql.conf. - * We can't change the setting, so give a warning if the DBA - * tries to change it. (Throwing an error would be more - * consistent, but seems overly rigid.) + * We are re-reading a PGC_POSTMASTER variable from + * postgresql.conf. We can't change the setting, so we should + * give a warning if the DBA tries to change it. However, + * because of variant formats, canonicalization by check + * hooks, etc, we can't just compare the given string directly + * to what's stored. Set a flag to check below after we have + * the final storable value. + * + * During the "checking" pass we just do nothing, to avoid + * printing the warning twice. */ - if (changeVal && !is_newvalue_equal(record, value)) - ereport(elevel, - (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), - errmsg("parameter \"%s\" cannot be changed without restarting the server", - name))); - return true; + if (!changeVal) + return true; + + prohibitValueChange = true; } - if (context != PGC_POSTMASTER) + else if (context != PGC_POSTMASTER) { ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), @@ -5001,6 +5284,7 @@ set_config_option(const char *name, const char *value, { struct config_bool *conf = (struct config_bool *) record; bool newval; + void *newextra = NULL; if (value) { @@ -5012,32 +5296,45 @@ set_config_option(const char *name, const char *value, name))); return false; } + if (!call_bool_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; } else if (source == PGC_S_DEFAULT) + { newval = conf->boot_val; + if (!call_bool_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; + } else { newval = conf->reset_val; + newextra = conf->reset_extra; 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)) - { + if (prohibitValueChange) + { + if (*conf->variable != newval) ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %d", - name, (int) newval))); - return false; - } + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + name))); + return false; + } if (changeVal) { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); conf->gen.source = source; } if (makeDefault) @@ -5047,17 +5344,25 @@ set_config_option(const char *name, const char *value, if (conf->gen.reset_source <= source) { conf->reset_val = newval; + set_extra_field(&conf->gen, &conf->reset_extra, + newextra); conf->gen.reset_source = source; } for (stack = conf->gen.stack; stack; stack = stack->prev) { if (stack->source <= source) { - stack->prior.boolval = newval; + stack->prior.val.boolval = newval; + set_extra_field(&conf->gen, &stack->prior.extra, + newextra); stack->source = source; } } } + + /* Perhaps we didn't install newextra anywhere */ + if (newextra && !extra_field_used(&conf->gen, newextra)) + free(newextra); break; } @@ -5065,6 +5370,7 @@ set_config_option(const char *name, const char *value, { struct config_int *conf = (struct config_int *) record; int newval; + void *newextra = NULL; if (value) { @@ -5087,32 +5393,45 @@ set_config_option(const char *name, const char *value, newval, name, conf->min, conf->max))); return false; } + if (!call_int_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; } else if (source == PGC_S_DEFAULT) + { newval = conf->boot_val; + if (!call_int_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; + } else { newval = conf->reset_val; + newextra = conf->reset_extra; 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)) - { + if (prohibitValueChange) + { + if (*conf->variable != newval) ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %d", - name, newval))); - return false; - } + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + name))); + return false; + } if (changeVal) { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); conf->gen.source = source; } if (makeDefault) @@ -5122,17 +5441,25 @@ set_config_option(const char *name, const char *value, if (conf->gen.reset_source <= source) { conf->reset_val = newval; + set_extra_field(&conf->gen, &conf->reset_extra, + newextra); conf->gen.reset_source = source; } for (stack = conf->gen.stack; stack; stack = stack->prev) { if (stack->source <= source) { - stack->prior.intval = newval; + stack->prior.val.intval = newval; + set_extra_field(&conf->gen, &stack->prior.extra, + newextra); stack->source = source; } } } + + /* Perhaps we didn't install newextra anywhere */ + if (newextra && !extra_field_used(&conf->gen, newextra)) + free(newextra); break; } @@ -5140,6 +5467,7 @@ set_config_option(const char *name, const char *value, { struct config_real *conf = (struct config_real *) record; double newval; + void *newextra = NULL; if (value) { @@ -5159,32 +5487,45 @@ set_config_option(const char *name, const char *value, newval, name, conf->min, conf->max))); return false; } + if (!call_real_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; } else if (source == PGC_S_DEFAULT) + { newval = conf->boot_val; + if (!call_real_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; + } else { newval = conf->reset_val; + newextra = conf->reset_extra; 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)) - { + if (prohibitValueChange) + { + if (*conf->variable != newval) ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": %g", - name, newval))); - return false; - } + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + name))); + return false; + } if (changeVal) { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); conf->gen.source = source; } if (makeDefault) @@ -5194,17 +5535,25 @@ set_config_option(const char *name, const char *value, if (conf->gen.reset_source <= source) { conf->reset_val = newval; + set_extra_field(&conf->gen, &conf->reset_extra, + newextra); conf->gen.reset_source = source; } for (stack = conf->gen.stack; stack; stack = stack->prev) { if (stack->source <= source) { - stack->prior.realval = newval; + stack->prior.val.realval = newval; + set_extra_field(&conf->gen, &stack->prior.extra, + newextra); stack->source = source; } } } + + /* Perhaps we didn't install newextra anywhere */ + if (newextra && !extra_field_used(&conf->gen, newextra)) + free(newextra); break; } @@ -5212,95 +5561,88 @@ set_config_option(const char *name, const char *value, { struct config_string *conf = (struct config_string *) record; char *newval; + void *newextra = NULL; if (value) { + /* + * The value passed by the caller could be transient, so + * we always strdup it. + */ newval = guc_strdup(elevel, value); if (newval == NULL) return false; /* - * The only sort of "parsing" check we need to do is apply + * The only built-in "parsing" check we have is to apply * truncation if GUC_IS_NAME. */ if (conf->gen.flags & GUC_IS_NAME) truncate_identifier(newval, strlen(newval), true); + + if (!call_string_check_hook(conf, &newval, &newextra, + source, elevel)) + { + free(newval); + return false; + } } else if (source == PGC_S_DEFAULT) { - if (conf->boot_val == NULL) - newval = NULL; - else + /* non-NULL boot_val must always get strdup'd */ + if (conf->boot_val != NULL) { newval = guc_strdup(elevel, conf->boot_val); if (newval == NULL) return false; } + else + newval = NULL; + + if (!call_string_check_hook(conf, &newval, &newextra, + source, elevel)) + { + free(newval); + return false; + } } else { /* - * We could possibly avoid strdup here, but easier to make - * this case work the same as the normal assignment case; - * note the possible free of newval below. + * strdup not needed, since reset_val is already under + * guc.c's control */ - if (conf->reset_val == NULL) - newval = NULL; - else - { - newval = guc_strdup(elevel, conf->reset_val); - if (newval == NULL) - return false; - } + newval = conf->reset_val; + newextra = conf->reset_extra; 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) + if (prohibitValueChange) { - const char *hookresult; - - /* - * If the hook ereports, we have to make sure we free - * newval, else it will be a permanent memory leak. - */ - hookresult = call_string_assign_hook(conf->assign_hook, - newval, - changeVal, - source); - if (hookresult == NULL) - { - free(newval); + /* newval shouldn't be NULL, so we're a bit sloppy here */ + if (*conf->variable == NULL || newval == NULL || + strcmp(*conf->variable, newval) != 0) ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": \"%s\"", - name, value ? value : ""))); - return false; - } - else if (hookresult != newval) - { - free(newval); - - /* - * Having to cast away const here is annoying, but the - * alternative is to declare assign_hooks as returning - * char*, which would mean they'd have to cast away - * const, or as both taking and returning char*, which - * doesn't seem attractive either --- we don't want - * them to scribble on the passed str. - */ - newval = (char *) hookresult; - } + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + name))); + return false; } if (changeVal) { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); set_string_field(conf, conf->variable, newval); + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); conf->gen.source = source; } + if (makeDefault) { GucStack *stack; @@ -5308,27 +5650,37 @@ set_config_option(const char *name, const char *value, if (conf->gen.reset_source <= source) { set_string_field(conf, &conf->reset_val, newval); + set_extra_field(&conf->gen, &conf->reset_extra, + newextra); conf->gen.reset_source = source; } for (stack = conf->gen.stack; stack; stack = stack->prev) { if (stack->source <= source) { - set_string_field(conf, &stack->prior.stringval, + set_string_field(conf, &stack->prior.val.stringval, newval); + set_extra_field(&conf->gen, &stack->prior.extra, + newextra); stack->source = source; } } } + /* Perhaps we didn't install newval anywhere */ if (newval && !string_field_used(conf, newval)) free(newval); + /* Perhaps we didn't install newextra anywhere */ + if (newextra && !extra_field_used(&conf->gen, newextra)) + free(newextra); break; } + case PGC_ENUM: { struct config_enum *conf = (struct config_enum *) record; int newval; + void *newextra = NULL; if (value) { @@ -5350,33 +5702,45 @@ set_config_option(const char *name, const char *value, pfree(hintmsg); return false; } + if (!call_enum_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; } else if (source == PGC_S_DEFAULT) + { newval = conf->boot_val; + if (!call_enum_check_hook(conf, &newval, &newextra, + source, elevel)) + return false; + } else { newval = conf->reset_val; + newextra = conf->reset_extra; 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)) - { + if (prohibitValueChange) + { + if (*conf->variable != newval) ereport(elevel, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid value for parameter \"%s\": \"%s\"", - name, - config_enum_lookup_by_value(conf, newval)))); - return false; - } + (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), + errmsg("parameter \"%s\" cannot be changed without restarting the server", + name))); + return false; + } if (changeVal) { + /* Save old value to support transaction abort */ + if (!makeDefault) + push_old_value(&conf->gen, action); + + if (conf->assign_hook) + (*conf->assign_hook) (newval, newextra); *conf->variable = newval; + set_extra_field(&conf->gen, &conf->gen.extra, + newextra); conf->gen.source = source; } if (makeDefault) @@ -5386,17 +5750,25 @@ set_config_option(const char *name, const char *value, if (conf->gen.reset_source <= source) { conf->reset_val = newval; + set_extra_field(&conf->gen, &conf->reset_extra, + newextra); conf->gen.reset_source = source; } for (stack = conf->gen.stack; stack; stack = stack->prev) { if (stack->source <= source) { - stack->prior.enumval = newval; + stack->prior.val.enumval = newval; + set_extra_field(&conf->gen, &stack->prior.extra, + newextra); stack->source = source; } } } + + /* Perhaps we didn't install newextra anywhere */ + if (newextra && !extra_field_used(&conf->gen, newextra)) + free(newextra); break; } } @@ -5557,51 +5929,6 @@ GetConfigOptionResetString(const char *name) /* - * GUC_complaint_elevel - * Get the ereport error level to use in an assign_hook's error report. - * - * This should be used by assign hooks that want to emit a custom error - * 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. - * - * 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. - */ -int -GUC_complaint_elevel(GucSource source) -{ - int elevel; - - if (source == PGC_S_FILE) - { - /* - * To avoid cluttering the log, only the postmaster bleats loudly - * about problems with the config file. - */ - elevel = IsUnderPostmaster ? DEBUG3 : LOG; - } - else if (source == PGC_S_OVERRIDE) - { - /* - * 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. - */ - elevel = IsUnderPostmaster ? DEBUG5 : LOG; - } - else if (source < PGC_S_INTERACTIVE) - elevel = LOG; - else - elevel = ERROR; - - return elevel; -} - - -/* * flatten_set_variable_args * Given a parsenode List as emitted by the grammar for SET, * convert to the flat string representation used by GUC. @@ -6013,6 +6340,7 @@ define_custom_variable(struct config_generic * variable) switch (pHolder->gen.source) { case PGC_S_DEFAULT: + case PGC_S_DYNAMIC_DEFAULT: case PGC_S_ENV_VAR: case PGC_S_FILE: case PGC_S_ARGV: @@ -6094,6 +6422,7 @@ DefineCustomBoolVariable(const char *name, bool bootValue, GucContext context, int flags, + GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook) { @@ -6105,6 +6434,7 @@ DefineCustomBoolVariable(const char *name, var->variable = valueAddr; var->boot_val = bootValue; var->reset_val = bootValue; + var->check_hook = check_hook; var->assign_hook = assign_hook; var->show_hook = show_hook; define_custom_variable(&var->gen); @@ -6120,6 +6450,7 @@ DefineCustomIntVariable(const char *name, int maxValue, GucContext context, int flags, + GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook) { @@ -6133,6 +6464,7 @@ DefineCustomIntVariable(const char *name, var->reset_val = bootValue; var->min = minValue; var->max = maxValue; + var->check_hook = check_hook; var->assign_hook = assign_hook; var->show_hook = show_hook; define_custom_variable(&var->gen); @@ -6148,6 +6480,7 @@ DefineCustomRealVariable(const char *name, double maxValue, GucContext context, int flags, + GucRealCheckHook check_hook, GucRealAssignHook assign_hook, GucShowHook show_hook) { @@ -6161,6 +6494,7 @@ DefineCustomRealVariable(const char *name, var->reset_val = bootValue; var->min = minValue; var->max = maxValue; + var->check_hook = check_hook; var->assign_hook = assign_hook; var->show_hook = show_hook; define_custom_variable(&var->gen); @@ -6174,6 +6508,7 @@ DefineCustomStringVariable(const char *name, const char *bootValue, GucContext context, int flags, + GucStringCheckHook check_hook, GucStringAssignHook assign_hook, GucShowHook show_hook) { @@ -6184,9 +6519,7 @@ DefineCustomStringVariable(const char *name, PGC_STRING, sizeof(struct config_string)); var->variable = 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); + var->check_hook = check_hook; var->assign_hook = assign_hook; var->show_hook = show_hook; define_custom_variable(&var->gen); @@ -6201,6 +6534,7 @@ DefineCustomEnumVariable(const char *name, const struct config_enum_entry * options, GucContext context, int flags, + GucEnumCheckHook check_hook, GucEnumAssignHook assign_hook, GucShowHook show_hook) { @@ -6213,6 +6547,7 @@ DefineCustomEnumVariable(const char *name, var->boot_val = bootValue; var->reset_val = bootValue; var->options = options; + var->check_hook = check_hook; var->assign_hook = assign_hook; var->show_hook = show_hook; define_custom_variable(&var->gen); @@ -6974,67 +7309,6 @@ _ShowOption(struct config_generic * record, bool use_units) } -/* - * Attempt (badly) to detect if a proposed new GUC setting is the same - * as the current value. - * - * XXX this does not really work because it doesn't account for the - * effects of canonicalization of string values by assign_hooks. - */ -static bool -is_newvalue_equal(struct config_generic * record, const char *newvalue) -{ - /* newvalue == NULL isn't supported */ - Assert(newvalue != NULL); - - switch (record->vartype) - { - case PGC_BOOL: - { - struct config_bool *conf = (struct config_bool *) record; - bool newval; - - return parse_bool(newvalue, &newval) - && *conf->variable == newval; - } - case PGC_INT: - { - struct config_int *conf = (struct config_int *) record; - int newval; - - return parse_int(newvalue, &newval, record->flags, NULL) - && *conf->variable == newval; - } - case PGC_REAL: - { - struct config_real *conf = (struct config_real *) record; - double newval; - - return parse_real(newvalue, &newval) - && *conf->variable == newval; - } - case PGC_STRING: - { - struct config_string *conf = (struct config_string *) record; - - 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; -} - - #ifdef EXEC_BACKEND /* @@ -7652,30 +7926,222 @@ validate_option_array_item(const char *name, const char *value, /* - * assign_hook and show_hook subroutines + * Called by check_hooks that want to override the normal + * ERRCODE_INVALID_PARAMETER_VALUE SQLSTATE for check hook failures. + * + * Note that GUC_check_errmsg() etc are just macros that result in a direct + * assignment to the associated variables. That is ugly, but forced by the + * limitations of C's macro mechanisms. + */ +void +GUC_check_errcode(int sqlerrcode) +{ + GUC_check_errcode_value = sqlerrcode; +} + + +/* + * Convenience functions to manage calling a variable's check_hook. + * These mostly take care of the protocol for letting check hooks supply + * portions of the error report on failure. */ -static const char * -assign_log_destination(const char *value, bool doit, GucSource source) +static bool +call_bool_check_hook(struct config_bool * conf, bool *newval, void **extra, + GucSource source, int elevel) +{ + /* Quick success if no hook */ + if (!conf->check_hook) + return true; + + /* Reset variables that might be set by hook */ + GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; + GUC_check_errmsg_string = NULL; + GUC_check_errdetail_string = NULL; + GUC_check_errhint_string = NULL; + + if (!(*conf->check_hook) (newval, extra, source)) + { + ereport(elevel, + (errcode(GUC_check_errcode_value), + GUC_check_errmsg_string ? + errmsg("%s", GUC_check_errmsg_string) : + errmsg("invalid value for parameter \"%s\": %d", + conf->gen.name, (int) *newval), + GUC_check_errdetail_string ? + errdetail("%s", GUC_check_errdetail_string) : 0, + GUC_check_errhint_string ? + errhint("%s", GUC_check_errhint_string) : 0)); + /* Flush any strings created in ErrorContext */ + FlushErrorState(); + return false; + } + + return true; +} + +static bool +call_int_check_hook(struct config_int * conf, int *newval, void **extra, + GucSource source, int elevel) +{ + /* Quick success if no hook */ + if (!conf->check_hook) + return true; + + /* Reset variables that might be set by hook */ + GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; + GUC_check_errmsg_string = NULL; + GUC_check_errdetail_string = NULL; + GUC_check_errhint_string = NULL; + + if (!(*conf->check_hook) (newval, extra, source)) + { + ereport(elevel, + (errcode(GUC_check_errcode_value), + GUC_check_errmsg_string ? + errmsg("%s", GUC_check_errmsg_string) : + errmsg("invalid value for parameter \"%s\": %d", + conf->gen.name, *newval), + GUC_check_errdetail_string ? + errdetail("%s", GUC_check_errdetail_string) : 0, + GUC_check_errhint_string ? + errhint("%s", GUC_check_errhint_string) : 0)); + /* Flush any strings created in ErrorContext */ + FlushErrorState(); + return false; + } + + return true; +} + +static bool +call_real_check_hook(struct config_real * conf, double *newval, void **extra, + GucSource source, int elevel) +{ + /* Quick success if no hook */ + if (!conf->check_hook) + return true; + + /* Reset variables that might be set by hook */ + GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; + GUC_check_errmsg_string = NULL; + GUC_check_errdetail_string = NULL; + GUC_check_errhint_string = NULL; + + if (!(*conf->check_hook) (newval, extra, source)) + { + ereport(elevel, + (errcode(GUC_check_errcode_value), + GUC_check_errmsg_string ? + errmsg("%s", GUC_check_errmsg_string) : + errmsg("invalid value for parameter \"%s\": %g", + conf->gen.name, *newval), + GUC_check_errdetail_string ? + errdetail("%s", GUC_check_errdetail_string) : 0, + GUC_check_errhint_string ? + errhint("%s", GUC_check_errhint_string) : 0)); + /* Flush any strings created in ErrorContext */ + FlushErrorState(); + return false; + } + + return true; +} + +static bool +call_string_check_hook(struct config_string * conf, char **newval, void **extra, + GucSource source, int elevel) +{ + /* Quick success if no hook */ + if (!conf->check_hook) + return true; + + /* Reset variables that might be set by hook */ + GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; + GUC_check_errmsg_string = NULL; + GUC_check_errdetail_string = NULL; + GUC_check_errhint_string = NULL; + + if (!(*conf->check_hook) (newval, extra, source)) + { + ereport(elevel, + (errcode(GUC_check_errcode_value), + GUC_check_errmsg_string ? + errmsg("%s", GUC_check_errmsg_string) : + errmsg("invalid value for parameter \"%s\": \"%s\"", + conf->gen.name, *newval ? *newval : ""), + GUC_check_errdetail_string ? + errdetail("%s", GUC_check_errdetail_string) : 0, + GUC_check_errhint_string ? + errhint("%s", GUC_check_errhint_string) : 0)); + /* Flush any strings created in ErrorContext */ + FlushErrorState(); + return false; + } + + return true; +} + +static bool +call_enum_check_hook(struct config_enum * conf, int *newval, void **extra, + GucSource source, int elevel) +{ + /* Quick success if no hook */ + if (!conf->check_hook) + return true; + + /* Reset variables that might be set by hook */ + GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; + GUC_check_errmsg_string = NULL; + GUC_check_errdetail_string = NULL; + GUC_check_errhint_string = NULL; + + if (!(*conf->check_hook) (newval, extra, source)) + { + ereport(elevel, + (errcode(GUC_check_errcode_value), + GUC_check_errmsg_string ? + errmsg("%s", GUC_check_errmsg_string) : + errmsg("invalid value for parameter \"%s\": \"%s\"", + conf->gen.name, + config_enum_lookup_by_value(conf, *newval)), + GUC_check_errdetail_string ? + errdetail("%s", GUC_check_errdetail_string) : 0, + GUC_check_errhint_string ? + errhint("%s", GUC_check_errhint_string) : 0)); + /* Flush any strings created in ErrorContext */ + FlushErrorState(); + return false; + } + + return true; +} + + +/* + * check_hook, assign_hook and show_hook subroutines + */ + +static bool +check_log_destination(char **newval, void **extra, GucSource source) { char *rawstring; List *elemlist; ListCell *l; int newlogdest = 0; + int *myextra; /* Need a modifiable copy of string */ - rawstring = pstrdup(value); + rawstring = pstrdup(*newval); /* Parse string into list of identifiers */ if (!SplitIdentifierString(rawstring, ',', &elemlist)) { /* syntax error in list */ + GUC_check_errdetail("List syntax is invalid."); pfree(rawstring); list_free(elemlist); - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid list syntax for parameter \"log_destination\""))); - return NULL; + return false; } foreach(l, elemlist) @@ -7696,105 +8162,103 @@ assign_log_destination(const char *value, bool doit, GucSource source) #endif else { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized \"log_destination\" key word: \"%s\"", - tok))); + GUC_check_errdetail("Unrecognized key word: \"%s\".", tok); pfree(rawstring); list_free(elemlist); - return NULL; + return false; } } - if (doit) - Log_destination = newlogdest; - pfree(rawstring); list_free(elemlist); - return value; + myextra = (int *) guc_malloc(ERROR, sizeof(int)); + *myextra = newlogdest; + *extra = (void *) myextra; + + return true; } -static bool -assign_syslog_facility(int newval, bool doit, GucSource source) +static void +assign_log_destination(const char *newval, void *extra) +{ + Log_destination = *((int *) extra); +} + +static void +assign_syslog_facility(int newval, void *extra) { #ifdef HAVE_SYSLOG - if (doit) - set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres", - newval); + set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres", + newval); #endif /* Without syslog support, just ignore it */ - - return true; } -static const char * -assign_syslog_ident(const char *ident, bool doit, GucSource source) +static void +assign_syslog_ident(const char *newval, void *extra) { #ifdef HAVE_SYSLOG - if (doit) - set_syslog_parameters(ident, syslog_facility); + set_syslog_parameters(newval, syslog_facility); #endif /* Without syslog support, it will always be set to "none", so ignore */ - - return ident; } -static bool -assign_session_replication_role(int newval, bool doit, GucSource source) +static void +assign_session_replication_role(int newval, void *extra) { /* * Must flush the plan cache when changing replication role; but don't * flush unnecessarily. */ - if (doit && SessionReplicationRole != newval) - { + if (SessionReplicationRole != newval) ResetPlanCache(); - } - - return true; } -static const char * -show_num_temp_buffers(void) +static bool +check_temp_buffers(int *newval, void **extra, GucSource source) { /* - * We show the GUC var until local buffers have been initialized, and - * NLocBuffer afterwards. + * Once local buffers have been initialized, it's too late to change this. */ - static char nbuf[32]; - - sprintf(nbuf, "%d", NLocBuffer ? NLocBuffer : num_temp_buffers); - return nbuf; + if (NLocBuffer && NLocBuffer != *newval) + { + GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session."); + return false; + } + return true; } static bool -assign_phony_autocommit(bool newval, bool doit, GucSource source) +check_phony_autocommit(bool *newval, void **extra, GucSource source) { - if (!newval) + if (!*newval) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("SET AUTOCOMMIT TO OFF is no longer supported"))); + GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED); + GUC_check_errmsg("SET AUTOCOMMIT TO OFF is no longer supported"); return false; } return true; } -static const char * -assign_custom_variable_classes(const char *newval, bool doit, GucSource source) +static bool +check_custom_variable_classes(char **newval, void **extra, GucSource source) { /* * Check syntax. newval must be a comma separated list of identifiers. * Whitespace is allowed but removed from the result. */ bool hasSpaceAfterToken = false; - const char *cp = newval; + const char *cp = *newval; int symLen = 0; char c; StringInfoData buf; + /* Default NULL is OK */ + if (cp == NULL) + return true; + initStringInfo(&buf); while ((c = *cp++) != '\0') { @@ -7823,7 +8287,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) * non-identifier character */ pfree(buf.data); - return NULL; + return false; } appendStringInfoChar(&buf, c); symLen++; @@ -7834,21 +8298,20 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source) buf.data[--buf.len] = '\0'; /* GUC wants the result malloc'd */ - newval = guc_strdup(LOG, buf.data); + free(*newval); + *newval = guc_strdup(LOG, buf.data); pfree(buf.data); - return newval; + return true; } static bool -assign_debug_assertions(bool newval, bool doit, GucSource source) +check_debug_assertions(bool *newval, void **extra, GucSource source) { #ifndef USE_ASSERT_CHECKING - if (newval) + if (*newval) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("assertion checking is not supported by this build"))); + GUC_check_errmsg("assertion checking is not supported by this build"); return false; } #endif @@ -7856,14 +8319,12 @@ assign_debug_assertions(bool newval, bool doit, GucSource source) } static bool -assign_bonjour(bool newval, bool doit, GucSource source) +check_bonjour(bool *newval, void **extra, GucSource source) { #ifndef USE_BONJOUR - if (newval) + if (*newval) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Bonjour is not supported by this build"))); + GUC_check_errmsg("Bonjour is not supported by this build"); return false; } #endif @@ -7871,14 +8332,12 @@ assign_bonjour(bool newval, bool doit, GucSource source) } static bool -assign_ssl(bool newval, bool doit, GucSource source) +check_ssl(bool *newval, void **extra, GucSource source) { #ifndef USE_SSL - if (newval) + if (*newval) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("SSL is not supported by this build"))); + GUC_check_errmsg("SSL is not supported by this build"); return false; } #endif @@ -7886,92 +8345,81 @@ assign_ssl(bool newval, bool doit, GucSource source) } static bool -assign_stage_log_stats(bool newval, bool doit, GucSource source) +check_stage_log_stats(bool *newval, void **extra, GucSource source) { - if (newval && log_statement_stats) + if (*newval && log_statement_stats) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot enable parameter when \"log_statement_stats\" is true"))); - /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */ - if (source != PGC_S_OVERRIDE) - return false; + GUC_check_errdetail("Cannot enable parameter when \"log_statement_stats\" is true."); + return false; } return true; } static bool -assign_log_stats(bool newval, bool doit, GucSource source) +check_log_stats(bool *newval, void **extra, GucSource source) { - if (newval && + if (*newval && (log_parser_stats || log_planner_stats || log_executor_stats)) { - ereport(GUC_complaint_elevel(source), - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot enable \"log_statement_stats\" when " - "\"log_parser_stats\", \"log_planner_stats\", " - "or \"log_executor_stats\" is true"))); - /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */ - if (source != PGC_S_OVERRIDE) - return false; + GUC_check_errdetail("Cannot enable \"log_statement_stats\" when " + "\"log_parser_stats\", \"log_planner_stats\", " + "or \"log_executor_stats\" is true."); + return false; } return true; } -static const char * -assign_canonical_path(const char *newval, bool doit, GucSource source) +static bool +check_canonical_path(char **newval, void **extra, GucSource source) { - if (doit) - { - char *canon_val = guc_strdup(ERROR, newval); - - canonicalize_path(canon_val); - return canon_val; - } - else - return newval; + /* + * Since canonicalize_path never enlarges the string, we can just modify + * newval in-place. But watch out for NULL, which is the default value + * for external_pid_file. + */ + if (*newval) + canonicalize_path(*newval); + return true; } -static const char * -assign_timezone_abbreviations(const char *newval, bool doit, GucSource source) +static bool +check_timezone_abbreviations(char **newval, void **extra, GucSource source) { /* - * The powerup value shown above for timezone_abbreviations is "UNKNOWN". - * When we see this we just do nothing. If this value isn't overridden - * from the config file then pg_timezone_abbrev_initialize() will - * eventually replace it with "Default". This hack has two purposes: to - * avoid wasting cycles loading values that might soon be overridden from - * the config file, and to avoid trying to read the timezone abbrev files + * The boot_val given above for timezone_abbreviations is NULL. When we + * see this we just do nothing. If this value isn't overridden from the + * config file then pg_timezone_abbrev_initialize() will eventually + * replace it with "Default". This hack has two purposes: to avoid + * wasting cycles loading values that might soon be overridden from the + * config file, and to avoid trying to read the timezone abbrev files * during InitializeGUCOptions(). The latter doesn't work in an * EXEC_BACKEND subprocess because my_exec_path hasn't been set yet and so - * we can't locate PGSHAREDIR. (Essentially the same hack is used to - * delay initializing TimeZone ... if we have any more, we should try to - * clean up and centralize this mechanism ...) + * we can't locate PGSHAREDIR. */ - if (strcmp(newval, "UNKNOWN") == 0) + if (*newval == NULL) { - return newval; + Assert(source == PGC_S_DEFAULT); + return true; } - /* Loading abbrev file is expensive, so only do it when value changes */ - if (timezone_abbreviations_string == NULL || - strcmp(timezone_abbreviations_string, newval) != 0) - { - int elevel; + /* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */ + *extra = load_tzoffsets(*newval); - /* - * If reading config file, only the postmaster should bleat loudly - * about problems. Otherwise, it's just this one process doing it, - * and we use WARNING message level. - */ - if (source == PGC_S_FILE) - elevel = IsUnderPostmaster ? DEBUG3 : LOG; - else - elevel = WARNING; - if (!load_tzoffsets(newval, doit, elevel)) - return NULL; - } - return newval; + /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */ + if (!*extra) + return false; + + return true; +} + +static void +assign_timezone_abbreviations(const char *newval, void *extra) +{ + /* Do nothing for the boot_val default of NULL */ + if (!extra) + return; + + InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra); } /* @@ -7979,15 +8427,13 @@ assign_timezone_abbreviations(const char *newval, bool doit, GucSource source) * * This is called after initial loading of postgresql.conf. If no * timezone_abbreviations setting was found therein, select default. + * If a non-default value is already installed, nothing will happen. */ void pg_timezone_abbrev_initialize(void) { - if (strcmp(timezone_abbreviations_string, "UNKNOWN") == 0) - { - SetConfigOption("timezone_abbreviations", "Default", - PGC_POSTMASTER, PGC_S_ARGV); - } + SetConfigOption("timezone_abbreviations", "Default", + PGC_POSTMASTER, PGC_S_DYNAMIC_DEFAULT); } static const char * @@ -7999,54 +8445,61 @@ show_archive_command(void) return "(disabled)"; } -static bool -assign_tcp_keepalives_idle(int newval, bool doit, GucSource source) +static void +assign_tcp_keepalives_idle(int newval, void *extra) { - if (doit) - return (pq_setkeepalivesidle(newval, MyProcPort) == STATUS_OK); - - return true; + /* + * The kernel API provides no way to test a value without setting it; and + * once we set it we might fail to unset it. So there seems little point + * in fully implementing the check-then-assign GUC API for these + * variables. Instead we just do the assignment on demand. pqcomm.c + * reports any problems via elog(LOG). + * + * This approach means that the GUC value might have little to do with the + * actual kernel value, so we use a show_hook that retrieves the kernel + * value rather than trusting GUC's copy. + */ + (void) pq_setkeepalivesidle(newval, MyProcPort); } static const char * show_tcp_keepalives_idle(void) { + /* See comments in assign_tcp_keepalives_idle */ static char nbuf[16]; snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesidle(MyProcPort)); return nbuf; } -static bool -assign_tcp_keepalives_interval(int newval, bool doit, GucSource source) +static void +assign_tcp_keepalives_interval(int newval, void *extra) { - if (doit) - return (pq_setkeepalivesinterval(newval, MyProcPort) == STATUS_OK); - - return true; + /* See comments in assign_tcp_keepalives_idle */ + (void) pq_setkeepalivesinterval(newval, MyProcPort); } static const char * show_tcp_keepalives_interval(void) { + /* See comments in assign_tcp_keepalives_idle */ static char nbuf[16]; snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesinterval(MyProcPort)); return nbuf; } -static bool -assign_tcp_keepalives_count(int newval, bool doit, GucSource source) +static void +assign_tcp_keepalives_count(int newval, void *extra) { - if (doit) - return (pq_setkeepalivescount(newval, MyProcPort) == STATUS_OK); - - return true; + /* See comments in assign_tcp_keepalives_idle */ + (void) pq_setkeepalivescount(newval, MyProcPort); } static const char * show_tcp_keepalives_count(void) { + /* See comments in assign_tcp_keepalives_idle */ static char nbuf[16]; snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivescount(MyProcPort)); @@ -8054,31 +8507,35 @@ show_tcp_keepalives_count(void) } static bool -assign_maxconnections(int newval, bool doit, GucSource source) +check_maxconnections(int *newval, void **extra, GucSource source) { - if (newval + autovacuum_max_workers + 1 > MAX_BACKENDS) + if (*newval + autovacuum_max_workers + 1 > MAX_BACKENDS) return false; - - if (doit) - MaxBackends = newval + autovacuum_max_workers + 1; - return true; } +static void +assign_maxconnections(int newval, void *extra) +{ + MaxBackends = newval + autovacuum_max_workers + 1; +} + static bool -assign_autovacuum_max_workers(int newval, bool doit, GucSource source) +check_autovacuum_max_workers(int *newval, void **extra, GucSource source) { - if (MaxConnections + newval + 1 > MAX_BACKENDS) + if (MaxConnections + *newval + 1 > MAX_BACKENDS) return false; - - if (doit) - MaxBackends = MaxConnections + newval + 1; - return true; } +static void +assign_autovacuum_max_workers(int newval, void *extra) +{ + MaxBackends = MaxConnections + newval + 1; +} + static bool -assign_effective_io_concurrency(int newval, bool doit, GucSource source) +check_effective_io_concurrency(int *newval, void **extra, GucSource source) { #ifdef USE_PREFETCH double new_prefetch_pages = 0.0; @@ -8087,6 +8544,8 @@ assign_effective_io_concurrency(int newval, bool doit, GucSource source) /*---------- * 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 target value is stashed in *extra and then assigned to the actual + * variable by assign_effective_io_concurrency. * * The expected number of prefetch pages needed to keep N drives busy is: * @@ -8111,18 +8570,21 @@ assign_effective_io_concurrency(int newval, bool doit, GucSource source) * 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. + * Note that if *newval = 0 (disabled), we must set target = 0. *---------- */ - for (i = 1; i <= newval; i++) - new_prefetch_pages += (double) newval / (double) i; + 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); + int *myextra = (int *) guc_malloc(ERROR, sizeof(int)); + + *myextra = (int) rint(new_prefetch_pages); + *extra = (void *) myextra; + return true; } else @@ -8132,57 +8594,54 @@ assign_effective_io_concurrency(int newval, bool doit, GucSource source) #endif /* USE_PREFETCH */ } -static const char * -assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source) +static void +assign_effective_io_concurrency(int newval, void *extra) { - 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); +#ifdef USE_PREFETCH + target_prefetch_pages = *((int *) extra); +#endif /* USE_PREFETCH */ +} - if (pgstat_stat_tmpname) - free(pgstat_stat_tmpname); - pgstat_stat_tmpname = tname; - if (pgstat_stat_filename) - free(pgstat_stat_filename); - pgstat_stat_filename = fname; +static void +assign_pgstat_temp_directory(const char *newval, void *extra) +{ + /* check_canonical_path already canonicalized newval for us */ + char *tname; + char *fname; - return canon_val; - } - else - return newval; + tname = guc_malloc(ERROR, strlen(newval) + 12); /* /pgstat.tmp */ + sprintf(tname, "%s/pgstat.tmp", newval); + fname = guc_malloc(ERROR, strlen(newval) + 13); /* /pgstat.stat */ + sprintf(fname, "%s/pgstat.stat", newval); + + if (pgstat_stat_tmpname) + free(pgstat_stat_tmpname); + pgstat_stat_tmpname = tname; + if (pgstat_stat_filename) + free(pgstat_stat_filename); + pgstat_stat_filename = fname; } -static const char * -assign_application_name(const char *newval, bool doit, GucSource source) +static bool +check_application_name(char **newval, void **extra, GucSource source) { - if (doit) - { - /* Only allow clean ASCII chars in the application name */ - char *repval = guc_strdup(ERROR, newval); - char *p; + /* Only allow clean ASCII chars in the application name */ + char *p; - for (p = repval; *p; p++) - { - if (*p < 32 || *p > 126) - *p = '?'; - } + for (p = *newval; *p; p++) + { + if (*p < 32 || *p > 126) + *p = '?'; + } - /* Update the pg_stat_activity view */ - pgstat_report_appname(repval); + return true; +} - return repval; - } - else - return newval; +static void +assign_application_name(const char *newval, void *extra) +{ + /* Update the pg_stat_activity view */ + pgstat_report_appname(newval); } static const char *