diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-04-07 00:11:01 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-04-07 00:12:02 -0400 |
commit | 2594cf0e8c04406ffff19b1651c5a406d376657c (patch) | |
tree | 8ced737d26b54f4499a8029d8cad0ab42fc83ba3 /src/backend/utils/misc/guc.c | |
parent | 5d0e462366f4521e37744fdb42fed3c6819a3374 (diff) | |
download | postgresql-2594cf0e8c04406ffff19b1651c5a406d376657c.tar.gz postgresql-2594cf0e8c04406ffff19b1651c5a406d376657c.zip |
Revise the API for GUC variable assign hooks.
The previous functions of assign hooks are now split between check hooks
and assign hooks, where the former can fail but the latter shouldn't.
Aside from being conceptually clearer, this approach exposes the
"canonicalized" form of the variable value to guc.c without having to do
an actual assignment. And that lets us fix the problem recently noted by
Bernd Helmle that the auto-tune patch for wal_buffers resulted in bogus
log messages about "parameter "wal_buffers" cannot be changed without
restarting the server". There may be some speed advantage too, because
this design lets hook functions avoid re-parsing variable values when
restoring a previous state after a rollback (they can store a pre-parsed
representation of the value instead). This patch also resolves a
longstanding annoyance about custom error messages from variable assign
hooks: they should modify, not appear separately from, guc.c's own message
about "invalid parameter value".
Diffstat (limited to 'src/backend/utils/misc/guc.c')
-rw-r--r-- | src/backend/utils/misc/guc.c | 2276 |
1 files changed, 1354 insertions, 922 deletions
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 2151fde3618..5e4904aeb7f 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); @@ -407,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; @@ -444,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; @@ -455,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; /* @@ -643,7 +661,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_seqscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -651,7 +670,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_indexscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -659,7 +679,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_bitmapscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD, @@ -667,7 +688,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_tidscan, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD, @@ -675,7 +697,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_sort, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD, @@ -683,7 +706,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_hashagg, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_material", PGC_USERSET, QUERY_TUNING_METHOD, @@ -691,7 +715,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_material, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD, @@ -699,7 +724,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_nestloop, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD, @@ -707,7 +733,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_mergejoin, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD, @@ -715,7 +742,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_hashjoin, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"geqo", PGC_USERSET, QUERY_TUNING_GEQO, @@ -724,7 +752,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 */ @@ -734,7 +763,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, @@ -742,7 +772,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &enable_bonjour, - false, assign_bonjour, NULL + false, + check_bonjour, NULL, NULL }, { {"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY, @@ -750,7 +781,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &EnableSSL, - false, assign_ssl, NULL + false, + check_ssl, NULL, NULL }, { {"fsync", PGC_SIGHUP, WAL_SETTINGS, @@ -761,7 +793,8 @@ static struct config_bool ConfigureNamesBool[] = "an operating system or hardware crash.") }, &enableFsync, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"zero_damaged_pages", PGC_SUSET, DEVELOPER_OPTIONS, @@ -774,7 +807,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, @@ -786,7 +820,8 @@ static struct config_bool ConfigureNamesBool[] = "is possible.") }, &fullPageWrites, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"silent_mode", PGC_POSTMASTER, LOGGING_WHERE, @@ -795,7 +830,8 @@ static struct config_bool ConfigureNamesBool[] = "background and any controlling terminals are dissociated.") }, &SilentMode, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_checkpoints", PGC_SIGHUP, LOGGING_WHAT, @@ -803,7 +839,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_checkpoints, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_connections", PGC_BACKEND, LOGGING_WHAT, @@ -811,7 +848,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_connections, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_disconnections", PGC_BACKEND, LOGGING_WHAT, @@ -819,7 +857,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_disconnections, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_assertions", PGC_USERSET, DEVELOPER_OPTIONS, @@ -833,7 +872,7 @@ static struct config_bool ConfigureNamesBool[] = #else false, #endif - assign_debug_assertions, NULL + check_debug_assertions, NULL, NULL }, { @@ -842,7 +881,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &ExitOnAnyError, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"restart_after_crash", PGC_SIGHUP, ERROR_HANDLING_OPTIONS, @@ -850,7 +890,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &restart_after_crash, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -859,7 +900,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_duration, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_parse", PGC_USERSET, LOGGING_WHAT, @@ -867,7 +909,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_parse, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_rewritten", PGC_USERSET, LOGGING_WHAT, @@ -875,7 +918,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_rewritten, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_print_plan", PGC_USERSET, LOGGING_WHAT, @@ -883,7 +927,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_print_plan, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"debug_pretty_print", PGC_USERSET, LOGGING_WHAT, @@ -891,7 +936,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Debug_pretty_print, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"log_parser_stats", PGC_SUSET, STATS_MONITORING, @@ -899,7 +945,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, @@ -907,7 +954,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, @@ -915,7 +963,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, @@ -923,7 +972,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 { @@ -933,7 +983,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &log_btree_build_stats, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -945,7 +996,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, @@ -953,7 +1005,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &pgstat_track_counts, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -962,7 +1015,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 }, { @@ -971,7 +1025,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &autovacuum_start_daemon, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -981,7 +1036,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Trace_notify, - false, NULL, NULL + false, + NULL, NULL, NULL }, #ifdef LOCK_DEBUG @@ -992,7 +1048,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, @@ -1001,7 +1058,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, @@ -1010,7 +1068,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, @@ -1019,7 +1078,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &Debug_deadlocks, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1029,7 +1089,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &log_lock_waits, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1041,7 +1102,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, @@ -1049,7 +1111,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &SQL_inheritance, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"password_encryption", PGC_USERSET, CONN_AUTH_SECURITY, @@ -1059,7 +1122,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, @@ -1071,7 +1135,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, @@ -1079,7 +1144,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Db_user_namespace, - false, NULL, NULL + false, + NULL, NULL, NULL }, { /* only here for backwards compatibility */ @@ -1089,7 +1155,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, @@ -1097,7 +1164,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &DefaultXactReadOnly, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1106,7 +1174,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, @@ -1114,7 +1183,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &DefaultXactDeferrable, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1123,7 +1193,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, @@ -1131,7 +1202,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &check_function_bodies, - true, NULL, NULL + true, + NULL, NULL, NULL }, { {"array_nulls", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, @@ -1141,7 +1213,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, @@ -1149,7 +1222,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &default_with_oids, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"logging_collector", PGC_POSTMASTER, LOGGING_WHERE, @@ -1157,7 +1231,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Logging_collector, - false, NULL, NULL + false, + NULL, NULL, NULL }, { {"log_truncate_on_rotation", PGC_SIGHUP, LOGGING_WHERE, @@ -1165,7 +1240,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &Log_truncate_on_rotation, - false, NULL, NULL + false, + NULL, NULL, NULL }, #ifdef TRACE_SORT @@ -1176,7 +1252,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &trace_sort, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1189,7 +1266,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &trace_syncscan, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1203,7 +1281,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &optimize_bounded_sort, - true, NULL, NULL + true, + NULL, NULL, NULL }, #endif @@ -1215,7 +1294,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &XLOG_DEBUG, - false, NULL, NULL + false, + NULL, NULL, NULL }, #endif @@ -1227,10 +1307,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 }, { @@ -1239,7 +1320,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &pg_krb_caseins_users, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1248,7 +1330,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &escape_string_warning, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1258,7 +1341,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_REPORT }, &standard_conforming_strings, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1267,7 +1351,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &synchronize_seqscans, - true, NULL, NULL + true, + NULL, NULL, NULL }, { @@ -1276,7 +1361,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &XLogArchiveMode, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1285,7 +1371,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &EnableHotStandby, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1294,7 +1381,8 @@ static struct config_bool ConfigureNamesBool[] = NULL }, &hot_standby_feedback, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1304,7 +1392,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &allowSystemTableMods, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1315,7 +1404,8 @@ static struct config_bool ConfigureNamesBool[] = GUC_NOT_IN_SAMPLE }, &IgnoreSystemIndexes, - false, NULL, NULL + false, + NULL, NULL, NULL }, { @@ -1325,7 +1415,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 }, { @@ -1334,12 +1425,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 } }; @@ -1354,7 +1446,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, @@ -1363,7 +1456,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, @@ -1372,7 +1466,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, @@ -1383,7 +1478,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, @@ -1394,7 +1490,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, @@ -1402,7 +1499,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, @@ -1410,7 +1508,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, @@ -1418,7 +1517,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, @@ -1426,7 +1526,8 @@ 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 }, { @@ -1437,7 +1538,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &DeadlockTimeout, - 1000, 1, INT_MAX, NULL, NULL + 1000, 1, INT_MAX, + NULL, NULL, NULL }, { @@ -1447,7 +1549,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &max_standby_archive_delay, - 30 * 1000, -1, INT_MAX, NULL, NULL + 30 * 1000, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1457,7 +1560,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &max_standby_streaming_delay, - 30 * 1000, -1, INT_MAX, NULL, NULL + 30 * 1000, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1467,7 +1571,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 }, { @@ -1476,7 +1581,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &MaxConnections, - 100, 1, MAX_BACKENDS, assign_maxconnections, NULL + 100, 1, MAX_BACKENDS, + check_maxconnections, assign_maxconnections, NULL }, { @@ -1485,7 +1591,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &ReservedBackends, - 3, 0, MAX_BACKENDS, NULL, NULL + 3, 0, MAX_BACKENDS, + NULL, NULL, NULL }, /* @@ -1499,7 +1606,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 }, { @@ -1509,7 +1617,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 }, { @@ -1518,7 +1627,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &PostPortNumber, - DEF_PGPORT, 1, 65535, NULL, NULL + DEF_PGPORT, 1, 65535, + NULL, NULL, NULL }, { @@ -1532,7 +1642,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 }, { @@ -1545,7 +1656,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 }, { @@ -1557,7 +1669,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_KB }, &work_mem, - 1024, 64, MAX_KILOBYTES, NULL, NULL + 1024, 64, MAX_KILOBYTES, + NULL, NULL, NULL }, { @@ -1567,7 +1680,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 }, /* @@ -1582,7 +1696,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 }, { @@ -1591,7 +1706,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageHit, - 1, 0, 10000, NULL, NULL + 1, 0, 10000, + NULL, NULL, NULL }, { @@ -1600,7 +1716,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageMiss, - 10, 0, 10000, NULL, NULL + 10, 0, 10000, + NULL, NULL, NULL }, { @@ -1609,7 +1726,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostPageDirty, - 20, 0, 10000, NULL, NULL + 20, 0, 10000, + NULL, NULL, NULL }, { @@ -1618,7 +1736,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &VacuumCostLimit, - 200, 1, 10000, NULL, NULL + 200, 1, 10000, + NULL, NULL, NULL }, { @@ -1628,7 +1747,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &VacuumCostDelay, - 0, 0, 100, NULL, NULL + 0, 0, 100, + NULL, NULL, NULL }, { @@ -1638,7 +1758,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &autovacuum_vac_cost_delay, - 20, -1, 100, NULL, NULL + 20, -1, 100, + NULL, NULL, NULL }, { @@ -1647,7 +1768,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &autovacuum_vac_cost_limit, - -1, -1, 10000, NULL, NULL + -1, -1, 10000, + NULL, NULL, NULL }, { @@ -1656,7 +1778,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_files_per_process, - 1000, 25, INT_MAX, NULL, NULL + 1000, 25, INT_MAX, + NULL, NULL, NULL }, /* @@ -1668,7 +1791,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 @@ -1679,7 +1803,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, @@ -1688,7 +1813,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 @@ -1699,7 +1825,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &StatementTimeout, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1708,7 +1835,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_freeze_min_age, - 50000000, 0, 1000000000, NULL, NULL + 50000000, 0, 1000000000, + NULL, NULL, NULL }, { @@ -1717,7 +1845,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_freeze_table_age, - 150000000, 0, 2000000000, NULL, NULL + 150000000, 0, 2000000000, + NULL, NULL, NULL }, { @@ -1726,7 +1855,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &vacuum_defer_cleanup_age, - 0, 0, 1000000, NULL, NULL + 0, 0, 1000000, + NULL, NULL, NULL }, /* @@ -1740,7 +1870,8 @@ 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 }, { @@ -1751,7 +1882,8 @@ static struct config_int ConfigureNamesInt[] = "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 }, { @@ -1761,7 +1893,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &AuthenticationTimeout, - 60, 1, 600, NULL, NULL + 60, 1, 600, + NULL, NULL, NULL }, { @@ -1772,7 +1905,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 }, { @@ -1781,7 +1915,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &wal_keep_segments, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1790,7 +1925,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CheckPointSegments, - 3, 1, INT_MAX, NULL, NULL + 3, 1, INT_MAX, + NULL, NULL, NULL }, { @@ -1800,7 +1936,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &CheckPointTimeout, - 300, 30, 3600, NULL, NULL + 300, 30, 3600, + NULL, NULL, NULL }, { @@ -1813,7 +1950,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_S }, &CheckPointWarning, - 30, 0, INT_MAX, NULL, NULL + 30, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1823,7 +1961,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 }, { @@ -1833,7 +1972,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &WalWriterDelay, - 200, 1, 10000, NULL, NULL + 200, 1, 10000, + NULL, NULL, NULL }, { @@ -1843,7 +1983,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &max_wal_senders, - 0, 0, MAX_BACKENDS, NULL, NULL + 0, 0, MAX_BACKENDS, + NULL, NULL, NULL }, { @@ -1853,7 +1994,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &WalSndDelay, - 1000, 1, 10000, NULL, NULL + 1000, 1, 10000, + NULL, NULL, NULL }, { @@ -1863,7 +2005,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &replication_timeout, - 60 * 1000, 0, INT_MAX, NULL, NULL + 60 * 1000, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -1873,7 +2016,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CommitDelay, - 0, 0, 100000, NULL, NULL + 0, 0, 100000, + NULL, NULL, NULL }, { @@ -1883,7 +2027,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &CommitSiblings, - 5, 0, 1000, NULL, NULL + 5, 0, 1000, + NULL, NULL, NULL }, { @@ -1894,7 +2039,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 }, { @@ -1905,7 +2051,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &log_min_duration_statement, - -1, -1, INT_MAX, NULL, NULL + -1, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1916,7 +2063,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &Log_autovacuum_min_duration, - -1, -1, INT_MAX, NULL, NULL + -1, -1, INT_MAX, + NULL, NULL, NULL }, { @@ -1926,7 +2074,8 @@ static struct config_int ConfigureNamesInt[] = GUC_UNIT_MS }, &BgWriterDelay, - 200, 10, 10000, NULL, NULL + 200, 10, 10000, + NULL, NULL, NULL }, { @@ -1935,7 +2084,8 @@ static struct config_int ConfigureNamesInt[] = NULL }, &bgwriter_lru_maxpages, - 100, 0, 1000, NULL, NULL + 100, 0, 1000, + NULL, NULL, NULL }, { @@ -1955,7 +2105,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 }, { @@ -1965,7 +2115,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 }, { @@ -1975,7 +2126,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 }, { @@ -1985,7 +2137,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 }, { @@ -1995,7 +2148,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 }, { @@ -2005,7 +2159,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 }, { @@ -2015,7 +2170,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 }, { @@ -2025,7 +2181,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 }, { @@ -2035,7 +2192,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 }, { @@ -2048,7 +2206,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 }, { @@ -2058,7 +2216,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, @@ -2066,7 +2225,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, @@ -2074,7 +2234,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 */ @@ -2084,7 +2245,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 */ @@ -2093,7 +2255,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 }, { @@ -2103,7 +2266,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 }, { @@ -2113,7 +2277,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 }, { @@ -2123,7 +2288,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 }, { @@ -2134,7 +2300,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 }, { @@ -2144,7 +2311,8 @@ static struct config_int ConfigureNamesInt[] = 0 }, &GinFuzzySearchLimit, - 0, 0, INT_MAX, NULL, NULL + 0, 0, INT_MAX, + NULL, NULL, NULL }, { @@ -2156,7 +2324,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 }, { @@ -2167,7 +2336,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 }, { @@ -2177,7 +2347,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 }, { @@ -2186,12 +2357,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 } }; @@ -2205,7 +2377,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, @@ -2214,7 +2387,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, @@ -2223,7 +2397,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, @@ -2232,7 +2407,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, @@ -2241,7 +2417,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 }, { @@ -2251,7 +2428,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 }, { @@ -2260,8 +2438,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, @@ -2269,7 +2448,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 }, { @@ -2278,7 +2458,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 }, { @@ -2288,7 +2469,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 }, { @@ -2297,7 +2479,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, @@ -2305,7 +2488,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 }, { @@ -2314,12 +2498,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 } }; @@ -2332,7 +2517,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &XLogArchiveCommand, - "", NULL, show_archive_command + "", + NULL, NULL, show_archive_command }, { @@ -2342,7 +2528,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 }, { @@ -2351,7 +2538,8 @@ static struct config_string ConfigureNamesString[] = gettext_noop("If blank, no prefix is used.") }, &Log_line_prefix, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2360,7 +2548,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 }, { @@ -2371,7 +2560,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 }, { @@ -2381,7 +2571,8 @@ static struct config_string ConfigureNamesString[] = GUC_IS_NAME }, &default_tablespace, - "", assign_default_tablespace, NULL + "", + check_default_tablespace, NULL, NULL }, { @@ -2391,7 +2582,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 }, { @@ -2404,7 +2596,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &Dynamic_library_path, - "$libdir", NULL, NULL + "$libdir", + NULL, NULL, NULL }, { @@ -2414,7 +2607,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &pg_krb_server_keyfile, - PG_KRB_SRVTAB, NULL, NULL + PG_KRB_SRVTAB, + NULL, NULL, NULL }, { @@ -2423,7 +2617,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &pg_krb_srvnam, - PG_KRB_SRVNAM, NULL, NULL + PG_KRB_SRVNAM, + NULL, NULL, NULL }, { @@ -2432,7 +2627,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 */ @@ -2444,7 +2640,8 @@ static struct config_string ConfigureNamesString[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &locale_collate, - "C", NULL, NULL + "C", + NULL, NULL, NULL }, { @@ -2454,7 +2651,8 @@ static struct config_string ConfigureNamesString[] = GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE }, &locale_ctype, - "C", NULL, NULL + "C", + NULL, NULL, NULL }, { @@ -2463,7 +2661,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_messages, - "", locale_messages_assign, NULL + "", + check_locale_messages, assign_locale_messages, NULL }, { @@ -2472,7 +2671,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_monetary, - "C", locale_monetary_assign, NULL + "C", + check_locale_monetary, assign_locale_monetary, NULL }, { @@ -2481,7 +2681,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_numeric, - "C", locale_numeric_assign, NULL + "C", + check_locale_numeric, assign_locale_numeric, NULL }, { @@ -2490,7 +2691,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &locale_time, - "C", locale_time_assign, NULL + "C", + check_locale_time, assign_locale_time, NULL }, { @@ -2500,7 +2702,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY }, &shared_preload_libraries_string, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2510,7 +2713,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT | GUC_LIST_QUOTE }, &local_preload_libraries_string, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2520,7 +2724,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 }, { @@ -2531,7 +2736,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 }, { @@ -2542,7 +2748,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 }, { @@ -2553,7 +2760,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 }, { @@ -2564,7 +2772,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 }, { @@ -2576,7 +2785,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, @@ -2586,7 +2796,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, @@ -2595,7 +2806,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 }, { @@ -2605,7 +2817,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &syslog_ident_str, - "postgres", assign_syslog_ident, NULL + "postgres", + NULL, assign_syslog_ident, NULL }, { @@ -2615,7 +2828,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, @@ -2623,7 +2837,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &timezone_abbreviations_string, - "UNKNOWN", assign_timezone_abbreviations, NULL + NULL, + check_timezone_abbreviations, assign_timezone_abbreviations, NULL }, { @@ -2633,7 +2848,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 }, { @@ -2643,7 +2859,8 @@ static struct config_string ConfigureNamesString[] = "that starts the server.") }, &Unix_socket_group, - "", NULL, NULL + "", + NULL, NULL, NULL }, { @@ -2653,7 +2870,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &UnixSocketDir, - "", assign_canonical_path, NULL + "", + check_canonical_path, NULL, NULL }, { @@ -2663,7 +2881,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT }, &ListenAddresses, - "localhost", NULL, NULL + "localhost", + NULL, NULL, NULL }, { @@ -2673,7 +2892,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 }, { @@ -2683,6 +2903,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &data_directory, + NULL, NULL, NULL, NULL }, @@ -2693,6 +2914,7 @@ static struct config_string ConfigureNamesString[] = GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY }, &ConfigFileName, + NULL, NULL, NULL, NULL }, @@ -2703,6 +2925,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &HbaFileName, + NULL, NULL, NULL, NULL }, @@ -2713,6 +2936,7 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &IdentFileName, + NULL, NULL, NULL, NULL }, @@ -2723,7 +2947,8 @@ static struct config_string ConfigureNamesString[] = GUC_SUPERUSER_ONLY }, &external_pid_file, - NULL, assign_canonical_path, NULL + NULL, + check_canonical_path, NULL, NULL }, { @@ -2733,7 +2958,8 @@ 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 }, { @@ -2743,7 +2969,8 @@ static struct config_string ConfigureNamesString[] = GUC_LIST_INPUT }, &SyncRepStandbyNames, - "", assign_synchronous_standby_names, NULL + "", + check_synchronous_standby_names, NULL, NULL }, { @@ -2752,7 +2979,8 @@ static struct config_string ConfigureNamesString[] = NULL }, &TSCurrentConfig, - "pg_catalog.simple", assignTSCurrentConfig, NULL + "pg_catalog.simple", + check_TSCurrentConfig, assign_TSCurrentConfig, NULL }, { @@ -2767,7 +2995,7 @@ static struct config_string ConfigureNamesString[] = #else "none", #endif - NULL, NULL + NULL, NULL, NULL }, { @@ -2777,12 +3005,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 } }; @@ -2795,7 +3024,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 }, { @@ -2804,7 +3034,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 }, { @@ -2814,7 +3045,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 }, { @@ -2825,7 +3057,7 @@ static struct config_enum ConfigureNamesEnum[] = }, &constraint_exclusion, CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options, - NULL, NULL + NULL, NULL, NULL }, { @@ -2834,7 +3066,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 }, { @@ -2844,7 +3077,8 @@ static struct config_enum ConfigureNamesEnum[] = GUC_REPORT }, &IntervalStyle, - INTSTYLE_POSTGRES, intervalstyle_options, NULL, NULL + INTSTYLE_POSTGRES, intervalstyle_options, + NULL, NULL, NULL }, { @@ -2853,7 +3087,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 }, { @@ -2863,7 +3098,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 }, { @@ -2873,7 +3109,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 }, { @@ -2882,7 +3119,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &log_statement, - LOGSTMT_NONE, log_statement_options, NULL, NULL + LOGSTMT_NONE, log_statement_options, + NULL, NULL, NULL }, { @@ -2896,7 +3134,8 @@ static struct config_enum ConfigureNamesEnum[] = #else 0, #endif - syslog_facility_options, assign_syslog_facility, NULL + syslog_facility_options, + NULL, assign_syslog_facility, NULL }, { @@ -2906,7 +3145,7 @@ 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 }, { @@ -2916,7 +3155,7 @@ static struct config_enum ConfigureNamesEnum[] = }, &synchronous_commit, SYNCHRONOUS_COMMIT_ON, synchronous_commit_options, - NULL, NULL + NULL, NULL, NULL }, { @@ -2930,7 +3169,8 @@ static struct config_enum ConfigureNamesEnum[] = * 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 }, { @@ -2939,7 +3179,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 }, { @@ -2948,7 +3189,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 }, { @@ -2958,7 +3200,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 }, { @@ -2967,7 +3209,8 @@ static struct config_enum ConfigureNamesEnum[] = NULL }, &xmlbinary, - XMLBINARY_BASE64, xmlbinary_options, NULL, NULL + XMLBINARY_BASE64, xmlbinary_options, + NULL, NULL, NULL }, { @@ -2977,13 +3220,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 } }; @@ -3030,7 +3274,6 @@ 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); @@ -3079,6 +3322,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). @@ -3087,87 +3351,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) + { + 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 (strval == stack->prior.stringval || - strval == stack->masked.stringval) + 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_stack_value(struct config_generic * gconf, union config_var_value * val) +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, 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) { @@ -3179,10 +3475,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); } @@ -3594,6 +3891,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) @@ -3602,6 +3902,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; @@ -3610,96 +3911,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; } } @@ -3888,11 +4184,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: @@ -3900,11 +4196,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: @@ -3912,40 +4208,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: @@ -3953,12 +4232,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; } } @@ -4209,7 +4487,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) @@ -4228,16 +4506,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; @@ -4245,16 +4524,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; @@ -4262,16 +4542,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; @@ -4279,33 +4560,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; } @@ -4315,30 +4580,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; } @@ -4748,33 +5019,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 @@ -4810,6 +5054,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) @@ -4846,15 +5091,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), @@ -4867,19 +5118,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), @@ -5022,6 +5277,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) { @@ -5033,32 +5289,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) @@ -5068,17 +5337,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; } @@ -5086,6 +5363,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) { @@ -5108,32 +5386,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) @@ -5143,17 +5434,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; } @@ -5161,6 +5460,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) { @@ -5180,32 +5480,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) @@ -5215,17 +5528,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; } @@ -5233,95 +5554,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; @@ -5329,27 +5643,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) { @@ -5371,33 +5695,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) @@ -5407,17 +5743,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; } } @@ -5578,51 +5922,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. @@ -6115,6 +6414,7 @@ DefineCustomBoolVariable(const char *name, bool bootValue, GucContext context, int flags, + GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook) { @@ -6126,6 +6426,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); @@ -6141,6 +6442,7 @@ DefineCustomIntVariable(const char *name, int maxValue, GucContext context, int flags, + GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook) { @@ -6154,6 +6456,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); @@ -6169,6 +6472,7 @@ DefineCustomRealVariable(const char *name, double maxValue, GucContext context, int flags, + GucRealCheckHook check_hook, GucRealAssignHook assign_hook, GucShowHook show_hook) { @@ -6182,6 +6486,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); @@ -6195,6 +6500,7 @@ DefineCustomStringVariable(const char *name, const char *bootValue, GucContext context, int flags, + GucStringCheckHook check_hook, GucStringAssignHook assign_hook, GucShowHook show_hook) { @@ -6205,9 +6511,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); @@ -6222,6 +6526,7 @@ DefineCustomEnumVariable(const char *name, const struct config_enum_entry * options, GucContext context, int flags, + GucEnumCheckHook check_hook, GucEnumAssignHook assign_hook, GucShowHook show_hook) { @@ -6234,6 +6539,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); @@ -6995,67 +7301,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 /* @@ -7673,30 +7918,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) @@ -7717,105 +8154,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 void +assign_log_destination(const char *newval, void *extra) +{ + Log_destination = *((int *) extra); } -static bool -assign_syslog_facility(int newval, bool doit, GucSource source) +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 temp 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') { @@ -7844,7 +8279,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++; @@ -7855,21 +8290,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 @@ -7877,14 +8311,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 @@ -7892,14 +8324,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 @@ -7907,57 +8337,48 @@ 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". + * 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 @@ -7965,34 +8386,32 @@ assign_timezone_abbreviations(const char *newval, bool doit, GucSource source) * 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); } /* @@ -8004,10 +8423,10 @@ assign_timezone_abbreviations(const char *newval, bool doit, GucSource source) void pg_timezone_abbrev_initialize(void) { - if (strcmp(timezone_abbreviations_string, "UNKNOWN") == 0) + if (timezone_abbreviations_string == NULL) { SetConfigOption("timezone_abbreviations", "Default", - PGC_POSTMASTER, PGC_S_ARGV); + PGC_POSTMASTER, PGC_S_DEFAULT); } } @@ -8020,54 +8439,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)); @@ -8075,31 +8501,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; @@ -8108,6 +8538,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: * @@ -8132,18 +8564,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 @@ -8153,57 +8588,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 * |