| 1 | /*-------------------------------------------------------------------- |
| 2 | * guc.c |
| 3 | * |
| 4 | * Support for grand unified configuration scheme, including SET |
| 5 | * command, configuration file, and command line options. |
| 6 | * See src/backend/utils/misc/README for more information. |
| 7 | * |
| 8 | * |
| 9 | * Copyright (c) 2000-2019, PostgreSQL Global Development Group |
| 10 | * Written by Peter Eisentraut <peter_e@gmx.net>. |
| 11 | * |
| 12 | * IDENTIFICATION |
| 13 | * src/backend/utils/misc/guc.c |
| 14 | * |
| 15 | *-------------------------------------------------------------------- |
| 16 | */ |
| 17 | #include "postgres.h" |
| 18 | |
| 19 | #include <ctype.h> |
| 20 | #include <float.h> |
| 21 | #include <math.h> |
| 22 | #include <limits.h> |
| 23 | #include <unistd.h> |
| 24 | #include <sys/stat.h> |
| 25 | #ifdef HAVE_SYSLOG |
| 26 | #include <syslog.h> |
| 27 | #endif |
| 28 | |
| 29 | #include "access/commit_ts.h" |
| 30 | #include "access/gin.h" |
| 31 | #include "access/rmgr.h" |
| 32 | #include "access/tableam.h" |
| 33 | #include "access/transam.h" |
| 34 | #include "access/twophase.h" |
| 35 | #include "access/xact.h" |
| 36 | #include "access/xlog_internal.h" |
| 37 | #include "catalog/namespace.h" |
| 38 | #include "catalog/pg_authid.h" |
| 39 | #include "commands/async.h" |
| 40 | #include "commands/prepare.h" |
| 41 | #include "commands/user.h" |
| 42 | #include "commands/vacuum.h" |
| 43 | #include "commands/variable.h" |
| 44 | #include "commands/trigger.h" |
| 45 | #include "common/string.h" |
| 46 | #include "funcapi.h" |
| 47 | #include "jit/jit.h" |
| 48 | #include "libpq/auth.h" |
| 49 | #include "libpq/libpq.h" |
| 50 | #include "libpq/pqformat.h" |
| 51 | #include "miscadmin.h" |
| 52 | #include "optimizer/cost.h" |
| 53 | #include "optimizer/geqo.h" |
| 54 | #include "optimizer/optimizer.h" |
| 55 | #include "optimizer/paths.h" |
| 56 | #include "optimizer/planmain.h" |
| 57 | #include "parser/parse_expr.h" |
| 58 | #include "parser/parse_type.h" |
| 59 | #include "parser/parser.h" |
| 60 | #include "parser/scansup.h" |
| 61 | #include "pgstat.h" |
| 62 | #include "postmaster/autovacuum.h" |
| 63 | #include "postmaster/bgworker_internals.h" |
| 64 | #include "postmaster/bgwriter.h" |
| 65 | #include "postmaster/postmaster.h" |
| 66 | #include "postmaster/syslogger.h" |
| 67 | #include "postmaster/walwriter.h" |
| 68 | #include "replication/logicallauncher.h" |
| 69 | #include "replication/slot.h" |
| 70 | #include "replication/syncrep.h" |
| 71 | #include "replication/walreceiver.h" |
| 72 | #include "replication/walsender.h" |
| 73 | #include "storage/bufmgr.h" |
| 74 | #include "storage/dsm_impl.h" |
| 75 | #include "storage/standby.h" |
| 76 | #include "storage/fd.h" |
| 77 | #include "storage/large_object.h" |
| 78 | #include "storage/pg_shmem.h" |
| 79 | #include "storage/proc.h" |
| 80 | #include "storage/predicate.h" |
| 81 | #include "tcop/tcopprot.h" |
| 82 | #include "tsearch/ts_cache.h" |
| 83 | #include "utils/builtins.h" |
| 84 | #include "utils/bytea.h" |
| 85 | #include "utils/guc_tables.h" |
| 86 | #include "utils/float.h" |
| 87 | #include "utils/memutils.h" |
| 88 | #include "utils/pg_locale.h" |
| 89 | #include "utils/pg_lsn.h" |
| 90 | #include "utils/plancache.h" |
| 91 | #include "utils/portal.h" |
| 92 | #include "utils/ps_status.h" |
| 93 | #include "utils/rls.h" |
| 94 | #include "utils/snapmgr.h" |
| 95 | #include "utils/tzparser.h" |
| 96 | #include "utils/varlena.h" |
| 97 | #include "utils/xml.h" |
| 98 | |
| 99 | #ifndef PG_KRB_SRVTAB |
| 100 | #define PG_KRB_SRVTAB "" |
| 101 | #endif |
| 102 | |
| 103 | #define CONFIG_FILENAME "postgresql.conf" |
| 104 | #define HBA_FILENAME "pg_hba.conf" |
| 105 | #define IDENT_FILENAME "pg_ident.conf" |
| 106 | |
| 107 | #ifdef EXEC_BACKEND |
| 108 | #define CONFIG_EXEC_PARAMS "global/config_exec_params" |
| 109 | #define CONFIG_EXEC_PARAMS_NEW "global/config_exec_params.new" |
| 110 | #endif |
| 111 | |
| 112 | /* |
| 113 | * Precision with which REAL type guc values are to be printed for GUC |
| 114 | * serialization. |
| 115 | */ |
| 116 | #define REALTYPE_PRECISION 17 |
| 117 | |
| 118 | /* XXX these should appear in other modules' header files */ |
| 119 | extern bool Log_disconnections; |
| 120 | extern int CommitDelay; |
| 121 | extern int CommitSiblings; |
| 122 | extern char *default_tablespace; |
| 123 | extern char *temp_tablespaces; |
| 124 | extern bool ignore_checksum_failure; |
| 125 | extern bool synchronize_seqscans; |
| 126 | |
| 127 | #ifdef TRACE_SYNCSCAN |
| 128 | extern bool trace_syncscan; |
| 129 | #endif |
| 130 | #ifdef DEBUG_BOUNDED_SORT |
| 131 | extern bool optimize_bounded_sort; |
| 132 | #endif |
| 133 | |
| 134 | static int GUC_check_errcode_value; |
| 135 | |
| 136 | /* global variables for check hook support */ |
| 137 | char *GUC_check_errmsg_string; |
| 138 | char *GUC_check_errdetail_string; |
| 139 | char *GUC_check_errhint_string; |
| 140 | |
| 141 | static void do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) pg_attribute_printf(3, 4); |
| 142 | |
| 143 | static void set_config_sourcefile(const char *name, char *sourcefile, |
| 144 | int sourceline); |
| 145 | static bool call_bool_check_hook(struct config_bool *conf, bool *newval, |
| 146 | void **, GucSource source, int elevel); |
| 147 | static bool call_int_check_hook(struct config_int *conf, int *newval, |
| 148 | void **, GucSource source, int elevel); |
| 149 | static bool call_real_check_hook(struct config_real *conf, double *newval, |
| 150 | void **, GucSource source, int elevel); |
| 151 | static bool call_string_check_hook(struct config_string *conf, char **newval, |
| 152 | void **, GucSource source, int elevel); |
| 153 | static bool call_enum_check_hook(struct config_enum *conf, int *newval, |
| 154 | void **, GucSource source, int elevel); |
| 155 | |
| 156 | static bool check_log_destination(char **newval, void **, GucSource source); |
| 157 | static void assign_log_destination(const char *newval, void *); |
| 158 | |
| 159 | static bool check_wal_consistency_checking(char **newval, void **, |
| 160 | GucSource source); |
| 161 | static void assign_wal_consistency_checking(const char *newval, void *); |
| 162 | |
| 163 | #ifdef HAVE_SYSLOG |
| 164 | static int syslog_facility = LOG_LOCAL0; |
| 165 | #else |
| 166 | static int syslog_facility = 0; |
| 167 | #endif |
| 168 | |
| 169 | static void assign_syslog_facility(int newval, void *); |
| 170 | static void assign_syslog_ident(const char *newval, void *); |
| 171 | static void assign_session_replication_role(int newval, void *); |
| 172 | static bool check_temp_buffers(int *newval, void **, GucSource source); |
| 173 | static bool check_bonjour(bool *newval, void **, GucSource source); |
| 174 | static bool check_ssl(bool *newval, void **, GucSource source); |
| 175 | static bool check_stage_log_stats(bool *newval, void **, GucSource source); |
| 176 | static bool check_log_stats(bool *newval, void **, GucSource source); |
| 177 | static bool check_canonical_path(char **newval, void **, GucSource source); |
| 178 | static bool check_timezone_abbreviations(char **newval, void **, GucSource source); |
| 179 | static void assign_timezone_abbreviations(const char *newval, void *); |
| 180 | static void pg_timezone_abbrev_initialize(void); |
| 181 | static const char *show_archive_command(void); |
| 182 | static void assign_tcp_keepalives_idle(int newval, void *); |
| 183 | static void assign_tcp_keepalives_interval(int newval, void *); |
| 184 | static void assign_tcp_keepalives_count(int newval, void *); |
| 185 | static void assign_tcp_user_timeout(int newval, void *); |
| 186 | static const char *show_tcp_keepalives_idle(void); |
| 187 | static const char *show_tcp_keepalives_interval(void); |
| 188 | static const char *show_tcp_keepalives_count(void); |
| 189 | static const char *show_tcp_user_timeout(void); |
| 190 | static bool check_maxconnections(int *newval, void **, GucSource source); |
| 191 | static bool check_max_worker_processes(int *newval, void **, GucSource source); |
| 192 | static bool check_autovacuum_max_workers(int *newval, void **, GucSource source); |
| 193 | static bool check_max_wal_senders(int *newval, void **, GucSource source); |
| 194 | static bool check_autovacuum_work_mem(int *newval, void **, GucSource source); |
| 195 | static bool check_effective_io_concurrency(int *newval, void **, GucSource source); |
| 196 | static void assign_effective_io_concurrency(int newval, void *); |
| 197 | static void assign_pgstat_temp_directory(const char *newval, void *); |
| 198 | static bool check_application_name(char **newval, void **, GucSource source); |
| 199 | static void assign_application_name(const char *newval, void *); |
| 200 | static bool check_cluster_name(char **newval, void **, GucSource source); |
| 201 | static const char *show_unix_socket_permissions(void); |
| 202 | static const char *show_log_file_mode(void); |
| 203 | static const char *show_data_directory_mode(void); |
| 204 | static bool check_recovery_target_timeline(char **newval, void **, GucSource source); |
| 205 | static void assign_recovery_target_timeline(const char *newval, void *); |
| 206 | static bool check_recovery_target(char **newval, void **, GucSource source); |
| 207 | static void assign_recovery_target(const char *newval, void *); |
| 208 | static bool check_recovery_target_xid(char **newval, void **, GucSource source); |
| 209 | static void assign_recovery_target_xid(const char *newval, void *); |
| 210 | static bool check_recovery_target_time(char **newval, void **, GucSource source); |
| 211 | static void assign_recovery_target_time(const char *newval, void *); |
| 212 | static bool check_recovery_target_name(char **newval, void **, GucSource source); |
| 213 | static void assign_recovery_target_name(const char *newval, void *); |
| 214 | static bool check_recovery_target_lsn(char **newval, void **, GucSource source); |
| 215 | static void assign_recovery_target_lsn(const char *newval, void *); |
| 216 | static bool check_primary_slot_name(char **newval, void **, GucSource source); |
| 217 | static bool check_default_with_oids(bool *newval, void **, GucSource source); |
| 218 | |
| 219 | /* Private functions in guc-file.l that need to be called from guc.c */ |
| 220 | static ConfigVariable *ProcessConfigFileInternal(GucContext context, |
| 221 | bool applySettings, int elevel); |
| 222 | |
| 223 | |
| 224 | /* |
| 225 | * Options for enum values defined in this module. |
| 226 | * |
| 227 | * NOTE! Option values may not contain double quotes! |
| 228 | */ |
| 229 | |
| 230 | static const struct config_enum_entry bytea_output_options[] = { |
| 231 | {"escape" , BYTEA_OUTPUT_ESCAPE, false}, |
| 232 | {"hex" , BYTEA_OUTPUT_HEX, false}, |
| 233 | {NULL, 0, false} |
| 234 | }; |
| 235 | |
| 236 | /* |
| 237 | * We have different sets for client and server message level options because |
| 238 | * they sort slightly different (see "log" level), and because "fatal"/"panic" |
| 239 | * aren't sensible for client_min_messages. |
| 240 | */ |
| 241 | static const struct config_enum_entry client_message_level_options[] = { |
| 242 | {"debug5" , DEBUG5, false}, |
| 243 | {"debug4" , DEBUG4, false}, |
| 244 | {"debug3" , DEBUG3, false}, |
| 245 | {"debug2" , DEBUG2, false}, |
| 246 | {"debug1" , DEBUG1, false}, |
| 247 | {"debug" , DEBUG2, true}, |
| 248 | {"log" , LOG, false}, |
| 249 | {"info" , INFO, true}, |
| 250 | {"notice" , NOTICE, false}, |
| 251 | {"warning" , WARNING, false}, |
| 252 | {"error" , ERROR, false}, |
| 253 | {NULL, 0, false} |
| 254 | }; |
| 255 | |
| 256 | static const struct config_enum_entry server_message_level_options[] = { |
| 257 | {"debug5" , DEBUG5, false}, |
| 258 | {"debug4" , DEBUG4, false}, |
| 259 | {"debug3" , DEBUG3, false}, |
| 260 | {"debug2" , DEBUG2, false}, |
| 261 | {"debug1" , DEBUG1, false}, |
| 262 | {"debug" , DEBUG2, true}, |
| 263 | {"info" , INFO, false}, |
| 264 | {"notice" , NOTICE, false}, |
| 265 | {"warning" , WARNING, false}, |
| 266 | {"error" , ERROR, false}, |
| 267 | {"log" , LOG, false}, |
| 268 | {"fatal" , FATAL, false}, |
| 269 | {"panic" , PANIC, false}, |
| 270 | {NULL, 0, false} |
| 271 | }; |
| 272 | |
| 273 | static const struct config_enum_entry intervalstyle_options[] = { |
| 274 | {"postgres" , INTSTYLE_POSTGRES, false}, |
| 275 | {"postgres_verbose" , INTSTYLE_POSTGRES_VERBOSE, false}, |
| 276 | {"sql_standard" , INTSTYLE_SQL_STANDARD, false}, |
| 277 | {"iso_8601" , INTSTYLE_ISO_8601, false}, |
| 278 | {NULL, 0, false} |
| 279 | }; |
| 280 | |
| 281 | static const struct config_enum_entry log_error_verbosity_options[] = { |
| 282 | {"terse" , PGERROR_TERSE, false}, |
| 283 | {"default" , PGERROR_DEFAULT, false}, |
| 284 | {"verbose" , PGERROR_VERBOSE, false}, |
| 285 | {NULL, 0, false} |
| 286 | }; |
| 287 | |
| 288 | static const struct config_enum_entry log_statement_options[] = { |
| 289 | {"none" , LOGSTMT_NONE, false}, |
| 290 | {"ddl" , LOGSTMT_DDL, false}, |
| 291 | {"mod" , LOGSTMT_MOD, false}, |
| 292 | {"all" , LOGSTMT_ALL, false}, |
| 293 | {NULL, 0, false} |
| 294 | }; |
| 295 | |
| 296 | static const struct config_enum_entry isolation_level_options[] = { |
| 297 | {"serializable" , XACT_SERIALIZABLE, false}, |
| 298 | {"repeatable read" , XACT_REPEATABLE_READ, false}, |
| 299 | {"read committed" , XACT_READ_COMMITTED, false}, |
| 300 | {"read uncommitted" , XACT_READ_UNCOMMITTED, false}, |
| 301 | {NULL, 0} |
| 302 | }; |
| 303 | |
| 304 | static const struct config_enum_entry session_replication_role_options[] = { |
| 305 | {"origin" , SESSION_REPLICATION_ROLE_ORIGIN, false}, |
| 306 | {"replica" , SESSION_REPLICATION_ROLE_REPLICA, false}, |
| 307 | {"local" , SESSION_REPLICATION_ROLE_LOCAL, false}, |
| 308 | {NULL, 0, false} |
| 309 | }; |
| 310 | |
| 311 | static const struct config_enum_entry syslog_facility_options[] = { |
| 312 | #ifdef HAVE_SYSLOG |
| 313 | {"local0" , LOG_LOCAL0, false}, |
| 314 | {"local1" , LOG_LOCAL1, false}, |
| 315 | {"local2" , LOG_LOCAL2, false}, |
| 316 | {"local3" , LOG_LOCAL3, false}, |
| 317 | {"local4" , LOG_LOCAL4, false}, |
| 318 | {"local5" , LOG_LOCAL5, false}, |
| 319 | {"local6" , LOG_LOCAL6, false}, |
| 320 | {"local7" , LOG_LOCAL7, false}, |
| 321 | #else |
| 322 | {"none" , 0, false}, |
| 323 | #endif |
| 324 | {NULL, 0} |
| 325 | }; |
| 326 | |
| 327 | static const struct config_enum_entry track_function_options[] = { |
| 328 | {"none" , TRACK_FUNC_OFF, false}, |
| 329 | {"pl" , TRACK_FUNC_PL, false}, |
| 330 | {"all" , TRACK_FUNC_ALL, false}, |
| 331 | {NULL, 0, false} |
| 332 | }; |
| 333 | |
| 334 | static const struct config_enum_entry xmlbinary_options[] = { |
| 335 | {"base64" , XMLBINARY_BASE64, false}, |
| 336 | {"hex" , XMLBINARY_HEX, false}, |
| 337 | {NULL, 0, false} |
| 338 | }; |
| 339 | |
| 340 | static const struct config_enum_entry xmloption_options[] = { |
| 341 | {"content" , XMLOPTION_CONTENT, false}, |
| 342 | {"document" , XMLOPTION_DOCUMENT, false}, |
| 343 | {NULL, 0, false} |
| 344 | }; |
| 345 | |
| 346 | /* |
| 347 | * Although only "on", "off", and "safe_encoding" are documented, we |
| 348 | * accept all the likely variants of "on" and "off". |
| 349 | */ |
| 350 | static const struct config_enum_entry backslash_quote_options[] = { |
| 351 | {"safe_encoding" , BACKSLASH_QUOTE_SAFE_ENCODING, false}, |
| 352 | {"on" , BACKSLASH_QUOTE_ON, false}, |
| 353 | {"off" , BACKSLASH_QUOTE_OFF, false}, |
| 354 | {"true" , BACKSLASH_QUOTE_ON, true}, |
| 355 | {"false" , BACKSLASH_QUOTE_OFF, true}, |
| 356 | {"yes" , BACKSLASH_QUOTE_ON, true}, |
| 357 | {"no" , BACKSLASH_QUOTE_OFF, true}, |
| 358 | {"1" , BACKSLASH_QUOTE_ON, true}, |
| 359 | {"0" , BACKSLASH_QUOTE_OFF, true}, |
| 360 | {NULL, 0, false} |
| 361 | }; |
| 362 | |
| 363 | /* |
| 364 | * Although only "on", "off", and "partition" are documented, we |
| 365 | * accept all the likely variants of "on" and "off". |
| 366 | */ |
| 367 | static const struct config_enum_entry constraint_exclusion_options[] = { |
| 368 | {"partition" , CONSTRAINT_EXCLUSION_PARTITION, false}, |
| 369 | {"on" , CONSTRAINT_EXCLUSION_ON, false}, |
| 370 | {"off" , CONSTRAINT_EXCLUSION_OFF, false}, |
| 371 | {"true" , CONSTRAINT_EXCLUSION_ON, true}, |
| 372 | {"false" , CONSTRAINT_EXCLUSION_OFF, true}, |
| 373 | {"yes" , CONSTRAINT_EXCLUSION_ON, true}, |
| 374 | {"no" , CONSTRAINT_EXCLUSION_OFF, true}, |
| 375 | {"1" , CONSTRAINT_EXCLUSION_ON, true}, |
| 376 | {"0" , CONSTRAINT_EXCLUSION_OFF, true}, |
| 377 | {NULL, 0, false} |
| 378 | }; |
| 379 | |
| 380 | /* |
| 381 | * Although only "on", "off", "remote_apply", "remote_write", and "local" are |
| 382 | * documented, we accept all the likely variants of "on" and "off". |
| 383 | */ |
| 384 | static const struct config_enum_entry synchronous_commit_options[] = { |
| 385 | {"local" , SYNCHRONOUS_COMMIT_LOCAL_FLUSH, false}, |
| 386 | {"remote_write" , SYNCHRONOUS_COMMIT_REMOTE_WRITE, false}, |
| 387 | {"remote_apply" , SYNCHRONOUS_COMMIT_REMOTE_APPLY, false}, |
| 388 | {"on" , SYNCHRONOUS_COMMIT_ON, false}, |
| 389 | {"off" , SYNCHRONOUS_COMMIT_OFF, false}, |
| 390 | {"true" , SYNCHRONOUS_COMMIT_ON, true}, |
| 391 | {"false" , SYNCHRONOUS_COMMIT_OFF, true}, |
| 392 | {"yes" , SYNCHRONOUS_COMMIT_ON, true}, |
| 393 | {"no" , SYNCHRONOUS_COMMIT_OFF, true}, |
| 394 | {"1" , SYNCHRONOUS_COMMIT_ON, true}, |
| 395 | {"0" , SYNCHRONOUS_COMMIT_OFF, true}, |
| 396 | {NULL, 0, false} |
| 397 | }; |
| 398 | |
| 399 | /* |
| 400 | * Although only "on", "off", "try" are documented, we accept all the likely |
| 401 | * variants of "on" and "off". |
| 402 | */ |
| 403 | static const struct config_enum_entry huge_pages_options[] = { |
| 404 | {"off" , HUGE_PAGES_OFF, false}, |
| 405 | {"on" , HUGE_PAGES_ON, false}, |
| 406 | {"try" , HUGE_PAGES_TRY, false}, |
| 407 | {"true" , HUGE_PAGES_ON, true}, |
| 408 | {"false" , HUGE_PAGES_OFF, true}, |
| 409 | {"yes" , HUGE_PAGES_ON, true}, |
| 410 | {"no" , HUGE_PAGES_OFF, true}, |
| 411 | {"1" , HUGE_PAGES_ON, true}, |
| 412 | {"0" , HUGE_PAGES_OFF, true}, |
| 413 | {NULL, 0, false} |
| 414 | }; |
| 415 | |
| 416 | static const struct config_enum_entry force_parallel_mode_options[] = { |
| 417 | {"off" , FORCE_PARALLEL_OFF, false}, |
| 418 | {"on" , FORCE_PARALLEL_ON, false}, |
| 419 | {"regress" , FORCE_PARALLEL_REGRESS, false}, |
| 420 | {"true" , FORCE_PARALLEL_ON, true}, |
| 421 | {"false" , FORCE_PARALLEL_OFF, true}, |
| 422 | {"yes" , FORCE_PARALLEL_ON, true}, |
| 423 | {"no" , FORCE_PARALLEL_OFF, true}, |
| 424 | {"1" , FORCE_PARALLEL_ON, true}, |
| 425 | {"0" , FORCE_PARALLEL_OFF, true}, |
| 426 | {NULL, 0, false} |
| 427 | }; |
| 428 | |
| 429 | static const struct config_enum_entry plan_cache_mode_options[] = { |
| 430 | {"auto" , PLAN_CACHE_MODE_AUTO, false}, |
| 431 | {"force_generic_plan" , PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, false}, |
| 432 | {"force_custom_plan" , PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, false}, |
| 433 | {NULL, 0, false} |
| 434 | }; |
| 435 | |
| 436 | /* |
| 437 | * password_encryption used to be a boolean, so accept all the likely |
| 438 | * variants of "on", too. "off" used to store passwords in plaintext, |
| 439 | * but we don't support that anymore. |
| 440 | */ |
| 441 | static const struct config_enum_entry password_encryption_options[] = { |
| 442 | {"md5" , PASSWORD_TYPE_MD5, false}, |
| 443 | {"scram-sha-256" , PASSWORD_TYPE_SCRAM_SHA_256, false}, |
| 444 | {"on" , PASSWORD_TYPE_MD5, true}, |
| 445 | {"true" , PASSWORD_TYPE_MD5, true}, |
| 446 | {"yes" , PASSWORD_TYPE_MD5, true}, |
| 447 | {"1" , PASSWORD_TYPE_MD5, true}, |
| 448 | {NULL, 0, false} |
| 449 | }; |
| 450 | |
| 451 | const struct config_enum_entry ssl_protocol_versions_info[] = { |
| 452 | {"" , PG_TLS_ANY, false}, |
| 453 | {"TLSv1" , PG_TLS1_VERSION, false}, |
| 454 | {"TLSv1.1" , PG_TLS1_1_VERSION, false}, |
| 455 | {"TLSv1.2" , PG_TLS1_2_VERSION, false}, |
| 456 | {"TLSv1.3" , PG_TLS1_3_VERSION, false}, |
| 457 | {NULL, 0, false} |
| 458 | }; |
| 459 | |
| 460 | static struct config_enum_entry shared_memory_options[] = { |
| 461 | #ifndef WIN32 |
| 462 | {"sysv" , SHMEM_TYPE_SYSV, false}, |
| 463 | #endif |
| 464 | #ifndef EXEC_BACKEND |
| 465 | {"mmap" , SHMEM_TYPE_MMAP, false}, |
| 466 | #endif |
| 467 | #ifdef WIN32 |
| 468 | {"windows" , SHMEM_TYPE_WINDOWS, false}, |
| 469 | #endif |
| 470 | {NULL, 0, false} |
| 471 | }; |
| 472 | |
| 473 | /* |
| 474 | * Options for enum values stored in other modules |
| 475 | */ |
| 476 | extern const struct config_enum_entry wal_level_options[]; |
| 477 | extern const struct config_enum_entry archive_mode_options[]; |
| 478 | extern const struct config_enum_entry recovery_target_action_options[]; |
| 479 | extern const struct config_enum_entry sync_method_options[]; |
| 480 | extern const struct config_enum_entry dynamic_shared_memory_options[]; |
| 481 | |
| 482 | /* |
| 483 | * GUC option variables that are exported from this module |
| 484 | */ |
| 485 | bool log_duration = false; |
| 486 | bool Debug_print_plan = false; |
| 487 | bool Debug_print_parse = false; |
| 488 | bool Debug_print_rewritten = false; |
| 489 | bool Debug_pretty_print = true; |
| 490 | |
| 491 | bool log_parser_stats = false; |
| 492 | bool log_planner_stats = false; |
| 493 | bool log_executor_stats = false; |
| 494 | bool log_statement_stats = false; /* this is sort of all three above |
| 495 | * together */ |
| 496 | bool log_btree_build_stats = false; |
| 497 | char *event_source; |
| 498 | |
| 499 | bool row_security; |
| 500 | bool check_function_bodies = true; |
| 501 | |
| 502 | /* |
| 503 | * This GUC exists solely for backward compatibility, check its definition for |
| 504 | * details. |
| 505 | */ |
| 506 | bool default_with_oids = false; |
| 507 | bool session_auth_is_superuser; |
| 508 | |
| 509 | int log_min_error_statement = ERROR; |
| 510 | int log_min_messages = WARNING; |
| 511 | int client_min_messages = NOTICE; |
| 512 | int log_min_duration_statement = -1; |
| 513 | int log_temp_files = -1; |
| 514 | double log_xact_sample_rate = 0; |
| 515 | int trace_recovery_messages = LOG; |
| 516 | |
| 517 | int temp_file_limit = -1; |
| 518 | |
| 519 | int num_temp_buffers = 1024; |
| 520 | |
| 521 | char *cluster_name = "" ; |
| 522 | char *ConfigFileName; |
| 523 | char *HbaFileName; |
| 524 | char *IdentFileName; |
| 525 | char *external_pid_file; |
| 526 | |
| 527 | char *pgstat_temp_directory; |
| 528 | |
| 529 | char *application_name; |
| 530 | |
| 531 | int tcp_keepalives_idle; |
| 532 | int tcp_keepalives_interval; |
| 533 | int tcp_keepalives_count; |
| 534 | int tcp_user_timeout; |
| 535 | |
| 536 | /* |
| 537 | * SSL renegotiation was been removed in PostgreSQL 9.5, but we tolerate it |
| 538 | * being set to zero (meaning never renegotiate) for backward compatibility. |
| 539 | * This avoids breaking compatibility with clients that have never supported |
| 540 | * renegotiation and therefore always try to zero it. |
| 541 | */ |
| 542 | int ssl_renegotiation_limit; |
| 543 | |
| 544 | /* |
| 545 | * This really belongs in pg_shmem.c, but is defined here so that it doesn't |
| 546 | * need to be duplicated in all the different implementations of pg_shmem.c. |
| 547 | */ |
| 548 | int huge_pages; |
| 549 | |
| 550 | /* |
| 551 | * These variables are all dummies that don't do anything, except in some |
| 552 | * cases provide the value for SHOW to display. The real state is elsewhere |
| 553 | * and is kept in sync by assign_hooks. |
| 554 | */ |
| 555 | static char *syslog_ident_str; |
| 556 | static double phony_random_seed; |
| 557 | static char *client_encoding_string; |
| 558 | static char *datestyle_string; |
| 559 | static char *locale_collate; |
| 560 | static char *locale_ctype; |
| 561 | static char *server_encoding_string; |
| 562 | static char *server_version_string; |
| 563 | static int server_version_num; |
| 564 | static char *timezone_string; |
| 565 | static char *log_timezone_string; |
| 566 | static char *timezone_abbreviations_string; |
| 567 | static char *data_directory; |
| 568 | static char *session_authorization_string; |
| 569 | static int max_function_args; |
| 570 | static int max_index_keys; |
| 571 | static int max_identifier_length; |
| 572 | static int block_size; |
| 573 | static int segment_size; |
| 574 | static int wal_block_size; |
| 575 | static bool data_checksums; |
| 576 | static bool integer_datetimes; |
| 577 | static bool assert_enabled; |
| 578 | static char *recovery_target_timeline_string; |
| 579 | static char *recovery_target_string; |
| 580 | static char *recovery_target_xid_string; |
| 581 | static char *recovery_target_name_string; |
| 582 | static char *recovery_target_lsn_string; |
| 583 | |
| 584 | |
| 585 | /* should be static, but commands/variable.c needs to get at this */ |
| 586 | char *role_string; |
| 587 | |
| 588 | |
| 589 | /* |
| 590 | * Displayable names for context types (enum GucContext) |
| 591 | * |
| 592 | * Note: these strings are deliberately not localized. |
| 593 | */ |
| 594 | const char *const GucContext_Names[] = |
| 595 | { |
| 596 | /* PGC_INTERNAL */ "internal" , |
| 597 | /* PGC_POSTMASTER */ "postmaster" , |
| 598 | /* PGC_SIGHUP */ "sighup" , |
| 599 | /* PGC_SU_BACKEND */ "superuser-backend" , |
| 600 | /* PGC_BACKEND */ "backend" , |
| 601 | /* PGC_SUSET */ "superuser" , |
| 602 | /* PGC_USERSET */ "user" |
| 603 | }; |
| 604 | |
| 605 | /* |
| 606 | * Displayable names for source types (enum GucSource) |
| 607 | * |
| 608 | * Note: these strings are deliberately not localized. |
| 609 | */ |
| 610 | const char *const GucSource_Names[] = |
| 611 | { |
| 612 | /* PGC_S_DEFAULT */ "default" , |
| 613 | /* PGC_S_DYNAMIC_DEFAULT */ "default" , |
| 614 | /* PGC_S_ENV_VAR */ "environment variable" , |
| 615 | /* PGC_S_FILE */ "configuration file" , |
| 616 | /* PGC_S_ARGV */ "command line" , |
| 617 | /* PGC_S_GLOBAL */ "global" , |
| 618 | /* PGC_S_DATABASE */ "database" , |
| 619 | /* PGC_S_USER */ "user" , |
| 620 | /* PGC_S_DATABASE_USER */ "database user" , |
| 621 | /* PGC_S_CLIENT */ "client" , |
| 622 | /* PGC_S_OVERRIDE */ "override" , |
| 623 | /* PGC_S_INTERACTIVE */ "interactive" , |
| 624 | /* PGC_S_TEST */ "test" , |
| 625 | /* PGC_S_SESSION */ "session" |
| 626 | }; |
| 627 | |
| 628 | /* |
| 629 | * Displayable names for the groupings defined in enum config_group |
| 630 | */ |
| 631 | const char *const config_group_names[] = |
| 632 | { |
| 633 | /* UNGROUPED */ |
| 634 | gettext_noop("Ungrouped" ), |
| 635 | /* FILE_LOCATIONS */ |
| 636 | gettext_noop("File Locations" ), |
| 637 | /* CONN_AUTH */ |
| 638 | gettext_noop("Connections and Authentication" ), |
| 639 | /* CONN_AUTH_SETTINGS */ |
| 640 | gettext_noop("Connections and Authentication / Connection Settings" ), |
| 641 | /* CONN_AUTH_AUTH */ |
| 642 | gettext_noop("Connections and Authentication / Authentication" ), |
| 643 | /* CONN_AUTH_SSL */ |
| 644 | gettext_noop("Connections and Authentication / SSL" ), |
| 645 | /* RESOURCES */ |
| 646 | gettext_noop("Resource Usage" ), |
| 647 | /* RESOURCES_MEM */ |
| 648 | gettext_noop("Resource Usage / Memory" ), |
| 649 | /* RESOURCES_DISK */ |
| 650 | gettext_noop("Resource Usage / Disk" ), |
| 651 | /* RESOURCES_KERNEL */ |
| 652 | gettext_noop("Resource Usage / Kernel Resources" ), |
| 653 | /* RESOURCES_VACUUM_DELAY */ |
| 654 | gettext_noop("Resource Usage / Cost-Based Vacuum Delay" ), |
| 655 | /* RESOURCES_BGWRITER */ |
| 656 | gettext_noop("Resource Usage / Background Writer" ), |
| 657 | /* RESOURCES_ASYNCHRONOUS */ |
| 658 | gettext_noop("Resource Usage / Asynchronous Behavior" ), |
| 659 | /* WAL */ |
| 660 | gettext_noop("Write-Ahead Log" ), |
| 661 | /* WAL_SETTINGS */ |
| 662 | gettext_noop("Write-Ahead Log / Settings" ), |
| 663 | /* WAL_CHECKPOINTS */ |
| 664 | gettext_noop("Write-Ahead Log / Checkpoints" ), |
| 665 | /* WAL_ARCHIVING */ |
| 666 | gettext_noop("Write-Ahead Log / Archiving" ), |
| 667 | /* WAL_ARCHIVE_RECOVERY */ |
| 668 | gettext_noop("Write-Ahead Log / Archive Recovery" ), |
| 669 | /* WAL_RECOVERY_TARGET */ |
| 670 | gettext_noop("Write-Ahead Log / Recovery Target" ), |
| 671 | /* REPLICATION */ |
| 672 | gettext_noop("Replication" ), |
| 673 | /* REPLICATION_SENDING */ |
| 674 | gettext_noop("Replication / Sending Servers" ), |
| 675 | /* REPLICATION_MASTER */ |
| 676 | gettext_noop("Replication / Master Server" ), |
| 677 | /* REPLICATION_STANDBY */ |
| 678 | gettext_noop("Replication / Standby Servers" ), |
| 679 | /* REPLICATION_SUBSCRIBERS */ |
| 680 | gettext_noop("Replication / Subscribers" ), |
| 681 | /* QUERY_TUNING */ |
| 682 | gettext_noop("Query Tuning" ), |
| 683 | /* QUERY_TUNING_METHOD */ |
| 684 | gettext_noop("Query Tuning / Planner Method Configuration" ), |
| 685 | /* QUERY_TUNING_COST */ |
| 686 | gettext_noop("Query Tuning / Planner Cost Constants" ), |
| 687 | /* QUERY_TUNING_GEQO */ |
| 688 | gettext_noop("Query Tuning / Genetic Query Optimizer" ), |
| 689 | /* QUERY_TUNING_OTHER */ |
| 690 | gettext_noop("Query Tuning / Other Planner Options" ), |
| 691 | /* LOGGING */ |
| 692 | gettext_noop("Reporting and Logging" ), |
| 693 | /* LOGGING_WHERE */ |
| 694 | gettext_noop("Reporting and Logging / Where to Log" ), |
| 695 | /* LOGGING_WHEN */ |
| 696 | gettext_noop("Reporting and Logging / When to Log" ), |
| 697 | /* LOGGING_WHAT */ |
| 698 | gettext_noop("Reporting and Logging / What to Log" ), |
| 699 | /* PROCESS_TITLE */ |
| 700 | gettext_noop("Process Title" ), |
| 701 | /* STATS */ |
| 702 | gettext_noop("Statistics" ), |
| 703 | /* STATS_MONITORING */ |
| 704 | gettext_noop("Statistics / Monitoring" ), |
| 705 | /* STATS_COLLECTOR */ |
| 706 | gettext_noop("Statistics / Query and Index Statistics Collector" ), |
| 707 | /* AUTOVACUUM */ |
| 708 | gettext_noop("Autovacuum" ), |
| 709 | /* CLIENT_CONN */ |
| 710 | gettext_noop("Client Connection Defaults" ), |
| 711 | /* CLIENT_CONN_STATEMENT */ |
| 712 | gettext_noop("Client Connection Defaults / Statement Behavior" ), |
| 713 | /* CLIENT_CONN_LOCALE */ |
| 714 | gettext_noop("Client Connection Defaults / Locale and Formatting" ), |
| 715 | /* CLIENT_CONN_PRELOAD */ |
| 716 | gettext_noop("Client Connection Defaults / Shared Library Preloading" ), |
| 717 | /* CLIENT_CONN_OTHER */ |
| 718 | gettext_noop("Client Connection Defaults / Other Defaults" ), |
| 719 | /* LOCK_MANAGEMENT */ |
| 720 | gettext_noop("Lock Management" ), |
| 721 | /* COMPAT_OPTIONS */ |
| 722 | gettext_noop("Version and Platform Compatibility" ), |
| 723 | /* COMPAT_OPTIONS_PREVIOUS */ |
| 724 | gettext_noop("Version and Platform Compatibility / Previous PostgreSQL Versions" ), |
| 725 | /* COMPAT_OPTIONS_CLIENT */ |
| 726 | gettext_noop("Version and Platform Compatibility / Other Platforms and Clients" ), |
| 727 | /* ERROR_HANDLING */ |
| 728 | gettext_noop("Error Handling" ), |
| 729 | /* PRESET_OPTIONS */ |
| 730 | gettext_noop("Preset Options" ), |
| 731 | /* CUSTOM_OPTIONS */ |
| 732 | gettext_noop("Customized Options" ), |
| 733 | /* DEVELOPER_OPTIONS */ |
| 734 | gettext_noop("Developer Options" ), |
| 735 | /* help_config wants this array to be null-terminated */ |
| 736 | NULL |
| 737 | }; |
| 738 | |
| 739 | /* |
| 740 | * Displayable names for GUC variable types (enum config_type) |
| 741 | * |
| 742 | * Note: these strings are deliberately not localized. |
| 743 | */ |
| 744 | const char *const config_type_names[] = |
| 745 | { |
| 746 | /* PGC_BOOL */ "bool" , |
| 747 | /* PGC_INT */ "integer" , |
| 748 | /* PGC_REAL */ "real" , |
| 749 | /* PGC_STRING */ "string" , |
| 750 | /* PGC_ENUM */ "enum" |
| 751 | }; |
| 752 | |
| 753 | /* |
| 754 | * Unit conversion tables. |
| 755 | * |
| 756 | * There are two tables, one for memory units, and another for time units. |
| 757 | * For each supported conversion from one unit to another, we have an entry |
| 758 | * in the table. |
| 759 | * |
| 760 | * To keep things simple, and to avoid possible roundoff error, |
| 761 | * conversions are never chained. There needs to be a direct conversion |
| 762 | * between all units (of the same type). |
| 763 | * |
| 764 | * The conversions for each base unit must be kept in order from greatest to |
| 765 | * smallest human-friendly unit; convert_xxx_from_base_unit() rely on that. |
| 766 | * (The order of the base-unit groups does not matter.) |
| 767 | */ |
| 768 | #define MAX_UNIT_LEN 3 /* length of longest recognized unit string */ |
| 769 | |
| 770 | typedef struct |
| 771 | { |
| 772 | char unit[MAX_UNIT_LEN + 1]; /* unit, as a string, like "kB" or |
| 773 | * "min" */ |
| 774 | int base_unit; /* GUC_UNIT_XXX */ |
| 775 | double multiplier; /* Factor for converting unit -> base_unit */ |
| 776 | } unit_conversion; |
| 777 | |
| 778 | /* Ensure that the constants in the tables don't overflow or underflow */ |
| 779 | #if BLCKSZ < 1024 || BLCKSZ > (1024*1024) |
| 780 | #error BLCKSZ must be between 1KB and 1MB |
| 781 | #endif |
| 782 | #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024) |
| 783 | #error XLOG_BLCKSZ must be between 1KB and 1MB |
| 784 | #endif |
| 785 | |
| 786 | static const char *memory_units_hint = gettext_noop("Valid units for this parameter are \"B\", \"kB\", \"MB\", \"GB\", and \"TB\"." ); |
| 787 | |
| 788 | static const unit_conversion memory_unit_conversion_table[] = |
| 789 | { |
| 790 | {"TB" , GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0 * 1024.0}, |
| 791 | {"GB" , GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0}, |
| 792 | {"MB" , GUC_UNIT_BYTE, 1024.0 * 1024.0}, |
| 793 | {"kB" , GUC_UNIT_BYTE, 1024.0}, |
| 794 | {"B" , GUC_UNIT_BYTE, 1.0}, |
| 795 | |
| 796 | {"TB" , GUC_UNIT_KB, 1024.0 * 1024.0 * 1024.0}, |
| 797 | {"GB" , GUC_UNIT_KB, 1024.0 * 1024.0}, |
| 798 | {"MB" , GUC_UNIT_KB, 1024.0}, |
| 799 | {"kB" , GUC_UNIT_KB, 1.0}, |
| 800 | {"B" , GUC_UNIT_KB, 1.0 / 1024.0}, |
| 801 | |
| 802 | {"TB" , GUC_UNIT_MB, 1024.0 * 1024.0}, |
| 803 | {"GB" , GUC_UNIT_MB, 1024.0}, |
| 804 | {"MB" , GUC_UNIT_MB, 1.0}, |
| 805 | {"kB" , GUC_UNIT_MB, 1.0 / 1024.0}, |
| 806 | {"B" , GUC_UNIT_MB, 1.0 / (1024.0 * 1024.0)}, |
| 807 | |
| 808 | {"TB" , GUC_UNIT_BLOCKS, (1024.0 * 1024.0 * 1024.0) / (BLCKSZ / 1024)}, |
| 809 | {"GB" , GUC_UNIT_BLOCKS, (1024.0 * 1024.0) / (BLCKSZ / 1024)}, |
| 810 | {"MB" , GUC_UNIT_BLOCKS, 1024.0 / (BLCKSZ / 1024)}, |
| 811 | {"kB" , GUC_UNIT_BLOCKS, 1.0 / (BLCKSZ / 1024)}, |
| 812 | {"B" , GUC_UNIT_BLOCKS, 1.0 / BLCKSZ}, |
| 813 | |
| 814 | {"TB" , GUC_UNIT_XBLOCKS, (1024.0 * 1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)}, |
| 815 | {"GB" , GUC_UNIT_XBLOCKS, (1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)}, |
| 816 | {"MB" , GUC_UNIT_XBLOCKS, 1024.0 / (XLOG_BLCKSZ / 1024)}, |
| 817 | {"kB" , GUC_UNIT_XBLOCKS, 1.0 / (XLOG_BLCKSZ / 1024)}, |
| 818 | {"B" , GUC_UNIT_XBLOCKS, 1.0 / XLOG_BLCKSZ}, |
| 819 | |
| 820 | {"" } /* end of table marker */ |
| 821 | }; |
| 822 | |
| 823 | static const char *time_units_hint = gettext_noop("Valid units for this parameter are \"us\", \"ms\", \"s\", \"min\", \"h\", and \"d\"." ); |
| 824 | |
| 825 | static const unit_conversion time_unit_conversion_table[] = |
| 826 | { |
| 827 | {"d" , GUC_UNIT_MS, 1000 * 60 * 60 * 24}, |
| 828 | {"h" , GUC_UNIT_MS, 1000 * 60 * 60}, |
| 829 | {"min" , GUC_UNIT_MS, 1000 * 60}, |
| 830 | {"s" , GUC_UNIT_MS, 1000}, |
| 831 | {"ms" , GUC_UNIT_MS, 1}, |
| 832 | {"us" , GUC_UNIT_MS, 1.0 / 1000}, |
| 833 | |
| 834 | {"d" , GUC_UNIT_S, 60 * 60 * 24}, |
| 835 | {"h" , GUC_UNIT_S, 60 * 60}, |
| 836 | {"min" , GUC_UNIT_S, 60}, |
| 837 | {"s" , GUC_UNIT_S, 1}, |
| 838 | {"ms" , GUC_UNIT_S, 1.0 / 1000}, |
| 839 | {"us" , GUC_UNIT_S, 1.0 / (1000 * 1000)}, |
| 840 | |
| 841 | {"d" , GUC_UNIT_MIN, 60 * 24}, |
| 842 | {"h" , GUC_UNIT_MIN, 60}, |
| 843 | {"min" , GUC_UNIT_MIN, 1}, |
| 844 | {"s" , GUC_UNIT_MIN, 1.0 / 60}, |
| 845 | {"ms" , GUC_UNIT_MIN, 1.0 / (1000 * 60)}, |
| 846 | {"us" , GUC_UNIT_MIN, 1.0 / (1000 * 1000 * 60)}, |
| 847 | |
| 848 | {"" } /* end of table marker */ |
| 849 | }; |
| 850 | |
| 851 | /* |
| 852 | * Contents of GUC tables |
| 853 | * |
| 854 | * See src/backend/utils/misc/README for design notes. |
| 855 | * |
| 856 | * TO ADD AN OPTION: |
| 857 | * |
| 858 | * 1. Declare a global variable of type bool, int, double, or char* |
| 859 | * and make use of it. |
| 860 | * |
| 861 | * 2. Decide at what times it's safe to set the option. See guc.h for |
| 862 | * details. |
| 863 | * |
| 864 | * 3. Decide on a name, a default value, upper and lower bounds (if |
| 865 | * applicable), etc. |
| 866 | * |
| 867 | * 4. Add a record below. |
| 868 | * |
| 869 | * 5. Add it to src/backend/utils/misc/postgresql.conf.sample, if |
| 870 | * appropriate. |
| 871 | * |
| 872 | * 6. Don't forget to document the option (at least in config.sgml). |
| 873 | * |
| 874 | * 7. If it's a new GUC_LIST_QUOTE option, you must add it to |
| 875 | * variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c. |
| 876 | */ |
| 877 | |
| 878 | |
| 879 | /******** option records follow ********/ |
| 880 | |
| 881 | static struct config_bool ConfigureNamesBool[] = |
| 882 | { |
| 883 | { |
| 884 | {"enable_seqscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 885 | gettext_noop("Enables the planner's use of sequential-scan plans." ), |
| 886 | NULL, |
| 887 | GUC_EXPLAIN |
| 888 | }, |
| 889 | &enable_seqscan, |
| 890 | true, |
| 891 | NULL, NULL, NULL |
| 892 | }, |
| 893 | { |
| 894 | {"enable_indexscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 895 | gettext_noop("Enables the planner's use of index-scan plans." ), |
| 896 | NULL, |
| 897 | GUC_EXPLAIN |
| 898 | }, |
| 899 | &enable_indexscan, |
| 900 | true, |
| 901 | NULL, NULL, NULL |
| 902 | }, |
| 903 | { |
| 904 | {"enable_indexonlyscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 905 | gettext_noop("Enables the planner's use of index-only-scan plans." ), |
| 906 | NULL, |
| 907 | GUC_EXPLAIN |
| 908 | }, |
| 909 | &enable_indexonlyscan, |
| 910 | true, |
| 911 | NULL, NULL, NULL |
| 912 | }, |
| 913 | { |
| 914 | {"enable_bitmapscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 915 | gettext_noop("Enables the planner's use of bitmap-scan plans." ), |
| 916 | NULL, |
| 917 | GUC_EXPLAIN |
| 918 | }, |
| 919 | &enable_bitmapscan, |
| 920 | true, |
| 921 | NULL, NULL, NULL |
| 922 | }, |
| 923 | { |
| 924 | {"enable_tidscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 925 | gettext_noop("Enables the planner's use of TID scan plans." ), |
| 926 | NULL, |
| 927 | GUC_EXPLAIN |
| 928 | }, |
| 929 | &enable_tidscan, |
| 930 | true, |
| 931 | NULL, NULL, NULL |
| 932 | }, |
| 933 | { |
| 934 | {"enable_sort" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 935 | gettext_noop("Enables the planner's use of explicit sort steps." ), |
| 936 | NULL, |
| 937 | GUC_EXPLAIN |
| 938 | }, |
| 939 | &enable_sort, |
| 940 | true, |
| 941 | NULL, NULL, NULL |
| 942 | }, |
| 943 | { |
| 944 | {"enable_hashagg" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 945 | gettext_noop("Enables the planner's use of hashed aggregation plans." ), |
| 946 | NULL, |
| 947 | GUC_EXPLAIN |
| 948 | }, |
| 949 | &enable_hashagg, |
| 950 | true, |
| 951 | NULL, NULL, NULL |
| 952 | }, |
| 953 | { |
| 954 | {"enable_material" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 955 | gettext_noop("Enables the planner's use of materialization." ), |
| 956 | NULL, |
| 957 | GUC_EXPLAIN |
| 958 | }, |
| 959 | &enable_material, |
| 960 | true, |
| 961 | NULL, NULL, NULL |
| 962 | }, |
| 963 | { |
| 964 | {"enable_nestloop" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 965 | gettext_noop("Enables the planner's use of nested-loop join plans." ), |
| 966 | NULL, |
| 967 | GUC_EXPLAIN |
| 968 | }, |
| 969 | &enable_nestloop, |
| 970 | true, |
| 971 | NULL, NULL, NULL |
| 972 | }, |
| 973 | { |
| 974 | {"enable_mergejoin" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 975 | gettext_noop("Enables the planner's use of merge join plans." ), |
| 976 | NULL, |
| 977 | GUC_EXPLAIN |
| 978 | }, |
| 979 | &enable_mergejoin, |
| 980 | true, |
| 981 | NULL, NULL, NULL |
| 982 | }, |
| 983 | { |
| 984 | {"enable_hashjoin" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 985 | gettext_noop("Enables the planner's use of hash join plans." ), |
| 986 | NULL, |
| 987 | GUC_EXPLAIN |
| 988 | }, |
| 989 | &enable_hashjoin, |
| 990 | true, |
| 991 | NULL, NULL, NULL |
| 992 | }, |
| 993 | { |
| 994 | {"enable_gathermerge" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 995 | gettext_noop("Enables the planner's use of gather merge plans." ), |
| 996 | NULL, |
| 997 | GUC_EXPLAIN |
| 998 | }, |
| 999 | &enable_gathermerge, |
| 1000 | true, |
| 1001 | NULL, NULL, NULL |
| 1002 | }, |
| 1003 | { |
| 1004 | {"enable_partitionwise_join" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1005 | gettext_noop("Enables partitionwise join." ), |
| 1006 | NULL, |
| 1007 | GUC_EXPLAIN |
| 1008 | }, |
| 1009 | &enable_partitionwise_join, |
| 1010 | false, |
| 1011 | NULL, NULL, NULL |
| 1012 | }, |
| 1013 | { |
| 1014 | {"enable_partitionwise_aggregate" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1015 | gettext_noop("Enables partitionwise aggregation and grouping." ), |
| 1016 | NULL, |
| 1017 | GUC_EXPLAIN |
| 1018 | }, |
| 1019 | &enable_partitionwise_aggregate, |
| 1020 | false, |
| 1021 | NULL, NULL, NULL |
| 1022 | }, |
| 1023 | { |
| 1024 | {"enable_parallel_append" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1025 | gettext_noop("Enables the planner's use of parallel append plans." ), |
| 1026 | NULL, |
| 1027 | GUC_EXPLAIN |
| 1028 | }, |
| 1029 | &enable_parallel_append, |
| 1030 | true, |
| 1031 | NULL, NULL, NULL |
| 1032 | }, |
| 1033 | { |
| 1034 | {"enable_parallel_hash" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1035 | gettext_noop("Enables the planner's use of parallel hash plans." ), |
| 1036 | NULL, |
| 1037 | GUC_EXPLAIN |
| 1038 | }, |
| 1039 | &enable_parallel_hash, |
| 1040 | true, |
| 1041 | NULL, NULL, NULL |
| 1042 | }, |
| 1043 | { |
| 1044 | {"enable_partition_pruning" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1045 | gettext_noop("Enables plan-time and run-time partition pruning." ), |
| 1046 | gettext_noop("Allows the query planner and executor to compare partition " |
| 1047 | "bounds to conditions in the query to determine which " |
| 1048 | "partitions must be scanned." ), |
| 1049 | GUC_EXPLAIN |
| 1050 | }, |
| 1051 | &enable_partition_pruning, |
| 1052 | true, |
| 1053 | NULL, NULL, NULL |
| 1054 | }, |
| 1055 | { |
| 1056 | {"geqo" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 1057 | gettext_noop("Enables genetic query optimization." ), |
| 1058 | gettext_noop("This algorithm attempts to do planning without " |
| 1059 | "exhaustive searching." ), |
| 1060 | GUC_EXPLAIN |
| 1061 | }, |
| 1062 | &enable_geqo, |
| 1063 | true, |
| 1064 | NULL, NULL, NULL |
| 1065 | }, |
| 1066 | { |
| 1067 | /* Not for general use --- used by SET SESSION AUTHORIZATION */ |
| 1068 | {"is_superuser" , PGC_INTERNAL, UNGROUPED, |
| 1069 | gettext_noop("Shows whether the current user is a superuser." ), |
| 1070 | NULL, |
| 1071 | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1072 | }, |
| 1073 | &session_auth_is_superuser, |
| 1074 | false, |
| 1075 | NULL, NULL, NULL |
| 1076 | }, |
| 1077 | { |
| 1078 | {"bonjour" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 1079 | gettext_noop("Enables advertising the server via Bonjour." ), |
| 1080 | NULL |
| 1081 | }, |
| 1082 | &enable_bonjour, |
| 1083 | false, |
| 1084 | check_bonjour, NULL, NULL |
| 1085 | }, |
| 1086 | { |
| 1087 | {"track_commit_timestamp" , PGC_POSTMASTER, REPLICATION, |
| 1088 | gettext_noop("Collects transaction commit time." ), |
| 1089 | NULL |
| 1090 | }, |
| 1091 | &track_commit_timestamp, |
| 1092 | false, |
| 1093 | NULL, NULL, NULL |
| 1094 | }, |
| 1095 | { |
| 1096 | {"ssl" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 1097 | gettext_noop("Enables SSL connections." ), |
| 1098 | NULL |
| 1099 | }, |
| 1100 | &EnableSSL, |
| 1101 | false, |
| 1102 | check_ssl, NULL, NULL |
| 1103 | }, |
| 1104 | { |
| 1105 | {"ssl_passphrase_command_supports_reload" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 1106 | gettext_noop("Also use ssl_passphrase_command during server reload." ), |
| 1107 | NULL |
| 1108 | }, |
| 1109 | &ssl_passphrase_command_supports_reload, |
| 1110 | false, |
| 1111 | NULL, NULL, NULL |
| 1112 | }, |
| 1113 | { |
| 1114 | {"ssl_prefer_server_ciphers" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 1115 | gettext_noop("Give priority to server ciphersuite order." ), |
| 1116 | NULL |
| 1117 | }, |
| 1118 | &SSLPreferServerCiphers, |
| 1119 | true, |
| 1120 | NULL, NULL, NULL |
| 1121 | }, |
| 1122 | { |
| 1123 | {"fsync" , PGC_SIGHUP, WAL_SETTINGS, |
| 1124 | gettext_noop("Forces synchronization of updates to disk." ), |
| 1125 | gettext_noop("The server will use the fsync() system call in several places to make " |
| 1126 | "sure that updates are physically written to disk. This insures " |
| 1127 | "that a database cluster will recover to a consistent state after " |
| 1128 | "an operating system or hardware crash." ) |
| 1129 | }, |
| 1130 | &enableFsync, |
| 1131 | true, |
| 1132 | NULL, NULL, NULL |
| 1133 | }, |
| 1134 | { |
| 1135 | {"ignore_checksum_failure" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1136 | gettext_noop("Continues processing after a checksum failure." ), |
| 1137 | gettext_noop("Detection of a checksum failure normally causes PostgreSQL to " |
| 1138 | "report an error, aborting the current transaction. Setting " |
| 1139 | "ignore_checksum_failure to true causes the system to ignore the failure " |
| 1140 | "(but still report a warning), and continue processing. This " |
| 1141 | "behavior could cause crashes or other serious problems. Only " |
| 1142 | "has an effect if checksums are enabled." ), |
| 1143 | GUC_NOT_IN_SAMPLE |
| 1144 | }, |
| 1145 | &ignore_checksum_failure, |
| 1146 | false, |
| 1147 | NULL, NULL, NULL |
| 1148 | }, |
| 1149 | { |
| 1150 | {"zero_damaged_pages" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1151 | gettext_noop("Continues processing past damaged page headers." ), |
| 1152 | gettext_noop("Detection of a damaged page header normally causes PostgreSQL to " |
| 1153 | "report an error, aborting the current transaction. Setting " |
| 1154 | "zero_damaged_pages to true causes the system to instead report a " |
| 1155 | "warning, zero out the damaged page, and continue processing. This " |
| 1156 | "behavior will destroy data, namely all the rows on the damaged page." ), |
| 1157 | GUC_NOT_IN_SAMPLE |
| 1158 | }, |
| 1159 | &zero_damaged_pages, |
| 1160 | false, |
| 1161 | NULL, NULL, NULL |
| 1162 | }, |
| 1163 | { |
| 1164 | {"full_page_writes" , PGC_SIGHUP, WAL_SETTINGS, |
| 1165 | gettext_noop("Writes full pages to WAL when first modified after a checkpoint." ), |
| 1166 | gettext_noop("A page write in process during an operating system crash might be " |
| 1167 | "only partially written to disk. During recovery, the row changes " |
| 1168 | "stored in WAL are not enough to recover. This option writes " |
| 1169 | "pages when first modified after a checkpoint to WAL so full recovery " |
| 1170 | "is possible." ) |
| 1171 | }, |
| 1172 | &fullPageWrites, |
| 1173 | true, |
| 1174 | NULL, NULL, NULL |
| 1175 | }, |
| 1176 | |
| 1177 | { |
| 1178 | {"wal_log_hints" , PGC_POSTMASTER, WAL_SETTINGS, |
| 1179 | gettext_noop("Writes full pages to WAL when first modified after a checkpoint, even for a non-critical modifications." ), |
| 1180 | NULL |
| 1181 | }, |
| 1182 | &wal_log_hints, |
| 1183 | false, |
| 1184 | NULL, NULL, NULL |
| 1185 | }, |
| 1186 | |
| 1187 | { |
| 1188 | {"wal_compression" , PGC_SUSET, WAL_SETTINGS, |
| 1189 | gettext_noop("Compresses full-page writes written in WAL file." ), |
| 1190 | NULL |
| 1191 | }, |
| 1192 | &wal_compression, |
| 1193 | false, |
| 1194 | NULL, NULL, NULL |
| 1195 | }, |
| 1196 | |
| 1197 | { |
| 1198 | {"wal_init_zero" , PGC_SUSET, WAL_SETTINGS, |
| 1199 | gettext_noop("Writes zeroes to new WAL files before first use." ), |
| 1200 | NULL |
| 1201 | }, |
| 1202 | &wal_init_zero, |
| 1203 | true, |
| 1204 | NULL, NULL, NULL |
| 1205 | }, |
| 1206 | |
| 1207 | { |
| 1208 | {"wal_recycle" , PGC_SUSET, WAL_SETTINGS, |
| 1209 | gettext_noop("Recycles WAL files by renaming them." ), |
| 1210 | NULL |
| 1211 | }, |
| 1212 | &wal_recycle, |
| 1213 | true, |
| 1214 | NULL, NULL, NULL |
| 1215 | }, |
| 1216 | |
| 1217 | { |
| 1218 | {"log_checkpoints" , PGC_SIGHUP, LOGGING_WHAT, |
| 1219 | gettext_noop("Logs each checkpoint." ), |
| 1220 | NULL |
| 1221 | }, |
| 1222 | &log_checkpoints, |
| 1223 | false, |
| 1224 | NULL, NULL, NULL |
| 1225 | }, |
| 1226 | { |
| 1227 | {"log_connections" , PGC_SU_BACKEND, LOGGING_WHAT, |
| 1228 | gettext_noop("Logs each successful connection." ), |
| 1229 | NULL |
| 1230 | }, |
| 1231 | &Log_connections, |
| 1232 | false, |
| 1233 | NULL, NULL, NULL |
| 1234 | }, |
| 1235 | { |
| 1236 | {"log_disconnections" , PGC_SU_BACKEND, LOGGING_WHAT, |
| 1237 | gettext_noop("Logs end of a session, including duration." ), |
| 1238 | NULL |
| 1239 | }, |
| 1240 | &Log_disconnections, |
| 1241 | false, |
| 1242 | NULL, NULL, NULL |
| 1243 | }, |
| 1244 | { |
| 1245 | {"log_replication_commands" , PGC_SUSET, LOGGING_WHAT, |
| 1246 | gettext_noop("Logs each replication command." ), |
| 1247 | NULL |
| 1248 | }, |
| 1249 | &log_replication_commands, |
| 1250 | false, |
| 1251 | NULL, NULL, NULL |
| 1252 | }, |
| 1253 | { |
| 1254 | {"debug_assertions" , PGC_INTERNAL, PRESET_OPTIONS, |
| 1255 | gettext_noop("Shows whether the running server has assertion checks enabled." ), |
| 1256 | NULL, |
| 1257 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1258 | }, |
| 1259 | &assert_enabled, |
| 1260 | #ifdef USE_ASSERT_CHECKING |
| 1261 | true, |
| 1262 | #else |
| 1263 | false, |
| 1264 | #endif |
| 1265 | NULL, NULL, NULL |
| 1266 | }, |
| 1267 | |
| 1268 | { |
| 1269 | {"exit_on_error" , PGC_USERSET, ERROR_HANDLING_OPTIONS, |
| 1270 | gettext_noop("Terminate session on any error." ), |
| 1271 | NULL |
| 1272 | }, |
| 1273 | &ExitOnAnyError, |
| 1274 | false, |
| 1275 | NULL, NULL, NULL |
| 1276 | }, |
| 1277 | { |
| 1278 | {"restart_after_crash" , PGC_SIGHUP, ERROR_HANDLING_OPTIONS, |
| 1279 | gettext_noop("Reinitialize server after backend crash." ), |
| 1280 | NULL |
| 1281 | }, |
| 1282 | &restart_after_crash, |
| 1283 | true, |
| 1284 | NULL, NULL, NULL |
| 1285 | }, |
| 1286 | |
| 1287 | { |
| 1288 | {"log_duration" , PGC_SUSET, LOGGING_WHAT, |
| 1289 | gettext_noop("Logs the duration of each completed SQL statement." ), |
| 1290 | NULL |
| 1291 | }, |
| 1292 | &log_duration, |
| 1293 | false, |
| 1294 | NULL, NULL, NULL |
| 1295 | }, |
| 1296 | { |
| 1297 | {"debug_print_parse" , PGC_USERSET, LOGGING_WHAT, |
| 1298 | gettext_noop("Logs each query's parse tree." ), |
| 1299 | NULL |
| 1300 | }, |
| 1301 | &Debug_print_parse, |
| 1302 | false, |
| 1303 | NULL, NULL, NULL |
| 1304 | }, |
| 1305 | { |
| 1306 | {"debug_print_rewritten" , PGC_USERSET, LOGGING_WHAT, |
| 1307 | gettext_noop("Logs each query's rewritten parse tree." ), |
| 1308 | NULL |
| 1309 | }, |
| 1310 | &Debug_print_rewritten, |
| 1311 | false, |
| 1312 | NULL, NULL, NULL |
| 1313 | }, |
| 1314 | { |
| 1315 | {"debug_print_plan" , PGC_USERSET, LOGGING_WHAT, |
| 1316 | gettext_noop("Logs each query's execution plan." ), |
| 1317 | NULL |
| 1318 | }, |
| 1319 | &Debug_print_plan, |
| 1320 | false, |
| 1321 | NULL, NULL, NULL |
| 1322 | }, |
| 1323 | { |
| 1324 | {"debug_pretty_print" , PGC_USERSET, LOGGING_WHAT, |
| 1325 | gettext_noop("Indents parse and plan tree displays." ), |
| 1326 | NULL |
| 1327 | }, |
| 1328 | &Debug_pretty_print, |
| 1329 | true, |
| 1330 | NULL, NULL, NULL |
| 1331 | }, |
| 1332 | { |
| 1333 | {"log_parser_stats" , PGC_SUSET, STATS_MONITORING, |
| 1334 | gettext_noop("Writes parser performance statistics to the server log." ), |
| 1335 | NULL |
| 1336 | }, |
| 1337 | &log_parser_stats, |
| 1338 | false, |
| 1339 | check_stage_log_stats, NULL, NULL |
| 1340 | }, |
| 1341 | { |
| 1342 | {"log_planner_stats" , PGC_SUSET, STATS_MONITORING, |
| 1343 | gettext_noop("Writes planner performance statistics to the server log." ), |
| 1344 | NULL |
| 1345 | }, |
| 1346 | &log_planner_stats, |
| 1347 | false, |
| 1348 | check_stage_log_stats, NULL, NULL |
| 1349 | }, |
| 1350 | { |
| 1351 | {"log_executor_stats" , PGC_SUSET, STATS_MONITORING, |
| 1352 | gettext_noop("Writes executor performance statistics to the server log." ), |
| 1353 | NULL |
| 1354 | }, |
| 1355 | &log_executor_stats, |
| 1356 | false, |
| 1357 | check_stage_log_stats, NULL, NULL |
| 1358 | }, |
| 1359 | { |
| 1360 | {"log_statement_stats" , PGC_SUSET, STATS_MONITORING, |
| 1361 | gettext_noop("Writes cumulative performance statistics to the server log." ), |
| 1362 | NULL |
| 1363 | }, |
| 1364 | &log_statement_stats, |
| 1365 | false, |
| 1366 | check_log_stats, NULL, NULL |
| 1367 | }, |
| 1368 | #ifdef BTREE_BUILD_STATS |
| 1369 | { |
| 1370 | {"log_btree_build_stats" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1371 | gettext_noop("Logs system resource usage statistics (memory and CPU) on various B-tree operations." ), |
| 1372 | NULL, |
| 1373 | GUC_NOT_IN_SAMPLE |
| 1374 | }, |
| 1375 | &log_btree_build_stats, |
| 1376 | false, |
| 1377 | NULL, NULL, NULL |
| 1378 | }, |
| 1379 | #endif |
| 1380 | |
| 1381 | { |
| 1382 | {"track_activities" , PGC_SUSET, STATS_COLLECTOR, |
| 1383 | gettext_noop("Collects information about executing commands." ), |
| 1384 | gettext_noop("Enables the collection of information on the currently " |
| 1385 | "executing command of each session, along with " |
| 1386 | "the time at which that command began execution." ) |
| 1387 | }, |
| 1388 | &pgstat_track_activities, |
| 1389 | true, |
| 1390 | NULL, NULL, NULL |
| 1391 | }, |
| 1392 | { |
| 1393 | {"track_counts" , PGC_SUSET, STATS_COLLECTOR, |
| 1394 | gettext_noop("Collects statistics on database activity." ), |
| 1395 | NULL |
| 1396 | }, |
| 1397 | &pgstat_track_counts, |
| 1398 | true, |
| 1399 | NULL, NULL, NULL |
| 1400 | }, |
| 1401 | { |
| 1402 | {"track_io_timing" , PGC_SUSET, STATS_COLLECTOR, |
| 1403 | gettext_noop("Collects timing statistics for database I/O activity." ), |
| 1404 | NULL |
| 1405 | }, |
| 1406 | &track_io_timing, |
| 1407 | false, |
| 1408 | NULL, NULL, NULL |
| 1409 | }, |
| 1410 | |
| 1411 | { |
| 1412 | {"update_process_title" , PGC_SUSET, PROCESS_TITLE, |
| 1413 | gettext_noop("Updates the process title to show the active SQL command." ), |
| 1414 | gettext_noop("Enables updating of the process title every time a new SQL command is received by the server." ) |
| 1415 | }, |
| 1416 | &update_process_title, |
| 1417 | #ifdef WIN32 |
| 1418 | false, |
| 1419 | #else |
| 1420 | true, |
| 1421 | #endif |
| 1422 | NULL, NULL, NULL |
| 1423 | }, |
| 1424 | |
| 1425 | { |
| 1426 | {"autovacuum" , PGC_SIGHUP, AUTOVACUUM, |
| 1427 | gettext_noop("Starts the autovacuum subprocess." ), |
| 1428 | NULL |
| 1429 | }, |
| 1430 | &autovacuum_start_daemon, |
| 1431 | true, |
| 1432 | NULL, NULL, NULL |
| 1433 | }, |
| 1434 | |
| 1435 | { |
| 1436 | {"trace_notify" , PGC_USERSET, DEVELOPER_OPTIONS, |
| 1437 | gettext_noop("Generates debugging output for LISTEN and NOTIFY." ), |
| 1438 | NULL, |
| 1439 | GUC_NOT_IN_SAMPLE |
| 1440 | }, |
| 1441 | &Trace_notify, |
| 1442 | false, |
| 1443 | NULL, NULL, NULL |
| 1444 | }, |
| 1445 | |
| 1446 | #ifdef LOCK_DEBUG |
| 1447 | { |
| 1448 | {"trace_locks" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1449 | gettext_noop("Emits information about lock usage." ), |
| 1450 | NULL, |
| 1451 | GUC_NOT_IN_SAMPLE |
| 1452 | }, |
| 1453 | &Trace_locks, |
| 1454 | false, |
| 1455 | NULL, NULL, NULL |
| 1456 | }, |
| 1457 | { |
| 1458 | {"trace_userlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1459 | gettext_noop("Emits information about user lock usage." ), |
| 1460 | NULL, |
| 1461 | GUC_NOT_IN_SAMPLE |
| 1462 | }, |
| 1463 | &Trace_userlocks, |
| 1464 | false, |
| 1465 | NULL, NULL, NULL |
| 1466 | }, |
| 1467 | { |
| 1468 | {"trace_lwlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1469 | gettext_noop("Emits information about lightweight lock usage." ), |
| 1470 | NULL, |
| 1471 | GUC_NOT_IN_SAMPLE |
| 1472 | }, |
| 1473 | &Trace_lwlocks, |
| 1474 | false, |
| 1475 | NULL, NULL, NULL |
| 1476 | }, |
| 1477 | { |
| 1478 | {"debug_deadlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1479 | gettext_noop("Dumps information about all current locks when a deadlock timeout occurs." ), |
| 1480 | NULL, |
| 1481 | GUC_NOT_IN_SAMPLE |
| 1482 | }, |
| 1483 | &Debug_deadlocks, |
| 1484 | false, |
| 1485 | NULL, NULL, NULL |
| 1486 | }, |
| 1487 | #endif |
| 1488 | |
| 1489 | { |
| 1490 | {"log_lock_waits" , PGC_SUSET, LOGGING_WHAT, |
| 1491 | gettext_noop("Logs long lock waits." ), |
| 1492 | NULL |
| 1493 | }, |
| 1494 | &log_lock_waits, |
| 1495 | false, |
| 1496 | NULL, NULL, NULL |
| 1497 | }, |
| 1498 | |
| 1499 | { |
| 1500 | {"log_hostname" , PGC_SIGHUP, LOGGING_WHAT, |
| 1501 | gettext_noop("Logs the host name in the connection logs." ), |
| 1502 | gettext_noop("By default, connection logs only show the IP address " |
| 1503 | "of the connecting host. If you want them to show the host name you " |
| 1504 | "can turn this on, but depending on your host name resolution " |
| 1505 | "setup it might impose a non-negligible performance penalty." ) |
| 1506 | }, |
| 1507 | &log_hostname, |
| 1508 | false, |
| 1509 | NULL, NULL, NULL |
| 1510 | }, |
| 1511 | { |
| 1512 | {"transform_null_equals" , PGC_USERSET, COMPAT_OPTIONS_CLIENT, |
| 1513 | gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"." ), |
| 1514 | gettext_noop("When turned on, expressions of the form expr = NULL " |
| 1515 | "(or NULL = expr) are treated as expr IS NULL, that is, they " |
| 1516 | "return true if expr evaluates to the null value, and false " |
| 1517 | "otherwise. The correct behavior of expr = NULL is to always " |
| 1518 | "return null (unknown)." ) |
| 1519 | }, |
| 1520 | &Transform_null_equals, |
| 1521 | false, |
| 1522 | NULL, NULL, NULL |
| 1523 | }, |
| 1524 | { |
| 1525 | {"db_user_namespace" , PGC_SIGHUP, CONN_AUTH_AUTH, |
| 1526 | gettext_noop("Enables per-database user names." ), |
| 1527 | NULL |
| 1528 | }, |
| 1529 | &Db_user_namespace, |
| 1530 | false, |
| 1531 | NULL, NULL, NULL |
| 1532 | }, |
| 1533 | { |
| 1534 | {"default_transaction_read_only" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1535 | gettext_noop("Sets the default read-only status of new transactions." ), |
| 1536 | NULL |
| 1537 | }, |
| 1538 | &DefaultXactReadOnly, |
| 1539 | false, |
| 1540 | NULL, NULL, NULL |
| 1541 | }, |
| 1542 | { |
| 1543 | {"transaction_read_only" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1544 | gettext_noop("Sets the current transaction's read-only status." ), |
| 1545 | NULL, |
| 1546 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1547 | }, |
| 1548 | &XactReadOnly, |
| 1549 | false, |
| 1550 | check_transaction_read_only, NULL, NULL |
| 1551 | }, |
| 1552 | { |
| 1553 | {"default_transaction_deferrable" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1554 | gettext_noop("Sets the default deferrable status of new transactions." ), |
| 1555 | NULL |
| 1556 | }, |
| 1557 | &DefaultXactDeferrable, |
| 1558 | false, |
| 1559 | NULL, NULL, NULL |
| 1560 | }, |
| 1561 | { |
| 1562 | {"transaction_deferrable" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1563 | gettext_noop("Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures." ), |
| 1564 | NULL, |
| 1565 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1566 | }, |
| 1567 | &XactDeferrable, |
| 1568 | false, |
| 1569 | check_transaction_deferrable, NULL, NULL |
| 1570 | }, |
| 1571 | { |
| 1572 | {"row_security" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1573 | gettext_noop("Enable row security." ), |
| 1574 | gettext_noop("When enabled, row security will be applied to all users." ) |
| 1575 | }, |
| 1576 | &row_security, |
| 1577 | true, |
| 1578 | NULL, NULL, NULL |
| 1579 | }, |
| 1580 | { |
| 1581 | {"check_function_bodies" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 1582 | gettext_noop("Check function bodies during CREATE FUNCTION." ), |
| 1583 | NULL |
| 1584 | }, |
| 1585 | &check_function_bodies, |
| 1586 | true, |
| 1587 | NULL, NULL, NULL |
| 1588 | }, |
| 1589 | { |
| 1590 | {"array_nulls" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1591 | gettext_noop("Enable input of NULL elements in arrays." ), |
| 1592 | gettext_noop("When turned on, unquoted NULL in an array input " |
| 1593 | "value means a null value; " |
| 1594 | "otherwise it is taken literally." ) |
| 1595 | }, |
| 1596 | &Array_nulls, |
| 1597 | true, |
| 1598 | NULL, NULL, NULL |
| 1599 | }, |
| 1600 | |
| 1601 | /* |
| 1602 | * WITH OIDS support, and consequently default_with_oids, was removed in |
| 1603 | * PostgreSQL 12, but we tolerate the parameter being set to false to |
| 1604 | * avoid unnecessarily breaking older dump files. |
| 1605 | */ |
| 1606 | { |
| 1607 | {"default_with_oids" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1608 | gettext_noop("WITH OIDS is no longer supported; this can only be false." ), |
| 1609 | NULL, |
| 1610 | GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE |
| 1611 | }, |
| 1612 | &default_with_oids, |
| 1613 | false, |
| 1614 | check_default_with_oids, NULL, NULL |
| 1615 | }, |
| 1616 | { |
| 1617 | {"logging_collector" , PGC_POSTMASTER, LOGGING_WHERE, |
| 1618 | gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files." ), |
| 1619 | NULL |
| 1620 | }, |
| 1621 | &Logging_collector, |
| 1622 | false, |
| 1623 | NULL, NULL, NULL |
| 1624 | }, |
| 1625 | { |
| 1626 | {"log_truncate_on_rotation" , PGC_SIGHUP, LOGGING_WHERE, |
| 1627 | gettext_noop("Truncate existing log files of same name during log rotation." ), |
| 1628 | NULL |
| 1629 | }, |
| 1630 | &Log_truncate_on_rotation, |
| 1631 | false, |
| 1632 | NULL, NULL, NULL |
| 1633 | }, |
| 1634 | |
| 1635 | #ifdef TRACE_SORT |
| 1636 | { |
| 1637 | {"trace_sort" , PGC_USERSET, DEVELOPER_OPTIONS, |
| 1638 | gettext_noop("Emit information about resource usage in sorting." ), |
| 1639 | NULL, |
| 1640 | GUC_NOT_IN_SAMPLE |
| 1641 | }, |
| 1642 | &trace_sort, |
| 1643 | false, |
| 1644 | NULL, NULL, NULL |
| 1645 | }, |
| 1646 | #endif |
| 1647 | |
| 1648 | #ifdef TRACE_SYNCSCAN |
| 1649 | /* this is undocumented because not exposed in a standard build */ |
| 1650 | { |
| 1651 | {"trace_syncscan" , PGC_USERSET, DEVELOPER_OPTIONS, |
| 1652 | gettext_noop("Generate debugging output for synchronized scanning." ), |
| 1653 | NULL, |
| 1654 | GUC_NOT_IN_SAMPLE |
| 1655 | }, |
| 1656 | &trace_syncscan, |
| 1657 | false, |
| 1658 | NULL, NULL, NULL |
| 1659 | }, |
| 1660 | #endif |
| 1661 | |
| 1662 | #ifdef DEBUG_BOUNDED_SORT |
| 1663 | /* this is undocumented because not exposed in a standard build */ |
| 1664 | { |
| 1665 | { |
| 1666 | "optimize_bounded_sort" , PGC_USERSET, QUERY_TUNING_METHOD, |
| 1667 | gettext_noop("Enable bounded sorting using heap sort." ), |
| 1668 | NULL, |
| 1669 | GUC_NOT_IN_SAMPLE | GUC_EXPLAIN |
| 1670 | }, |
| 1671 | &optimize_bounded_sort, |
| 1672 | true, |
| 1673 | NULL, NULL, NULL |
| 1674 | }, |
| 1675 | #endif |
| 1676 | |
| 1677 | #ifdef WAL_DEBUG |
| 1678 | { |
| 1679 | {"wal_debug" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1680 | gettext_noop("Emit WAL-related debugging output." ), |
| 1681 | NULL, |
| 1682 | GUC_NOT_IN_SAMPLE |
| 1683 | }, |
| 1684 | &XLOG_DEBUG, |
| 1685 | false, |
| 1686 | NULL, NULL, NULL |
| 1687 | }, |
| 1688 | #endif |
| 1689 | |
| 1690 | { |
| 1691 | {"integer_datetimes" , PGC_INTERNAL, PRESET_OPTIONS, |
| 1692 | gettext_noop("Datetimes are integer based." ), |
| 1693 | NULL, |
| 1694 | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1695 | }, |
| 1696 | &integer_datetimes, |
| 1697 | true, |
| 1698 | NULL, NULL, NULL |
| 1699 | }, |
| 1700 | |
| 1701 | { |
| 1702 | {"krb_caseins_users" , PGC_SIGHUP, CONN_AUTH_AUTH, |
| 1703 | gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive." ), |
| 1704 | NULL |
| 1705 | }, |
| 1706 | &pg_krb_caseins_users, |
| 1707 | false, |
| 1708 | NULL, NULL, NULL |
| 1709 | }, |
| 1710 | |
| 1711 | { |
| 1712 | {"escape_string_warning" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1713 | gettext_noop("Warn about backslash escapes in ordinary string literals." ), |
| 1714 | NULL |
| 1715 | }, |
| 1716 | &escape_string_warning, |
| 1717 | true, |
| 1718 | NULL, NULL, NULL |
| 1719 | }, |
| 1720 | |
| 1721 | { |
| 1722 | {"standard_conforming_strings" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1723 | gettext_noop("Causes '...' strings to treat backslashes literally." ), |
| 1724 | NULL, |
| 1725 | GUC_REPORT |
| 1726 | }, |
| 1727 | &standard_conforming_strings, |
| 1728 | true, |
| 1729 | NULL, NULL, NULL |
| 1730 | }, |
| 1731 | |
| 1732 | { |
| 1733 | {"synchronize_seqscans" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1734 | gettext_noop("Enable synchronized sequential scans." ), |
| 1735 | NULL |
| 1736 | }, |
| 1737 | &synchronize_seqscans, |
| 1738 | true, |
| 1739 | NULL, NULL, NULL |
| 1740 | }, |
| 1741 | |
| 1742 | { |
| 1743 | {"recovery_target_inclusive" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 1744 | gettext_noop("Sets whether to include or exclude transaction with recovery target." ), |
| 1745 | NULL |
| 1746 | }, |
| 1747 | &recoveryTargetInclusive, |
| 1748 | true, |
| 1749 | NULL, NULL, NULL |
| 1750 | }, |
| 1751 | |
| 1752 | { |
| 1753 | {"hot_standby" , PGC_POSTMASTER, REPLICATION_STANDBY, |
| 1754 | gettext_noop("Allows connections and queries during recovery." ), |
| 1755 | NULL |
| 1756 | }, |
| 1757 | &EnableHotStandby, |
| 1758 | true, |
| 1759 | NULL, NULL, NULL |
| 1760 | }, |
| 1761 | |
| 1762 | { |
| 1763 | {"hot_standby_feedback" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 1764 | gettext_noop("Allows feedback from a hot standby to the primary that will avoid query conflicts." ), |
| 1765 | NULL |
| 1766 | }, |
| 1767 | &hot_standby_feedback, |
| 1768 | false, |
| 1769 | NULL, NULL, NULL |
| 1770 | }, |
| 1771 | |
| 1772 | { |
| 1773 | {"allow_system_table_mods" , PGC_POSTMASTER, DEVELOPER_OPTIONS, |
| 1774 | gettext_noop("Allows modifications of the structure of system tables." ), |
| 1775 | NULL, |
| 1776 | GUC_NOT_IN_SAMPLE |
| 1777 | }, |
| 1778 | &allowSystemTableMods, |
| 1779 | false, |
| 1780 | NULL, NULL, NULL |
| 1781 | }, |
| 1782 | |
| 1783 | { |
| 1784 | {"ignore_system_indexes" , PGC_BACKEND, DEVELOPER_OPTIONS, |
| 1785 | gettext_noop("Disables reading from system indexes." ), |
| 1786 | gettext_noop("It does not prevent updating the indexes, so it is safe " |
| 1787 | "to use. The worst consequence is slowness." ), |
| 1788 | GUC_NOT_IN_SAMPLE |
| 1789 | }, |
| 1790 | &IgnoreSystemIndexes, |
| 1791 | false, |
| 1792 | NULL, NULL, NULL |
| 1793 | }, |
| 1794 | |
| 1795 | { |
| 1796 | {"lo_compat_privileges" , PGC_SUSET, COMPAT_OPTIONS_PREVIOUS, |
| 1797 | gettext_noop("Enables backward compatibility mode for privilege checks on large objects." ), |
| 1798 | gettext_noop("Skips privilege checks when reading or modifying large objects, " |
| 1799 | "for compatibility with PostgreSQL releases prior to 9.0." ) |
| 1800 | }, |
| 1801 | &lo_compat_privileges, |
| 1802 | false, |
| 1803 | NULL, NULL, NULL |
| 1804 | }, |
| 1805 | |
| 1806 | { |
| 1807 | {"operator_precedence_warning" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1808 | gettext_noop("Emit a warning for constructs that changed meaning since PostgreSQL 9.4." ), |
| 1809 | NULL, |
| 1810 | }, |
| 1811 | &operator_precedence_warning, |
| 1812 | false, |
| 1813 | NULL, NULL, NULL |
| 1814 | }, |
| 1815 | |
| 1816 | { |
| 1817 | {"quote_all_identifiers" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 1818 | gettext_noop("When generating SQL fragments, quote all identifiers." ), |
| 1819 | NULL, |
| 1820 | }, |
| 1821 | "e_all_identifiers, |
| 1822 | false, |
| 1823 | NULL, NULL, NULL |
| 1824 | }, |
| 1825 | |
| 1826 | { |
| 1827 | {"data_checksums" , PGC_INTERNAL, PRESET_OPTIONS, |
| 1828 | gettext_noop("Shows whether data checksums are turned on for this cluster." ), |
| 1829 | NULL, |
| 1830 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 1831 | }, |
| 1832 | &data_checksums, |
| 1833 | false, |
| 1834 | NULL, NULL, NULL |
| 1835 | }, |
| 1836 | |
| 1837 | { |
| 1838 | {"syslog_sequence_numbers" , PGC_SIGHUP, LOGGING_WHERE, |
| 1839 | gettext_noop("Add sequence number to syslog messages to avoid duplicate suppression." ), |
| 1840 | NULL |
| 1841 | }, |
| 1842 | &syslog_sequence_numbers, |
| 1843 | true, |
| 1844 | NULL, NULL, NULL |
| 1845 | }, |
| 1846 | |
| 1847 | { |
| 1848 | {"syslog_split_messages" , PGC_SIGHUP, LOGGING_WHERE, |
| 1849 | gettext_noop("Split messages sent to syslog by lines and to fit into 1024 bytes." ), |
| 1850 | NULL |
| 1851 | }, |
| 1852 | &syslog_split_messages, |
| 1853 | true, |
| 1854 | NULL, NULL, NULL |
| 1855 | }, |
| 1856 | |
| 1857 | { |
| 1858 | {"parallel_leader_participation" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
| 1859 | gettext_noop("Controls whether Gather and Gather Merge also run subplans." ), |
| 1860 | gettext_noop("Should gather nodes also run subplans, or just gather tuples?" ), |
| 1861 | GUC_EXPLAIN |
| 1862 | }, |
| 1863 | ¶llel_leader_participation, |
| 1864 | true, |
| 1865 | NULL, NULL, NULL |
| 1866 | }, |
| 1867 | |
| 1868 | { |
| 1869 | {"jit" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 1870 | gettext_noop("Allow JIT compilation." ), |
| 1871 | NULL, |
| 1872 | GUC_EXPLAIN |
| 1873 | }, |
| 1874 | &jit_enabled, |
| 1875 | true, |
| 1876 | NULL, NULL, NULL |
| 1877 | }, |
| 1878 | |
| 1879 | { |
| 1880 | {"jit_debugging_support" , PGC_SU_BACKEND, DEVELOPER_OPTIONS, |
| 1881 | gettext_noop("Register JIT compiled function with debugger." ), |
| 1882 | NULL, |
| 1883 | GUC_NOT_IN_SAMPLE |
| 1884 | }, |
| 1885 | &jit_debugging_support, |
| 1886 | false, |
| 1887 | |
| 1888 | /* |
| 1889 | * This is not guaranteed to be available, but given it's a developer |
| 1890 | * oriented option, it doesn't seem worth adding code checking |
| 1891 | * availability. |
| 1892 | */ |
| 1893 | NULL, NULL, NULL |
| 1894 | }, |
| 1895 | |
| 1896 | { |
| 1897 | {"jit_dump_bitcode" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 1898 | gettext_noop("Write out LLVM bitcode to facilitate JIT debugging." ), |
| 1899 | NULL, |
| 1900 | GUC_NOT_IN_SAMPLE |
| 1901 | }, |
| 1902 | &jit_dump_bitcode, |
| 1903 | false, |
| 1904 | NULL, NULL, NULL |
| 1905 | }, |
| 1906 | |
| 1907 | { |
| 1908 | {"jit_expressions" , PGC_USERSET, DEVELOPER_OPTIONS, |
| 1909 | gettext_noop("Allow JIT compilation of expressions." ), |
| 1910 | NULL, |
| 1911 | GUC_NOT_IN_SAMPLE |
| 1912 | }, |
| 1913 | &jit_expressions, |
| 1914 | true, |
| 1915 | NULL, NULL, NULL |
| 1916 | }, |
| 1917 | |
| 1918 | { |
| 1919 | {"jit_profiling_support" , PGC_SU_BACKEND, DEVELOPER_OPTIONS, |
| 1920 | gettext_noop("Register JIT compiled function with perf profiler." ), |
| 1921 | NULL, |
| 1922 | GUC_NOT_IN_SAMPLE |
| 1923 | }, |
| 1924 | &jit_profiling_support, |
| 1925 | false, |
| 1926 | |
| 1927 | /* |
| 1928 | * This is not guaranteed to be available, but given it's a developer |
| 1929 | * oriented option, it doesn't seem worth adding code checking |
| 1930 | * availability. |
| 1931 | */ |
| 1932 | NULL, NULL, NULL |
| 1933 | }, |
| 1934 | |
| 1935 | { |
| 1936 | {"jit_tuple_deforming" , PGC_USERSET, DEVELOPER_OPTIONS, |
| 1937 | gettext_noop("Allow JIT compilation of tuple deforming." ), |
| 1938 | NULL, |
| 1939 | GUC_NOT_IN_SAMPLE |
| 1940 | }, |
| 1941 | &jit_tuple_deforming, |
| 1942 | true, |
| 1943 | NULL, NULL, NULL |
| 1944 | }, |
| 1945 | |
| 1946 | { |
| 1947 | {"data_sync_retry" , PGC_POSTMASTER, ERROR_HANDLING_OPTIONS, |
| 1948 | gettext_noop("Whether to continue running after a failure to sync data files." ), |
| 1949 | }, |
| 1950 | &data_sync_retry, |
| 1951 | false, |
| 1952 | NULL, NULL, NULL |
| 1953 | }, |
| 1954 | |
| 1955 | /* End-of-list marker */ |
| 1956 | { |
| 1957 | {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL |
| 1958 | } |
| 1959 | }; |
| 1960 | |
| 1961 | |
| 1962 | static struct config_int ConfigureNamesInt[] = |
| 1963 | { |
| 1964 | { |
| 1965 | {"archive_timeout" , PGC_SIGHUP, WAL_ARCHIVING, |
| 1966 | gettext_noop("Forces a switch to the next WAL file if a " |
| 1967 | "new file has not been started within N seconds." ), |
| 1968 | NULL, |
| 1969 | GUC_UNIT_S |
| 1970 | }, |
| 1971 | &XLogArchiveTimeout, |
| 1972 | 0, 0, INT_MAX / 2, |
| 1973 | NULL, NULL, NULL |
| 1974 | }, |
| 1975 | { |
| 1976 | {"post_auth_delay" , PGC_BACKEND, DEVELOPER_OPTIONS, |
| 1977 | gettext_noop("Waits N seconds on connection startup after authentication." ), |
| 1978 | gettext_noop("This allows attaching a debugger to the process." ), |
| 1979 | GUC_NOT_IN_SAMPLE | GUC_UNIT_S |
| 1980 | }, |
| 1981 | &PostAuthDelay, |
| 1982 | 0, 0, INT_MAX / 1000000, |
| 1983 | NULL, NULL, NULL |
| 1984 | }, |
| 1985 | { |
| 1986 | {"default_statistics_target" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 1987 | gettext_noop("Sets the default statistics target." ), |
| 1988 | gettext_noop("This applies to table columns that have not had a " |
| 1989 | "column-specific target set via ALTER TABLE SET STATISTICS." ) |
| 1990 | }, |
| 1991 | &default_statistics_target, |
| 1992 | 100, 1, 10000, |
| 1993 | NULL, NULL, NULL |
| 1994 | }, |
| 1995 | { |
| 1996 | {"from_collapse_limit" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 1997 | gettext_noop("Sets the FROM-list size beyond which subqueries " |
| 1998 | "are not collapsed." ), |
| 1999 | gettext_noop("The planner will merge subqueries into upper " |
| 2000 | "queries if the resulting FROM list would have no more than " |
| 2001 | "this many items." ), |
| 2002 | GUC_EXPLAIN |
| 2003 | }, |
| 2004 | &from_collapse_limit, |
| 2005 | 8, 1, INT_MAX, |
| 2006 | NULL, NULL, NULL |
| 2007 | }, |
| 2008 | { |
| 2009 | {"join_collapse_limit" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 2010 | gettext_noop("Sets the FROM-list size beyond which JOIN " |
| 2011 | "constructs are not flattened." ), |
| 2012 | gettext_noop("The planner will flatten explicit JOIN " |
| 2013 | "constructs into lists of FROM items whenever a " |
| 2014 | "list of no more than this many items would result." ), |
| 2015 | GUC_EXPLAIN |
| 2016 | }, |
| 2017 | &join_collapse_limit, |
| 2018 | 8, 1, INT_MAX, |
| 2019 | NULL, NULL, NULL |
| 2020 | }, |
| 2021 | { |
| 2022 | {"geqo_threshold" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 2023 | gettext_noop("Sets the threshold of FROM items beyond which GEQO is used." ), |
| 2024 | NULL, |
| 2025 | GUC_EXPLAIN |
| 2026 | }, |
| 2027 | &geqo_threshold, |
| 2028 | 12, 2, INT_MAX, |
| 2029 | NULL, NULL, NULL |
| 2030 | }, |
| 2031 | { |
| 2032 | {"geqo_effort" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 2033 | gettext_noop("GEQO: effort is used to set the default for other GEQO parameters." ), |
| 2034 | NULL, |
| 2035 | GUC_EXPLAIN |
| 2036 | }, |
| 2037 | &Geqo_effort, |
| 2038 | DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT, |
| 2039 | NULL, NULL, NULL |
| 2040 | }, |
| 2041 | { |
| 2042 | {"geqo_pool_size" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 2043 | gettext_noop("GEQO: number of individuals in the population." ), |
| 2044 | gettext_noop("Zero selects a suitable default value." ), |
| 2045 | GUC_EXPLAIN |
| 2046 | }, |
| 2047 | &Geqo_pool_size, |
| 2048 | 0, 0, INT_MAX, |
| 2049 | NULL, NULL, NULL |
| 2050 | }, |
| 2051 | { |
| 2052 | {"geqo_generations" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 2053 | gettext_noop("GEQO: number of iterations of the algorithm." ), |
| 2054 | gettext_noop("Zero selects a suitable default value." ), |
| 2055 | GUC_EXPLAIN |
| 2056 | }, |
| 2057 | &Geqo_generations, |
| 2058 | 0, 0, INT_MAX, |
| 2059 | NULL, NULL, NULL |
| 2060 | }, |
| 2061 | |
| 2062 | { |
| 2063 | /* This is PGC_SUSET to prevent hiding from log_lock_waits. */ |
| 2064 | {"deadlock_timeout" , PGC_SUSET, LOCK_MANAGEMENT, |
| 2065 | gettext_noop("Sets the time to wait on a lock before checking for deadlock." ), |
| 2066 | NULL, |
| 2067 | GUC_UNIT_MS |
| 2068 | }, |
| 2069 | &DeadlockTimeout, |
| 2070 | 1000, 1, INT_MAX, |
| 2071 | NULL, NULL, NULL |
| 2072 | }, |
| 2073 | |
| 2074 | { |
| 2075 | {"max_standby_archive_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2076 | gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing archived WAL data." ), |
| 2077 | NULL, |
| 2078 | GUC_UNIT_MS |
| 2079 | }, |
| 2080 | &max_standby_archive_delay, |
| 2081 | 30 * 1000, -1, INT_MAX, |
| 2082 | NULL, NULL, NULL |
| 2083 | }, |
| 2084 | |
| 2085 | { |
| 2086 | {"max_standby_streaming_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2087 | gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing streamed WAL data." ), |
| 2088 | NULL, |
| 2089 | GUC_UNIT_MS |
| 2090 | }, |
| 2091 | &max_standby_streaming_delay, |
| 2092 | 30 * 1000, -1, INT_MAX, |
| 2093 | NULL, NULL, NULL |
| 2094 | }, |
| 2095 | |
| 2096 | { |
| 2097 | {"recovery_min_apply_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2098 | gettext_noop("Sets the minimum delay for applying changes during recovery." ), |
| 2099 | NULL, |
| 2100 | GUC_UNIT_MS |
| 2101 | }, |
| 2102 | &recovery_min_apply_delay, |
| 2103 | 0, 0, INT_MAX, |
| 2104 | NULL, NULL, NULL |
| 2105 | }, |
| 2106 | |
| 2107 | { |
| 2108 | {"wal_receiver_status_interval" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2109 | gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server." ), |
| 2110 | NULL, |
| 2111 | GUC_UNIT_S |
| 2112 | }, |
| 2113 | &wal_receiver_status_interval, |
| 2114 | 10, 0, INT_MAX / 1000, |
| 2115 | NULL, NULL, NULL |
| 2116 | }, |
| 2117 | |
| 2118 | { |
| 2119 | {"wal_receiver_timeout" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2120 | gettext_noop("Sets the maximum wait time to receive data from the sending server." ), |
| 2121 | NULL, |
| 2122 | GUC_UNIT_MS |
| 2123 | }, |
| 2124 | &wal_receiver_timeout, |
| 2125 | 60 * 1000, 0, INT_MAX, |
| 2126 | NULL, NULL, NULL |
| 2127 | }, |
| 2128 | |
| 2129 | { |
| 2130 | {"max_connections" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 2131 | gettext_noop("Sets the maximum number of concurrent connections." ), |
| 2132 | NULL |
| 2133 | }, |
| 2134 | &MaxConnections, |
| 2135 | 100, 1, MAX_BACKENDS, |
| 2136 | check_maxconnections, NULL, NULL |
| 2137 | }, |
| 2138 | |
| 2139 | { |
| 2140 | /* see max_connections */ |
| 2141 | {"superuser_reserved_connections" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 2142 | gettext_noop("Sets the number of connection slots reserved for superusers." ), |
| 2143 | NULL |
| 2144 | }, |
| 2145 | &ReservedBackends, |
| 2146 | 3, 0, MAX_BACKENDS, |
| 2147 | NULL, NULL, NULL |
| 2148 | }, |
| 2149 | |
| 2150 | /* |
| 2151 | * We sometimes multiply the number of shared buffers by two without |
| 2152 | * checking for overflow, so we mustn't allow more than INT_MAX / 2. |
| 2153 | */ |
| 2154 | { |
| 2155 | {"shared_buffers" , PGC_POSTMASTER, RESOURCES_MEM, |
| 2156 | gettext_noop("Sets the number of shared memory buffers used by the server." ), |
| 2157 | NULL, |
| 2158 | GUC_UNIT_BLOCKS |
| 2159 | }, |
| 2160 | &NBuffers, |
| 2161 | 1024, 16, INT_MAX / 2, |
| 2162 | NULL, NULL, NULL |
| 2163 | }, |
| 2164 | |
| 2165 | { |
| 2166 | {"temp_buffers" , PGC_USERSET, RESOURCES_MEM, |
| 2167 | gettext_noop("Sets the maximum number of temporary buffers used by each session." ), |
| 2168 | NULL, |
| 2169 | GUC_UNIT_BLOCKS | GUC_EXPLAIN |
| 2170 | }, |
| 2171 | &num_temp_buffers, |
| 2172 | 1024, 100, INT_MAX / 2, |
| 2173 | check_temp_buffers, NULL, NULL |
| 2174 | }, |
| 2175 | |
| 2176 | { |
| 2177 | {"port" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 2178 | gettext_noop("Sets the TCP port the server listens on." ), |
| 2179 | NULL |
| 2180 | }, |
| 2181 | &PostPortNumber, |
| 2182 | DEF_PGPORT, 1, 65535, |
| 2183 | NULL, NULL, NULL |
| 2184 | }, |
| 2185 | |
| 2186 | { |
| 2187 | {"unix_socket_permissions" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 2188 | gettext_noop("Sets the access permissions of the Unix-domain socket." ), |
| 2189 | gettext_noop("Unix-domain sockets use the usual Unix file system " |
| 2190 | "permission set. The parameter value is expected " |
| 2191 | "to be a numeric mode specification in the form " |
| 2192 | "accepted by the chmod and umask system calls. " |
| 2193 | "(To use the customary octal format the number must " |
| 2194 | "start with a 0 (zero).)" ) |
| 2195 | }, |
| 2196 | &Unix_socket_permissions, |
| 2197 | 0777, 0000, 0777, |
| 2198 | NULL, NULL, show_unix_socket_permissions |
| 2199 | }, |
| 2200 | |
| 2201 | { |
| 2202 | {"log_file_mode" , PGC_SIGHUP, LOGGING_WHERE, |
| 2203 | gettext_noop("Sets the file permissions for log files." ), |
| 2204 | gettext_noop("The parameter value is expected " |
| 2205 | "to be a numeric mode specification in the form " |
| 2206 | "accepted by the chmod and umask system calls. " |
| 2207 | "(To use the customary octal format the number must " |
| 2208 | "start with a 0 (zero).)" ) |
| 2209 | }, |
| 2210 | &Log_file_mode, |
| 2211 | 0600, 0000, 0777, |
| 2212 | NULL, NULL, show_log_file_mode |
| 2213 | }, |
| 2214 | |
| 2215 | |
| 2216 | { |
| 2217 | {"data_directory_mode" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2218 | gettext_noop("Mode of the data directory." ), |
| 2219 | gettext_noop("The parameter value is a numeric mode specification " |
| 2220 | "in the form accepted by the chmod and umask system " |
| 2221 | "calls. (To use the customary octal format the number " |
| 2222 | "must start with a 0 (zero).)" ), |
| 2223 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2224 | }, |
| 2225 | &data_directory_mode, |
| 2226 | 0700, 0000, 0777, |
| 2227 | NULL, NULL, show_data_directory_mode |
| 2228 | }, |
| 2229 | |
| 2230 | { |
| 2231 | {"work_mem" , PGC_USERSET, RESOURCES_MEM, |
| 2232 | gettext_noop("Sets the maximum memory to be used for query workspaces." ), |
| 2233 | gettext_noop("This much memory can be used by each internal " |
| 2234 | "sort operation and hash table before switching to " |
| 2235 | "temporary disk files." ), |
| 2236 | GUC_UNIT_KB | GUC_EXPLAIN |
| 2237 | }, |
| 2238 | &work_mem, |
| 2239 | 4096, 64, MAX_KILOBYTES, |
| 2240 | NULL, NULL, NULL |
| 2241 | }, |
| 2242 | |
| 2243 | { |
| 2244 | {"maintenance_work_mem" , PGC_USERSET, RESOURCES_MEM, |
| 2245 | gettext_noop("Sets the maximum memory to be used for maintenance operations." ), |
| 2246 | gettext_noop("This includes operations such as VACUUM and CREATE INDEX." ), |
| 2247 | GUC_UNIT_KB |
| 2248 | }, |
| 2249 | &maintenance_work_mem, |
| 2250 | 65536, 1024, MAX_KILOBYTES, |
| 2251 | NULL, NULL, NULL |
| 2252 | }, |
| 2253 | |
| 2254 | /* |
| 2255 | * We use the hopefully-safely-small value of 100kB as the compiled-in |
| 2256 | * default for max_stack_depth. InitializeGUCOptions will increase it if |
| 2257 | * possible, depending on the actual platform-specific stack limit. |
| 2258 | */ |
| 2259 | { |
| 2260 | {"max_stack_depth" , PGC_SUSET, RESOURCES_MEM, |
| 2261 | gettext_noop("Sets the maximum stack depth, in kilobytes." ), |
| 2262 | NULL, |
| 2263 | GUC_UNIT_KB |
| 2264 | }, |
| 2265 | &max_stack_depth, |
| 2266 | 100, 100, MAX_KILOBYTES, |
| 2267 | check_max_stack_depth, assign_max_stack_depth, NULL |
| 2268 | }, |
| 2269 | |
| 2270 | { |
| 2271 | {"temp_file_limit" , PGC_SUSET, RESOURCES_DISK, |
| 2272 | gettext_noop("Limits the total size of all temporary files used by each process." ), |
| 2273 | gettext_noop("-1 means no limit." ), |
| 2274 | GUC_UNIT_KB |
| 2275 | }, |
| 2276 | &temp_file_limit, |
| 2277 | -1, -1, INT_MAX, |
| 2278 | NULL, NULL, NULL |
| 2279 | }, |
| 2280 | |
| 2281 | { |
| 2282 | {"vacuum_cost_page_hit" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
| 2283 | gettext_noop("Vacuum cost for a page found in the buffer cache." ), |
| 2284 | NULL |
| 2285 | }, |
| 2286 | &VacuumCostPageHit, |
| 2287 | 1, 0, 10000, |
| 2288 | NULL, NULL, NULL |
| 2289 | }, |
| 2290 | |
| 2291 | { |
| 2292 | {"vacuum_cost_page_miss" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
| 2293 | gettext_noop("Vacuum cost for a page not found in the buffer cache." ), |
| 2294 | NULL |
| 2295 | }, |
| 2296 | &VacuumCostPageMiss, |
| 2297 | 10, 0, 10000, |
| 2298 | NULL, NULL, NULL |
| 2299 | }, |
| 2300 | |
| 2301 | { |
| 2302 | {"vacuum_cost_page_dirty" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
| 2303 | gettext_noop("Vacuum cost for a page dirtied by vacuum." ), |
| 2304 | NULL |
| 2305 | }, |
| 2306 | &VacuumCostPageDirty, |
| 2307 | 20, 0, 10000, |
| 2308 | NULL, NULL, NULL |
| 2309 | }, |
| 2310 | |
| 2311 | { |
| 2312 | {"vacuum_cost_limit" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
| 2313 | gettext_noop("Vacuum cost amount available before napping." ), |
| 2314 | NULL |
| 2315 | }, |
| 2316 | &VacuumCostLimit, |
| 2317 | 200, 1, 10000, |
| 2318 | NULL, NULL, NULL |
| 2319 | }, |
| 2320 | |
| 2321 | { |
| 2322 | {"autovacuum_vacuum_cost_limit" , PGC_SIGHUP, AUTOVACUUM, |
| 2323 | gettext_noop("Vacuum cost amount available before napping, for autovacuum." ), |
| 2324 | NULL |
| 2325 | }, |
| 2326 | &autovacuum_vac_cost_limit, |
| 2327 | -1, -1, 10000, |
| 2328 | NULL, NULL, NULL |
| 2329 | }, |
| 2330 | |
| 2331 | { |
| 2332 | {"max_files_per_process" , PGC_POSTMASTER, RESOURCES_KERNEL, |
| 2333 | gettext_noop("Sets the maximum number of simultaneously open files for each server process." ), |
| 2334 | NULL |
| 2335 | }, |
| 2336 | &max_files_per_process, |
| 2337 | 1000, 25, INT_MAX, |
| 2338 | NULL, NULL, NULL |
| 2339 | }, |
| 2340 | |
| 2341 | /* |
| 2342 | * See also CheckRequiredParameterValues() if this parameter changes |
| 2343 | */ |
| 2344 | { |
| 2345 | {"max_prepared_transactions" , PGC_POSTMASTER, RESOURCES_MEM, |
| 2346 | gettext_noop("Sets the maximum number of simultaneously prepared transactions." ), |
| 2347 | NULL |
| 2348 | }, |
| 2349 | &max_prepared_xacts, |
| 2350 | 0, 0, MAX_BACKENDS, |
| 2351 | NULL, NULL, NULL |
| 2352 | }, |
| 2353 | |
| 2354 | #ifdef LOCK_DEBUG |
| 2355 | { |
| 2356 | {"trace_lock_oidmin" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 2357 | gettext_noop("Sets the minimum OID of tables for tracking locks." ), |
| 2358 | gettext_noop("Is used to avoid output on system tables." ), |
| 2359 | GUC_NOT_IN_SAMPLE |
| 2360 | }, |
| 2361 | &Trace_lock_oidmin, |
| 2362 | FirstNormalObjectId, 0, INT_MAX, |
| 2363 | NULL, NULL, NULL |
| 2364 | }, |
| 2365 | { |
| 2366 | {"trace_lock_table" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 2367 | gettext_noop("Sets the OID of the table with unconditionally lock tracing." ), |
| 2368 | NULL, |
| 2369 | GUC_NOT_IN_SAMPLE |
| 2370 | }, |
| 2371 | &Trace_lock_table, |
| 2372 | 0, 0, INT_MAX, |
| 2373 | NULL, NULL, NULL |
| 2374 | }, |
| 2375 | #endif |
| 2376 | |
| 2377 | { |
| 2378 | {"statement_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2379 | gettext_noop("Sets the maximum allowed duration of any statement." ), |
| 2380 | gettext_noop("A value of 0 turns off the timeout." ), |
| 2381 | GUC_UNIT_MS |
| 2382 | }, |
| 2383 | &StatementTimeout, |
| 2384 | 0, 0, INT_MAX, |
| 2385 | NULL, NULL, NULL |
| 2386 | }, |
| 2387 | |
| 2388 | { |
| 2389 | {"lock_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2390 | gettext_noop("Sets the maximum allowed duration of any wait for a lock." ), |
| 2391 | gettext_noop("A value of 0 turns off the timeout." ), |
| 2392 | GUC_UNIT_MS |
| 2393 | }, |
| 2394 | &LockTimeout, |
| 2395 | 0, 0, INT_MAX, |
| 2396 | NULL, NULL, NULL |
| 2397 | }, |
| 2398 | |
| 2399 | { |
| 2400 | {"idle_in_transaction_session_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2401 | gettext_noop("Sets the maximum allowed duration of any idling transaction." ), |
| 2402 | gettext_noop("A value of 0 turns off the timeout." ), |
| 2403 | GUC_UNIT_MS |
| 2404 | }, |
| 2405 | &IdleInTransactionSessionTimeout, |
| 2406 | 0, 0, INT_MAX, |
| 2407 | NULL, NULL, NULL |
| 2408 | }, |
| 2409 | |
| 2410 | { |
| 2411 | {"vacuum_freeze_min_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2412 | gettext_noop("Minimum age at which VACUUM should freeze a table row." ), |
| 2413 | NULL |
| 2414 | }, |
| 2415 | &vacuum_freeze_min_age, |
| 2416 | 50000000, 0, 1000000000, |
| 2417 | NULL, NULL, NULL |
| 2418 | }, |
| 2419 | |
| 2420 | { |
| 2421 | {"vacuum_freeze_table_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2422 | gettext_noop("Age at which VACUUM should scan whole table to freeze tuples." ), |
| 2423 | NULL |
| 2424 | }, |
| 2425 | &vacuum_freeze_table_age, |
| 2426 | 150000000, 0, 2000000000, |
| 2427 | NULL, NULL, NULL |
| 2428 | }, |
| 2429 | |
| 2430 | { |
| 2431 | {"vacuum_multixact_freeze_min_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2432 | gettext_noop("Minimum age at which VACUUM should freeze a MultiXactId in a table row." ), |
| 2433 | NULL |
| 2434 | }, |
| 2435 | &vacuum_multixact_freeze_min_age, |
| 2436 | 5000000, 0, 1000000000, |
| 2437 | NULL, NULL, NULL |
| 2438 | }, |
| 2439 | |
| 2440 | { |
| 2441 | {"vacuum_multixact_freeze_table_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 2442 | gettext_noop("Multixact age at which VACUUM should scan whole table to freeze tuples." ), |
| 2443 | NULL |
| 2444 | }, |
| 2445 | &vacuum_multixact_freeze_table_age, |
| 2446 | 150000000, 0, 2000000000, |
| 2447 | NULL, NULL, NULL |
| 2448 | }, |
| 2449 | |
| 2450 | { |
| 2451 | {"vacuum_defer_cleanup_age" , PGC_SIGHUP, REPLICATION_MASTER, |
| 2452 | gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any." ), |
| 2453 | NULL |
| 2454 | }, |
| 2455 | &vacuum_defer_cleanup_age, |
| 2456 | 0, 0, 1000000, |
| 2457 | NULL, NULL, NULL |
| 2458 | }, |
| 2459 | |
| 2460 | /* |
| 2461 | * See also CheckRequiredParameterValues() if this parameter changes |
| 2462 | */ |
| 2463 | { |
| 2464 | {"max_locks_per_transaction" , PGC_POSTMASTER, LOCK_MANAGEMENT, |
| 2465 | gettext_noop("Sets the maximum number of locks per transaction." ), |
| 2466 | gettext_noop("The shared lock table is sized on the assumption that " |
| 2467 | "at most max_locks_per_transaction * max_connections distinct " |
| 2468 | "objects will need to be locked at any one time." ) |
| 2469 | }, |
| 2470 | &max_locks_per_xact, |
| 2471 | 64, 10, INT_MAX, |
| 2472 | NULL, NULL, NULL |
| 2473 | }, |
| 2474 | |
| 2475 | { |
| 2476 | {"max_pred_locks_per_transaction" , PGC_POSTMASTER, LOCK_MANAGEMENT, |
| 2477 | gettext_noop("Sets the maximum number of predicate locks per transaction." ), |
| 2478 | gettext_noop("The shared predicate lock table is sized on the assumption that " |
| 2479 | "at most max_pred_locks_per_transaction * max_connections distinct " |
| 2480 | "objects will need to be locked at any one time." ) |
| 2481 | }, |
| 2482 | &max_predicate_locks_per_xact, |
| 2483 | 64, 10, INT_MAX, |
| 2484 | NULL, NULL, NULL |
| 2485 | }, |
| 2486 | |
| 2487 | { |
| 2488 | {"max_pred_locks_per_relation" , PGC_SIGHUP, LOCK_MANAGEMENT, |
| 2489 | gettext_noop("Sets the maximum number of predicate-locked pages and tuples per relation." ), |
| 2490 | gettext_noop("If more than this total of pages and tuples in the same relation are locked " |
| 2491 | "by a connection, those locks are replaced by a relation-level lock." ) |
| 2492 | }, |
| 2493 | &max_predicate_locks_per_relation, |
| 2494 | -2, INT_MIN, INT_MAX, |
| 2495 | NULL, NULL, NULL |
| 2496 | }, |
| 2497 | |
| 2498 | { |
| 2499 | {"max_pred_locks_per_page" , PGC_SIGHUP, LOCK_MANAGEMENT, |
| 2500 | gettext_noop("Sets the maximum number of predicate-locked tuples per page." ), |
| 2501 | gettext_noop("If more than this number of tuples on the same page are locked " |
| 2502 | "by a connection, those locks are replaced by a page-level lock." ) |
| 2503 | }, |
| 2504 | &max_predicate_locks_per_page, |
| 2505 | 2, 0, INT_MAX, |
| 2506 | NULL, NULL, NULL |
| 2507 | }, |
| 2508 | |
| 2509 | { |
| 2510 | {"authentication_timeout" , PGC_SIGHUP, CONN_AUTH_AUTH, |
| 2511 | gettext_noop("Sets the maximum allowed time to complete client authentication." ), |
| 2512 | NULL, |
| 2513 | GUC_UNIT_S |
| 2514 | }, |
| 2515 | &AuthenticationTimeout, |
| 2516 | 60, 1, 600, |
| 2517 | NULL, NULL, NULL |
| 2518 | }, |
| 2519 | |
| 2520 | { |
| 2521 | /* Not for general use */ |
| 2522 | {"pre_auth_delay" , PGC_SIGHUP, DEVELOPER_OPTIONS, |
| 2523 | gettext_noop("Waits N seconds on connection startup before authentication." ), |
| 2524 | gettext_noop("This allows attaching a debugger to the process." ), |
| 2525 | GUC_NOT_IN_SAMPLE | GUC_UNIT_S |
| 2526 | }, |
| 2527 | &PreAuthDelay, |
| 2528 | 0, 0, 60, |
| 2529 | NULL, NULL, NULL |
| 2530 | }, |
| 2531 | |
| 2532 | { |
| 2533 | {"wal_keep_segments" , PGC_SIGHUP, REPLICATION_SENDING, |
| 2534 | gettext_noop("Sets the number of WAL files held for standby servers." ), |
| 2535 | NULL |
| 2536 | }, |
| 2537 | &wal_keep_segments, |
| 2538 | 0, 0, INT_MAX, |
| 2539 | NULL, NULL, NULL |
| 2540 | }, |
| 2541 | |
| 2542 | { |
| 2543 | {"min_wal_size" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 2544 | gettext_noop("Sets the minimum size to shrink the WAL to." ), |
| 2545 | NULL, |
| 2546 | GUC_UNIT_MB |
| 2547 | }, |
| 2548 | &min_wal_size_mb, |
| 2549 | DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)), |
| 2550 | 2, MAX_KILOBYTES, |
| 2551 | NULL, NULL, NULL |
| 2552 | }, |
| 2553 | |
| 2554 | { |
| 2555 | {"max_wal_size" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 2556 | gettext_noop("Sets the WAL size that triggers a checkpoint." ), |
| 2557 | NULL, |
| 2558 | GUC_UNIT_MB |
| 2559 | }, |
| 2560 | &max_wal_size_mb, |
| 2561 | DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)), |
| 2562 | 2, MAX_KILOBYTES, |
| 2563 | NULL, assign_max_wal_size, NULL |
| 2564 | }, |
| 2565 | |
| 2566 | { |
| 2567 | {"checkpoint_timeout" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 2568 | gettext_noop("Sets the maximum time between automatic WAL checkpoints." ), |
| 2569 | NULL, |
| 2570 | GUC_UNIT_S |
| 2571 | }, |
| 2572 | &CheckPointTimeout, |
| 2573 | 300, 30, 86400, |
| 2574 | NULL, NULL, NULL |
| 2575 | }, |
| 2576 | |
| 2577 | { |
| 2578 | {"checkpoint_warning" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 2579 | gettext_noop("Enables warnings if checkpoint segments are filled more " |
| 2580 | "frequently than this." ), |
| 2581 | gettext_noop("Write a message to the server log if checkpoints " |
| 2582 | "caused by the filling of checkpoint segment files happens more " |
| 2583 | "frequently than this number of seconds. Zero turns off the warning." ), |
| 2584 | GUC_UNIT_S |
| 2585 | }, |
| 2586 | &CheckPointWarning, |
| 2587 | 30, 0, INT_MAX, |
| 2588 | NULL, NULL, NULL |
| 2589 | }, |
| 2590 | |
| 2591 | { |
| 2592 | {"checkpoint_flush_after" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 2593 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
| 2594 | NULL, |
| 2595 | GUC_UNIT_BLOCKS |
| 2596 | }, |
| 2597 | &checkpoint_flush_after, |
| 2598 | DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
| 2599 | NULL, NULL, NULL |
| 2600 | }, |
| 2601 | |
| 2602 | { |
| 2603 | {"wal_buffers" , PGC_POSTMASTER, WAL_SETTINGS, |
| 2604 | gettext_noop("Sets the number of disk-page buffers in shared memory for WAL." ), |
| 2605 | NULL, |
| 2606 | GUC_UNIT_XBLOCKS |
| 2607 | }, |
| 2608 | &XLOGbuffers, |
| 2609 | -1, -1, (INT_MAX / XLOG_BLCKSZ), |
| 2610 | check_wal_buffers, NULL, NULL |
| 2611 | }, |
| 2612 | |
| 2613 | { |
| 2614 | {"wal_writer_delay" , PGC_SIGHUP, WAL_SETTINGS, |
| 2615 | gettext_noop("Time between WAL flushes performed in the WAL writer." ), |
| 2616 | NULL, |
| 2617 | GUC_UNIT_MS |
| 2618 | }, |
| 2619 | &WalWriterDelay, |
| 2620 | 200, 1, 10000, |
| 2621 | NULL, NULL, NULL |
| 2622 | }, |
| 2623 | |
| 2624 | { |
| 2625 | {"wal_writer_flush_after" , PGC_SIGHUP, WAL_SETTINGS, |
| 2626 | gettext_noop("Amount of WAL written out by WAL writer that triggers a flush." ), |
| 2627 | NULL, |
| 2628 | GUC_UNIT_XBLOCKS |
| 2629 | }, |
| 2630 | &WalWriterFlushAfter, |
| 2631 | (1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX, |
| 2632 | NULL, NULL, NULL |
| 2633 | }, |
| 2634 | |
| 2635 | { |
| 2636 | {"max_wal_senders" , PGC_POSTMASTER, REPLICATION_SENDING, |
| 2637 | gettext_noop("Sets the maximum number of simultaneously running WAL sender processes." ), |
| 2638 | NULL |
| 2639 | }, |
| 2640 | &max_wal_senders, |
| 2641 | 10, 0, MAX_BACKENDS, |
| 2642 | check_max_wal_senders, NULL, NULL |
| 2643 | }, |
| 2644 | |
| 2645 | { |
| 2646 | /* see max_wal_senders */ |
| 2647 | {"max_replication_slots" , PGC_POSTMASTER, REPLICATION_SENDING, |
| 2648 | gettext_noop("Sets the maximum number of simultaneously defined replication slots." ), |
| 2649 | NULL |
| 2650 | }, |
| 2651 | &max_replication_slots, |
| 2652 | 10, 0, MAX_BACKENDS /* XXX? */ , |
| 2653 | NULL, NULL, NULL |
| 2654 | }, |
| 2655 | |
| 2656 | { |
| 2657 | {"wal_sender_timeout" , PGC_USERSET, REPLICATION_SENDING, |
| 2658 | gettext_noop("Sets the maximum time to wait for WAL replication." ), |
| 2659 | NULL, |
| 2660 | GUC_UNIT_MS |
| 2661 | }, |
| 2662 | &wal_sender_timeout, |
| 2663 | 60 * 1000, 0, INT_MAX, |
| 2664 | NULL, NULL, NULL |
| 2665 | }, |
| 2666 | |
| 2667 | { |
| 2668 | {"commit_delay" , PGC_SUSET, WAL_SETTINGS, |
| 2669 | gettext_noop("Sets the delay in microseconds between transaction commit and " |
| 2670 | "flushing WAL to disk." ), |
| 2671 | NULL |
| 2672 | /* we have no microseconds designation, so can't supply units here */ |
| 2673 | }, |
| 2674 | &CommitDelay, |
| 2675 | 0, 0, 100000, |
| 2676 | NULL, NULL, NULL |
| 2677 | }, |
| 2678 | |
| 2679 | { |
| 2680 | {"commit_siblings" , PGC_USERSET, WAL_SETTINGS, |
| 2681 | gettext_noop("Sets the minimum concurrent open transactions before performing " |
| 2682 | "commit_delay." ), |
| 2683 | NULL |
| 2684 | }, |
| 2685 | &CommitSiblings, |
| 2686 | 5, 0, 1000, |
| 2687 | NULL, NULL, NULL |
| 2688 | }, |
| 2689 | |
| 2690 | { |
| 2691 | {"extra_float_digits" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 2692 | gettext_noop("Sets the number of digits displayed for floating-point values." ), |
| 2693 | gettext_noop("This affects real, double precision, and geometric data types. " |
| 2694 | "A zero or negative parameter value is added to the standard " |
| 2695 | "number of digits (FLT_DIG or DBL_DIG as appropriate). " |
| 2696 | "Any value greater than zero selects precise output mode." ) |
| 2697 | }, |
| 2698 | &extra_float_digits, |
| 2699 | 1, -15, 3, |
| 2700 | NULL, NULL, NULL |
| 2701 | }, |
| 2702 | |
| 2703 | { |
| 2704 | {"log_min_duration_statement" , PGC_SUSET, LOGGING_WHEN, |
| 2705 | gettext_noop("Sets the minimum execution time above which " |
| 2706 | "statements will be logged." ), |
| 2707 | gettext_noop("Zero prints all queries. -1 turns this feature off." ), |
| 2708 | GUC_UNIT_MS |
| 2709 | }, |
| 2710 | &log_min_duration_statement, |
| 2711 | -1, -1, INT_MAX, |
| 2712 | NULL, NULL, NULL |
| 2713 | }, |
| 2714 | |
| 2715 | { |
| 2716 | {"log_autovacuum_min_duration" , PGC_SIGHUP, LOGGING_WHAT, |
| 2717 | gettext_noop("Sets the minimum execution time above which " |
| 2718 | "autovacuum actions will be logged." ), |
| 2719 | gettext_noop("Zero prints all actions. -1 turns autovacuum logging off." ), |
| 2720 | GUC_UNIT_MS |
| 2721 | }, |
| 2722 | &Log_autovacuum_min_duration, |
| 2723 | -1, -1, INT_MAX, |
| 2724 | NULL, NULL, NULL |
| 2725 | }, |
| 2726 | |
| 2727 | { |
| 2728 | {"bgwriter_delay" , PGC_SIGHUP, RESOURCES_BGWRITER, |
| 2729 | gettext_noop("Background writer sleep time between rounds." ), |
| 2730 | NULL, |
| 2731 | GUC_UNIT_MS |
| 2732 | }, |
| 2733 | &BgWriterDelay, |
| 2734 | 200, 10, 10000, |
| 2735 | NULL, NULL, NULL |
| 2736 | }, |
| 2737 | |
| 2738 | { |
| 2739 | {"bgwriter_lru_maxpages" , PGC_SIGHUP, RESOURCES_BGWRITER, |
| 2740 | gettext_noop("Background writer maximum number of LRU pages to flush per round." ), |
| 2741 | NULL |
| 2742 | }, |
| 2743 | &bgwriter_lru_maxpages, |
| 2744 | 100, 0, INT_MAX / 2, /* Same upper limit as shared_buffers */ |
| 2745 | NULL, NULL, NULL |
| 2746 | }, |
| 2747 | |
| 2748 | { |
| 2749 | {"bgwriter_flush_after" , PGC_SIGHUP, RESOURCES_BGWRITER, |
| 2750 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
| 2751 | NULL, |
| 2752 | GUC_UNIT_BLOCKS |
| 2753 | }, |
| 2754 | &bgwriter_flush_after, |
| 2755 | DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
| 2756 | NULL, NULL, NULL |
| 2757 | }, |
| 2758 | |
| 2759 | { |
| 2760 | {"effective_io_concurrency" , |
| 2761 | PGC_USERSET, |
| 2762 | RESOURCES_ASYNCHRONOUS, |
| 2763 | gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem." ), |
| 2764 | gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array." ), |
| 2765 | GUC_EXPLAIN |
| 2766 | }, |
| 2767 | &effective_io_concurrency, |
| 2768 | #ifdef USE_PREFETCH |
| 2769 | 1, |
| 2770 | #else |
| 2771 | 0, |
| 2772 | #endif |
| 2773 | 0, MAX_IO_CONCURRENCY, |
| 2774 | check_effective_io_concurrency, assign_effective_io_concurrency, NULL |
| 2775 | }, |
| 2776 | |
| 2777 | { |
| 2778 | {"backend_flush_after" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
| 2779 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
| 2780 | NULL, |
| 2781 | GUC_UNIT_BLOCKS |
| 2782 | }, |
| 2783 | &backend_flush_after, |
| 2784 | DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
| 2785 | NULL, NULL, NULL |
| 2786 | }, |
| 2787 | |
| 2788 | { |
| 2789 | {"max_worker_processes" , |
| 2790 | PGC_POSTMASTER, |
| 2791 | RESOURCES_ASYNCHRONOUS, |
| 2792 | gettext_noop("Maximum number of concurrent worker processes." ), |
| 2793 | NULL, |
| 2794 | }, |
| 2795 | &max_worker_processes, |
| 2796 | 8, 0, MAX_BACKENDS, |
| 2797 | check_max_worker_processes, NULL, NULL |
| 2798 | }, |
| 2799 | |
| 2800 | { |
| 2801 | {"max_logical_replication_workers" , |
| 2802 | PGC_POSTMASTER, |
| 2803 | REPLICATION_SUBSCRIBERS, |
| 2804 | gettext_noop("Maximum number of logical replication worker processes." ), |
| 2805 | NULL, |
| 2806 | }, |
| 2807 | &max_logical_replication_workers, |
| 2808 | 4, 0, MAX_BACKENDS, |
| 2809 | NULL, NULL, NULL |
| 2810 | }, |
| 2811 | |
| 2812 | { |
| 2813 | {"max_sync_workers_per_subscription" , |
| 2814 | PGC_SIGHUP, |
| 2815 | REPLICATION_SUBSCRIBERS, |
| 2816 | gettext_noop("Maximum number of table synchronization workers per subscription." ), |
| 2817 | NULL, |
| 2818 | }, |
| 2819 | &max_sync_workers_per_subscription, |
| 2820 | 2, 0, MAX_BACKENDS, |
| 2821 | NULL, NULL, NULL |
| 2822 | }, |
| 2823 | |
| 2824 | { |
| 2825 | {"log_rotation_age" , PGC_SIGHUP, LOGGING_WHERE, |
| 2826 | gettext_noop("Automatic log file rotation will occur after N minutes." ), |
| 2827 | NULL, |
| 2828 | GUC_UNIT_MIN |
| 2829 | }, |
| 2830 | &Log_RotationAge, |
| 2831 | HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE, |
| 2832 | NULL, NULL, NULL |
| 2833 | }, |
| 2834 | |
| 2835 | { |
| 2836 | {"log_rotation_size" , PGC_SIGHUP, LOGGING_WHERE, |
| 2837 | gettext_noop("Automatic log file rotation will occur after N kilobytes." ), |
| 2838 | NULL, |
| 2839 | GUC_UNIT_KB |
| 2840 | }, |
| 2841 | &Log_RotationSize, |
| 2842 | 10 * 1024, 0, INT_MAX / 1024, |
| 2843 | NULL, NULL, NULL |
| 2844 | }, |
| 2845 | |
| 2846 | { |
| 2847 | {"max_function_args" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2848 | gettext_noop("Shows the maximum number of function arguments." ), |
| 2849 | NULL, |
| 2850 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2851 | }, |
| 2852 | &max_function_args, |
| 2853 | FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS, |
| 2854 | NULL, NULL, NULL |
| 2855 | }, |
| 2856 | |
| 2857 | { |
| 2858 | {"max_index_keys" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2859 | gettext_noop("Shows the maximum number of index keys." ), |
| 2860 | NULL, |
| 2861 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2862 | }, |
| 2863 | &max_index_keys, |
| 2864 | INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS, |
| 2865 | NULL, NULL, NULL |
| 2866 | }, |
| 2867 | |
| 2868 | { |
| 2869 | {"max_identifier_length" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2870 | gettext_noop("Shows the maximum identifier length." ), |
| 2871 | NULL, |
| 2872 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2873 | }, |
| 2874 | &max_identifier_length, |
| 2875 | NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1, |
| 2876 | NULL, NULL, NULL |
| 2877 | }, |
| 2878 | |
| 2879 | { |
| 2880 | {"block_size" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2881 | gettext_noop("Shows the size of a disk block." ), |
| 2882 | NULL, |
| 2883 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2884 | }, |
| 2885 | &block_size, |
| 2886 | BLCKSZ, BLCKSZ, BLCKSZ, |
| 2887 | NULL, NULL, NULL |
| 2888 | }, |
| 2889 | |
| 2890 | { |
| 2891 | {"segment_size" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2892 | gettext_noop("Shows the number of pages per disk file." ), |
| 2893 | NULL, |
| 2894 | GUC_UNIT_BLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2895 | }, |
| 2896 | &segment_size, |
| 2897 | RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE, |
| 2898 | NULL, NULL, NULL |
| 2899 | }, |
| 2900 | |
| 2901 | { |
| 2902 | {"wal_block_size" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2903 | gettext_noop("Shows the block size in the write ahead log." ), |
| 2904 | NULL, |
| 2905 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2906 | }, |
| 2907 | &wal_block_size, |
| 2908 | XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ, |
| 2909 | NULL, NULL, NULL |
| 2910 | }, |
| 2911 | |
| 2912 | { |
| 2913 | {"wal_retrieve_retry_interval" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 2914 | gettext_noop("Sets the time to wait before retrying to retrieve WAL " |
| 2915 | "after a failed attempt." ), |
| 2916 | NULL, |
| 2917 | GUC_UNIT_MS |
| 2918 | }, |
| 2919 | &wal_retrieve_retry_interval, |
| 2920 | 5000, 1, INT_MAX, |
| 2921 | NULL, NULL, NULL |
| 2922 | }, |
| 2923 | |
| 2924 | { |
| 2925 | {"wal_segment_size" , PGC_INTERNAL, PRESET_OPTIONS, |
| 2926 | gettext_noop("Shows the size of write ahead log segments." ), |
| 2927 | NULL, |
| 2928 | GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 2929 | }, |
| 2930 | &wal_segment_size, |
| 2931 | DEFAULT_XLOG_SEG_SIZE, |
| 2932 | WalSegMinSize, |
| 2933 | WalSegMaxSize, |
| 2934 | NULL, NULL, NULL |
| 2935 | }, |
| 2936 | |
| 2937 | { |
| 2938 | {"autovacuum_naptime" , PGC_SIGHUP, AUTOVACUUM, |
| 2939 | gettext_noop("Time to sleep between autovacuum runs." ), |
| 2940 | NULL, |
| 2941 | GUC_UNIT_S |
| 2942 | }, |
| 2943 | &autovacuum_naptime, |
| 2944 | 60, 1, INT_MAX / 1000, |
| 2945 | NULL, NULL, NULL |
| 2946 | }, |
| 2947 | { |
| 2948 | {"autovacuum_vacuum_threshold" , PGC_SIGHUP, AUTOVACUUM, |
| 2949 | gettext_noop("Minimum number of tuple updates or deletes prior to vacuum." ), |
| 2950 | NULL |
| 2951 | }, |
| 2952 | &autovacuum_vac_thresh, |
| 2953 | 50, 0, INT_MAX, |
| 2954 | NULL, NULL, NULL |
| 2955 | }, |
| 2956 | { |
| 2957 | {"autovacuum_analyze_threshold" , PGC_SIGHUP, AUTOVACUUM, |
| 2958 | gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze." ), |
| 2959 | NULL |
| 2960 | }, |
| 2961 | &autovacuum_anl_thresh, |
| 2962 | 50, 0, INT_MAX, |
| 2963 | NULL, NULL, NULL |
| 2964 | }, |
| 2965 | { |
| 2966 | /* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */ |
| 2967 | {"autovacuum_freeze_max_age" , PGC_POSTMASTER, AUTOVACUUM, |
| 2968 | gettext_noop("Age at which to autovacuum a table to prevent transaction ID wraparound." ), |
| 2969 | NULL |
| 2970 | }, |
| 2971 | &autovacuum_freeze_max_age, |
| 2972 | /* see pg_resetwal if you change the upper-limit value */ |
| 2973 | 200000000, 100000, 2000000000, |
| 2974 | NULL, NULL, NULL |
| 2975 | }, |
| 2976 | { |
| 2977 | /* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */ |
| 2978 | {"autovacuum_multixact_freeze_max_age" , PGC_POSTMASTER, AUTOVACUUM, |
| 2979 | gettext_noop("Multixact age at which to autovacuum a table to prevent multixact wraparound." ), |
| 2980 | NULL |
| 2981 | }, |
| 2982 | &autovacuum_multixact_freeze_max_age, |
| 2983 | 400000000, 10000, 2000000000, |
| 2984 | NULL, NULL, NULL |
| 2985 | }, |
| 2986 | { |
| 2987 | /* see max_connections */ |
| 2988 | {"autovacuum_max_workers" , PGC_POSTMASTER, AUTOVACUUM, |
| 2989 | gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes." ), |
| 2990 | NULL |
| 2991 | }, |
| 2992 | &autovacuum_max_workers, |
| 2993 | 3, 1, MAX_BACKENDS, |
| 2994 | check_autovacuum_max_workers, NULL, NULL |
| 2995 | }, |
| 2996 | |
| 2997 | { |
| 2998 | {"max_parallel_maintenance_workers" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
| 2999 | gettext_noop("Sets the maximum number of parallel processes per maintenance operation." ), |
| 3000 | NULL |
| 3001 | }, |
| 3002 | &max_parallel_maintenance_workers, |
| 3003 | 2, 0, 1024, |
| 3004 | NULL, NULL, NULL |
| 3005 | }, |
| 3006 | |
| 3007 | { |
| 3008 | {"max_parallel_workers_per_gather" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
| 3009 | gettext_noop("Sets the maximum number of parallel processes per executor node." ), |
| 3010 | NULL, |
| 3011 | GUC_EXPLAIN |
| 3012 | }, |
| 3013 | &max_parallel_workers_per_gather, |
| 3014 | 2, 0, MAX_PARALLEL_WORKER_LIMIT, |
| 3015 | NULL, NULL, NULL |
| 3016 | }, |
| 3017 | |
| 3018 | { |
| 3019 | {"max_parallel_workers" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
| 3020 | gettext_noop("Sets the maximum number of parallel workers that can be active at one time." ), |
| 3021 | NULL, |
| 3022 | GUC_EXPLAIN |
| 3023 | }, |
| 3024 | &max_parallel_workers, |
| 3025 | 8, 0, MAX_PARALLEL_WORKER_LIMIT, |
| 3026 | NULL, NULL, NULL |
| 3027 | }, |
| 3028 | |
| 3029 | { |
| 3030 | {"autovacuum_work_mem" , PGC_SIGHUP, RESOURCES_MEM, |
| 3031 | gettext_noop("Sets the maximum memory to be used by each autovacuum worker process." ), |
| 3032 | NULL, |
| 3033 | GUC_UNIT_KB |
| 3034 | }, |
| 3035 | &autovacuum_work_mem, |
| 3036 | -1, -1, MAX_KILOBYTES, |
| 3037 | check_autovacuum_work_mem, NULL, NULL |
| 3038 | }, |
| 3039 | |
| 3040 | { |
| 3041 | {"old_snapshot_threshold" , PGC_POSTMASTER, RESOURCES_ASYNCHRONOUS, |
| 3042 | gettext_noop("Time before a snapshot is too old to read pages changed after the snapshot was taken." ), |
| 3043 | gettext_noop("A value of -1 disables this feature." ), |
| 3044 | GUC_UNIT_MIN |
| 3045 | }, |
| 3046 | &old_snapshot_threshold, |
| 3047 | -1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60, |
| 3048 | NULL, NULL, NULL |
| 3049 | }, |
| 3050 | |
| 3051 | { |
| 3052 | {"tcp_keepalives_idle" , PGC_USERSET, CLIENT_CONN_OTHER, |
| 3053 | gettext_noop("Time between issuing TCP keepalives." ), |
| 3054 | gettext_noop("A value of 0 uses the system default." ), |
| 3055 | GUC_UNIT_S |
| 3056 | }, |
| 3057 | &tcp_keepalives_idle, |
| 3058 | 0, 0, INT_MAX, |
| 3059 | NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle |
| 3060 | }, |
| 3061 | |
| 3062 | { |
| 3063 | {"tcp_keepalives_interval" , PGC_USERSET, CLIENT_CONN_OTHER, |
| 3064 | gettext_noop("Time between TCP keepalive retransmits." ), |
| 3065 | gettext_noop("A value of 0 uses the system default." ), |
| 3066 | GUC_UNIT_S |
| 3067 | }, |
| 3068 | &tcp_keepalives_interval, |
| 3069 | 0, 0, INT_MAX, |
| 3070 | NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval |
| 3071 | }, |
| 3072 | |
| 3073 | { |
| 3074 | {"ssl_renegotiation_limit" , PGC_USERSET, CONN_AUTH_SSL, |
| 3075 | gettext_noop("SSL renegotiation is no longer supported; this can only be 0." ), |
| 3076 | NULL, |
| 3077 | GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE, |
| 3078 | }, |
| 3079 | &ssl_renegotiation_limit, |
| 3080 | 0, 0, 0, |
| 3081 | NULL, NULL, NULL |
| 3082 | }, |
| 3083 | |
| 3084 | { |
| 3085 | {"tcp_keepalives_count" , PGC_USERSET, CLIENT_CONN_OTHER, |
| 3086 | gettext_noop("Maximum number of TCP keepalive retransmits." ), |
| 3087 | gettext_noop("This controls the number of consecutive keepalive retransmits that can be " |
| 3088 | "lost before a connection is considered dead. A value of 0 uses the " |
| 3089 | "system default." ), |
| 3090 | }, |
| 3091 | &tcp_keepalives_count, |
| 3092 | 0, 0, INT_MAX, |
| 3093 | NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count |
| 3094 | }, |
| 3095 | |
| 3096 | { |
| 3097 | {"gin_fuzzy_search_limit" , PGC_USERSET, CLIENT_CONN_OTHER, |
| 3098 | gettext_noop("Sets the maximum allowed result for exact search by GIN." ), |
| 3099 | NULL, |
| 3100 | 0 |
| 3101 | }, |
| 3102 | &GinFuzzySearchLimit, |
| 3103 | 0, 0, INT_MAX, |
| 3104 | NULL, NULL, NULL |
| 3105 | }, |
| 3106 | |
| 3107 | { |
| 3108 | {"effective_cache_size" , PGC_USERSET, QUERY_TUNING_COST, |
| 3109 | gettext_noop("Sets the planner's assumption about the total size of the data caches." ), |
| 3110 | gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. " |
| 3111 | "This is measured in disk pages, which are normally 8 kB each." ), |
| 3112 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
| 3113 | }, |
| 3114 | &effective_cache_size, |
| 3115 | DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, |
| 3116 | NULL, NULL, NULL |
| 3117 | }, |
| 3118 | |
| 3119 | { |
| 3120 | {"min_parallel_table_scan_size" , PGC_USERSET, QUERY_TUNING_COST, |
| 3121 | gettext_noop("Sets the minimum amount of table data for a parallel scan." ), |
| 3122 | gettext_noop("If the planner estimates that it will read a number of table pages too small to reach this limit, a parallel scan will not be considered." ), |
| 3123 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
| 3124 | }, |
| 3125 | &min_parallel_table_scan_size, |
| 3126 | (8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3, |
| 3127 | NULL, NULL, NULL |
| 3128 | }, |
| 3129 | |
| 3130 | { |
| 3131 | {"min_parallel_index_scan_size" , PGC_USERSET, QUERY_TUNING_COST, |
| 3132 | gettext_noop("Sets the minimum amount of index data for a parallel scan." ), |
| 3133 | gettext_noop("If the planner estimates that it will read a number of index pages too small to reach this limit, a parallel scan will not be considered." ), |
| 3134 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
| 3135 | }, |
| 3136 | &min_parallel_index_scan_size, |
| 3137 | (512 * 1024) / BLCKSZ, 0, INT_MAX / 3, |
| 3138 | NULL, NULL, NULL |
| 3139 | }, |
| 3140 | |
| 3141 | { |
| 3142 | /* Can't be set in postgresql.conf */ |
| 3143 | {"server_version_num" , PGC_INTERNAL, PRESET_OPTIONS, |
| 3144 | gettext_noop("Shows the server version as an integer." ), |
| 3145 | NULL, |
| 3146 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3147 | }, |
| 3148 | &server_version_num, |
| 3149 | PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM, |
| 3150 | NULL, NULL, NULL |
| 3151 | }, |
| 3152 | |
| 3153 | { |
| 3154 | {"log_temp_files" , PGC_SUSET, LOGGING_WHAT, |
| 3155 | gettext_noop("Log the use of temporary files larger than this number of kilobytes." ), |
| 3156 | gettext_noop("Zero logs all files. The default is -1 (turning this feature off)." ), |
| 3157 | GUC_UNIT_KB |
| 3158 | }, |
| 3159 | &log_temp_files, |
| 3160 | -1, -1, INT_MAX, |
| 3161 | NULL, NULL, NULL |
| 3162 | }, |
| 3163 | |
| 3164 | { |
| 3165 | {"track_activity_query_size" , PGC_POSTMASTER, RESOURCES_MEM, |
| 3166 | gettext_noop("Sets the size reserved for pg_stat_activity.query, in bytes." ), |
| 3167 | NULL, |
| 3168 | GUC_UNIT_BYTE |
| 3169 | }, |
| 3170 | &pgstat_track_activity_query_size, |
| 3171 | 1024, 100, 102400, |
| 3172 | NULL, NULL, NULL |
| 3173 | }, |
| 3174 | |
| 3175 | { |
| 3176 | {"gin_pending_list_limit" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3177 | gettext_noop("Sets the maximum size of the pending list for GIN index." ), |
| 3178 | NULL, |
| 3179 | GUC_UNIT_KB |
| 3180 | }, |
| 3181 | &gin_pending_list_limit, |
| 3182 | 4096, 64, MAX_KILOBYTES, |
| 3183 | NULL, NULL, NULL |
| 3184 | }, |
| 3185 | |
| 3186 | { |
| 3187 | {"tcp_user_timeout" , PGC_USERSET, CLIENT_CONN_OTHER, |
| 3188 | gettext_noop("TCP user timeout." ), |
| 3189 | gettext_noop("A value of 0 uses the system default." ), |
| 3190 | GUC_UNIT_MS |
| 3191 | }, |
| 3192 | &tcp_user_timeout, |
| 3193 | 0, 0, INT_MAX, |
| 3194 | NULL, assign_tcp_user_timeout, show_tcp_user_timeout |
| 3195 | }, |
| 3196 | |
| 3197 | /* End-of-list marker */ |
| 3198 | { |
| 3199 | {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL |
| 3200 | } |
| 3201 | }; |
| 3202 | |
| 3203 | |
| 3204 | static struct config_real ConfigureNamesReal[] = |
| 3205 | { |
| 3206 | { |
| 3207 | {"seq_page_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3208 | gettext_noop("Sets the planner's estimate of the cost of a " |
| 3209 | "sequentially fetched disk page." ), |
| 3210 | NULL, |
| 3211 | GUC_EXPLAIN |
| 3212 | }, |
| 3213 | &seq_page_cost, |
| 3214 | DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX, |
| 3215 | NULL, NULL, NULL |
| 3216 | }, |
| 3217 | { |
| 3218 | {"random_page_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3219 | gettext_noop("Sets the planner's estimate of the cost of a " |
| 3220 | "nonsequentially fetched disk page." ), |
| 3221 | NULL, |
| 3222 | GUC_EXPLAIN |
| 3223 | }, |
| 3224 | &random_page_cost, |
| 3225 | DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, |
| 3226 | NULL, NULL, NULL |
| 3227 | }, |
| 3228 | { |
| 3229 | {"cpu_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3230 | gettext_noop("Sets the planner's estimate of the cost of " |
| 3231 | "processing each tuple (row)." ), |
| 3232 | NULL, |
| 3233 | GUC_EXPLAIN |
| 3234 | }, |
| 3235 | &cpu_tuple_cost, |
| 3236 | DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, |
| 3237 | NULL, NULL, NULL |
| 3238 | }, |
| 3239 | { |
| 3240 | {"cpu_index_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3241 | gettext_noop("Sets the planner's estimate of the cost of " |
| 3242 | "processing each index entry during an index scan." ), |
| 3243 | NULL, |
| 3244 | GUC_EXPLAIN |
| 3245 | }, |
| 3246 | &cpu_index_tuple_cost, |
| 3247 | DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, |
| 3248 | NULL, NULL, NULL |
| 3249 | }, |
| 3250 | { |
| 3251 | {"cpu_operator_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3252 | gettext_noop("Sets the planner's estimate of the cost of " |
| 3253 | "processing each operator or function call." ), |
| 3254 | NULL, |
| 3255 | GUC_EXPLAIN |
| 3256 | }, |
| 3257 | &cpu_operator_cost, |
| 3258 | DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, |
| 3259 | NULL, NULL, NULL |
| 3260 | }, |
| 3261 | { |
| 3262 | {"parallel_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3263 | gettext_noop("Sets the planner's estimate of the cost of " |
| 3264 | "passing each tuple (row) from worker to master backend." ), |
| 3265 | NULL, |
| 3266 | GUC_EXPLAIN |
| 3267 | }, |
| 3268 | ¶llel_tuple_cost, |
| 3269 | DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX, |
| 3270 | NULL, NULL, NULL |
| 3271 | }, |
| 3272 | { |
| 3273 | {"parallel_setup_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3274 | gettext_noop("Sets the planner's estimate of the cost of " |
| 3275 | "starting up worker processes for parallel query." ), |
| 3276 | NULL, |
| 3277 | GUC_EXPLAIN |
| 3278 | }, |
| 3279 | ¶llel_setup_cost, |
| 3280 | DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX, |
| 3281 | NULL, NULL, NULL |
| 3282 | }, |
| 3283 | |
| 3284 | { |
| 3285 | {"jit_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3286 | gettext_noop("Perform JIT compilation if query is more expensive." ), |
| 3287 | gettext_noop("-1 disables JIT compilation." ), |
| 3288 | GUC_EXPLAIN |
| 3289 | }, |
| 3290 | &jit_above_cost, |
| 3291 | 100000, -1, DBL_MAX, |
| 3292 | NULL, NULL, NULL |
| 3293 | }, |
| 3294 | |
| 3295 | { |
| 3296 | {"jit_optimize_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3297 | gettext_noop("Optimize JITed functions if query is more expensive." ), |
| 3298 | gettext_noop("-1 disables optimization." ), |
| 3299 | GUC_EXPLAIN |
| 3300 | }, |
| 3301 | &jit_optimize_above_cost, |
| 3302 | 500000, -1, DBL_MAX, |
| 3303 | NULL, NULL, NULL |
| 3304 | }, |
| 3305 | |
| 3306 | { |
| 3307 | {"jit_inline_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
| 3308 | gettext_noop("Perform JIT inlining if query is more expensive." ), |
| 3309 | gettext_noop("-1 disables inlining." ), |
| 3310 | GUC_EXPLAIN |
| 3311 | }, |
| 3312 | &jit_inline_above_cost, |
| 3313 | 500000, -1, DBL_MAX, |
| 3314 | NULL, NULL, NULL |
| 3315 | }, |
| 3316 | |
| 3317 | { |
| 3318 | {"cursor_tuple_fraction" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 3319 | gettext_noop("Sets the planner's estimate of the fraction of " |
| 3320 | "a cursor's rows that will be retrieved." ), |
| 3321 | NULL, |
| 3322 | GUC_EXPLAIN |
| 3323 | }, |
| 3324 | &cursor_tuple_fraction, |
| 3325 | DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0, |
| 3326 | NULL, NULL, NULL |
| 3327 | }, |
| 3328 | |
| 3329 | { |
| 3330 | {"geqo_selection_bias" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 3331 | gettext_noop("GEQO: selective pressure within the population." ), |
| 3332 | NULL, |
| 3333 | GUC_EXPLAIN |
| 3334 | }, |
| 3335 | &Geqo_selection_bias, |
| 3336 | DEFAULT_GEQO_SELECTION_BIAS, |
| 3337 | MIN_GEQO_SELECTION_BIAS, MAX_GEQO_SELECTION_BIAS, |
| 3338 | NULL, NULL, NULL |
| 3339 | }, |
| 3340 | { |
| 3341 | {"geqo_seed" , PGC_USERSET, QUERY_TUNING_GEQO, |
| 3342 | gettext_noop("GEQO: seed for random path selection." ), |
| 3343 | NULL, |
| 3344 | GUC_EXPLAIN |
| 3345 | }, |
| 3346 | &Geqo_seed, |
| 3347 | 0.0, 0.0, 1.0, |
| 3348 | NULL, NULL, NULL |
| 3349 | }, |
| 3350 | |
| 3351 | { |
| 3352 | {"bgwriter_lru_multiplier" , PGC_SIGHUP, RESOURCES_BGWRITER, |
| 3353 | gettext_noop("Multiple of the average buffer usage to free per round." ), |
| 3354 | NULL |
| 3355 | }, |
| 3356 | &bgwriter_lru_multiplier, |
| 3357 | 2.0, 0.0, 10.0, |
| 3358 | NULL, NULL, NULL |
| 3359 | }, |
| 3360 | |
| 3361 | { |
| 3362 | {"seed" , PGC_USERSET, UNGROUPED, |
| 3363 | gettext_noop("Sets the seed for random-number generation." ), |
| 3364 | NULL, |
| 3365 | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3366 | }, |
| 3367 | &phony_random_seed, |
| 3368 | 0.0, -1.0, 1.0, |
| 3369 | check_random_seed, assign_random_seed, show_random_seed |
| 3370 | }, |
| 3371 | |
| 3372 | { |
| 3373 | {"vacuum_cost_delay" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
| 3374 | gettext_noop("Vacuum cost delay in milliseconds." ), |
| 3375 | NULL, |
| 3376 | GUC_UNIT_MS |
| 3377 | }, |
| 3378 | &VacuumCostDelay, |
| 3379 | 0, 0, 100, |
| 3380 | NULL, NULL, NULL |
| 3381 | }, |
| 3382 | |
| 3383 | { |
| 3384 | {"autovacuum_vacuum_cost_delay" , PGC_SIGHUP, AUTOVACUUM, |
| 3385 | gettext_noop("Vacuum cost delay in milliseconds, for autovacuum." ), |
| 3386 | NULL, |
| 3387 | GUC_UNIT_MS |
| 3388 | }, |
| 3389 | &autovacuum_vac_cost_delay, |
| 3390 | 2, -1, 100, |
| 3391 | NULL, NULL, NULL |
| 3392 | }, |
| 3393 | |
| 3394 | { |
| 3395 | {"autovacuum_vacuum_scale_factor" , PGC_SIGHUP, AUTOVACUUM, |
| 3396 | gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples." ), |
| 3397 | NULL |
| 3398 | }, |
| 3399 | &autovacuum_vac_scale, |
| 3400 | 0.2, 0.0, 100.0, |
| 3401 | NULL, NULL, NULL |
| 3402 | }, |
| 3403 | { |
| 3404 | {"autovacuum_analyze_scale_factor" , PGC_SIGHUP, AUTOVACUUM, |
| 3405 | gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples." ), |
| 3406 | NULL |
| 3407 | }, |
| 3408 | &autovacuum_anl_scale, |
| 3409 | 0.1, 0.0, 100.0, |
| 3410 | NULL, NULL, NULL |
| 3411 | }, |
| 3412 | |
| 3413 | { |
| 3414 | {"checkpoint_completion_target" , PGC_SIGHUP, WAL_CHECKPOINTS, |
| 3415 | gettext_noop("Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval." ), |
| 3416 | NULL |
| 3417 | }, |
| 3418 | &CheckPointCompletionTarget, |
| 3419 | 0.5, 0.0, 1.0, |
| 3420 | NULL, NULL, NULL |
| 3421 | }, |
| 3422 | |
| 3423 | { |
| 3424 | {"vacuum_cleanup_index_scale_factor" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3425 | gettext_noop("Number of tuple inserts prior to index cleanup as a fraction of reltuples." ), |
| 3426 | NULL |
| 3427 | }, |
| 3428 | &vacuum_cleanup_index_scale_factor, |
| 3429 | 0.1, 0.0, 1e10, |
| 3430 | NULL, NULL, NULL |
| 3431 | }, |
| 3432 | |
| 3433 | { |
| 3434 | {"log_transaction_sample_rate" , PGC_SUSET, LOGGING_WHEN, |
| 3435 | gettext_noop("Set the fraction of transactions to log for new transactions." ), |
| 3436 | gettext_noop("Logs all statements from a fraction of transactions. " |
| 3437 | "Use a value between 0.0 (never log) and 1.0 (log all " |
| 3438 | "statements for all transactions)." ) |
| 3439 | }, |
| 3440 | &log_xact_sample_rate, |
| 3441 | 0.0, 0.0, 1.0, |
| 3442 | NULL, NULL, NULL |
| 3443 | }, |
| 3444 | |
| 3445 | /* End-of-list marker */ |
| 3446 | { |
| 3447 | {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL |
| 3448 | } |
| 3449 | }; |
| 3450 | |
| 3451 | |
| 3452 | static struct config_string ConfigureNamesString[] = |
| 3453 | { |
| 3454 | { |
| 3455 | {"archive_command" , PGC_SIGHUP, WAL_ARCHIVING, |
| 3456 | gettext_noop("Sets the shell command that will be called to archive a WAL file." ), |
| 3457 | NULL |
| 3458 | }, |
| 3459 | &XLogArchiveCommand, |
| 3460 | "" , |
| 3461 | NULL, NULL, show_archive_command |
| 3462 | }, |
| 3463 | |
| 3464 | { |
| 3465 | {"restore_command" , PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, |
| 3466 | gettext_noop("Sets the shell command that will retrieve an archived WAL file." ), |
| 3467 | NULL |
| 3468 | }, |
| 3469 | &recoveryRestoreCommand, |
| 3470 | "" , |
| 3471 | NULL, NULL, NULL |
| 3472 | }, |
| 3473 | |
| 3474 | { |
| 3475 | {"archive_cleanup_command" , PGC_SIGHUP, WAL_ARCHIVE_RECOVERY, |
| 3476 | gettext_noop("Sets the shell command that will be executed at every restart point." ), |
| 3477 | NULL |
| 3478 | }, |
| 3479 | &archiveCleanupCommand, |
| 3480 | "" , |
| 3481 | NULL, NULL, NULL |
| 3482 | }, |
| 3483 | |
| 3484 | { |
| 3485 | {"recovery_end_command" , PGC_SIGHUP, WAL_ARCHIVE_RECOVERY, |
| 3486 | gettext_noop("Sets the shell command that will be executed once at the end of recovery." ), |
| 3487 | NULL |
| 3488 | }, |
| 3489 | &recoveryEndCommand, |
| 3490 | "" , |
| 3491 | NULL, NULL, NULL |
| 3492 | }, |
| 3493 | |
| 3494 | { |
| 3495 | {"recovery_target_timeline" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3496 | gettext_noop("Specifies the timeline to recover into." ), |
| 3497 | NULL |
| 3498 | }, |
| 3499 | &recovery_target_timeline_string, |
| 3500 | "latest" , |
| 3501 | check_recovery_target_timeline, assign_recovery_target_timeline, NULL |
| 3502 | }, |
| 3503 | |
| 3504 | { |
| 3505 | {"recovery_target" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3506 | gettext_noop("Set to \"immediate\" to end recovery as soon as a consistent state is reached." ), |
| 3507 | NULL |
| 3508 | }, |
| 3509 | &recovery_target_string, |
| 3510 | "" , |
| 3511 | check_recovery_target, assign_recovery_target, NULL |
| 3512 | }, |
| 3513 | { |
| 3514 | {"recovery_target_xid" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3515 | gettext_noop("Sets the transaction ID up to which recovery will proceed." ), |
| 3516 | NULL |
| 3517 | }, |
| 3518 | &recovery_target_xid_string, |
| 3519 | "" , |
| 3520 | check_recovery_target_xid, assign_recovery_target_xid, NULL |
| 3521 | }, |
| 3522 | { |
| 3523 | {"recovery_target_time" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3524 | gettext_noop("Sets the time stamp up to which recovery will proceed." ), |
| 3525 | NULL |
| 3526 | }, |
| 3527 | &recovery_target_time_string, |
| 3528 | "" , |
| 3529 | check_recovery_target_time, assign_recovery_target_time, NULL |
| 3530 | }, |
| 3531 | { |
| 3532 | {"recovery_target_name" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3533 | gettext_noop("Sets the named restore point up to which recovery will proceed." ), |
| 3534 | NULL |
| 3535 | }, |
| 3536 | &recovery_target_name_string, |
| 3537 | "" , |
| 3538 | check_recovery_target_name, assign_recovery_target_name, NULL |
| 3539 | }, |
| 3540 | { |
| 3541 | {"recovery_target_lsn" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 3542 | gettext_noop("Sets the LSN of the write-ahead log location up to which recovery will proceed." ), |
| 3543 | NULL |
| 3544 | }, |
| 3545 | &recovery_target_lsn_string, |
| 3546 | "" , |
| 3547 | check_recovery_target_lsn, assign_recovery_target_lsn, NULL |
| 3548 | }, |
| 3549 | |
| 3550 | { |
| 3551 | {"promote_trigger_file" , PGC_SIGHUP, REPLICATION_STANDBY, |
| 3552 | gettext_noop("Specifies a file name whose presence ends recovery in the standby." ), |
| 3553 | NULL |
| 3554 | }, |
| 3555 | &PromoteTriggerFile, |
| 3556 | "" , |
| 3557 | NULL, NULL, NULL |
| 3558 | }, |
| 3559 | |
| 3560 | { |
| 3561 | {"primary_conninfo" , PGC_POSTMASTER, REPLICATION_STANDBY, |
| 3562 | gettext_noop("Sets the connection string to be used to connect to the sending server." ), |
| 3563 | NULL, |
| 3564 | GUC_SUPERUSER_ONLY |
| 3565 | }, |
| 3566 | &PrimaryConnInfo, |
| 3567 | "" , |
| 3568 | NULL, NULL, NULL |
| 3569 | }, |
| 3570 | |
| 3571 | { |
| 3572 | {"primary_slot_name" , PGC_POSTMASTER, REPLICATION_STANDBY, |
| 3573 | gettext_noop("Sets the name of the replication slot to use on the sending server." ), |
| 3574 | NULL |
| 3575 | }, |
| 3576 | &PrimarySlotName, |
| 3577 | "" , |
| 3578 | check_primary_slot_name, NULL, NULL |
| 3579 | }, |
| 3580 | |
| 3581 | { |
| 3582 | {"client_encoding" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3583 | gettext_noop("Sets the client's character set encoding." ), |
| 3584 | NULL, |
| 3585 | GUC_IS_NAME | GUC_REPORT |
| 3586 | }, |
| 3587 | &client_encoding_string, |
| 3588 | "SQL_ASCII" , |
| 3589 | check_client_encoding, assign_client_encoding, NULL |
| 3590 | }, |
| 3591 | |
| 3592 | { |
| 3593 | {"log_line_prefix" , PGC_SIGHUP, LOGGING_WHAT, |
| 3594 | gettext_noop("Controls information prefixed to each log line." ), |
| 3595 | gettext_noop("If blank, no prefix is used." ) |
| 3596 | }, |
| 3597 | &Log_line_prefix, |
| 3598 | "%m [%p] " , |
| 3599 | NULL, NULL, NULL |
| 3600 | }, |
| 3601 | |
| 3602 | { |
| 3603 | {"log_timezone" , PGC_SIGHUP, LOGGING_WHAT, |
| 3604 | gettext_noop("Sets the time zone to use in log messages." ), |
| 3605 | NULL |
| 3606 | }, |
| 3607 | &log_timezone_string, |
| 3608 | "GMT" , |
| 3609 | check_log_timezone, assign_log_timezone, show_log_timezone |
| 3610 | }, |
| 3611 | |
| 3612 | { |
| 3613 | {"DateStyle" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3614 | gettext_noop("Sets the display format for date and time values." ), |
| 3615 | gettext_noop("Also controls interpretation of ambiguous " |
| 3616 | "date inputs." ), |
| 3617 | GUC_LIST_INPUT | GUC_REPORT |
| 3618 | }, |
| 3619 | &datestyle_string, |
| 3620 | "ISO, MDY" , |
| 3621 | check_datestyle, assign_datestyle, NULL |
| 3622 | }, |
| 3623 | |
| 3624 | { |
| 3625 | {"default_table_access_method" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3626 | gettext_noop("Sets the default table access method for new tables." ), |
| 3627 | NULL, |
| 3628 | GUC_IS_NAME |
| 3629 | }, |
| 3630 | &default_table_access_method, |
| 3631 | DEFAULT_TABLE_ACCESS_METHOD, |
| 3632 | check_default_table_access_method, NULL, NULL |
| 3633 | }, |
| 3634 | |
| 3635 | { |
| 3636 | {"default_tablespace" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3637 | gettext_noop("Sets the default tablespace to create tables and indexes in." ), |
| 3638 | gettext_noop("An empty string selects the database's default tablespace." ), |
| 3639 | GUC_IS_NAME |
| 3640 | }, |
| 3641 | &default_tablespace, |
| 3642 | "" , |
| 3643 | check_default_tablespace, NULL, NULL |
| 3644 | }, |
| 3645 | |
| 3646 | { |
| 3647 | {"temp_tablespaces" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3648 | gettext_noop("Sets the tablespace(s) to use for temporary tables and sort files." ), |
| 3649 | NULL, |
| 3650 | GUC_LIST_INPUT | GUC_LIST_QUOTE |
| 3651 | }, |
| 3652 | &temp_tablespaces, |
| 3653 | "" , |
| 3654 | check_temp_tablespaces, assign_temp_tablespaces, NULL |
| 3655 | }, |
| 3656 | |
| 3657 | { |
| 3658 | {"dynamic_library_path" , PGC_SUSET, CLIENT_CONN_OTHER, |
| 3659 | gettext_noop("Sets the path for dynamically loadable modules." ), |
| 3660 | gettext_noop("If a dynamically loadable module needs to be opened and " |
| 3661 | "the specified name does not have a directory component (i.e., the " |
| 3662 | "name does not contain a slash), the system will search this path for " |
| 3663 | "the specified file." ), |
| 3664 | GUC_SUPERUSER_ONLY |
| 3665 | }, |
| 3666 | &Dynamic_library_path, |
| 3667 | "$libdir" , |
| 3668 | NULL, NULL, NULL |
| 3669 | }, |
| 3670 | |
| 3671 | { |
| 3672 | {"krb_server_keyfile" , PGC_SIGHUP, CONN_AUTH_AUTH, |
| 3673 | gettext_noop("Sets the location of the Kerberos server key file." ), |
| 3674 | NULL, |
| 3675 | GUC_SUPERUSER_ONLY |
| 3676 | }, |
| 3677 | &pg_krb_server_keyfile, |
| 3678 | PG_KRB_SRVTAB, |
| 3679 | NULL, NULL, NULL |
| 3680 | }, |
| 3681 | |
| 3682 | { |
| 3683 | {"bonjour_name" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 3684 | gettext_noop("Sets the Bonjour service name." ), |
| 3685 | NULL |
| 3686 | }, |
| 3687 | &bonjour_name, |
| 3688 | "" , |
| 3689 | NULL, NULL, NULL |
| 3690 | }, |
| 3691 | |
| 3692 | /* See main.c about why defaults for LC_foo are not all alike */ |
| 3693 | |
| 3694 | { |
| 3695 | {"lc_collate" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
| 3696 | gettext_noop("Shows the collation order locale." ), |
| 3697 | NULL, |
| 3698 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3699 | }, |
| 3700 | &locale_collate, |
| 3701 | "C" , |
| 3702 | NULL, NULL, NULL |
| 3703 | }, |
| 3704 | |
| 3705 | { |
| 3706 | {"lc_ctype" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
| 3707 | gettext_noop("Shows the character classification and case conversion locale." ), |
| 3708 | NULL, |
| 3709 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3710 | }, |
| 3711 | &locale_ctype, |
| 3712 | "C" , |
| 3713 | NULL, NULL, NULL |
| 3714 | }, |
| 3715 | |
| 3716 | { |
| 3717 | {"lc_messages" , PGC_SUSET, CLIENT_CONN_LOCALE, |
| 3718 | gettext_noop("Sets the language in which messages are displayed." ), |
| 3719 | NULL |
| 3720 | }, |
| 3721 | &locale_messages, |
| 3722 | "" , |
| 3723 | check_locale_messages, assign_locale_messages, NULL |
| 3724 | }, |
| 3725 | |
| 3726 | { |
| 3727 | {"lc_monetary" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3728 | gettext_noop("Sets the locale for formatting monetary amounts." ), |
| 3729 | NULL |
| 3730 | }, |
| 3731 | &locale_monetary, |
| 3732 | "C" , |
| 3733 | check_locale_monetary, assign_locale_monetary, NULL |
| 3734 | }, |
| 3735 | |
| 3736 | { |
| 3737 | {"lc_numeric" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3738 | gettext_noop("Sets the locale for formatting numbers." ), |
| 3739 | NULL |
| 3740 | }, |
| 3741 | &locale_numeric, |
| 3742 | "C" , |
| 3743 | check_locale_numeric, assign_locale_numeric, NULL |
| 3744 | }, |
| 3745 | |
| 3746 | { |
| 3747 | {"lc_time" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3748 | gettext_noop("Sets the locale for formatting date and time values." ), |
| 3749 | NULL |
| 3750 | }, |
| 3751 | &locale_time, |
| 3752 | "C" , |
| 3753 | check_locale_time, assign_locale_time, NULL |
| 3754 | }, |
| 3755 | |
| 3756 | { |
| 3757 | {"session_preload_libraries" , PGC_SUSET, CLIENT_CONN_PRELOAD, |
| 3758 | gettext_noop("Lists shared libraries to preload into each backend." ), |
| 3759 | NULL, |
| 3760 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY |
| 3761 | }, |
| 3762 | &session_preload_libraries_string, |
| 3763 | "" , |
| 3764 | NULL, NULL, NULL |
| 3765 | }, |
| 3766 | |
| 3767 | { |
| 3768 | {"shared_preload_libraries" , PGC_POSTMASTER, CLIENT_CONN_PRELOAD, |
| 3769 | gettext_noop("Lists shared libraries to preload into server." ), |
| 3770 | NULL, |
| 3771 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY |
| 3772 | }, |
| 3773 | &shared_preload_libraries_string, |
| 3774 | "" , |
| 3775 | NULL, NULL, NULL |
| 3776 | }, |
| 3777 | |
| 3778 | { |
| 3779 | {"local_preload_libraries" , PGC_USERSET, CLIENT_CONN_PRELOAD, |
| 3780 | gettext_noop("Lists unprivileged shared libraries to preload into each backend." ), |
| 3781 | NULL, |
| 3782 | GUC_LIST_INPUT | GUC_LIST_QUOTE |
| 3783 | }, |
| 3784 | &local_preload_libraries_string, |
| 3785 | "" , |
| 3786 | NULL, NULL, NULL |
| 3787 | }, |
| 3788 | |
| 3789 | { |
| 3790 | {"search_path" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 3791 | gettext_noop("Sets the schema search order for names that are not schema-qualified." ), |
| 3792 | NULL, |
| 3793 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN |
| 3794 | }, |
| 3795 | &namespace_search_path, |
| 3796 | "\"$user\", public" , |
| 3797 | check_search_path, assign_search_path, NULL |
| 3798 | }, |
| 3799 | |
| 3800 | { |
| 3801 | /* Can't be set in postgresql.conf */ |
| 3802 | {"server_encoding" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
| 3803 | gettext_noop("Sets the server (database) character set encoding." ), |
| 3804 | NULL, |
| 3805 | GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3806 | }, |
| 3807 | &server_encoding_string, |
| 3808 | "SQL_ASCII" , |
| 3809 | NULL, NULL, NULL |
| 3810 | }, |
| 3811 | |
| 3812 | { |
| 3813 | /* Can't be set in postgresql.conf */ |
| 3814 | {"server_version" , PGC_INTERNAL, PRESET_OPTIONS, |
| 3815 | gettext_noop("Shows the server version." ), |
| 3816 | NULL, |
| 3817 | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 3818 | }, |
| 3819 | &server_version_string, |
| 3820 | PG_VERSION, |
| 3821 | NULL, NULL, NULL |
| 3822 | }, |
| 3823 | |
| 3824 | { |
| 3825 | /* Not for general use --- used by SET ROLE */ |
| 3826 | {"role" , PGC_USERSET, UNGROUPED, |
| 3827 | gettext_noop("Sets the current role." ), |
| 3828 | NULL, |
| 3829 | GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST |
| 3830 | }, |
| 3831 | &role_string, |
| 3832 | "none" , |
| 3833 | check_role, assign_role, show_role |
| 3834 | }, |
| 3835 | |
| 3836 | { |
| 3837 | /* Not for general use --- used by SET SESSION AUTHORIZATION */ |
| 3838 | {"session_authorization" , PGC_USERSET, UNGROUPED, |
| 3839 | gettext_noop("Sets the session user name." ), |
| 3840 | NULL, |
| 3841 | 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 |
| 3842 | }, |
| 3843 | &session_authorization_string, |
| 3844 | NULL, |
| 3845 | check_session_authorization, assign_session_authorization, NULL |
| 3846 | }, |
| 3847 | |
| 3848 | { |
| 3849 | {"log_destination" , PGC_SIGHUP, LOGGING_WHERE, |
| 3850 | gettext_noop("Sets the destination for server log output." ), |
| 3851 | gettext_noop("Valid values are combinations of \"stderr\", " |
| 3852 | "\"syslog\", \"csvlog\", and \"eventlog\", " |
| 3853 | "depending on the platform." ), |
| 3854 | GUC_LIST_INPUT |
| 3855 | }, |
| 3856 | &Log_destination_string, |
| 3857 | "stderr" , |
| 3858 | check_log_destination, assign_log_destination, NULL |
| 3859 | }, |
| 3860 | { |
| 3861 | {"log_directory" , PGC_SIGHUP, LOGGING_WHERE, |
| 3862 | gettext_noop("Sets the destination directory for log files." ), |
| 3863 | gettext_noop("Can be specified as relative to the data directory " |
| 3864 | "or as absolute path." ), |
| 3865 | GUC_SUPERUSER_ONLY |
| 3866 | }, |
| 3867 | &Log_directory, |
| 3868 | "log" , |
| 3869 | check_canonical_path, NULL, NULL |
| 3870 | }, |
| 3871 | { |
| 3872 | {"log_filename" , PGC_SIGHUP, LOGGING_WHERE, |
| 3873 | gettext_noop("Sets the file name pattern for log files." ), |
| 3874 | NULL, |
| 3875 | GUC_SUPERUSER_ONLY |
| 3876 | }, |
| 3877 | &Log_filename, |
| 3878 | "postgresql-%Y-%m-%d_%H%M%S.log" , |
| 3879 | NULL, NULL, NULL |
| 3880 | }, |
| 3881 | |
| 3882 | { |
| 3883 | {"syslog_ident" , PGC_SIGHUP, LOGGING_WHERE, |
| 3884 | gettext_noop("Sets the program name used to identify PostgreSQL " |
| 3885 | "messages in syslog." ), |
| 3886 | NULL |
| 3887 | }, |
| 3888 | &syslog_ident_str, |
| 3889 | "postgres" , |
| 3890 | NULL, assign_syslog_ident, NULL |
| 3891 | }, |
| 3892 | |
| 3893 | { |
| 3894 | {"event_source" , PGC_POSTMASTER, LOGGING_WHERE, |
| 3895 | gettext_noop("Sets the application name used to identify " |
| 3896 | "PostgreSQL messages in the event log." ), |
| 3897 | NULL |
| 3898 | }, |
| 3899 | &event_source, |
| 3900 | DEFAULT_EVENT_SOURCE, |
| 3901 | NULL, NULL, NULL |
| 3902 | }, |
| 3903 | |
| 3904 | { |
| 3905 | {"TimeZone" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3906 | gettext_noop("Sets the time zone for displaying and interpreting time stamps." ), |
| 3907 | NULL, |
| 3908 | GUC_REPORT |
| 3909 | }, |
| 3910 | &timezone_string, |
| 3911 | "GMT" , |
| 3912 | check_timezone, assign_timezone, show_timezone |
| 3913 | }, |
| 3914 | { |
| 3915 | {"timezone_abbreviations" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 3916 | gettext_noop("Selects a file of time zone abbreviations." ), |
| 3917 | NULL |
| 3918 | }, |
| 3919 | &timezone_abbreviations_string, |
| 3920 | NULL, |
| 3921 | check_timezone_abbreviations, assign_timezone_abbreviations, NULL |
| 3922 | }, |
| 3923 | |
| 3924 | { |
| 3925 | {"unix_socket_group" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 3926 | gettext_noop("Sets the owning group of the Unix-domain socket." ), |
| 3927 | gettext_noop("The owning user of the socket is always the user " |
| 3928 | "that starts the server." ) |
| 3929 | }, |
| 3930 | &Unix_socket_group, |
| 3931 | "" , |
| 3932 | NULL, NULL, NULL |
| 3933 | }, |
| 3934 | |
| 3935 | { |
| 3936 | {"unix_socket_directories" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 3937 | gettext_noop("Sets the directories where Unix-domain sockets will be created." ), |
| 3938 | NULL, |
| 3939 | GUC_SUPERUSER_ONLY |
| 3940 | }, |
| 3941 | &Unix_socket_directories, |
| 3942 | #ifdef HAVE_UNIX_SOCKETS |
| 3943 | DEFAULT_PGSOCKET_DIR, |
| 3944 | #else |
| 3945 | "" , |
| 3946 | #endif |
| 3947 | NULL, NULL, NULL |
| 3948 | }, |
| 3949 | |
| 3950 | { |
| 3951 | {"listen_addresses" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
| 3952 | gettext_noop("Sets the host name or IP address(es) to listen to." ), |
| 3953 | NULL, |
| 3954 | GUC_LIST_INPUT |
| 3955 | }, |
| 3956 | &ListenAddresses, |
| 3957 | "localhost" , |
| 3958 | NULL, NULL, NULL |
| 3959 | }, |
| 3960 | |
| 3961 | { |
| 3962 | /* |
| 3963 | * Can't be set by ALTER SYSTEM as it can lead to recursive definition |
| 3964 | * of data_directory. |
| 3965 | */ |
| 3966 | {"data_directory" , PGC_POSTMASTER, FILE_LOCATIONS, |
| 3967 | gettext_noop("Sets the server's data directory." ), |
| 3968 | NULL, |
| 3969 | GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE |
| 3970 | }, |
| 3971 | &data_directory, |
| 3972 | NULL, |
| 3973 | NULL, NULL, NULL |
| 3974 | }, |
| 3975 | |
| 3976 | { |
| 3977 | {"config_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
| 3978 | gettext_noop("Sets the server's main configuration file." ), |
| 3979 | NULL, |
| 3980 | GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY |
| 3981 | }, |
| 3982 | &ConfigFileName, |
| 3983 | NULL, |
| 3984 | NULL, NULL, NULL |
| 3985 | }, |
| 3986 | |
| 3987 | { |
| 3988 | {"hba_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
| 3989 | gettext_noop("Sets the server's \"hba\" configuration file." ), |
| 3990 | NULL, |
| 3991 | GUC_SUPERUSER_ONLY |
| 3992 | }, |
| 3993 | &HbaFileName, |
| 3994 | NULL, |
| 3995 | NULL, NULL, NULL |
| 3996 | }, |
| 3997 | |
| 3998 | { |
| 3999 | {"ident_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
| 4000 | gettext_noop("Sets the server's \"ident\" configuration file." ), |
| 4001 | NULL, |
| 4002 | GUC_SUPERUSER_ONLY |
| 4003 | }, |
| 4004 | &IdentFileName, |
| 4005 | NULL, |
| 4006 | NULL, NULL, NULL |
| 4007 | }, |
| 4008 | |
| 4009 | { |
| 4010 | {"external_pid_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
| 4011 | gettext_noop("Writes the postmaster PID to the specified file." ), |
| 4012 | NULL, |
| 4013 | GUC_SUPERUSER_ONLY |
| 4014 | }, |
| 4015 | &external_pid_file, |
| 4016 | NULL, |
| 4017 | check_canonical_path, NULL, NULL |
| 4018 | }, |
| 4019 | |
| 4020 | { |
| 4021 | {"ssl_library" , PGC_INTERNAL, PRESET_OPTIONS, |
| 4022 | gettext_noop("Name of the SSL library." ), |
| 4023 | NULL, |
| 4024 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 4025 | }, |
| 4026 | &ssl_library, |
| 4027 | #ifdef USE_SSL |
| 4028 | "OpenSSL" , |
| 4029 | #else |
| 4030 | "" , |
| 4031 | #endif |
| 4032 | NULL, NULL, NULL |
| 4033 | }, |
| 4034 | |
| 4035 | { |
| 4036 | {"ssl_cert_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4037 | gettext_noop("Location of the SSL server certificate file." ), |
| 4038 | NULL |
| 4039 | }, |
| 4040 | &ssl_cert_file, |
| 4041 | "server.crt" , |
| 4042 | NULL, NULL, NULL |
| 4043 | }, |
| 4044 | |
| 4045 | { |
| 4046 | {"ssl_key_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4047 | gettext_noop("Location of the SSL server private key file." ), |
| 4048 | NULL |
| 4049 | }, |
| 4050 | &ssl_key_file, |
| 4051 | "server.key" , |
| 4052 | NULL, NULL, NULL |
| 4053 | }, |
| 4054 | |
| 4055 | { |
| 4056 | {"ssl_ca_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4057 | gettext_noop("Location of the SSL certificate authority file." ), |
| 4058 | NULL |
| 4059 | }, |
| 4060 | &ssl_ca_file, |
| 4061 | "" , |
| 4062 | NULL, NULL, NULL |
| 4063 | }, |
| 4064 | |
| 4065 | { |
| 4066 | {"ssl_crl_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4067 | gettext_noop("Location of the SSL certificate revocation list file." ), |
| 4068 | NULL |
| 4069 | }, |
| 4070 | &ssl_crl_file, |
| 4071 | "" , |
| 4072 | NULL, NULL, NULL |
| 4073 | }, |
| 4074 | |
| 4075 | { |
| 4076 | {"stats_temp_directory" , PGC_SIGHUP, STATS_COLLECTOR, |
| 4077 | gettext_noop("Writes temporary statistics files to the specified directory." ), |
| 4078 | NULL, |
| 4079 | GUC_SUPERUSER_ONLY |
| 4080 | }, |
| 4081 | &pgstat_temp_directory, |
| 4082 | PG_STAT_TMP_DIR, |
| 4083 | check_canonical_path, assign_pgstat_temp_directory, NULL |
| 4084 | }, |
| 4085 | |
| 4086 | { |
| 4087 | {"synchronous_standby_names" , PGC_SIGHUP, REPLICATION_MASTER, |
| 4088 | gettext_noop("Number of synchronous standbys and list of names of potential synchronous ones." ), |
| 4089 | NULL, |
| 4090 | GUC_LIST_INPUT |
| 4091 | }, |
| 4092 | &SyncRepStandbyNames, |
| 4093 | "" , |
| 4094 | check_synchronous_standby_names, assign_synchronous_standby_names, NULL |
| 4095 | }, |
| 4096 | |
| 4097 | { |
| 4098 | {"default_text_search_config" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 4099 | gettext_noop("Sets default text search configuration." ), |
| 4100 | NULL |
| 4101 | }, |
| 4102 | &TSCurrentConfig, |
| 4103 | "pg_catalog.simple" , |
| 4104 | check_TSCurrentConfig, assign_TSCurrentConfig, NULL |
| 4105 | }, |
| 4106 | |
| 4107 | { |
| 4108 | {"ssl_ciphers" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4109 | gettext_noop("Sets the list of allowed SSL ciphers." ), |
| 4110 | NULL, |
| 4111 | GUC_SUPERUSER_ONLY |
| 4112 | }, |
| 4113 | &SSLCipherSuites, |
| 4114 | #ifdef USE_SSL |
| 4115 | "HIGH:MEDIUM:+3DES:!aNULL" , |
| 4116 | #else |
| 4117 | "none" , |
| 4118 | #endif |
| 4119 | NULL, NULL, NULL |
| 4120 | }, |
| 4121 | |
| 4122 | { |
| 4123 | {"ssl_ecdh_curve" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4124 | gettext_noop("Sets the curve to use for ECDH." ), |
| 4125 | NULL, |
| 4126 | GUC_SUPERUSER_ONLY |
| 4127 | }, |
| 4128 | &SSLECDHCurve, |
| 4129 | #ifdef USE_SSL |
| 4130 | "prime256v1" , |
| 4131 | #else |
| 4132 | "none" , |
| 4133 | #endif |
| 4134 | NULL, NULL, NULL |
| 4135 | }, |
| 4136 | |
| 4137 | { |
| 4138 | {"ssl_dh_params_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4139 | gettext_noop("Location of the SSL DH parameters file." ), |
| 4140 | NULL, |
| 4141 | GUC_SUPERUSER_ONLY |
| 4142 | }, |
| 4143 | &ssl_dh_params_file, |
| 4144 | "" , |
| 4145 | NULL, NULL, NULL |
| 4146 | }, |
| 4147 | |
| 4148 | { |
| 4149 | {"ssl_passphrase_command" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4150 | gettext_noop("Command to obtain passphrases for SSL." ), |
| 4151 | NULL |
| 4152 | }, |
| 4153 | &ssl_passphrase_command, |
| 4154 | "" , |
| 4155 | NULL, NULL, NULL |
| 4156 | }, |
| 4157 | |
| 4158 | { |
| 4159 | {"application_name" , PGC_USERSET, LOGGING_WHAT, |
| 4160 | gettext_noop("Sets the application name to be reported in statistics and logs." ), |
| 4161 | NULL, |
| 4162 | GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE |
| 4163 | }, |
| 4164 | &application_name, |
| 4165 | "" , |
| 4166 | check_application_name, assign_application_name, NULL |
| 4167 | }, |
| 4168 | |
| 4169 | { |
| 4170 | {"cluster_name" , PGC_POSTMASTER, PROCESS_TITLE, |
| 4171 | gettext_noop("Sets the name of the cluster, which is included in the process title." ), |
| 4172 | NULL, |
| 4173 | GUC_IS_NAME |
| 4174 | }, |
| 4175 | &cluster_name, |
| 4176 | "" , |
| 4177 | check_cluster_name, NULL, NULL |
| 4178 | }, |
| 4179 | |
| 4180 | { |
| 4181 | {"wal_consistency_checking" , PGC_SUSET, DEVELOPER_OPTIONS, |
| 4182 | gettext_noop("Sets the WAL resource managers for which WAL consistency checks are done." ), |
| 4183 | gettext_noop("Full-page images will be logged for all data blocks and cross-checked against the results of WAL replay." ), |
| 4184 | GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE |
| 4185 | }, |
| 4186 | &wal_consistency_checking_string, |
| 4187 | "" , |
| 4188 | check_wal_consistency_checking, assign_wal_consistency_checking, NULL |
| 4189 | }, |
| 4190 | |
| 4191 | { |
| 4192 | {"jit_provider" , PGC_POSTMASTER, CLIENT_CONN_PRELOAD, |
| 4193 | gettext_noop("JIT provider to use." ), |
| 4194 | NULL, |
| 4195 | GUC_SUPERUSER_ONLY |
| 4196 | }, |
| 4197 | &jit_provider, |
| 4198 | "llvmjit" , |
| 4199 | NULL, NULL, NULL |
| 4200 | }, |
| 4201 | |
| 4202 | /* End-of-list marker */ |
| 4203 | { |
| 4204 | {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL |
| 4205 | } |
| 4206 | }; |
| 4207 | |
| 4208 | |
| 4209 | static struct config_enum ConfigureNamesEnum[] = |
| 4210 | { |
| 4211 | { |
| 4212 | {"backslash_quote" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
| 4213 | gettext_noop("Sets whether \"\\'\" is allowed in string literals." ), |
| 4214 | NULL |
| 4215 | }, |
| 4216 | &backslash_quote, |
| 4217 | BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options, |
| 4218 | NULL, NULL, NULL |
| 4219 | }, |
| 4220 | |
| 4221 | { |
| 4222 | {"bytea_output" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4223 | gettext_noop("Sets the output format for bytea." ), |
| 4224 | NULL |
| 4225 | }, |
| 4226 | &bytea_output, |
| 4227 | BYTEA_OUTPUT_HEX, bytea_output_options, |
| 4228 | NULL, NULL, NULL |
| 4229 | }, |
| 4230 | |
| 4231 | { |
| 4232 | {"client_min_messages" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4233 | gettext_noop("Sets the message levels that are sent to the client." ), |
| 4234 | gettext_noop("Each level includes all the levels that follow it. The later" |
| 4235 | " the level, the fewer messages are sent." ) |
| 4236 | }, |
| 4237 | &client_min_messages, |
| 4238 | NOTICE, client_message_level_options, |
| 4239 | NULL, NULL, NULL |
| 4240 | }, |
| 4241 | |
| 4242 | { |
| 4243 | {"constraint_exclusion" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 4244 | gettext_noop("Enables the planner to use constraints to optimize queries." ), |
| 4245 | gettext_noop("Table scans will be skipped if their constraints" |
| 4246 | " guarantee that no rows match the query." ), |
| 4247 | GUC_EXPLAIN |
| 4248 | }, |
| 4249 | &constraint_exclusion, |
| 4250 | CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options, |
| 4251 | NULL, NULL, NULL |
| 4252 | }, |
| 4253 | |
| 4254 | { |
| 4255 | {"default_transaction_isolation" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4256 | gettext_noop("Sets the transaction isolation level of each new transaction." ), |
| 4257 | NULL |
| 4258 | }, |
| 4259 | &DefaultXactIsoLevel, |
| 4260 | XACT_READ_COMMITTED, isolation_level_options, |
| 4261 | NULL, NULL, NULL |
| 4262 | }, |
| 4263 | |
| 4264 | { |
| 4265 | {"transaction_isolation" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4266 | gettext_noop("Sets the current transaction's isolation level." ), |
| 4267 | NULL, |
| 4268 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
| 4269 | }, |
| 4270 | &XactIsoLevel, |
| 4271 | XACT_READ_COMMITTED, isolation_level_options, |
| 4272 | check_XactIsoLevel, NULL, NULL |
| 4273 | }, |
| 4274 | |
| 4275 | { |
| 4276 | {"IntervalStyle" , PGC_USERSET, CLIENT_CONN_LOCALE, |
| 4277 | gettext_noop("Sets the display format for interval values." ), |
| 4278 | NULL, |
| 4279 | GUC_REPORT |
| 4280 | }, |
| 4281 | &IntervalStyle, |
| 4282 | INTSTYLE_POSTGRES, intervalstyle_options, |
| 4283 | NULL, NULL, NULL |
| 4284 | }, |
| 4285 | |
| 4286 | { |
| 4287 | {"log_error_verbosity" , PGC_SUSET, LOGGING_WHAT, |
| 4288 | gettext_noop("Sets the verbosity of logged messages." ), |
| 4289 | NULL |
| 4290 | }, |
| 4291 | &Log_error_verbosity, |
| 4292 | PGERROR_DEFAULT, log_error_verbosity_options, |
| 4293 | NULL, NULL, NULL |
| 4294 | }, |
| 4295 | |
| 4296 | { |
| 4297 | {"log_min_messages" , PGC_SUSET, LOGGING_WHEN, |
| 4298 | gettext_noop("Sets the message levels that are logged." ), |
| 4299 | gettext_noop("Each level includes all the levels that follow it. The later" |
| 4300 | " the level, the fewer messages are sent." ) |
| 4301 | }, |
| 4302 | &log_min_messages, |
| 4303 | WARNING, server_message_level_options, |
| 4304 | NULL, NULL, NULL |
| 4305 | }, |
| 4306 | |
| 4307 | { |
| 4308 | {"log_min_error_statement" , PGC_SUSET, LOGGING_WHEN, |
| 4309 | gettext_noop("Causes all statements generating error at or above this level to be logged." ), |
| 4310 | gettext_noop("Each level includes all the levels that follow it. The later" |
| 4311 | " the level, the fewer messages are sent." ) |
| 4312 | }, |
| 4313 | &log_min_error_statement, |
| 4314 | ERROR, server_message_level_options, |
| 4315 | NULL, NULL, NULL |
| 4316 | }, |
| 4317 | |
| 4318 | { |
| 4319 | {"log_statement" , PGC_SUSET, LOGGING_WHAT, |
| 4320 | gettext_noop("Sets the type of statements logged." ), |
| 4321 | NULL |
| 4322 | }, |
| 4323 | &log_statement, |
| 4324 | LOGSTMT_NONE, log_statement_options, |
| 4325 | NULL, NULL, NULL |
| 4326 | }, |
| 4327 | |
| 4328 | { |
| 4329 | {"syslog_facility" , PGC_SIGHUP, LOGGING_WHERE, |
| 4330 | gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled." ), |
| 4331 | NULL |
| 4332 | }, |
| 4333 | &syslog_facility, |
| 4334 | #ifdef HAVE_SYSLOG |
| 4335 | LOG_LOCAL0, |
| 4336 | #else |
| 4337 | 0, |
| 4338 | #endif |
| 4339 | syslog_facility_options, |
| 4340 | NULL, assign_syslog_facility, NULL |
| 4341 | }, |
| 4342 | |
| 4343 | { |
| 4344 | {"session_replication_role" , PGC_SUSET, CLIENT_CONN_STATEMENT, |
| 4345 | gettext_noop("Sets the session's behavior for triggers and rewrite rules." ), |
| 4346 | NULL |
| 4347 | }, |
| 4348 | &SessionReplicationRole, |
| 4349 | SESSION_REPLICATION_ROLE_ORIGIN, session_replication_role_options, |
| 4350 | NULL, assign_session_replication_role, NULL |
| 4351 | }, |
| 4352 | |
| 4353 | { |
| 4354 | {"synchronous_commit" , PGC_USERSET, WAL_SETTINGS, |
| 4355 | gettext_noop("Sets the current transaction's synchronization level." ), |
| 4356 | NULL |
| 4357 | }, |
| 4358 | &synchronous_commit, |
| 4359 | SYNCHRONOUS_COMMIT_ON, synchronous_commit_options, |
| 4360 | NULL, assign_synchronous_commit, NULL |
| 4361 | }, |
| 4362 | |
| 4363 | { |
| 4364 | {"archive_mode" , PGC_POSTMASTER, WAL_ARCHIVING, |
| 4365 | gettext_noop("Allows archiving of WAL files using archive_command." ), |
| 4366 | NULL |
| 4367 | }, |
| 4368 | &XLogArchiveMode, |
| 4369 | ARCHIVE_MODE_OFF, archive_mode_options, |
| 4370 | NULL, NULL, NULL |
| 4371 | }, |
| 4372 | |
| 4373 | { |
| 4374 | {"recovery_target_action" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
| 4375 | gettext_noop("Sets the action to perform upon reaching the recovery target." ), |
| 4376 | NULL |
| 4377 | }, |
| 4378 | &recoveryTargetAction, |
| 4379 | RECOVERY_TARGET_ACTION_PAUSE, recovery_target_action_options, |
| 4380 | NULL, NULL, NULL |
| 4381 | }, |
| 4382 | |
| 4383 | { |
| 4384 | {"trace_recovery_messages" , PGC_SIGHUP, DEVELOPER_OPTIONS, |
| 4385 | gettext_noop("Enables logging of recovery-related debugging information." ), |
| 4386 | gettext_noop("Each level includes all the levels that follow it. The later" |
| 4387 | " the level, the fewer messages are sent." ) |
| 4388 | }, |
| 4389 | &trace_recovery_messages, |
| 4390 | |
| 4391 | /* |
| 4392 | * client_message_level_options allows too many values, really, but |
| 4393 | * it's not worth having a separate options array for this. |
| 4394 | */ |
| 4395 | LOG, client_message_level_options, |
| 4396 | NULL, NULL, NULL |
| 4397 | }, |
| 4398 | |
| 4399 | { |
| 4400 | {"track_functions" , PGC_SUSET, STATS_COLLECTOR, |
| 4401 | gettext_noop("Collects function-level statistics on database activity." ), |
| 4402 | NULL |
| 4403 | }, |
| 4404 | &pgstat_track_functions, |
| 4405 | TRACK_FUNC_OFF, track_function_options, |
| 4406 | NULL, NULL, NULL |
| 4407 | }, |
| 4408 | |
| 4409 | { |
| 4410 | {"wal_level" , PGC_POSTMASTER, WAL_SETTINGS, |
| 4411 | gettext_noop("Set the level of information written to the WAL." ), |
| 4412 | NULL |
| 4413 | }, |
| 4414 | &wal_level, |
| 4415 | WAL_LEVEL_REPLICA, wal_level_options, |
| 4416 | NULL, NULL, NULL |
| 4417 | }, |
| 4418 | |
| 4419 | { |
| 4420 | {"dynamic_shared_memory_type" , PGC_POSTMASTER, RESOURCES_MEM, |
| 4421 | gettext_noop("Selects the dynamic shared memory implementation used." ), |
| 4422 | NULL |
| 4423 | }, |
| 4424 | &dynamic_shared_memory_type, |
| 4425 | DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE, dynamic_shared_memory_options, |
| 4426 | NULL, NULL, NULL |
| 4427 | }, |
| 4428 | |
| 4429 | { |
| 4430 | {"shared_memory_type" , PGC_POSTMASTER, RESOURCES_MEM, |
| 4431 | gettext_noop("Selects the shared memory implementation used for the main shared memory region." ), |
| 4432 | NULL |
| 4433 | }, |
| 4434 | &shared_memory_type, |
| 4435 | DEFAULT_SHARED_MEMORY_TYPE, shared_memory_options, |
| 4436 | NULL, NULL, NULL |
| 4437 | }, |
| 4438 | |
| 4439 | { |
| 4440 | {"wal_sync_method" , PGC_SIGHUP, WAL_SETTINGS, |
| 4441 | gettext_noop("Selects the method used for forcing WAL updates to disk." ), |
| 4442 | NULL |
| 4443 | }, |
| 4444 | &sync_method, |
| 4445 | DEFAULT_SYNC_METHOD, sync_method_options, |
| 4446 | NULL, assign_xlog_sync_method, NULL |
| 4447 | }, |
| 4448 | |
| 4449 | { |
| 4450 | {"xmlbinary" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4451 | gettext_noop("Sets how binary values are to be encoded in XML." ), |
| 4452 | NULL |
| 4453 | }, |
| 4454 | &xmlbinary, |
| 4455 | XMLBINARY_BASE64, xmlbinary_options, |
| 4456 | NULL, NULL, NULL |
| 4457 | }, |
| 4458 | |
| 4459 | { |
| 4460 | {"xmloption" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
| 4461 | gettext_noop("Sets whether XML data in implicit parsing and serialization " |
| 4462 | "operations is to be considered as documents or content fragments." ), |
| 4463 | NULL |
| 4464 | }, |
| 4465 | &xmloption, |
| 4466 | XMLOPTION_CONTENT, xmloption_options, |
| 4467 | NULL, NULL, NULL |
| 4468 | }, |
| 4469 | |
| 4470 | { |
| 4471 | {"huge_pages" , PGC_POSTMASTER, RESOURCES_MEM, |
| 4472 | gettext_noop("Use of huge pages on Linux or Windows." ), |
| 4473 | NULL |
| 4474 | }, |
| 4475 | &huge_pages, |
| 4476 | HUGE_PAGES_TRY, huge_pages_options, |
| 4477 | NULL, NULL, NULL |
| 4478 | }, |
| 4479 | |
| 4480 | { |
| 4481 | {"force_parallel_mode" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 4482 | gettext_noop("Forces use of parallel query facilities." ), |
| 4483 | gettext_noop("If possible, run query using a parallel worker and with parallel restrictions." ), |
| 4484 | GUC_EXPLAIN |
| 4485 | }, |
| 4486 | &force_parallel_mode, |
| 4487 | FORCE_PARALLEL_OFF, force_parallel_mode_options, |
| 4488 | NULL, NULL, NULL |
| 4489 | }, |
| 4490 | |
| 4491 | { |
| 4492 | {"password_encryption" , PGC_USERSET, CONN_AUTH_AUTH, |
| 4493 | gettext_noop("Encrypt passwords." ), |
| 4494 | gettext_noop("When a password is specified in CREATE USER or " |
| 4495 | "ALTER USER without writing either ENCRYPTED or UNENCRYPTED, " |
| 4496 | "this parameter determines whether the password is to be encrypted." ) |
| 4497 | }, |
| 4498 | &Password_encryption, |
| 4499 | PASSWORD_TYPE_MD5, password_encryption_options, |
| 4500 | NULL, NULL, NULL |
| 4501 | }, |
| 4502 | |
| 4503 | { |
| 4504 | {"plan_cache_mode" , PGC_USERSET, QUERY_TUNING_OTHER, |
| 4505 | gettext_noop("Controls the planner's selection of custom or generic plan." ), |
| 4506 | gettext_noop("Prepared statements can have custom and generic plans, and the planner " |
| 4507 | "will attempt to choose which is better. This can be set to override " |
| 4508 | "the default behavior." ), |
| 4509 | GUC_EXPLAIN |
| 4510 | }, |
| 4511 | &plan_cache_mode, |
| 4512 | PLAN_CACHE_MODE_AUTO, plan_cache_mode_options, |
| 4513 | NULL, NULL, NULL |
| 4514 | }, |
| 4515 | |
| 4516 | { |
| 4517 | {"ssl_min_protocol_version" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4518 | gettext_noop("Sets the minimum SSL/TLS protocol version to use." ), |
| 4519 | NULL, |
| 4520 | GUC_SUPERUSER_ONLY |
| 4521 | }, |
| 4522 | &ssl_min_protocol_version, |
| 4523 | PG_TLS1_VERSION, |
| 4524 | ssl_protocol_versions_info + 1, /* don't allow PG_TLS_ANY */ |
| 4525 | NULL, NULL, NULL |
| 4526 | }, |
| 4527 | |
| 4528 | { |
| 4529 | {"ssl_max_protocol_version" , PGC_SIGHUP, CONN_AUTH_SSL, |
| 4530 | gettext_noop("Sets the maximum SSL/TLS protocol version to use." ), |
| 4531 | NULL, |
| 4532 | GUC_SUPERUSER_ONLY |
| 4533 | }, |
| 4534 | &ssl_max_protocol_version, |
| 4535 | PG_TLS_ANY, |
| 4536 | ssl_protocol_versions_info, |
| 4537 | NULL, NULL, NULL |
| 4538 | }, |
| 4539 | |
| 4540 | /* End-of-list marker */ |
| 4541 | { |
| 4542 | {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL |
| 4543 | } |
| 4544 | }; |
| 4545 | |
| 4546 | /******** end of options list ********/ |
| 4547 | |
| 4548 | |
| 4549 | /* |
| 4550 | * To allow continued support of obsolete names for GUC variables, we apply |
| 4551 | * the following mappings to any unrecognized name. Note that an old name |
| 4552 | * should be mapped to a new one only if the new variable has very similar |
| 4553 | * semantics to the old. |
| 4554 | */ |
| 4555 | static const char *const map_old_guc_names[] = { |
| 4556 | "sort_mem" , "work_mem" , |
| 4557 | "vacuum_mem" , "maintenance_work_mem" , |
| 4558 | NULL |
| 4559 | }; |
| 4560 | |
| 4561 | |
| 4562 | /* |
| 4563 | * Actual lookup of variables is done through this single, sorted array. |
| 4564 | */ |
| 4565 | static struct config_generic **guc_variables; |
| 4566 | |
| 4567 | /* Current number of variables contained in the vector */ |
| 4568 | static int num_guc_variables; |
| 4569 | |
| 4570 | /* Current number of variables marked with GUC_EXPLAIN */ |
| 4571 | static int num_guc_explain_variables; |
| 4572 | |
| 4573 | /* Vector capacity */ |
| 4574 | static int size_guc_variables; |
| 4575 | |
| 4576 | |
| 4577 | static bool guc_dirty; /* true if need to do commit/abort work */ |
| 4578 | |
| 4579 | static bool reporting_enabled; /* true to enable GUC_REPORT */ |
| 4580 | |
| 4581 | static int GUCNestLevel = 0; /* 1 when in main transaction */ |
| 4582 | |
| 4583 | |
| 4584 | static int guc_var_compare(const void *a, const void *b); |
| 4585 | static int guc_name_compare(const char *namea, const char *nameb); |
| 4586 | static void InitializeGUCOptionsFromEnvironment(void); |
| 4587 | static void InitializeOneGUCOption(struct config_generic *gconf); |
| 4588 | static void push_old_value(struct config_generic *gconf, GucAction action); |
| 4589 | static void ReportGUCOption(struct config_generic *record); |
| 4590 | static void reapply_stacked_values(struct config_generic *variable, |
| 4591 | struct config_string *pHolder, |
| 4592 | GucStack *stack, |
| 4593 | const char *curvalue, |
| 4594 | GucContext curscontext, GucSource cursource); |
| 4595 | static void ShowGUCConfigOption(const char *name, DestReceiver *dest); |
| 4596 | static void ShowAllGUCConfig(DestReceiver *dest); |
| 4597 | static char *_ShowOption(struct config_generic *record, bool use_units); |
| 4598 | static bool validate_option_array_item(const char *name, const char *value, |
| 4599 | bool skipIfNoPermissions); |
| 4600 | static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p); |
| 4601 | static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, |
| 4602 | const char *name, const char *value); |
| 4603 | |
| 4604 | |
| 4605 | /* |
| 4606 | * Some infrastructure for checking malloc/strdup/realloc calls |
| 4607 | */ |
| 4608 | static void * |
| 4609 | guc_malloc(int elevel, size_t size) |
| 4610 | { |
| 4611 | void *data; |
| 4612 | |
| 4613 | /* Avoid unportable behavior of malloc(0) */ |
| 4614 | if (size == 0) |
| 4615 | size = 1; |
| 4616 | data = malloc(size); |
| 4617 | if (data == NULL) |
| 4618 | ereport(elevel, |
| 4619 | (errcode(ERRCODE_OUT_OF_MEMORY), |
| 4620 | errmsg("out of memory" ))); |
| 4621 | return data; |
| 4622 | } |
| 4623 | |
| 4624 | static void * |
| 4625 | guc_realloc(int elevel, void *old, size_t size) |
| 4626 | { |
| 4627 | void *data; |
| 4628 | |
| 4629 | /* Avoid unportable behavior of realloc(NULL, 0) */ |
| 4630 | if (old == NULL && size == 0) |
| 4631 | size = 1; |
| 4632 | data = realloc(old, size); |
| 4633 | if (data == NULL) |
| 4634 | ereport(elevel, |
| 4635 | (errcode(ERRCODE_OUT_OF_MEMORY), |
| 4636 | errmsg("out of memory" ))); |
| 4637 | return data; |
| 4638 | } |
| 4639 | |
| 4640 | static char * |
| 4641 | guc_strdup(int elevel, const char *src) |
| 4642 | { |
| 4643 | char *data; |
| 4644 | |
| 4645 | data = strdup(src); |
| 4646 | if (data == NULL) |
| 4647 | ereport(elevel, |
| 4648 | (errcode(ERRCODE_OUT_OF_MEMORY), |
| 4649 | errmsg("out of memory" ))); |
| 4650 | return data; |
| 4651 | } |
| 4652 | |
| 4653 | |
| 4654 | /* |
| 4655 | * Detect whether strval is referenced anywhere in a GUC string item |
| 4656 | */ |
| 4657 | static bool |
| 4658 | string_field_used(struct config_string *conf, char *strval) |
| 4659 | { |
| 4660 | GucStack *stack; |
| 4661 | |
| 4662 | if (strval == *(conf->variable) || |
| 4663 | strval == conf->reset_val || |
| 4664 | strval == conf->boot_val) |
| 4665 | return true; |
| 4666 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 4667 | { |
| 4668 | if (strval == stack->prior.val.stringval || |
| 4669 | strval == stack->masked.val.stringval) |
| 4670 | return true; |
| 4671 | } |
| 4672 | return false; |
| 4673 | } |
| 4674 | |
| 4675 | /* |
| 4676 | * Support for assigning to a field of a string GUC item. Free the prior |
| 4677 | * value if it's not referenced anywhere else in the item (including stacked |
| 4678 | * states). |
| 4679 | */ |
| 4680 | static void |
| 4681 | set_string_field(struct config_string *conf, char **field, char *newval) |
| 4682 | { |
| 4683 | char *oldval = *field; |
| 4684 | |
| 4685 | /* Do the assignment */ |
| 4686 | *field = newval; |
| 4687 | |
| 4688 | /* Free old value if it's not NULL and isn't referenced anymore */ |
| 4689 | if (oldval && !string_field_used(conf, oldval)) |
| 4690 | free(oldval); |
| 4691 | } |
| 4692 | |
| 4693 | /* |
| 4694 | * Detect whether an "extra" struct is referenced anywhere in a GUC item |
| 4695 | */ |
| 4696 | static bool |
| 4697 | (struct config_generic *gconf, void *) |
| 4698 | { |
| 4699 | GucStack *stack; |
| 4700 | |
| 4701 | if (extra == gconf->extra) |
| 4702 | return true; |
| 4703 | switch (gconf->vartype) |
| 4704 | { |
| 4705 | case PGC_BOOL: |
| 4706 | if (extra == ((struct config_bool *) gconf)->reset_extra) |
| 4707 | return true; |
| 4708 | break; |
| 4709 | case PGC_INT: |
| 4710 | if (extra == ((struct config_int *) gconf)->reset_extra) |
| 4711 | return true; |
| 4712 | break; |
| 4713 | case PGC_REAL: |
| 4714 | if (extra == ((struct config_real *) gconf)->reset_extra) |
| 4715 | return true; |
| 4716 | break; |
| 4717 | case PGC_STRING: |
| 4718 | if (extra == ((struct config_string *) gconf)->reset_extra) |
| 4719 | return true; |
| 4720 | break; |
| 4721 | case PGC_ENUM: |
| 4722 | if (extra == ((struct config_enum *) gconf)->reset_extra) |
| 4723 | return true; |
| 4724 | break; |
| 4725 | } |
| 4726 | for (stack = gconf->stack; stack; stack = stack->prev) |
| 4727 | { |
| 4728 | if (extra == stack->prior.extra || |
| 4729 | extra == stack->masked.extra) |
| 4730 | return true; |
| 4731 | } |
| 4732 | |
| 4733 | return false; |
| 4734 | } |
| 4735 | |
| 4736 | /* |
| 4737 | * Support for assigning to an "extra" field of a GUC item. Free the prior |
| 4738 | * value if it's not referenced anywhere else in the item (including stacked |
| 4739 | * states). |
| 4740 | */ |
| 4741 | static void |
| 4742 | (struct config_generic *gconf, void **field, void *newval) |
| 4743 | { |
| 4744 | void *oldval = *field; |
| 4745 | |
| 4746 | /* Do the assignment */ |
| 4747 | *field = newval; |
| 4748 | |
| 4749 | /* Free old value if it's not NULL and isn't referenced anymore */ |
| 4750 | if (oldval && !extra_field_used(gconf, oldval)) |
| 4751 | free(oldval); |
| 4752 | } |
| 4753 | |
| 4754 | /* |
| 4755 | * Support for copying a variable's active value into a stack entry. |
| 4756 | * The "extra" field associated with the active value is copied, too. |
| 4757 | * |
| 4758 | * NB: be sure stringval and extra fields of a new stack entry are |
| 4759 | * initialized to NULL before this is used, else we'll try to free() them. |
| 4760 | */ |
| 4761 | static void |
| 4762 | set_stack_value(struct config_generic *gconf, config_var_value *val) |
| 4763 | { |
| 4764 | switch (gconf->vartype) |
| 4765 | { |
| 4766 | case PGC_BOOL: |
| 4767 | val->val.boolval = |
| 4768 | *((struct config_bool *) gconf)->variable; |
| 4769 | break; |
| 4770 | case PGC_INT: |
| 4771 | val->val.intval = |
| 4772 | *((struct config_int *) gconf)->variable; |
| 4773 | break; |
| 4774 | case PGC_REAL: |
| 4775 | val->val.realval = |
| 4776 | *((struct config_real *) gconf)->variable; |
| 4777 | break; |
| 4778 | case PGC_STRING: |
| 4779 | set_string_field((struct config_string *) gconf, |
| 4780 | &(val->val.stringval), |
| 4781 | *((struct config_string *) gconf)->variable); |
| 4782 | break; |
| 4783 | case PGC_ENUM: |
| 4784 | val->val.enumval = |
| 4785 | *((struct config_enum *) gconf)->variable; |
| 4786 | break; |
| 4787 | } |
| 4788 | set_extra_field(gconf, &(val->extra), gconf->extra); |
| 4789 | } |
| 4790 | |
| 4791 | /* |
| 4792 | * Support for discarding a no-longer-needed value in a stack entry. |
| 4793 | * The "extra" field associated with the stack entry is cleared, too. |
| 4794 | */ |
| 4795 | static void |
| 4796 | discard_stack_value(struct config_generic *gconf, config_var_value *val) |
| 4797 | { |
| 4798 | switch (gconf->vartype) |
| 4799 | { |
| 4800 | case PGC_BOOL: |
| 4801 | case PGC_INT: |
| 4802 | case PGC_REAL: |
| 4803 | case PGC_ENUM: |
| 4804 | /* no need to do anything */ |
| 4805 | break; |
| 4806 | case PGC_STRING: |
| 4807 | set_string_field((struct config_string *) gconf, |
| 4808 | &(val->val.stringval), |
| 4809 | NULL); |
| 4810 | break; |
| 4811 | } |
| 4812 | set_extra_field(gconf, &(val->extra), NULL); |
| 4813 | } |
| 4814 | |
| 4815 | |
| 4816 | /* |
| 4817 | * Fetch the sorted array pointer (exported for help_config.c's use ONLY) |
| 4818 | */ |
| 4819 | struct config_generic ** |
| 4820 | get_guc_variables(void) |
| 4821 | { |
| 4822 | return guc_variables; |
| 4823 | } |
| 4824 | |
| 4825 | |
| 4826 | /* |
| 4827 | * Build the sorted array. This is split out so that it could be |
| 4828 | * re-executed after startup (e.g., we could allow loadable modules to |
| 4829 | * add vars, and then we'd need to re-sort). |
| 4830 | */ |
| 4831 | void |
| 4832 | build_guc_variables(void) |
| 4833 | { |
| 4834 | int size_vars; |
| 4835 | int num_vars = 0; |
| 4836 | int num_explain_vars = 0; |
| 4837 | struct config_generic **guc_vars; |
| 4838 | int i; |
| 4839 | |
| 4840 | for (i = 0; ConfigureNamesBool[i].gen.name; i++) |
| 4841 | { |
| 4842 | struct config_bool *conf = &ConfigureNamesBool[i]; |
| 4843 | |
| 4844 | /* Rather than requiring vartype to be filled in by hand, do this: */ |
| 4845 | conf->gen.vartype = PGC_BOOL; |
| 4846 | num_vars++; |
| 4847 | |
| 4848 | if (conf->gen.flags & GUC_EXPLAIN) |
| 4849 | num_explain_vars++; |
| 4850 | } |
| 4851 | |
| 4852 | for (i = 0; ConfigureNamesInt[i].gen.name; i++) |
| 4853 | { |
| 4854 | struct config_int *conf = &ConfigureNamesInt[i]; |
| 4855 | |
| 4856 | conf->gen.vartype = PGC_INT; |
| 4857 | num_vars++; |
| 4858 | |
| 4859 | if (conf->gen.flags & GUC_EXPLAIN) |
| 4860 | num_explain_vars++; |
| 4861 | } |
| 4862 | |
| 4863 | for (i = 0; ConfigureNamesReal[i].gen.name; i++) |
| 4864 | { |
| 4865 | struct config_real *conf = &ConfigureNamesReal[i]; |
| 4866 | |
| 4867 | conf->gen.vartype = PGC_REAL; |
| 4868 | num_vars++; |
| 4869 | |
| 4870 | if (conf->gen.flags & GUC_EXPLAIN) |
| 4871 | num_explain_vars++; |
| 4872 | } |
| 4873 | |
| 4874 | for (i = 0; ConfigureNamesString[i].gen.name; i++) |
| 4875 | { |
| 4876 | struct config_string *conf = &ConfigureNamesString[i]; |
| 4877 | |
| 4878 | conf->gen.vartype = PGC_STRING; |
| 4879 | num_vars++; |
| 4880 | |
| 4881 | if (conf->gen.flags & GUC_EXPLAIN) |
| 4882 | num_explain_vars++; |
| 4883 | } |
| 4884 | |
| 4885 | for (i = 0; ConfigureNamesEnum[i].gen.name; i++) |
| 4886 | { |
| 4887 | struct config_enum *conf = &ConfigureNamesEnum[i]; |
| 4888 | |
| 4889 | conf->gen.vartype = PGC_ENUM; |
| 4890 | num_vars++; |
| 4891 | |
| 4892 | if (conf->gen.flags & GUC_EXPLAIN) |
| 4893 | num_explain_vars++; |
| 4894 | } |
| 4895 | |
| 4896 | /* |
| 4897 | * Create table with 20% slack |
| 4898 | */ |
| 4899 | size_vars = num_vars + num_vars / 4; |
| 4900 | |
| 4901 | guc_vars = (struct config_generic **) |
| 4902 | guc_malloc(FATAL, size_vars * sizeof(struct config_generic *)); |
| 4903 | |
| 4904 | num_vars = 0; |
| 4905 | |
| 4906 | for (i = 0; ConfigureNamesBool[i].gen.name; i++) |
| 4907 | guc_vars[num_vars++] = &ConfigureNamesBool[i].gen; |
| 4908 | |
| 4909 | for (i = 0; ConfigureNamesInt[i].gen.name; i++) |
| 4910 | guc_vars[num_vars++] = &ConfigureNamesInt[i].gen; |
| 4911 | |
| 4912 | for (i = 0; ConfigureNamesReal[i].gen.name; i++) |
| 4913 | guc_vars[num_vars++] = &ConfigureNamesReal[i].gen; |
| 4914 | |
| 4915 | for (i = 0; ConfigureNamesString[i].gen.name; i++) |
| 4916 | guc_vars[num_vars++] = &ConfigureNamesString[i].gen; |
| 4917 | |
| 4918 | for (i = 0; ConfigureNamesEnum[i].gen.name; i++) |
| 4919 | guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen; |
| 4920 | |
| 4921 | if (guc_variables) |
| 4922 | free(guc_variables); |
| 4923 | guc_variables = guc_vars; |
| 4924 | num_guc_variables = num_vars; |
| 4925 | num_guc_explain_variables = num_explain_vars; |
| 4926 | size_guc_variables = size_vars; |
| 4927 | qsort((void *) guc_variables, num_guc_variables, |
| 4928 | sizeof(struct config_generic *), guc_var_compare); |
| 4929 | } |
| 4930 | |
| 4931 | /* |
| 4932 | * Add a new GUC variable to the list of known variables. The |
| 4933 | * list is expanded if needed. |
| 4934 | */ |
| 4935 | static bool |
| 4936 | add_guc_variable(struct config_generic *var, int elevel) |
| 4937 | { |
| 4938 | if (num_guc_variables + 1 >= size_guc_variables) |
| 4939 | { |
| 4940 | /* |
| 4941 | * Increase the vector by 25% |
| 4942 | */ |
| 4943 | int size_vars = size_guc_variables + size_guc_variables / 4; |
| 4944 | struct config_generic **guc_vars; |
| 4945 | |
| 4946 | if (size_vars == 0) |
| 4947 | { |
| 4948 | size_vars = 100; |
| 4949 | guc_vars = (struct config_generic **) |
| 4950 | guc_malloc(elevel, size_vars * sizeof(struct config_generic *)); |
| 4951 | } |
| 4952 | else |
| 4953 | { |
| 4954 | guc_vars = (struct config_generic **) |
| 4955 | guc_realloc(elevel, guc_variables, size_vars * sizeof(struct config_generic *)); |
| 4956 | } |
| 4957 | |
| 4958 | if (guc_vars == NULL) |
| 4959 | return false; /* out of memory */ |
| 4960 | |
| 4961 | guc_variables = guc_vars; |
| 4962 | size_guc_variables = size_vars; |
| 4963 | } |
| 4964 | guc_variables[num_guc_variables++] = var; |
| 4965 | qsort((void *) guc_variables, num_guc_variables, |
| 4966 | sizeof(struct config_generic *), guc_var_compare); |
| 4967 | return true; |
| 4968 | } |
| 4969 | |
| 4970 | /* |
| 4971 | * Create and add a placeholder variable for a custom variable name. |
| 4972 | */ |
| 4973 | static struct config_generic * |
| 4974 | add_placeholder_variable(const char *name, int elevel) |
| 4975 | { |
| 4976 | size_t sz = sizeof(struct config_string) + sizeof(char *); |
| 4977 | struct config_string *var; |
| 4978 | struct config_generic *gen; |
| 4979 | |
| 4980 | var = (struct config_string *) guc_malloc(elevel, sz); |
| 4981 | if (var == NULL) |
| 4982 | return NULL; |
| 4983 | memset(var, 0, sz); |
| 4984 | gen = &var->gen; |
| 4985 | |
| 4986 | gen->name = guc_strdup(elevel, name); |
| 4987 | if (gen->name == NULL) |
| 4988 | { |
| 4989 | free(var); |
| 4990 | return NULL; |
| 4991 | } |
| 4992 | |
| 4993 | gen->context = PGC_USERSET; |
| 4994 | gen->group = CUSTOM_OPTIONS; |
| 4995 | gen->short_desc = "GUC placeholder variable" ; |
| 4996 | gen->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER; |
| 4997 | gen->vartype = PGC_STRING; |
| 4998 | |
| 4999 | /* |
| 5000 | * The char* is allocated at the end of the struct since we have no |
| 5001 | * 'static' place to point to. Note that the current value, as well as |
| 5002 | * the boot and reset values, start out NULL. |
| 5003 | */ |
| 5004 | var->variable = (char **) (var + 1); |
| 5005 | |
| 5006 | if (!add_guc_variable((struct config_generic *) var, elevel)) |
| 5007 | { |
| 5008 | free(unconstify(char *, gen->name)); |
| 5009 | free(var); |
| 5010 | return NULL; |
| 5011 | } |
| 5012 | |
| 5013 | return gen; |
| 5014 | } |
| 5015 | |
| 5016 | /* |
| 5017 | * Look up option NAME. If it exists, return a pointer to its record, |
| 5018 | * else return NULL. If create_placeholders is true, we'll create a |
| 5019 | * placeholder record for a valid-looking custom variable name. |
| 5020 | */ |
| 5021 | static struct config_generic * |
| 5022 | find_option(const char *name, bool create_placeholders, int elevel) |
| 5023 | { |
| 5024 | const char **key = &name; |
| 5025 | struct config_generic **res; |
| 5026 | int i; |
| 5027 | |
| 5028 | Assert(name); |
| 5029 | |
| 5030 | /* |
| 5031 | * By equating const char ** with struct config_generic *, we are assuming |
| 5032 | * the name field is first in config_generic. |
| 5033 | */ |
| 5034 | res = (struct config_generic **) bsearch((void *) &key, |
| 5035 | (void *) guc_variables, |
| 5036 | num_guc_variables, |
| 5037 | sizeof(struct config_generic *), |
| 5038 | guc_var_compare); |
| 5039 | if (res) |
| 5040 | return *res; |
| 5041 | |
| 5042 | /* |
| 5043 | * See if the name is an obsolete name for a variable. We assume that the |
| 5044 | * set of supported old names is short enough that a brute-force search is |
| 5045 | * the best way. |
| 5046 | */ |
| 5047 | for (i = 0; map_old_guc_names[i] != NULL; i += 2) |
| 5048 | { |
| 5049 | if (guc_name_compare(name, map_old_guc_names[i]) == 0) |
| 5050 | return find_option(map_old_guc_names[i + 1], false, elevel); |
| 5051 | } |
| 5052 | |
| 5053 | if (create_placeholders) |
| 5054 | { |
| 5055 | /* |
| 5056 | * Check if the name is qualified, and if so, add a placeholder. |
| 5057 | */ |
| 5058 | if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL) |
| 5059 | return add_placeholder_variable(name, elevel); |
| 5060 | } |
| 5061 | |
| 5062 | /* Unknown name */ |
| 5063 | return NULL; |
| 5064 | } |
| 5065 | |
| 5066 | |
| 5067 | /* |
| 5068 | * comparator for qsorting and bsearching guc_variables array |
| 5069 | */ |
| 5070 | static int |
| 5071 | guc_var_compare(const void *a, const void *b) |
| 5072 | { |
| 5073 | const struct config_generic *confa = *(struct config_generic *const *) a; |
| 5074 | const struct config_generic *confb = *(struct config_generic *const *) b; |
| 5075 | |
| 5076 | return guc_name_compare(confa->name, confb->name); |
| 5077 | } |
| 5078 | |
| 5079 | /* |
| 5080 | * the bare comparison function for GUC names |
| 5081 | */ |
| 5082 | static int |
| 5083 | guc_name_compare(const char *namea, const char *nameb) |
| 5084 | { |
| 5085 | /* |
| 5086 | * The temptation to use strcasecmp() here must be resisted, because the |
| 5087 | * array ordering has to remain stable across setlocale() calls. So, build |
| 5088 | * our own with a simple ASCII-only downcasing. |
| 5089 | */ |
| 5090 | while (*namea && *nameb) |
| 5091 | { |
| 5092 | char cha = *namea++; |
| 5093 | char chb = *nameb++; |
| 5094 | |
| 5095 | if (cha >= 'A' && cha <= 'Z') |
| 5096 | cha += 'a' - 'A'; |
| 5097 | if (chb >= 'A' && chb <= 'Z') |
| 5098 | chb += 'a' - 'A'; |
| 5099 | if (cha != chb) |
| 5100 | return cha - chb; |
| 5101 | } |
| 5102 | if (*namea) |
| 5103 | return 1; /* a is longer */ |
| 5104 | if (*nameb) |
| 5105 | return -1; /* b is longer */ |
| 5106 | return 0; |
| 5107 | } |
| 5108 | |
| 5109 | |
| 5110 | /* |
| 5111 | * Initialize GUC options during program startup. |
| 5112 | * |
| 5113 | * Note that we cannot read the config file yet, since we have not yet |
| 5114 | * processed command-line switches. |
| 5115 | */ |
| 5116 | void |
| 5117 | InitializeGUCOptions(void) |
| 5118 | { |
| 5119 | int i; |
| 5120 | |
| 5121 | /* |
| 5122 | * Before log_line_prefix could possibly receive a nonempty setting, make |
| 5123 | * sure that timezone processing is minimally alive (see elog.c). |
| 5124 | */ |
| 5125 | pg_timezone_initialize(); |
| 5126 | |
| 5127 | /* |
| 5128 | * Build sorted array of all GUC variables. |
| 5129 | */ |
| 5130 | build_guc_variables(); |
| 5131 | |
| 5132 | /* |
| 5133 | * Load all variables with their compiled-in defaults, and initialize |
| 5134 | * status fields as needed. |
| 5135 | */ |
| 5136 | for (i = 0; i < num_guc_variables; i++) |
| 5137 | { |
| 5138 | InitializeOneGUCOption(guc_variables[i]); |
| 5139 | } |
| 5140 | |
| 5141 | guc_dirty = false; |
| 5142 | |
| 5143 | reporting_enabled = false; |
| 5144 | |
| 5145 | /* |
| 5146 | * Prevent any attempt to override the transaction modes from |
| 5147 | * non-interactive sources. |
| 5148 | */ |
| 5149 | SetConfigOption("transaction_isolation" , "read committed" , |
| 5150 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5151 | SetConfigOption("transaction_read_only" , "no" , |
| 5152 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5153 | SetConfigOption("transaction_deferrable" , "no" , |
| 5154 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5155 | |
| 5156 | /* |
| 5157 | * For historical reasons, some GUC parameters can receive defaults from |
| 5158 | * environment variables. Process those settings. |
| 5159 | */ |
| 5160 | InitializeGUCOptionsFromEnvironment(); |
| 5161 | } |
| 5162 | |
| 5163 | /* |
| 5164 | * Assign any GUC values that can come from the server's environment. |
| 5165 | * |
| 5166 | * This is called from InitializeGUCOptions, and also from ProcessConfigFile |
| 5167 | * to deal with the possibility that a setting has been removed from |
| 5168 | * postgresql.conf and should now get a value from the environment. |
| 5169 | * (The latter is a kludge that should probably go away someday; if so, |
| 5170 | * fold this back into InitializeGUCOptions.) |
| 5171 | */ |
| 5172 | static void |
| 5173 | InitializeGUCOptionsFromEnvironment(void) |
| 5174 | { |
| 5175 | char *env; |
| 5176 | long stack_rlimit; |
| 5177 | |
| 5178 | env = getenv("PGPORT" ); |
| 5179 | if (env != NULL) |
| 5180 | SetConfigOption("port" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
| 5181 | |
| 5182 | env = getenv("PGDATESTYLE" ); |
| 5183 | if (env != NULL) |
| 5184 | SetConfigOption("datestyle" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
| 5185 | |
| 5186 | env = getenv("PGCLIENTENCODING" ); |
| 5187 | if (env != NULL) |
| 5188 | SetConfigOption("client_encoding" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
| 5189 | |
| 5190 | /* |
| 5191 | * rlimit isn't exactly an "environment variable", but it behaves about |
| 5192 | * the same. If we can identify the platform stack depth rlimit, increase |
| 5193 | * default stack depth setting up to whatever is safe (but at most 2MB). |
| 5194 | */ |
| 5195 | stack_rlimit = get_stack_depth_rlimit(); |
| 5196 | if (stack_rlimit > 0) |
| 5197 | { |
| 5198 | long new_limit = (stack_rlimit - STACK_DEPTH_SLOP) / 1024L; |
| 5199 | |
| 5200 | if (new_limit > 100) |
| 5201 | { |
| 5202 | char limbuf[16]; |
| 5203 | |
| 5204 | new_limit = Min(new_limit, 2048); |
| 5205 | sprintf(limbuf, "%ld" , new_limit); |
| 5206 | SetConfigOption("max_stack_depth" , limbuf, |
| 5207 | PGC_POSTMASTER, PGC_S_ENV_VAR); |
| 5208 | } |
| 5209 | } |
| 5210 | } |
| 5211 | |
| 5212 | /* |
| 5213 | * Initialize one GUC option variable to its compiled-in default. |
| 5214 | * |
| 5215 | * Note: the reason for calling check_hooks is not that we think the boot_val |
| 5216 | * might fail, but that the hooks might wish to compute an "extra" struct. |
| 5217 | */ |
| 5218 | static void |
| 5219 | InitializeOneGUCOption(struct config_generic *gconf) |
| 5220 | { |
| 5221 | gconf->status = 0; |
| 5222 | gconf->source = PGC_S_DEFAULT; |
| 5223 | gconf->reset_source = PGC_S_DEFAULT; |
| 5224 | gconf->scontext = PGC_INTERNAL; |
| 5225 | gconf->reset_scontext = PGC_INTERNAL; |
| 5226 | gconf->stack = NULL; |
| 5227 | gconf->extra = NULL; |
| 5228 | gconf->sourcefile = NULL; |
| 5229 | gconf->sourceline = 0; |
| 5230 | |
| 5231 | switch (gconf->vartype) |
| 5232 | { |
| 5233 | case PGC_BOOL: |
| 5234 | { |
| 5235 | struct config_bool *conf = (struct config_bool *) gconf; |
| 5236 | bool newval = conf->boot_val; |
| 5237 | void * = NULL; |
| 5238 | |
| 5239 | if (!call_bool_check_hook(conf, &newval, &extra, |
| 5240 | PGC_S_DEFAULT, LOG)) |
| 5241 | elog(FATAL, "failed to initialize %s to %d" , |
| 5242 | conf->gen.name, (int) newval); |
| 5243 | if (conf->assign_hook) |
| 5244 | conf->assign_hook(newval, extra); |
| 5245 | *conf->variable = conf->reset_val = newval; |
| 5246 | conf->gen.extra = conf->reset_extra = extra; |
| 5247 | break; |
| 5248 | } |
| 5249 | case PGC_INT: |
| 5250 | { |
| 5251 | struct config_int *conf = (struct config_int *) gconf; |
| 5252 | int newval = conf->boot_val; |
| 5253 | void * = NULL; |
| 5254 | |
| 5255 | Assert(newval >= conf->min); |
| 5256 | Assert(newval <= conf->max); |
| 5257 | if (!call_int_check_hook(conf, &newval, &extra, |
| 5258 | PGC_S_DEFAULT, LOG)) |
| 5259 | elog(FATAL, "failed to initialize %s to %d" , |
| 5260 | conf->gen.name, newval); |
| 5261 | if (conf->assign_hook) |
| 5262 | conf->assign_hook(newval, extra); |
| 5263 | *conf->variable = conf->reset_val = newval; |
| 5264 | conf->gen.extra = conf->reset_extra = extra; |
| 5265 | break; |
| 5266 | } |
| 5267 | case PGC_REAL: |
| 5268 | { |
| 5269 | struct config_real *conf = (struct config_real *) gconf; |
| 5270 | double newval = conf->boot_val; |
| 5271 | void * = NULL; |
| 5272 | |
| 5273 | Assert(newval >= conf->min); |
| 5274 | Assert(newval <= conf->max); |
| 5275 | if (!call_real_check_hook(conf, &newval, &extra, |
| 5276 | PGC_S_DEFAULT, LOG)) |
| 5277 | elog(FATAL, "failed to initialize %s to %g" , |
| 5278 | conf->gen.name, newval); |
| 5279 | if (conf->assign_hook) |
| 5280 | conf->assign_hook(newval, extra); |
| 5281 | *conf->variable = conf->reset_val = newval; |
| 5282 | conf->gen.extra = conf->reset_extra = extra; |
| 5283 | break; |
| 5284 | } |
| 5285 | case PGC_STRING: |
| 5286 | { |
| 5287 | struct config_string *conf = (struct config_string *) gconf; |
| 5288 | char *newval; |
| 5289 | void * = NULL; |
| 5290 | |
| 5291 | /* non-NULL boot_val must always get strdup'd */ |
| 5292 | if (conf->boot_val != NULL) |
| 5293 | newval = guc_strdup(FATAL, conf->boot_val); |
| 5294 | else |
| 5295 | newval = NULL; |
| 5296 | |
| 5297 | if (!call_string_check_hook(conf, &newval, &extra, |
| 5298 | PGC_S_DEFAULT, LOG)) |
| 5299 | elog(FATAL, "failed to initialize %s to \"%s\"" , |
| 5300 | conf->gen.name, newval ? newval : "" ); |
| 5301 | if (conf->assign_hook) |
| 5302 | conf->assign_hook(newval, extra); |
| 5303 | *conf->variable = conf->reset_val = newval; |
| 5304 | conf->gen.extra = conf->reset_extra = extra; |
| 5305 | break; |
| 5306 | } |
| 5307 | case PGC_ENUM: |
| 5308 | { |
| 5309 | struct config_enum *conf = (struct config_enum *) gconf; |
| 5310 | int newval = conf->boot_val; |
| 5311 | void * = NULL; |
| 5312 | |
| 5313 | if (!call_enum_check_hook(conf, &newval, &extra, |
| 5314 | PGC_S_DEFAULT, LOG)) |
| 5315 | elog(FATAL, "failed to initialize %s to %d" , |
| 5316 | conf->gen.name, newval); |
| 5317 | if (conf->assign_hook) |
| 5318 | conf->assign_hook(newval, extra); |
| 5319 | *conf->variable = conf->reset_val = newval; |
| 5320 | conf->gen.extra = conf->reset_extra = extra; |
| 5321 | break; |
| 5322 | } |
| 5323 | } |
| 5324 | } |
| 5325 | |
| 5326 | |
| 5327 | /* |
| 5328 | * Select the configuration files and data directory to be used, and |
| 5329 | * do the initial read of postgresql.conf. |
| 5330 | * |
| 5331 | * This is called after processing command-line switches. |
| 5332 | * userDoption is the -D switch value if any (NULL if unspecified). |
| 5333 | * progname is just for use in error messages. |
| 5334 | * |
| 5335 | * Returns true on success; on failure, prints a suitable error message |
| 5336 | * to stderr and returns false. |
| 5337 | */ |
| 5338 | bool |
| 5339 | SelectConfigFiles(const char *userDoption, const char *progname) |
| 5340 | { |
| 5341 | char *configdir; |
| 5342 | char *fname; |
| 5343 | struct stat stat_buf; |
| 5344 | |
| 5345 | /* configdir is -D option, or $PGDATA if no -D */ |
| 5346 | if (userDoption) |
| 5347 | configdir = make_absolute_path(userDoption); |
| 5348 | else |
| 5349 | configdir = make_absolute_path(getenv("PGDATA" )); |
| 5350 | |
| 5351 | if (configdir && stat(configdir, &stat_buf) != 0) |
| 5352 | { |
| 5353 | write_stderr("%s: could not access directory \"%s\": %s\n" , |
| 5354 | progname, |
| 5355 | configdir, |
| 5356 | strerror(errno)); |
| 5357 | if (errno == ENOENT) |
| 5358 | write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n" ); |
| 5359 | return false; |
| 5360 | } |
| 5361 | |
| 5362 | /* |
| 5363 | * Find the configuration file: if config_file was specified on the |
| 5364 | * command line, use it, else use configdir/postgresql.conf. In any case |
| 5365 | * ensure the result is an absolute path, so that it will be interpreted |
| 5366 | * the same way by future backends. |
| 5367 | */ |
| 5368 | if (ConfigFileName) |
| 5369 | fname = make_absolute_path(ConfigFileName); |
| 5370 | else if (configdir) |
| 5371 | { |
| 5372 | fname = guc_malloc(FATAL, |
| 5373 | strlen(configdir) + strlen(CONFIG_FILENAME) + 2); |
| 5374 | sprintf(fname, "%s/%s" , configdir, CONFIG_FILENAME); |
| 5375 | } |
| 5376 | else |
| 5377 | { |
| 5378 | write_stderr("%s does not know where to find the server configuration file.\n" |
| 5379 | "You must specify the --config-file or -D invocation " |
| 5380 | "option or set the PGDATA environment variable.\n" , |
| 5381 | progname); |
| 5382 | return false; |
| 5383 | } |
| 5384 | |
| 5385 | /* |
| 5386 | * Set the ConfigFileName GUC variable to its final value, ensuring that |
| 5387 | * it can't be overridden later. |
| 5388 | */ |
| 5389 | SetConfigOption("config_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5390 | free(fname); |
| 5391 | |
| 5392 | /* |
| 5393 | * Now read the config file for the first time. |
| 5394 | */ |
| 5395 | if (stat(ConfigFileName, &stat_buf) != 0) |
| 5396 | { |
| 5397 | write_stderr("%s: could not access the server configuration file \"%s\": %s\n" , |
| 5398 | progname, ConfigFileName, strerror(errno)); |
| 5399 | free(configdir); |
| 5400 | return false; |
| 5401 | } |
| 5402 | |
| 5403 | /* |
| 5404 | * Read the configuration file for the first time. This time only the |
| 5405 | * data_directory parameter is picked up to determine the data directory, |
| 5406 | * so that we can read the PG_AUTOCONF_FILENAME file next time. |
| 5407 | */ |
| 5408 | ProcessConfigFile(PGC_POSTMASTER); |
| 5409 | |
| 5410 | /* |
| 5411 | * If the data_directory GUC variable has been set, use that as DataDir; |
| 5412 | * otherwise use configdir if set; else punt. |
| 5413 | * |
| 5414 | * Note: SetDataDir will copy and absolute-ize its argument, so we don't |
| 5415 | * have to. |
| 5416 | */ |
| 5417 | if (data_directory) |
| 5418 | SetDataDir(data_directory); |
| 5419 | else if (configdir) |
| 5420 | SetDataDir(configdir); |
| 5421 | else |
| 5422 | { |
| 5423 | write_stderr("%s does not know where to find the database system data.\n" |
| 5424 | "This can be specified as \"data_directory\" in \"%s\", " |
| 5425 | "or by the -D invocation option, or by the " |
| 5426 | "PGDATA environment variable.\n" , |
| 5427 | progname, ConfigFileName); |
| 5428 | return false; |
| 5429 | } |
| 5430 | |
| 5431 | /* |
| 5432 | * Reflect the final DataDir value back into the data_directory GUC var. |
| 5433 | * (If you are wondering why we don't just make them a single variable, |
| 5434 | * it's because the EXEC_BACKEND case needs DataDir to be transmitted to |
| 5435 | * child backends specially. XXX is that still true? Given that we now |
| 5436 | * chdir to DataDir, EXEC_BACKEND can read the config file without knowing |
| 5437 | * DataDir in advance.) |
| 5438 | */ |
| 5439 | SetConfigOption("data_directory" , DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5440 | |
| 5441 | /* |
| 5442 | * Now read the config file a second time, allowing any settings in the |
| 5443 | * PG_AUTOCONF_FILENAME file to take effect. (This is pretty ugly, but |
| 5444 | * since we have to determine the DataDir before we can find the autoconf |
| 5445 | * file, the alternatives seem worse.) |
| 5446 | */ |
| 5447 | ProcessConfigFile(PGC_POSTMASTER); |
| 5448 | |
| 5449 | /* |
| 5450 | * If timezone_abbreviations wasn't set in the configuration file, install |
| 5451 | * the default value. We do it this way because we can't safely install a |
| 5452 | * "real" value until my_exec_path is set, which may not have happened |
| 5453 | * when InitializeGUCOptions runs, so the bootstrap default value cannot |
| 5454 | * be the real desired default. |
| 5455 | */ |
| 5456 | pg_timezone_abbrev_initialize(); |
| 5457 | |
| 5458 | /* |
| 5459 | * Figure out where pg_hba.conf is, and make sure the path is absolute. |
| 5460 | */ |
| 5461 | if (HbaFileName) |
| 5462 | fname = make_absolute_path(HbaFileName); |
| 5463 | else if (configdir) |
| 5464 | { |
| 5465 | fname = guc_malloc(FATAL, |
| 5466 | strlen(configdir) + strlen(HBA_FILENAME) + 2); |
| 5467 | sprintf(fname, "%s/%s" , configdir, HBA_FILENAME); |
| 5468 | } |
| 5469 | else |
| 5470 | { |
| 5471 | write_stderr("%s does not know where to find the \"hba\" configuration file.\n" |
| 5472 | "This can be specified as \"hba_file\" in \"%s\", " |
| 5473 | "or by the -D invocation option, or by the " |
| 5474 | "PGDATA environment variable.\n" , |
| 5475 | progname, ConfigFileName); |
| 5476 | return false; |
| 5477 | } |
| 5478 | SetConfigOption("hba_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5479 | free(fname); |
| 5480 | |
| 5481 | /* |
| 5482 | * Likewise for pg_ident.conf. |
| 5483 | */ |
| 5484 | if (IdentFileName) |
| 5485 | fname = make_absolute_path(IdentFileName); |
| 5486 | else if (configdir) |
| 5487 | { |
| 5488 | fname = guc_malloc(FATAL, |
| 5489 | strlen(configdir) + strlen(IDENT_FILENAME) + 2); |
| 5490 | sprintf(fname, "%s/%s" , configdir, IDENT_FILENAME); |
| 5491 | } |
| 5492 | else |
| 5493 | { |
| 5494 | write_stderr("%s does not know where to find the \"ident\" configuration file.\n" |
| 5495 | "This can be specified as \"ident_file\" in \"%s\", " |
| 5496 | "or by the -D invocation option, or by the " |
| 5497 | "PGDATA environment variable.\n" , |
| 5498 | progname, ConfigFileName); |
| 5499 | return false; |
| 5500 | } |
| 5501 | SetConfigOption("ident_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
| 5502 | free(fname); |
| 5503 | |
| 5504 | free(configdir); |
| 5505 | |
| 5506 | return true; |
| 5507 | } |
| 5508 | |
| 5509 | |
| 5510 | /* |
| 5511 | * Reset all options to their saved default values (implements RESET ALL) |
| 5512 | */ |
| 5513 | void |
| 5514 | ResetAllOptions(void) |
| 5515 | { |
| 5516 | int i; |
| 5517 | |
| 5518 | for (i = 0; i < num_guc_variables; i++) |
| 5519 | { |
| 5520 | struct config_generic *gconf = guc_variables[i]; |
| 5521 | |
| 5522 | /* Don't reset non-SET-able values */ |
| 5523 | if (gconf->context != PGC_SUSET && |
| 5524 | gconf->context != PGC_USERSET) |
| 5525 | continue; |
| 5526 | /* Don't reset if special exclusion from RESET ALL */ |
| 5527 | if (gconf->flags & GUC_NO_RESET_ALL) |
| 5528 | continue; |
| 5529 | /* No need to reset if wasn't SET */ |
| 5530 | if (gconf->source <= PGC_S_OVERRIDE) |
| 5531 | continue; |
| 5532 | |
| 5533 | /* Save old value to support transaction abort */ |
| 5534 | push_old_value(gconf, GUC_ACTION_SET); |
| 5535 | |
| 5536 | switch (gconf->vartype) |
| 5537 | { |
| 5538 | case PGC_BOOL: |
| 5539 | { |
| 5540 | struct config_bool *conf = (struct config_bool *) gconf; |
| 5541 | |
| 5542 | if (conf->assign_hook) |
| 5543 | conf->assign_hook(conf->reset_val, |
| 5544 | conf->reset_extra); |
| 5545 | *conf->variable = conf->reset_val; |
| 5546 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5547 | conf->reset_extra); |
| 5548 | break; |
| 5549 | } |
| 5550 | case PGC_INT: |
| 5551 | { |
| 5552 | struct config_int *conf = (struct config_int *) gconf; |
| 5553 | |
| 5554 | if (conf->assign_hook) |
| 5555 | conf->assign_hook(conf->reset_val, |
| 5556 | conf->reset_extra); |
| 5557 | *conf->variable = conf->reset_val; |
| 5558 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5559 | conf->reset_extra); |
| 5560 | break; |
| 5561 | } |
| 5562 | case PGC_REAL: |
| 5563 | { |
| 5564 | struct config_real *conf = (struct config_real *) gconf; |
| 5565 | |
| 5566 | if (conf->assign_hook) |
| 5567 | conf->assign_hook(conf->reset_val, |
| 5568 | conf->reset_extra); |
| 5569 | *conf->variable = conf->reset_val; |
| 5570 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5571 | conf->reset_extra); |
| 5572 | break; |
| 5573 | } |
| 5574 | case PGC_STRING: |
| 5575 | { |
| 5576 | struct config_string *conf = (struct config_string *) gconf; |
| 5577 | |
| 5578 | if (conf->assign_hook) |
| 5579 | conf->assign_hook(conf->reset_val, |
| 5580 | conf->reset_extra); |
| 5581 | set_string_field(conf, conf->variable, conf->reset_val); |
| 5582 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5583 | conf->reset_extra); |
| 5584 | break; |
| 5585 | } |
| 5586 | case PGC_ENUM: |
| 5587 | { |
| 5588 | struct config_enum *conf = (struct config_enum *) gconf; |
| 5589 | |
| 5590 | if (conf->assign_hook) |
| 5591 | conf->assign_hook(conf->reset_val, |
| 5592 | conf->reset_extra); |
| 5593 | *conf->variable = conf->reset_val; |
| 5594 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5595 | conf->reset_extra); |
| 5596 | break; |
| 5597 | } |
| 5598 | } |
| 5599 | |
| 5600 | gconf->source = gconf->reset_source; |
| 5601 | gconf->scontext = gconf->reset_scontext; |
| 5602 | |
| 5603 | if (gconf->flags & GUC_REPORT) |
| 5604 | ReportGUCOption(gconf); |
| 5605 | } |
| 5606 | } |
| 5607 | |
| 5608 | |
| 5609 | /* |
| 5610 | * push_old_value |
| 5611 | * Push previous state during transactional assignment to a GUC variable. |
| 5612 | */ |
| 5613 | static void |
| 5614 | push_old_value(struct config_generic *gconf, GucAction action) |
| 5615 | { |
| 5616 | GucStack *stack; |
| 5617 | |
| 5618 | /* If we're not inside a nest level, do nothing */ |
| 5619 | if (GUCNestLevel == 0) |
| 5620 | return; |
| 5621 | |
| 5622 | /* Do we already have a stack entry of the current nest level? */ |
| 5623 | stack = gconf->stack; |
| 5624 | if (stack && stack->nest_level >= GUCNestLevel) |
| 5625 | { |
| 5626 | /* Yes, so adjust its state if necessary */ |
| 5627 | Assert(stack->nest_level == GUCNestLevel); |
| 5628 | switch (action) |
| 5629 | { |
| 5630 | case GUC_ACTION_SET: |
| 5631 | /* SET overrides any prior action at same nest level */ |
| 5632 | if (stack->state == GUC_SET_LOCAL) |
| 5633 | { |
| 5634 | /* must discard old masked value */ |
| 5635 | discard_stack_value(gconf, &stack->masked); |
| 5636 | } |
| 5637 | stack->state = GUC_SET; |
| 5638 | break; |
| 5639 | case GUC_ACTION_LOCAL: |
| 5640 | if (stack->state == GUC_SET) |
| 5641 | { |
| 5642 | /* SET followed by SET LOCAL, remember SET's value */ |
| 5643 | stack->masked_scontext = gconf->scontext; |
| 5644 | set_stack_value(gconf, &stack->masked); |
| 5645 | stack->state = GUC_SET_LOCAL; |
| 5646 | } |
| 5647 | /* in all other cases, no change to stack entry */ |
| 5648 | break; |
| 5649 | case GUC_ACTION_SAVE: |
| 5650 | /* Could only have a prior SAVE of same variable */ |
| 5651 | Assert(stack->state == GUC_SAVE); |
| 5652 | break; |
| 5653 | } |
| 5654 | Assert(guc_dirty); /* must be set already */ |
| 5655 | return; |
| 5656 | } |
| 5657 | |
| 5658 | /* |
| 5659 | * Push a new stack entry |
| 5660 | * |
| 5661 | * We keep all the stack entries in TopTransactionContext for simplicity. |
| 5662 | */ |
| 5663 | stack = (GucStack *) MemoryContextAllocZero(TopTransactionContext, |
| 5664 | sizeof(GucStack)); |
| 5665 | |
| 5666 | stack->prev = gconf->stack; |
| 5667 | stack->nest_level = GUCNestLevel; |
| 5668 | switch (action) |
| 5669 | { |
| 5670 | case GUC_ACTION_SET: |
| 5671 | stack->state = GUC_SET; |
| 5672 | break; |
| 5673 | case GUC_ACTION_LOCAL: |
| 5674 | stack->state = GUC_LOCAL; |
| 5675 | break; |
| 5676 | case GUC_ACTION_SAVE: |
| 5677 | stack->state = GUC_SAVE; |
| 5678 | break; |
| 5679 | } |
| 5680 | stack->source = gconf->source; |
| 5681 | stack->scontext = gconf->scontext; |
| 5682 | set_stack_value(gconf, &stack->prior); |
| 5683 | |
| 5684 | gconf->stack = stack; |
| 5685 | |
| 5686 | /* Ensure we remember to pop at end of xact */ |
| 5687 | guc_dirty = true; |
| 5688 | } |
| 5689 | |
| 5690 | |
| 5691 | /* |
| 5692 | * Do GUC processing at main transaction start. |
| 5693 | */ |
| 5694 | void |
| 5695 | AtStart_GUC(void) |
| 5696 | { |
| 5697 | /* |
| 5698 | * The nest level should be 0 between transactions; if it isn't, somebody |
| 5699 | * didn't call AtEOXact_GUC, or called it with the wrong nestLevel. We |
| 5700 | * throw a warning but make no other effort to clean up. |
| 5701 | */ |
| 5702 | if (GUCNestLevel != 0) |
| 5703 | elog(WARNING, "GUC nest level = %d at transaction start" , |
| 5704 | GUCNestLevel); |
| 5705 | GUCNestLevel = 1; |
| 5706 | } |
| 5707 | |
| 5708 | /* |
| 5709 | * Enter a new nesting level for GUC values. This is called at subtransaction |
| 5710 | * start, and when entering a function that has proconfig settings, and in |
| 5711 | * some other places where we want to set GUC variables transiently. |
| 5712 | * NOTE we must not risk error here, else subtransaction start will be unhappy. |
| 5713 | */ |
| 5714 | int |
| 5715 | NewGUCNestLevel(void) |
| 5716 | { |
| 5717 | return ++GUCNestLevel; |
| 5718 | } |
| 5719 | |
| 5720 | /* |
| 5721 | * Do GUC processing at transaction or subtransaction commit or abort, or |
| 5722 | * when exiting a function that has proconfig settings, or when undoing a |
| 5723 | * transient assignment to some GUC variables. (The name is thus a bit of |
| 5724 | * a misnomer; perhaps it should be ExitGUCNestLevel or some such.) |
| 5725 | * During abort, we discard all GUC settings that were applied at nesting |
| 5726 | * levels >= nestLevel. nestLevel == 1 corresponds to the main transaction. |
| 5727 | */ |
| 5728 | void |
| 5729 | AtEOXact_GUC(bool isCommit, int nestLevel) |
| 5730 | { |
| 5731 | bool still_dirty; |
| 5732 | int i; |
| 5733 | |
| 5734 | /* |
| 5735 | * Note: it's possible to get here with GUCNestLevel == nestLevel-1 during |
| 5736 | * abort, if there is a failure during transaction start before |
| 5737 | * AtStart_GUC is called. |
| 5738 | */ |
| 5739 | Assert(nestLevel > 0 && |
| 5740 | (nestLevel <= GUCNestLevel || |
| 5741 | (nestLevel == GUCNestLevel + 1 && !isCommit))); |
| 5742 | |
| 5743 | /* Quick exit if nothing's changed in this transaction */ |
| 5744 | if (!guc_dirty) |
| 5745 | { |
| 5746 | GUCNestLevel = nestLevel - 1; |
| 5747 | return; |
| 5748 | } |
| 5749 | |
| 5750 | still_dirty = false; |
| 5751 | for (i = 0; i < num_guc_variables; i++) |
| 5752 | { |
| 5753 | struct config_generic *gconf = guc_variables[i]; |
| 5754 | GucStack *stack; |
| 5755 | |
| 5756 | /* |
| 5757 | * Process and pop each stack entry within the nest level. To simplify |
| 5758 | * fmgr_security_definer() and other places that use GUC_ACTION_SAVE, |
| 5759 | * we allow failure exit from code that uses a local nest level to be |
| 5760 | * recovered at the surrounding transaction or subtransaction abort; |
| 5761 | * so there could be more than one stack entry to pop. |
| 5762 | */ |
| 5763 | while ((stack = gconf->stack) != NULL && |
| 5764 | stack->nest_level >= nestLevel) |
| 5765 | { |
| 5766 | GucStack *prev = stack->prev; |
| 5767 | bool restorePrior = false; |
| 5768 | bool restoreMasked = false; |
| 5769 | bool changed; |
| 5770 | |
| 5771 | /* |
| 5772 | * In this next bit, if we don't set either restorePrior or |
| 5773 | * restoreMasked, we must "discard" any unwanted fields of the |
| 5774 | * stack entries to avoid leaking memory. If we do set one of |
| 5775 | * those flags, unused fields will be cleaned up after restoring. |
| 5776 | */ |
| 5777 | if (!isCommit) /* if abort, always restore prior value */ |
| 5778 | restorePrior = true; |
| 5779 | else if (stack->state == GUC_SAVE) |
| 5780 | restorePrior = true; |
| 5781 | else if (stack->nest_level == 1) |
| 5782 | { |
| 5783 | /* transaction commit */ |
| 5784 | if (stack->state == GUC_SET_LOCAL) |
| 5785 | restoreMasked = true; |
| 5786 | else if (stack->state == GUC_SET) |
| 5787 | { |
| 5788 | /* we keep the current active value */ |
| 5789 | discard_stack_value(gconf, &stack->prior); |
| 5790 | } |
| 5791 | else /* must be GUC_LOCAL */ |
| 5792 | restorePrior = true; |
| 5793 | } |
| 5794 | else if (prev == NULL || |
| 5795 | prev->nest_level < stack->nest_level - 1) |
| 5796 | { |
| 5797 | /* decrement entry's level and do not pop it */ |
| 5798 | stack->nest_level--; |
| 5799 | continue; |
| 5800 | } |
| 5801 | else |
| 5802 | { |
| 5803 | /* |
| 5804 | * We have to merge this stack entry into prev. See README for |
| 5805 | * discussion of this bit. |
| 5806 | */ |
| 5807 | switch (stack->state) |
| 5808 | { |
| 5809 | case GUC_SAVE: |
| 5810 | Assert(false); /* can't get here */ |
| 5811 | break; |
| 5812 | |
| 5813 | case GUC_SET: |
| 5814 | /* next level always becomes SET */ |
| 5815 | discard_stack_value(gconf, &stack->prior); |
| 5816 | if (prev->state == GUC_SET_LOCAL) |
| 5817 | discard_stack_value(gconf, &prev->masked); |
| 5818 | prev->state = GUC_SET; |
| 5819 | break; |
| 5820 | |
| 5821 | case GUC_LOCAL: |
| 5822 | if (prev->state == GUC_SET) |
| 5823 | { |
| 5824 | /* LOCAL migrates down */ |
| 5825 | prev->masked_scontext = stack->scontext; |
| 5826 | prev->masked = stack->prior; |
| 5827 | prev->state = GUC_SET_LOCAL; |
| 5828 | } |
| 5829 | else |
| 5830 | { |
| 5831 | /* else just forget this stack level */ |
| 5832 | discard_stack_value(gconf, &stack->prior); |
| 5833 | } |
| 5834 | break; |
| 5835 | |
| 5836 | case GUC_SET_LOCAL: |
| 5837 | /* prior state at this level no longer wanted */ |
| 5838 | discard_stack_value(gconf, &stack->prior); |
| 5839 | /* copy down the masked state */ |
| 5840 | prev->masked_scontext = stack->masked_scontext; |
| 5841 | if (prev->state == GUC_SET_LOCAL) |
| 5842 | discard_stack_value(gconf, &prev->masked); |
| 5843 | prev->masked = stack->masked; |
| 5844 | prev->state = GUC_SET_LOCAL; |
| 5845 | break; |
| 5846 | } |
| 5847 | } |
| 5848 | |
| 5849 | changed = false; |
| 5850 | |
| 5851 | if (restorePrior || restoreMasked) |
| 5852 | { |
| 5853 | /* Perform appropriate restoration of the stacked value */ |
| 5854 | config_var_value newvalue; |
| 5855 | GucSource newsource; |
| 5856 | GucContext newscontext; |
| 5857 | |
| 5858 | if (restoreMasked) |
| 5859 | { |
| 5860 | newvalue = stack->masked; |
| 5861 | newsource = PGC_S_SESSION; |
| 5862 | newscontext = stack->masked_scontext; |
| 5863 | } |
| 5864 | else |
| 5865 | { |
| 5866 | newvalue = stack->prior; |
| 5867 | newsource = stack->source; |
| 5868 | newscontext = stack->scontext; |
| 5869 | } |
| 5870 | |
| 5871 | switch (gconf->vartype) |
| 5872 | { |
| 5873 | case PGC_BOOL: |
| 5874 | { |
| 5875 | struct config_bool *conf = (struct config_bool *) gconf; |
| 5876 | bool newval = newvalue.val.boolval; |
| 5877 | void * = newvalue.extra; |
| 5878 | |
| 5879 | if (*conf->variable != newval || |
| 5880 | conf->gen.extra != newextra) |
| 5881 | { |
| 5882 | if (conf->assign_hook) |
| 5883 | conf->assign_hook(newval, newextra); |
| 5884 | *conf->variable = newval; |
| 5885 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5886 | newextra); |
| 5887 | changed = true; |
| 5888 | } |
| 5889 | break; |
| 5890 | } |
| 5891 | case PGC_INT: |
| 5892 | { |
| 5893 | struct config_int *conf = (struct config_int *) gconf; |
| 5894 | int newval = newvalue.val.intval; |
| 5895 | void * = newvalue.extra; |
| 5896 | |
| 5897 | if (*conf->variable != newval || |
| 5898 | conf->gen.extra != newextra) |
| 5899 | { |
| 5900 | if (conf->assign_hook) |
| 5901 | conf->assign_hook(newval, newextra); |
| 5902 | *conf->variable = newval; |
| 5903 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5904 | newextra); |
| 5905 | changed = true; |
| 5906 | } |
| 5907 | break; |
| 5908 | } |
| 5909 | case PGC_REAL: |
| 5910 | { |
| 5911 | struct config_real *conf = (struct config_real *) gconf; |
| 5912 | double newval = newvalue.val.realval; |
| 5913 | void * = newvalue.extra; |
| 5914 | |
| 5915 | if (*conf->variable != newval || |
| 5916 | conf->gen.extra != newextra) |
| 5917 | { |
| 5918 | if (conf->assign_hook) |
| 5919 | conf->assign_hook(newval, newextra); |
| 5920 | *conf->variable = newval; |
| 5921 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5922 | newextra); |
| 5923 | changed = true; |
| 5924 | } |
| 5925 | break; |
| 5926 | } |
| 5927 | case PGC_STRING: |
| 5928 | { |
| 5929 | struct config_string *conf = (struct config_string *) gconf; |
| 5930 | char *newval = newvalue.val.stringval; |
| 5931 | void * = newvalue.extra; |
| 5932 | |
| 5933 | if (*conf->variable != newval || |
| 5934 | conf->gen.extra != newextra) |
| 5935 | { |
| 5936 | if (conf->assign_hook) |
| 5937 | conf->assign_hook(newval, newextra); |
| 5938 | set_string_field(conf, conf->variable, newval); |
| 5939 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5940 | newextra); |
| 5941 | changed = true; |
| 5942 | } |
| 5943 | |
| 5944 | /* |
| 5945 | * Release stacked values if not used anymore. We |
| 5946 | * could use discard_stack_value() here, but since |
| 5947 | * we have type-specific code anyway, might as |
| 5948 | * well inline it. |
| 5949 | */ |
| 5950 | set_string_field(conf, &stack->prior.val.stringval, NULL); |
| 5951 | set_string_field(conf, &stack->masked.val.stringval, NULL); |
| 5952 | break; |
| 5953 | } |
| 5954 | case PGC_ENUM: |
| 5955 | { |
| 5956 | struct config_enum *conf = (struct config_enum *) gconf; |
| 5957 | int newval = newvalue.val.enumval; |
| 5958 | void * = newvalue.extra; |
| 5959 | |
| 5960 | if (*conf->variable != newval || |
| 5961 | conf->gen.extra != newextra) |
| 5962 | { |
| 5963 | if (conf->assign_hook) |
| 5964 | conf->assign_hook(newval, newextra); |
| 5965 | *conf->variable = newval; |
| 5966 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 5967 | newextra); |
| 5968 | changed = true; |
| 5969 | } |
| 5970 | break; |
| 5971 | } |
| 5972 | } |
| 5973 | |
| 5974 | /* |
| 5975 | * Release stacked extra values if not used anymore. |
| 5976 | */ |
| 5977 | set_extra_field(gconf, &(stack->prior.extra), NULL); |
| 5978 | set_extra_field(gconf, &(stack->masked.extra), NULL); |
| 5979 | |
| 5980 | /* And restore source information */ |
| 5981 | gconf->source = newsource; |
| 5982 | gconf->scontext = newscontext; |
| 5983 | } |
| 5984 | |
| 5985 | /* Finish popping the state stack */ |
| 5986 | gconf->stack = prev; |
| 5987 | pfree(stack); |
| 5988 | |
| 5989 | /* Report new value if we changed it */ |
| 5990 | if (changed && (gconf->flags & GUC_REPORT)) |
| 5991 | ReportGUCOption(gconf); |
| 5992 | } /* end of stack-popping loop */ |
| 5993 | |
| 5994 | if (stack != NULL) |
| 5995 | still_dirty = true; |
| 5996 | } |
| 5997 | |
| 5998 | /* If there are no remaining stack entries, we can reset guc_dirty */ |
| 5999 | guc_dirty = still_dirty; |
| 6000 | |
| 6001 | /* Update nesting level */ |
| 6002 | GUCNestLevel = nestLevel - 1; |
| 6003 | } |
| 6004 | |
| 6005 | |
| 6006 | /* |
| 6007 | * Start up automatic reporting of changes to variables marked GUC_REPORT. |
| 6008 | * This is executed at completion of backend startup. |
| 6009 | */ |
| 6010 | void |
| 6011 | BeginReportingGUCOptions(void) |
| 6012 | { |
| 6013 | int i; |
| 6014 | |
| 6015 | /* |
| 6016 | * Don't do anything unless talking to an interactive frontend of protocol |
| 6017 | * 3.0 or later. |
| 6018 | */ |
| 6019 | if (whereToSendOutput != DestRemote || |
| 6020 | PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) |
| 6021 | return; |
| 6022 | |
| 6023 | reporting_enabled = true; |
| 6024 | |
| 6025 | /* Transmit initial values of interesting variables */ |
| 6026 | for (i = 0; i < num_guc_variables; i++) |
| 6027 | { |
| 6028 | struct config_generic *conf = guc_variables[i]; |
| 6029 | |
| 6030 | if (conf->flags & GUC_REPORT) |
| 6031 | ReportGUCOption(conf); |
| 6032 | } |
| 6033 | } |
| 6034 | |
| 6035 | /* |
| 6036 | * ReportGUCOption: if appropriate, transmit option value to frontend |
| 6037 | */ |
| 6038 | static void |
| 6039 | ReportGUCOption(struct config_generic *record) |
| 6040 | { |
| 6041 | if (reporting_enabled && (record->flags & GUC_REPORT)) |
| 6042 | { |
| 6043 | char *val = _ShowOption(record, false); |
| 6044 | StringInfoData msgbuf; |
| 6045 | |
| 6046 | pq_beginmessage(&msgbuf, 'S'); |
| 6047 | pq_sendstring(&msgbuf, record->name); |
| 6048 | pq_sendstring(&msgbuf, val); |
| 6049 | pq_endmessage(&msgbuf); |
| 6050 | |
| 6051 | pfree(val); |
| 6052 | } |
| 6053 | } |
| 6054 | |
| 6055 | /* |
| 6056 | * Convert a value from one of the human-friendly units ("kB", "min" etc.) |
| 6057 | * to the given base unit. 'value' and 'unit' are the input value and unit |
| 6058 | * to convert from (there can be trailing spaces in the unit string). |
| 6059 | * The converted value is stored in *base_value. |
| 6060 | * It's caller's responsibility to round off the converted value as necessary |
| 6061 | * and check for out-of-range. |
| 6062 | * |
| 6063 | * Returns true on success, false if the input unit is not recognized. |
| 6064 | */ |
| 6065 | static bool |
| 6066 | convert_to_base_unit(double value, const char *unit, |
| 6067 | int base_unit, double *base_value) |
| 6068 | { |
| 6069 | char unitstr[MAX_UNIT_LEN + 1]; |
| 6070 | int unitlen; |
| 6071 | const unit_conversion *table; |
| 6072 | int i; |
| 6073 | |
| 6074 | /* extract unit string to compare to table entries */ |
| 6075 | unitlen = 0; |
| 6076 | while (*unit != '\0' && !isspace((unsigned char) *unit) && |
| 6077 | unitlen < MAX_UNIT_LEN) |
| 6078 | unitstr[unitlen++] = *(unit++); |
| 6079 | unitstr[unitlen] = '\0'; |
| 6080 | /* allow whitespace after unit */ |
| 6081 | while (isspace((unsigned char) *unit)) |
| 6082 | unit++; |
| 6083 | if (*unit != '\0') |
| 6084 | return false; /* unit too long, or garbage after it */ |
| 6085 | |
| 6086 | /* now search the appropriate table */ |
| 6087 | if (base_unit & GUC_UNIT_MEMORY) |
| 6088 | table = memory_unit_conversion_table; |
| 6089 | else |
| 6090 | table = time_unit_conversion_table; |
| 6091 | |
| 6092 | for (i = 0; *table[i].unit; i++) |
| 6093 | { |
| 6094 | if (base_unit == table[i].base_unit && |
| 6095 | strcmp(unitstr, table[i].unit) == 0) |
| 6096 | { |
| 6097 | double cvalue = value * table[i].multiplier; |
| 6098 | |
| 6099 | /* |
| 6100 | * If the user gave a fractional value such as "30.1GB", round it |
| 6101 | * off to the nearest multiple of the next smaller unit, if there |
| 6102 | * is one. |
| 6103 | */ |
| 6104 | if (*table[i + 1].unit && |
| 6105 | base_unit == table[i + 1].base_unit) |
| 6106 | cvalue = rint(cvalue / table[i + 1].multiplier) * |
| 6107 | table[i + 1].multiplier; |
| 6108 | |
| 6109 | *base_value = cvalue; |
| 6110 | return true; |
| 6111 | } |
| 6112 | } |
| 6113 | return false; |
| 6114 | } |
| 6115 | |
| 6116 | /* |
| 6117 | * Convert an integer value in some base unit to a human-friendly unit. |
| 6118 | * |
| 6119 | * The output unit is chosen so that it's the greatest unit that can represent |
| 6120 | * the value without loss. For example, if the base unit is GUC_UNIT_KB, 1024 |
| 6121 | * is converted to 1 MB, but 1025 is represented as 1025 kB. |
| 6122 | */ |
| 6123 | static void |
| 6124 | convert_int_from_base_unit(int64 base_value, int base_unit, |
| 6125 | int64 *value, const char **unit) |
| 6126 | { |
| 6127 | const unit_conversion *table; |
| 6128 | int i; |
| 6129 | |
| 6130 | *unit = NULL; |
| 6131 | |
| 6132 | if (base_unit & GUC_UNIT_MEMORY) |
| 6133 | table = memory_unit_conversion_table; |
| 6134 | else |
| 6135 | table = time_unit_conversion_table; |
| 6136 | |
| 6137 | for (i = 0; *table[i].unit; i++) |
| 6138 | { |
| 6139 | if (base_unit == table[i].base_unit) |
| 6140 | { |
| 6141 | /* |
| 6142 | * Accept the first conversion that divides the value evenly. We |
| 6143 | * assume that the conversions for each base unit are ordered from |
| 6144 | * greatest unit to the smallest! |
| 6145 | */ |
| 6146 | if (table[i].multiplier <= 1.0 || |
| 6147 | base_value % (int64) table[i].multiplier == 0) |
| 6148 | { |
| 6149 | *value = (int64) rint(base_value / table[i].multiplier); |
| 6150 | *unit = table[i].unit; |
| 6151 | break; |
| 6152 | } |
| 6153 | } |
| 6154 | } |
| 6155 | |
| 6156 | Assert(*unit != NULL); |
| 6157 | } |
| 6158 | |
| 6159 | /* |
| 6160 | * Convert a floating-point value in some base unit to a human-friendly unit. |
| 6161 | * |
| 6162 | * Same as above, except we have to do the math a bit differently, and |
| 6163 | * there's a possibility that we don't find any exact divisor. |
| 6164 | */ |
| 6165 | static void |
| 6166 | convert_real_from_base_unit(double base_value, int base_unit, |
| 6167 | double *value, const char **unit) |
| 6168 | { |
| 6169 | const unit_conversion *table; |
| 6170 | int i; |
| 6171 | |
| 6172 | *unit = NULL; |
| 6173 | |
| 6174 | if (base_unit & GUC_UNIT_MEMORY) |
| 6175 | table = memory_unit_conversion_table; |
| 6176 | else |
| 6177 | table = time_unit_conversion_table; |
| 6178 | |
| 6179 | for (i = 0; *table[i].unit; i++) |
| 6180 | { |
| 6181 | if (base_unit == table[i].base_unit) |
| 6182 | { |
| 6183 | /* |
| 6184 | * Accept the first conversion that divides the value evenly; or |
| 6185 | * if there is none, use the smallest (last) target unit. |
| 6186 | * |
| 6187 | * What we actually care about here is whether snprintf with "%g" |
| 6188 | * will print the value as an integer, so the obvious test of |
| 6189 | * "*value == rint(*value)" is too strict; roundoff error might |
| 6190 | * make us choose an unreasonably small unit. As a compromise, |
| 6191 | * accept a divisor that is within 1e-8 of producing an integer. |
| 6192 | */ |
| 6193 | *value = base_value / table[i].multiplier; |
| 6194 | *unit = table[i].unit; |
| 6195 | if (*value > 0 && |
| 6196 | fabs((rint(*value) / *value) - 1.0) <= 1e-8) |
| 6197 | break; |
| 6198 | } |
| 6199 | } |
| 6200 | |
| 6201 | Assert(*unit != NULL); |
| 6202 | } |
| 6203 | |
| 6204 | /* |
| 6205 | * Return the name of a GUC's base unit (e.g. "ms") given its flags. |
| 6206 | * Return NULL if the GUC is unitless. |
| 6207 | */ |
| 6208 | static const char * |
| 6209 | get_config_unit_name(int flags) |
| 6210 | { |
| 6211 | switch (flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)) |
| 6212 | { |
| 6213 | case 0: |
| 6214 | return NULL; /* GUC has no units */ |
| 6215 | case GUC_UNIT_BYTE: |
| 6216 | return "B" ; |
| 6217 | case GUC_UNIT_KB: |
| 6218 | return "kB" ; |
| 6219 | case GUC_UNIT_MB: |
| 6220 | return "MB" ; |
| 6221 | case GUC_UNIT_BLOCKS: |
| 6222 | { |
| 6223 | static char bbuf[8]; |
| 6224 | |
| 6225 | /* initialize if first time through */ |
| 6226 | if (bbuf[0] == '\0') |
| 6227 | snprintf(bbuf, sizeof(bbuf), "%dkB" , BLCKSZ / 1024); |
| 6228 | return bbuf; |
| 6229 | } |
| 6230 | case GUC_UNIT_XBLOCKS: |
| 6231 | { |
| 6232 | static char xbuf[8]; |
| 6233 | |
| 6234 | /* initialize if first time through */ |
| 6235 | if (xbuf[0] == '\0') |
| 6236 | snprintf(xbuf, sizeof(xbuf), "%dkB" , XLOG_BLCKSZ / 1024); |
| 6237 | return xbuf; |
| 6238 | } |
| 6239 | case GUC_UNIT_MS: |
| 6240 | return "ms" ; |
| 6241 | case GUC_UNIT_S: |
| 6242 | return "s" ; |
| 6243 | case GUC_UNIT_MIN: |
| 6244 | return "min" ; |
| 6245 | default: |
| 6246 | elog(ERROR, "unrecognized GUC units value: %d" , |
| 6247 | flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)); |
| 6248 | return NULL; |
| 6249 | } |
| 6250 | } |
| 6251 | |
| 6252 | |
| 6253 | /* |
| 6254 | * Try to parse value as an integer. The accepted formats are the |
| 6255 | * usual decimal, octal, or hexadecimal formats, as well as floating-point |
| 6256 | * formats (which will be rounded to integer after any units conversion). |
| 6257 | * Optionally, the value can be followed by a unit name if "flags" indicates |
| 6258 | * a unit is allowed. |
| 6259 | * |
| 6260 | * If the string parses okay, return true, else false. |
| 6261 | * If okay and result is not NULL, return the value in *result. |
| 6262 | * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable |
| 6263 | * HINT message, or NULL if no hint provided. |
| 6264 | */ |
| 6265 | bool |
| 6266 | parse_int(const char *value, int *result, int flags, const char **hintmsg) |
| 6267 | { |
| 6268 | /* |
| 6269 | * We assume here that double is wide enough to represent any integer |
| 6270 | * value with adequate precision. |
| 6271 | */ |
| 6272 | double val; |
| 6273 | char *endptr; |
| 6274 | |
| 6275 | /* To suppress compiler warnings, always set output params */ |
| 6276 | if (result) |
| 6277 | *result = 0; |
| 6278 | if (hintmsg) |
| 6279 | *hintmsg = NULL; |
| 6280 | |
| 6281 | /* |
| 6282 | * Try to parse as an integer (allowing octal or hex input). If the |
| 6283 | * conversion stops at a decimal point or 'e', or overflows, re-parse as |
| 6284 | * float. This should work fine as long as we have no unit names starting |
| 6285 | * with 'e'. If we ever do, the test could be extended to check for a |
| 6286 | * sign or digit after 'e', but for now that's unnecessary. |
| 6287 | */ |
| 6288 | errno = 0; |
| 6289 | val = strtol(value, &endptr, 0); |
| 6290 | if (*endptr == '.' || *endptr == 'e' || *endptr == 'E' || |
| 6291 | errno == ERANGE) |
| 6292 | { |
| 6293 | errno = 0; |
| 6294 | val = strtod(value, &endptr); |
| 6295 | } |
| 6296 | |
| 6297 | if (endptr == value || errno == ERANGE) |
| 6298 | return false; /* no HINT for these cases */ |
| 6299 | |
| 6300 | /* reject NaN (infinities will fail range check below) */ |
| 6301 | if (isnan(val)) |
| 6302 | return false; /* treat same as syntax error; no HINT */ |
| 6303 | |
| 6304 | /* allow whitespace between number and unit */ |
| 6305 | while (isspace((unsigned char) *endptr)) |
| 6306 | endptr++; |
| 6307 | |
| 6308 | /* Handle possible unit */ |
| 6309 | if (*endptr != '\0') |
| 6310 | { |
| 6311 | if ((flags & GUC_UNIT) == 0) |
| 6312 | return false; /* this setting does not accept a unit */ |
| 6313 | |
| 6314 | if (!convert_to_base_unit(val, |
| 6315 | endptr, (flags & GUC_UNIT), |
| 6316 | &val)) |
| 6317 | { |
| 6318 | /* invalid unit, or garbage after the unit; set hint and fail. */ |
| 6319 | if (hintmsg) |
| 6320 | { |
| 6321 | if (flags & GUC_UNIT_MEMORY) |
| 6322 | *hintmsg = memory_units_hint; |
| 6323 | else |
| 6324 | *hintmsg = time_units_hint; |
| 6325 | } |
| 6326 | return false; |
| 6327 | } |
| 6328 | } |
| 6329 | |
| 6330 | /* Round to int, then check for overflow */ |
| 6331 | val = rint(val); |
| 6332 | |
| 6333 | if (val > INT_MAX || val < INT_MIN) |
| 6334 | { |
| 6335 | if (hintmsg) |
| 6336 | *hintmsg = gettext_noop("Value exceeds integer range." ); |
| 6337 | return false; |
| 6338 | } |
| 6339 | |
| 6340 | if (result) |
| 6341 | *result = (int) val; |
| 6342 | return true; |
| 6343 | } |
| 6344 | |
| 6345 | /* |
| 6346 | * Try to parse value as a floating point number in the usual format. |
| 6347 | * Optionally, the value can be followed by a unit name if "flags" indicates |
| 6348 | * a unit is allowed. |
| 6349 | * |
| 6350 | * If the string parses okay, return true, else false. |
| 6351 | * If okay and result is not NULL, return the value in *result. |
| 6352 | * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable |
| 6353 | * HINT message, or NULL if no hint provided. |
| 6354 | */ |
| 6355 | bool |
| 6356 | parse_real(const char *value, double *result, int flags, const char **hintmsg) |
| 6357 | { |
| 6358 | double val; |
| 6359 | char *endptr; |
| 6360 | |
| 6361 | /* To suppress compiler warnings, always set output params */ |
| 6362 | if (result) |
| 6363 | *result = 0; |
| 6364 | if (hintmsg) |
| 6365 | *hintmsg = NULL; |
| 6366 | |
| 6367 | errno = 0; |
| 6368 | val = strtod(value, &endptr); |
| 6369 | |
| 6370 | if (endptr == value || errno == ERANGE) |
| 6371 | return false; /* no HINT for these cases */ |
| 6372 | |
| 6373 | /* reject NaN (infinities will fail range checks later) */ |
| 6374 | if (isnan(val)) |
| 6375 | return false; /* treat same as syntax error; no HINT */ |
| 6376 | |
| 6377 | /* allow whitespace between number and unit */ |
| 6378 | while (isspace((unsigned char) *endptr)) |
| 6379 | endptr++; |
| 6380 | |
| 6381 | /* Handle possible unit */ |
| 6382 | if (*endptr != '\0') |
| 6383 | { |
| 6384 | if ((flags & GUC_UNIT) == 0) |
| 6385 | return false; /* this setting does not accept a unit */ |
| 6386 | |
| 6387 | if (!convert_to_base_unit(val, |
| 6388 | endptr, (flags & GUC_UNIT), |
| 6389 | &val)) |
| 6390 | { |
| 6391 | /* invalid unit, or garbage after the unit; set hint and fail. */ |
| 6392 | if (hintmsg) |
| 6393 | { |
| 6394 | if (flags & GUC_UNIT_MEMORY) |
| 6395 | *hintmsg = memory_units_hint; |
| 6396 | else |
| 6397 | *hintmsg = time_units_hint; |
| 6398 | } |
| 6399 | return false; |
| 6400 | } |
| 6401 | } |
| 6402 | |
| 6403 | if (result) |
| 6404 | *result = val; |
| 6405 | return true; |
| 6406 | } |
| 6407 | |
| 6408 | |
| 6409 | /* |
| 6410 | * Lookup the name for an enum option with the selected value. |
| 6411 | * Should only ever be called with known-valid values, so throws |
| 6412 | * an elog(ERROR) if the enum option is not found. |
| 6413 | * |
| 6414 | * The returned string is a pointer to static data and not |
| 6415 | * allocated for modification. |
| 6416 | */ |
| 6417 | const char * |
| 6418 | config_enum_lookup_by_value(struct config_enum *record, int val) |
| 6419 | { |
| 6420 | const struct config_enum_entry *entry; |
| 6421 | |
| 6422 | for (entry = record->options; entry && entry->name; entry++) |
| 6423 | { |
| 6424 | if (entry->val == val) |
| 6425 | return entry->name; |
| 6426 | } |
| 6427 | |
| 6428 | elog(ERROR, "could not find enum option %d for %s" , |
| 6429 | val, record->gen.name); |
| 6430 | return NULL; /* silence compiler */ |
| 6431 | } |
| 6432 | |
| 6433 | |
| 6434 | /* |
| 6435 | * Lookup the value for an enum option with the selected name |
| 6436 | * (case-insensitive). |
| 6437 | * If the enum option is found, sets the retval value and returns |
| 6438 | * true. If it's not found, return false and retval is set to 0. |
| 6439 | */ |
| 6440 | bool |
| 6441 | config_enum_lookup_by_name(struct config_enum *record, const char *value, |
| 6442 | int *retval) |
| 6443 | { |
| 6444 | const struct config_enum_entry *entry; |
| 6445 | |
| 6446 | for (entry = record->options; entry && entry->name; entry++) |
| 6447 | { |
| 6448 | if (pg_strcasecmp(value, entry->name) == 0) |
| 6449 | { |
| 6450 | *retval = entry->val; |
| 6451 | return true; |
| 6452 | } |
| 6453 | } |
| 6454 | |
| 6455 | *retval = 0; |
| 6456 | return false; |
| 6457 | } |
| 6458 | |
| 6459 | |
| 6460 | /* |
| 6461 | * Return a list of all available options for an enum, excluding |
| 6462 | * hidden ones, separated by the given separator. |
| 6463 | * If prefix is non-NULL, it is added before the first enum value. |
| 6464 | * If suffix is non-NULL, it is added to the end of the string. |
| 6465 | */ |
| 6466 | static char * |
| 6467 | config_enum_get_options(struct config_enum *record, const char *prefix, |
| 6468 | const char *suffix, const char *separator) |
| 6469 | { |
| 6470 | const struct config_enum_entry *entry; |
| 6471 | StringInfoData retstr; |
| 6472 | int seplen; |
| 6473 | |
| 6474 | initStringInfo(&retstr); |
| 6475 | appendStringInfoString(&retstr, prefix); |
| 6476 | |
| 6477 | seplen = strlen(separator); |
| 6478 | for (entry = record->options; entry && entry->name; entry++) |
| 6479 | { |
| 6480 | if (!entry->hidden) |
| 6481 | { |
| 6482 | appendStringInfoString(&retstr, entry->name); |
| 6483 | appendBinaryStringInfo(&retstr, separator, seplen); |
| 6484 | } |
| 6485 | } |
| 6486 | |
| 6487 | /* |
| 6488 | * All the entries may have been hidden, leaving the string empty if no |
| 6489 | * prefix was given. This indicates a broken GUC setup, since there is no |
| 6490 | * use for an enum without any values, so we just check to make sure we |
| 6491 | * don't write to invalid memory instead of actually trying to do |
| 6492 | * something smart with it. |
| 6493 | */ |
| 6494 | if (retstr.len >= seplen) |
| 6495 | { |
| 6496 | /* Replace final separator */ |
| 6497 | retstr.data[retstr.len - seplen] = '\0'; |
| 6498 | retstr.len -= seplen; |
| 6499 | } |
| 6500 | |
| 6501 | appendStringInfoString(&retstr, suffix); |
| 6502 | |
| 6503 | return retstr.data; |
| 6504 | } |
| 6505 | |
| 6506 | /* |
| 6507 | * Parse and validate a proposed value for the specified configuration |
| 6508 | * parameter. |
| 6509 | * |
| 6510 | * This does built-in checks (such as range limits for an integer parameter) |
| 6511 | * and also calls any check hook the parameter may have. |
| 6512 | * |
| 6513 | * record: GUC variable's info record |
| 6514 | * name: variable name (should match the record of course) |
| 6515 | * value: proposed value, as a string |
| 6516 | * source: identifies source of value (check hooks may need this) |
| 6517 | * elevel: level to log any error reports at |
| 6518 | * newval: on success, converted parameter value is returned here |
| 6519 | * newextra: on success, receives any "extra" data returned by check hook |
| 6520 | * (caller must initialize *newextra to NULL) |
| 6521 | * |
| 6522 | * Returns true if OK, false if not (or throws error, if elevel >= ERROR) |
| 6523 | */ |
| 6524 | static bool |
| 6525 | parse_and_validate_value(struct config_generic *record, |
| 6526 | const char *name, const char *value, |
| 6527 | GucSource source, int elevel, |
| 6528 | union config_var_val *newval, void **) |
| 6529 | { |
| 6530 | switch (record->vartype) |
| 6531 | { |
| 6532 | case PGC_BOOL: |
| 6533 | { |
| 6534 | struct config_bool *conf = (struct config_bool *) record; |
| 6535 | |
| 6536 | if (!parse_bool(value, &newval->boolval)) |
| 6537 | { |
| 6538 | ereport(elevel, |
| 6539 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6540 | errmsg("parameter \"%s\" requires a Boolean value" , |
| 6541 | name))); |
| 6542 | return false; |
| 6543 | } |
| 6544 | |
| 6545 | if (!call_bool_check_hook(conf, &newval->boolval, newextra, |
| 6546 | source, elevel)) |
| 6547 | return false; |
| 6548 | } |
| 6549 | break; |
| 6550 | case PGC_INT: |
| 6551 | { |
| 6552 | struct config_int *conf = (struct config_int *) record; |
| 6553 | const char *hintmsg; |
| 6554 | |
| 6555 | if (!parse_int(value, &newval->intval, |
| 6556 | conf->gen.flags, &hintmsg)) |
| 6557 | { |
| 6558 | ereport(elevel, |
| 6559 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6560 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 6561 | name, value), |
| 6562 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
| 6563 | return false; |
| 6564 | } |
| 6565 | |
| 6566 | if (newval->intval < conf->min || newval->intval > conf->max) |
| 6567 | { |
| 6568 | const char *unit = get_config_unit_name(conf->gen.flags); |
| 6569 | |
| 6570 | ereport(elevel, |
| 6571 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6572 | errmsg("%d%s%s is outside the valid range for parameter \"%s\" (%d .. %d)" , |
| 6573 | newval->intval, |
| 6574 | unit ? " " : "" , |
| 6575 | unit ? unit : "" , |
| 6576 | name, |
| 6577 | conf->min, conf->max))); |
| 6578 | return false; |
| 6579 | } |
| 6580 | |
| 6581 | if (!call_int_check_hook(conf, &newval->intval, newextra, |
| 6582 | source, elevel)) |
| 6583 | return false; |
| 6584 | } |
| 6585 | break; |
| 6586 | case PGC_REAL: |
| 6587 | { |
| 6588 | struct config_real *conf = (struct config_real *) record; |
| 6589 | const char *hintmsg; |
| 6590 | |
| 6591 | if (!parse_real(value, &newval->realval, |
| 6592 | conf->gen.flags, &hintmsg)) |
| 6593 | { |
| 6594 | ereport(elevel, |
| 6595 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6596 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 6597 | name, value), |
| 6598 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
| 6599 | return false; |
| 6600 | } |
| 6601 | |
| 6602 | if (newval->realval < conf->min || newval->realval > conf->max) |
| 6603 | { |
| 6604 | const char *unit = get_config_unit_name(conf->gen.flags); |
| 6605 | |
| 6606 | ereport(elevel, |
| 6607 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6608 | errmsg("%g%s%s is outside the valid range for parameter \"%s\" (%g .. %g)" , |
| 6609 | newval->realval, |
| 6610 | unit ? " " : "" , |
| 6611 | unit ? unit : "" , |
| 6612 | name, |
| 6613 | conf->min, conf->max))); |
| 6614 | return false; |
| 6615 | } |
| 6616 | |
| 6617 | if (!call_real_check_hook(conf, &newval->realval, newextra, |
| 6618 | source, elevel)) |
| 6619 | return false; |
| 6620 | } |
| 6621 | break; |
| 6622 | case PGC_STRING: |
| 6623 | { |
| 6624 | struct config_string *conf = (struct config_string *) record; |
| 6625 | |
| 6626 | /* |
| 6627 | * The value passed by the caller could be transient, so we |
| 6628 | * always strdup it. |
| 6629 | */ |
| 6630 | newval->stringval = guc_strdup(elevel, value); |
| 6631 | if (newval->stringval == NULL) |
| 6632 | return false; |
| 6633 | |
| 6634 | /* |
| 6635 | * The only built-in "parsing" check we have is to apply |
| 6636 | * truncation if GUC_IS_NAME. |
| 6637 | */ |
| 6638 | if (conf->gen.flags & GUC_IS_NAME) |
| 6639 | truncate_identifier(newval->stringval, |
| 6640 | strlen(newval->stringval), |
| 6641 | true); |
| 6642 | |
| 6643 | if (!call_string_check_hook(conf, &newval->stringval, newextra, |
| 6644 | source, elevel)) |
| 6645 | { |
| 6646 | free(newval->stringval); |
| 6647 | newval->stringval = NULL; |
| 6648 | return false; |
| 6649 | } |
| 6650 | } |
| 6651 | break; |
| 6652 | case PGC_ENUM: |
| 6653 | { |
| 6654 | struct config_enum *conf = (struct config_enum *) record; |
| 6655 | |
| 6656 | if (!config_enum_lookup_by_name(conf, value, &newval->enumval)) |
| 6657 | { |
| 6658 | char *hintmsg; |
| 6659 | |
| 6660 | hintmsg = config_enum_get_options(conf, |
| 6661 | "Available values: " , |
| 6662 | "." , ", " ); |
| 6663 | |
| 6664 | ereport(elevel, |
| 6665 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 6666 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 6667 | name, value), |
| 6668 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
| 6669 | |
| 6670 | if (hintmsg) |
| 6671 | pfree(hintmsg); |
| 6672 | return false; |
| 6673 | } |
| 6674 | |
| 6675 | if (!call_enum_check_hook(conf, &newval->enumval, newextra, |
| 6676 | source, elevel)) |
| 6677 | return false; |
| 6678 | } |
| 6679 | break; |
| 6680 | } |
| 6681 | |
| 6682 | return true; |
| 6683 | } |
| 6684 | |
| 6685 | |
| 6686 | /* |
| 6687 | * Sets option `name' to given value. |
| 6688 | * |
| 6689 | * The value should be a string, which will be parsed and converted to |
| 6690 | * the appropriate data type. The context and source parameters indicate |
| 6691 | * in which context this function is being called, so that it can apply the |
| 6692 | * access restrictions properly. |
| 6693 | * |
| 6694 | * If value is NULL, set the option to its default value (normally the |
| 6695 | * reset_val, but if source == PGC_S_DEFAULT we instead use the boot_val). |
| 6696 | * |
| 6697 | * action indicates whether to set the value globally in the session, locally |
| 6698 | * to the current top transaction, or just for the duration of a function call. |
| 6699 | * |
| 6700 | * If changeVal is false then don't really set the option but do all |
| 6701 | * the checks to see if it would work. |
| 6702 | * |
| 6703 | * elevel should normally be passed as zero, allowing this function to make |
| 6704 | * its standard choice of ereport level. However some callers need to be |
| 6705 | * able to override that choice; they should pass the ereport level to use. |
| 6706 | * |
| 6707 | * Return value: |
| 6708 | * +1: the value is valid and was successfully applied. |
| 6709 | * 0: the name or value is invalid (but see below). |
| 6710 | * -1: the value was not applied because of context, priority, or changeVal. |
| 6711 | * |
| 6712 | * If there is an error (non-existing option, invalid value) then an |
| 6713 | * ereport(ERROR) is thrown *unless* this is called for a source for which |
| 6714 | * we don't want an ERROR (currently, those are defaults, the config file, |
| 6715 | * and per-database or per-user settings, as well as callers who specify |
| 6716 | * a less-than-ERROR elevel). In those cases we write a suitable error |
| 6717 | * message via ereport() and return 0. |
| 6718 | * |
| 6719 | * See also SetConfigOption for an external interface. |
| 6720 | */ |
| 6721 | int |
| 6722 | set_config_option(const char *name, const char *value, |
| 6723 | GucContext context, GucSource source, |
| 6724 | GucAction action, bool changeVal, int elevel, |
| 6725 | bool is_reload) |
| 6726 | { |
| 6727 | struct config_generic *record; |
| 6728 | union config_var_val newval_union; |
| 6729 | void * = NULL; |
| 6730 | bool prohibitValueChange = false; |
| 6731 | bool makeDefault; |
| 6732 | |
| 6733 | if (elevel == 0) |
| 6734 | { |
| 6735 | if (source == PGC_S_DEFAULT || source == PGC_S_FILE) |
| 6736 | { |
| 6737 | /* |
| 6738 | * To avoid cluttering the log, only the postmaster bleats loudly |
| 6739 | * about problems with the config file. |
| 6740 | */ |
| 6741 | elevel = IsUnderPostmaster ? DEBUG3 : LOG; |
| 6742 | } |
| 6743 | else if (source == PGC_S_GLOBAL || |
| 6744 | source == PGC_S_DATABASE || |
| 6745 | source == PGC_S_USER || |
| 6746 | source == PGC_S_DATABASE_USER) |
| 6747 | elevel = WARNING; |
| 6748 | else |
| 6749 | elevel = ERROR; |
| 6750 | } |
| 6751 | |
| 6752 | /* |
| 6753 | * GUC_ACTION_SAVE changes are acceptable during a parallel operation, |
| 6754 | * because the current worker will also pop the change. We're probably |
| 6755 | * dealing with a function having a proconfig entry. Only the function's |
| 6756 | * body should observe the change, and peer workers do not share in the |
| 6757 | * execution of a function call started by this worker. |
| 6758 | * |
| 6759 | * Other changes might need to affect other workers, so forbid them. |
| 6760 | */ |
| 6761 | if (IsInParallelMode() && changeVal && action != GUC_ACTION_SAVE) |
| 6762 | ereport(elevel, |
| 6763 | (errcode(ERRCODE_INVALID_TRANSACTION_STATE), |
| 6764 | errmsg("cannot set parameters during a parallel operation" ))); |
| 6765 | |
| 6766 | record = find_option(name, true, elevel); |
| 6767 | if (record == NULL) |
| 6768 | { |
| 6769 | ereport(elevel, |
| 6770 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 6771 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
| 6772 | return 0; |
| 6773 | } |
| 6774 | |
| 6775 | /* |
| 6776 | * Check if the option can be set at this time. See guc.h for the precise |
| 6777 | * rules. |
| 6778 | */ |
| 6779 | switch (record->context) |
| 6780 | { |
| 6781 | case PGC_INTERNAL: |
| 6782 | if (context != PGC_INTERNAL) |
| 6783 | { |
| 6784 | ereport(elevel, |
| 6785 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 6786 | errmsg("parameter \"%s\" cannot be changed" , |
| 6787 | name))); |
| 6788 | return 0; |
| 6789 | } |
| 6790 | break; |
| 6791 | case PGC_POSTMASTER: |
| 6792 | if (context == PGC_SIGHUP) |
| 6793 | { |
| 6794 | /* |
| 6795 | * We are re-reading a PGC_POSTMASTER variable from |
| 6796 | * postgresql.conf. We can't change the setting, so we should |
| 6797 | * give a warning if the DBA tries to change it. However, |
| 6798 | * because of variant formats, canonicalization by check |
| 6799 | * hooks, etc, we can't just compare the given string directly |
| 6800 | * to what's stored. Set a flag to check below after we have |
| 6801 | * the final storable value. |
| 6802 | */ |
| 6803 | prohibitValueChange = true; |
| 6804 | } |
| 6805 | else if (context != PGC_POSTMASTER) |
| 6806 | { |
| 6807 | ereport(elevel, |
| 6808 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 6809 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 6810 | name))); |
| 6811 | return 0; |
| 6812 | } |
| 6813 | break; |
| 6814 | case PGC_SIGHUP: |
| 6815 | if (context != PGC_SIGHUP && context != PGC_POSTMASTER) |
| 6816 | { |
| 6817 | ereport(elevel, |
| 6818 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 6819 | errmsg("parameter \"%s\" cannot be changed now" , |
| 6820 | name))); |
| 6821 | return 0; |
| 6822 | } |
| 6823 | |
| 6824 | /* |
| 6825 | * Hmm, the idea of the SIGHUP context is "ought to be global, but |
| 6826 | * can be changed after postmaster start". But there's nothing |
| 6827 | * that prevents a crafty administrator from sending SIGHUP |
| 6828 | * signals to individual backends only. |
| 6829 | */ |
| 6830 | break; |
| 6831 | case PGC_SU_BACKEND: |
| 6832 | /* Reject if we're connecting but user is not superuser */ |
| 6833 | if (context == PGC_BACKEND) |
| 6834 | { |
| 6835 | ereport(elevel, |
| 6836 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 6837 | errmsg("permission denied to set parameter \"%s\"" , |
| 6838 | name))); |
| 6839 | return 0; |
| 6840 | } |
| 6841 | /* fall through to process the same as PGC_BACKEND */ |
| 6842 | /* FALLTHROUGH */ |
| 6843 | case PGC_BACKEND: |
| 6844 | if (context == PGC_SIGHUP) |
| 6845 | { |
| 6846 | /* |
| 6847 | * If a PGC_BACKEND or PGC_SU_BACKEND parameter is changed in |
| 6848 | * the config file, we want to accept the new value in the |
| 6849 | * postmaster (whence it will propagate to |
| 6850 | * subsequently-started backends), but ignore it in existing |
| 6851 | * backends. This is a tad klugy, but necessary because we |
| 6852 | * don't re-read the config file during backend start. |
| 6853 | * |
| 6854 | * In EXEC_BACKEND builds, this works differently: we load all |
| 6855 | * non-default settings from the CONFIG_EXEC_PARAMS file |
| 6856 | * during backend start. In that case we must accept |
| 6857 | * PGC_SIGHUP settings, so as to have the same value as if |
| 6858 | * we'd forked from the postmaster. This can also happen when |
| 6859 | * using RestoreGUCState() within a background worker that |
| 6860 | * needs to have the same settings as the user backend that |
| 6861 | * started it. is_reload will be true when either situation |
| 6862 | * applies. |
| 6863 | */ |
| 6864 | if (IsUnderPostmaster && !is_reload) |
| 6865 | return -1; |
| 6866 | } |
| 6867 | else if (context != PGC_POSTMASTER && |
| 6868 | context != PGC_BACKEND && |
| 6869 | context != PGC_SU_BACKEND && |
| 6870 | source != PGC_S_CLIENT) |
| 6871 | { |
| 6872 | ereport(elevel, |
| 6873 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 6874 | errmsg("parameter \"%s\" cannot be set after connection start" , |
| 6875 | name))); |
| 6876 | return 0; |
| 6877 | } |
| 6878 | break; |
| 6879 | case PGC_SUSET: |
| 6880 | if (context == PGC_USERSET || context == PGC_BACKEND) |
| 6881 | { |
| 6882 | ereport(elevel, |
| 6883 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 6884 | errmsg("permission denied to set parameter \"%s\"" , |
| 6885 | name))); |
| 6886 | return 0; |
| 6887 | } |
| 6888 | break; |
| 6889 | case PGC_USERSET: |
| 6890 | /* always okay */ |
| 6891 | break; |
| 6892 | } |
| 6893 | |
| 6894 | /* |
| 6895 | * Disallow changing GUC_NOT_WHILE_SEC_REST values if we are inside a |
| 6896 | * security restriction context. We can reject this regardless of the GUC |
| 6897 | * context or source, mainly because sources that it might be reasonable |
| 6898 | * to override for won't be seen while inside a function. |
| 6899 | * |
| 6900 | * Note: variables marked GUC_NOT_WHILE_SEC_REST should usually be marked |
| 6901 | * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this. |
| 6902 | * An exception might be made if the reset value is assumed to be "safe". |
| 6903 | * |
| 6904 | * Note: this flag is currently used for "session_authorization" and |
| 6905 | * "role". We need to prohibit changing these inside a local userid |
| 6906 | * context because when we exit it, GUC won't be notified, leaving things |
| 6907 | * out of sync. (This could be fixed by forcing a new GUC nesting level, |
| 6908 | * but that would change behavior in possibly-undesirable ways.) Also, we |
| 6909 | * prohibit changing these in a security-restricted operation because |
| 6910 | * otherwise RESET could be used to regain the session user's privileges. |
| 6911 | */ |
| 6912 | if (record->flags & GUC_NOT_WHILE_SEC_REST) |
| 6913 | { |
| 6914 | if (InLocalUserIdChange()) |
| 6915 | { |
| 6916 | /* |
| 6917 | * Phrasing of this error message is historical, but it's the most |
| 6918 | * common case. |
| 6919 | */ |
| 6920 | ereport(elevel, |
| 6921 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 6922 | errmsg("cannot set parameter \"%s\" within security-definer function" , |
| 6923 | name))); |
| 6924 | return 0; |
| 6925 | } |
| 6926 | if (InSecurityRestrictedOperation()) |
| 6927 | { |
| 6928 | ereport(elevel, |
| 6929 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 6930 | errmsg("cannot set parameter \"%s\" within security-restricted operation" , |
| 6931 | name))); |
| 6932 | return 0; |
| 6933 | } |
| 6934 | } |
| 6935 | |
| 6936 | /* |
| 6937 | * Should we set reset/stacked values? (If so, the behavior is not |
| 6938 | * transactional.) This is done either when we get a default value from |
| 6939 | * the database's/user's/client's default settings or when we reset a |
| 6940 | * value to its default. |
| 6941 | */ |
| 6942 | makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && |
| 6943 | ((value != NULL) || source == PGC_S_DEFAULT); |
| 6944 | |
| 6945 | /* |
| 6946 | * Ignore attempted set if overridden by previously processed setting. |
| 6947 | * However, if changeVal is false then plow ahead anyway since we are |
| 6948 | * trying to find out if the value is potentially good, not actually use |
| 6949 | * it. Also keep going if makeDefault is true, since we may want to set |
| 6950 | * the reset/stacked values even if we can't set the variable itself. |
| 6951 | */ |
| 6952 | if (record->source > source) |
| 6953 | { |
| 6954 | if (changeVal && !makeDefault) |
| 6955 | { |
| 6956 | elog(DEBUG3, "\"%s\": setting ignored because previous source is higher priority" , |
| 6957 | name); |
| 6958 | return -1; |
| 6959 | } |
| 6960 | changeVal = false; |
| 6961 | } |
| 6962 | |
| 6963 | /* |
| 6964 | * Evaluate value and set variable. |
| 6965 | */ |
| 6966 | switch (record->vartype) |
| 6967 | { |
| 6968 | case PGC_BOOL: |
| 6969 | { |
| 6970 | struct config_bool *conf = (struct config_bool *) record; |
| 6971 | |
| 6972 | #define newval (newval_union.boolval) |
| 6973 | |
| 6974 | if (value) |
| 6975 | { |
| 6976 | if (!parse_and_validate_value(record, name, value, |
| 6977 | source, elevel, |
| 6978 | &newval_union, &newextra)) |
| 6979 | return 0; |
| 6980 | } |
| 6981 | else if (source == PGC_S_DEFAULT) |
| 6982 | { |
| 6983 | newval = conf->boot_val; |
| 6984 | if (!call_bool_check_hook(conf, &newval, &newextra, |
| 6985 | source, elevel)) |
| 6986 | return 0; |
| 6987 | } |
| 6988 | else |
| 6989 | { |
| 6990 | newval = conf->reset_val; |
| 6991 | newextra = conf->reset_extra; |
| 6992 | source = conf->gen.reset_source; |
| 6993 | context = conf->gen.reset_scontext; |
| 6994 | } |
| 6995 | |
| 6996 | if (prohibitValueChange) |
| 6997 | { |
| 6998 | if (*conf->variable != newval) |
| 6999 | { |
| 7000 | record->status |= GUC_PENDING_RESTART; |
| 7001 | ereport(elevel, |
| 7002 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7003 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 7004 | name))); |
| 7005 | return 0; |
| 7006 | } |
| 7007 | record->status &= ~GUC_PENDING_RESTART; |
| 7008 | return -1; |
| 7009 | } |
| 7010 | |
| 7011 | if (changeVal) |
| 7012 | { |
| 7013 | /* Save old value to support transaction abort */ |
| 7014 | if (!makeDefault) |
| 7015 | push_old_value(&conf->gen, action); |
| 7016 | |
| 7017 | if (conf->assign_hook) |
| 7018 | conf->assign_hook(newval, newextra); |
| 7019 | *conf->variable = newval; |
| 7020 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 7021 | newextra); |
| 7022 | conf->gen.source = source; |
| 7023 | conf->gen.scontext = context; |
| 7024 | } |
| 7025 | if (makeDefault) |
| 7026 | { |
| 7027 | GucStack *stack; |
| 7028 | |
| 7029 | if (conf->gen.reset_source <= source) |
| 7030 | { |
| 7031 | conf->reset_val = newval; |
| 7032 | set_extra_field(&conf->gen, &conf->reset_extra, |
| 7033 | newextra); |
| 7034 | conf->gen.reset_source = source; |
| 7035 | conf->gen.reset_scontext = context; |
| 7036 | } |
| 7037 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 7038 | { |
| 7039 | if (stack->source <= source) |
| 7040 | { |
| 7041 | stack->prior.val.boolval = newval; |
| 7042 | set_extra_field(&conf->gen, &stack->prior.extra, |
| 7043 | newextra); |
| 7044 | stack->source = source; |
| 7045 | stack->scontext = context; |
| 7046 | } |
| 7047 | } |
| 7048 | } |
| 7049 | |
| 7050 | /* Perhaps we didn't install newextra anywhere */ |
| 7051 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
| 7052 | free(newextra); |
| 7053 | break; |
| 7054 | |
| 7055 | #undef newval |
| 7056 | } |
| 7057 | |
| 7058 | case PGC_INT: |
| 7059 | { |
| 7060 | struct config_int *conf = (struct config_int *) record; |
| 7061 | |
| 7062 | #define newval (newval_union.intval) |
| 7063 | |
| 7064 | if (value) |
| 7065 | { |
| 7066 | if (!parse_and_validate_value(record, name, value, |
| 7067 | source, elevel, |
| 7068 | &newval_union, &newextra)) |
| 7069 | return 0; |
| 7070 | } |
| 7071 | else if (source == PGC_S_DEFAULT) |
| 7072 | { |
| 7073 | newval = conf->boot_val; |
| 7074 | if (!call_int_check_hook(conf, &newval, &newextra, |
| 7075 | source, elevel)) |
| 7076 | return 0; |
| 7077 | } |
| 7078 | else |
| 7079 | { |
| 7080 | newval = conf->reset_val; |
| 7081 | newextra = conf->reset_extra; |
| 7082 | source = conf->gen.reset_source; |
| 7083 | context = conf->gen.reset_scontext; |
| 7084 | } |
| 7085 | |
| 7086 | if (prohibitValueChange) |
| 7087 | { |
| 7088 | if (*conf->variable != newval) |
| 7089 | { |
| 7090 | record->status |= GUC_PENDING_RESTART; |
| 7091 | ereport(elevel, |
| 7092 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7093 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 7094 | name))); |
| 7095 | return 0; |
| 7096 | } |
| 7097 | record->status &= ~GUC_PENDING_RESTART; |
| 7098 | return -1; |
| 7099 | } |
| 7100 | |
| 7101 | if (changeVal) |
| 7102 | { |
| 7103 | /* Save old value to support transaction abort */ |
| 7104 | if (!makeDefault) |
| 7105 | push_old_value(&conf->gen, action); |
| 7106 | |
| 7107 | if (conf->assign_hook) |
| 7108 | conf->assign_hook(newval, newextra); |
| 7109 | *conf->variable = newval; |
| 7110 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 7111 | newextra); |
| 7112 | conf->gen.source = source; |
| 7113 | conf->gen.scontext = context; |
| 7114 | } |
| 7115 | if (makeDefault) |
| 7116 | { |
| 7117 | GucStack *stack; |
| 7118 | |
| 7119 | if (conf->gen.reset_source <= source) |
| 7120 | { |
| 7121 | conf->reset_val = newval; |
| 7122 | set_extra_field(&conf->gen, &conf->reset_extra, |
| 7123 | newextra); |
| 7124 | conf->gen.reset_source = source; |
| 7125 | conf->gen.reset_scontext = context; |
| 7126 | } |
| 7127 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 7128 | { |
| 7129 | if (stack->source <= source) |
| 7130 | { |
| 7131 | stack->prior.val.intval = newval; |
| 7132 | set_extra_field(&conf->gen, &stack->prior.extra, |
| 7133 | newextra); |
| 7134 | stack->source = source; |
| 7135 | stack->scontext = context; |
| 7136 | } |
| 7137 | } |
| 7138 | } |
| 7139 | |
| 7140 | /* Perhaps we didn't install newextra anywhere */ |
| 7141 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
| 7142 | free(newextra); |
| 7143 | break; |
| 7144 | |
| 7145 | #undef newval |
| 7146 | } |
| 7147 | |
| 7148 | case PGC_REAL: |
| 7149 | { |
| 7150 | struct config_real *conf = (struct config_real *) record; |
| 7151 | |
| 7152 | #define newval (newval_union.realval) |
| 7153 | |
| 7154 | if (value) |
| 7155 | { |
| 7156 | if (!parse_and_validate_value(record, name, value, |
| 7157 | source, elevel, |
| 7158 | &newval_union, &newextra)) |
| 7159 | return 0; |
| 7160 | } |
| 7161 | else if (source == PGC_S_DEFAULT) |
| 7162 | { |
| 7163 | newval = conf->boot_val; |
| 7164 | if (!call_real_check_hook(conf, &newval, &newextra, |
| 7165 | source, elevel)) |
| 7166 | return 0; |
| 7167 | } |
| 7168 | else |
| 7169 | { |
| 7170 | newval = conf->reset_val; |
| 7171 | newextra = conf->reset_extra; |
| 7172 | source = conf->gen.reset_source; |
| 7173 | context = conf->gen.reset_scontext; |
| 7174 | } |
| 7175 | |
| 7176 | if (prohibitValueChange) |
| 7177 | { |
| 7178 | if (*conf->variable != newval) |
| 7179 | { |
| 7180 | record->status |= GUC_PENDING_RESTART; |
| 7181 | ereport(elevel, |
| 7182 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7183 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 7184 | name))); |
| 7185 | return 0; |
| 7186 | } |
| 7187 | record->status &= ~GUC_PENDING_RESTART; |
| 7188 | return -1; |
| 7189 | } |
| 7190 | |
| 7191 | if (changeVal) |
| 7192 | { |
| 7193 | /* Save old value to support transaction abort */ |
| 7194 | if (!makeDefault) |
| 7195 | push_old_value(&conf->gen, action); |
| 7196 | |
| 7197 | if (conf->assign_hook) |
| 7198 | conf->assign_hook(newval, newextra); |
| 7199 | *conf->variable = newval; |
| 7200 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 7201 | newextra); |
| 7202 | conf->gen.source = source; |
| 7203 | conf->gen.scontext = context; |
| 7204 | } |
| 7205 | if (makeDefault) |
| 7206 | { |
| 7207 | GucStack *stack; |
| 7208 | |
| 7209 | if (conf->gen.reset_source <= source) |
| 7210 | { |
| 7211 | conf->reset_val = newval; |
| 7212 | set_extra_field(&conf->gen, &conf->reset_extra, |
| 7213 | newextra); |
| 7214 | conf->gen.reset_source = source; |
| 7215 | conf->gen.reset_scontext = context; |
| 7216 | } |
| 7217 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 7218 | { |
| 7219 | if (stack->source <= source) |
| 7220 | { |
| 7221 | stack->prior.val.realval = newval; |
| 7222 | set_extra_field(&conf->gen, &stack->prior.extra, |
| 7223 | newextra); |
| 7224 | stack->source = source; |
| 7225 | stack->scontext = context; |
| 7226 | } |
| 7227 | } |
| 7228 | } |
| 7229 | |
| 7230 | /* Perhaps we didn't install newextra anywhere */ |
| 7231 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
| 7232 | free(newextra); |
| 7233 | break; |
| 7234 | |
| 7235 | #undef newval |
| 7236 | } |
| 7237 | |
| 7238 | case PGC_STRING: |
| 7239 | { |
| 7240 | struct config_string *conf = (struct config_string *) record; |
| 7241 | |
| 7242 | #define newval (newval_union.stringval) |
| 7243 | |
| 7244 | if (value) |
| 7245 | { |
| 7246 | if (!parse_and_validate_value(record, name, value, |
| 7247 | source, elevel, |
| 7248 | &newval_union, &newextra)) |
| 7249 | return 0; |
| 7250 | } |
| 7251 | else if (source == PGC_S_DEFAULT) |
| 7252 | { |
| 7253 | /* non-NULL boot_val must always get strdup'd */ |
| 7254 | if (conf->boot_val != NULL) |
| 7255 | { |
| 7256 | newval = guc_strdup(elevel, conf->boot_val); |
| 7257 | if (newval == NULL) |
| 7258 | return 0; |
| 7259 | } |
| 7260 | else |
| 7261 | newval = NULL; |
| 7262 | |
| 7263 | if (!call_string_check_hook(conf, &newval, &newextra, |
| 7264 | source, elevel)) |
| 7265 | { |
| 7266 | free(newval); |
| 7267 | return 0; |
| 7268 | } |
| 7269 | } |
| 7270 | else |
| 7271 | { |
| 7272 | /* |
| 7273 | * strdup not needed, since reset_val is already under |
| 7274 | * guc.c's control |
| 7275 | */ |
| 7276 | newval = conf->reset_val; |
| 7277 | newextra = conf->reset_extra; |
| 7278 | source = conf->gen.reset_source; |
| 7279 | context = conf->gen.reset_scontext; |
| 7280 | } |
| 7281 | |
| 7282 | if (prohibitValueChange) |
| 7283 | { |
| 7284 | /* newval shouldn't be NULL, so we're a bit sloppy here */ |
| 7285 | if (*conf->variable == NULL || newval == NULL || |
| 7286 | strcmp(*conf->variable, newval) != 0) |
| 7287 | { |
| 7288 | record->status |= GUC_PENDING_RESTART; |
| 7289 | ereport(elevel, |
| 7290 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7291 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 7292 | name))); |
| 7293 | return 0; |
| 7294 | } |
| 7295 | record->status &= ~GUC_PENDING_RESTART; |
| 7296 | return -1; |
| 7297 | } |
| 7298 | |
| 7299 | if (changeVal) |
| 7300 | { |
| 7301 | /* Save old value to support transaction abort */ |
| 7302 | if (!makeDefault) |
| 7303 | push_old_value(&conf->gen, action); |
| 7304 | |
| 7305 | if (conf->assign_hook) |
| 7306 | conf->assign_hook(newval, newextra); |
| 7307 | set_string_field(conf, conf->variable, newval); |
| 7308 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 7309 | newextra); |
| 7310 | conf->gen.source = source; |
| 7311 | conf->gen.scontext = context; |
| 7312 | } |
| 7313 | |
| 7314 | if (makeDefault) |
| 7315 | { |
| 7316 | GucStack *stack; |
| 7317 | |
| 7318 | if (conf->gen.reset_source <= source) |
| 7319 | { |
| 7320 | set_string_field(conf, &conf->reset_val, newval); |
| 7321 | set_extra_field(&conf->gen, &conf->reset_extra, |
| 7322 | newextra); |
| 7323 | conf->gen.reset_source = source; |
| 7324 | conf->gen.reset_scontext = context; |
| 7325 | } |
| 7326 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 7327 | { |
| 7328 | if (stack->source <= source) |
| 7329 | { |
| 7330 | set_string_field(conf, &stack->prior.val.stringval, |
| 7331 | newval); |
| 7332 | set_extra_field(&conf->gen, &stack->prior.extra, |
| 7333 | newextra); |
| 7334 | stack->source = source; |
| 7335 | stack->scontext = context; |
| 7336 | } |
| 7337 | } |
| 7338 | } |
| 7339 | |
| 7340 | /* Perhaps we didn't install newval anywhere */ |
| 7341 | if (newval && !string_field_used(conf, newval)) |
| 7342 | free(newval); |
| 7343 | /* Perhaps we didn't install newextra anywhere */ |
| 7344 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
| 7345 | free(newextra); |
| 7346 | break; |
| 7347 | |
| 7348 | #undef newval |
| 7349 | } |
| 7350 | |
| 7351 | case PGC_ENUM: |
| 7352 | { |
| 7353 | struct config_enum *conf = (struct config_enum *) record; |
| 7354 | |
| 7355 | #define newval (newval_union.enumval) |
| 7356 | |
| 7357 | if (value) |
| 7358 | { |
| 7359 | if (!parse_and_validate_value(record, name, value, |
| 7360 | source, elevel, |
| 7361 | &newval_union, &newextra)) |
| 7362 | return 0; |
| 7363 | } |
| 7364 | else if (source == PGC_S_DEFAULT) |
| 7365 | { |
| 7366 | newval = conf->boot_val; |
| 7367 | if (!call_enum_check_hook(conf, &newval, &newextra, |
| 7368 | source, elevel)) |
| 7369 | return 0; |
| 7370 | } |
| 7371 | else |
| 7372 | { |
| 7373 | newval = conf->reset_val; |
| 7374 | newextra = conf->reset_extra; |
| 7375 | source = conf->gen.reset_source; |
| 7376 | context = conf->gen.reset_scontext; |
| 7377 | } |
| 7378 | |
| 7379 | if (prohibitValueChange) |
| 7380 | { |
| 7381 | if (*conf->variable != newval) |
| 7382 | { |
| 7383 | record->status |= GUC_PENDING_RESTART; |
| 7384 | ereport(elevel, |
| 7385 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7386 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
| 7387 | name))); |
| 7388 | return 0; |
| 7389 | } |
| 7390 | record->status &= ~GUC_PENDING_RESTART; |
| 7391 | return -1; |
| 7392 | } |
| 7393 | |
| 7394 | if (changeVal) |
| 7395 | { |
| 7396 | /* Save old value to support transaction abort */ |
| 7397 | if (!makeDefault) |
| 7398 | push_old_value(&conf->gen, action); |
| 7399 | |
| 7400 | if (conf->assign_hook) |
| 7401 | conf->assign_hook(newval, newextra); |
| 7402 | *conf->variable = newval; |
| 7403 | set_extra_field(&conf->gen, &conf->gen.extra, |
| 7404 | newextra); |
| 7405 | conf->gen.source = source; |
| 7406 | conf->gen.scontext = context; |
| 7407 | } |
| 7408 | if (makeDefault) |
| 7409 | { |
| 7410 | GucStack *stack; |
| 7411 | |
| 7412 | if (conf->gen.reset_source <= source) |
| 7413 | { |
| 7414 | conf->reset_val = newval; |
| 7415 | set_extra_field(&conf->gen, &conf->reset_extra, |
| 7416 | newextra); |
| 7417 | conf->gen.reset_source = source; |
| 7418 | conf->gen.reset_scontext = context; |
| 7419 | } |
| 7420 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
| 7421 | { |
| 7422 | if (stack->source <= source) |
| 7423 | { |
| 7424 | stack->prior.val.enumval = newval; |
| 7425 | set_extra_field(&conf->gen, &stack->prior.extra, |
| 7426 | newextra); |
| 7427 | stack->source = source; |
| 7428 | stack->scontext = context; |
| 7429 | } |
| 7430 | } |
| 7431 | } |
| 7432 | |
| 7433 | /* Perhaps we didn't install newextra anywhere */ |
| 7434 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
| 7435 | free(newextra); |
| 7436 | break; |
| 7437 | |
| 7438 | #undef newval |
| 7439 | } |
| 7440 | } |
| 7441 | |
| 7442 | if (changeVal && (record->flags & GUC_REPORT)) |
| 7443 | ReportGUCOption(record); |
| 7444 | |
| 7445 | return changeVal ? 1 : -1; |
| 7446 | } |
| 7447 | |
| 7448 | |
| 7449 | /* |
| 7450 | * Set the fields for source file and line number the setting came from. |
| 7451 | */ |
| 7452 | static void |
| 7453 | set_config_sourcefile(const char *name, char *sourcefile, int sourceline) |
| 7454 | { |
| 7455 | struct config_generic *record; |
| 7456 | int elevel; |
| 7457 | |
| 7458 | /* |
| 7459 | * To avoid cluttering the log, only the postmaster bleats loudly about |
| 7460 | * problems with the config file. |
| 7461 | */ |
| 7462 | elevel = IsUnderPostmaster ? DEBUG3 : LOG; |
| 7463 | |
| 7464 | record = find_option(name, true, elevel); |
| 7465 | /* should not happen */ |
| 7466 | if (record == NULL) |
| 7467 | elog(ERROR, "unrecognized configuration parameter \"%s\"" , name); |
| 7468 | |
| 7469 | sourcefile = guc_strdup(elevel, sourcefile); |
| 7470 | if (record->sourcefile) |
| 7471 | free(record->sourcefile); |
| 7472 | record->sourcefile = sourcefile; |
| 7473 | record->sourceline = sourceline; |
| 7474 | } |
| 7475 | |
| 7476 | /* |
| 7477 | * Set a config option to the given value. |
| 7478 | * |
| 7479 | * See also set_config_option; this is just the wrapper to be called from |
| 7480 | * outside GUC. (This function should be used when possible, because its API |
| 7481 | * is more stable than set_config_option's.) |
| 7482 | * |
| 7483 | * Note: there is no support here for setting source file/line, as it |
| 7484 | * is currently not needed. |
| 7485 | */ |
| 7486 | void |
| 7487 | SetConfigOption(const char *name, const char *value, |
| 7488 | GucContext context, GucSource source) |
| 7489 | { |
| 7490 | (void) set_config_option(name, value, context, source, |
| 7491 | GUC_ACTION_SET, true, 0, false); |
| 7492 | } |
| 7493 | |
| 7494 | |
| 7495 | |
| 7496 | /* |
| 7497 | * Fetch the current value of the option `name', as a string. |
| 7498 | * |
| 7499 | * If the option doesn't exist, return NULL if missing_ok is true (NOTE that |
| 7500 | * this cannot be distinguished from a string variable with a NULL value!), |
| 7501 | * otherwise throw an ereport and don't return. |
| 7502 | * |
| 7503 | * If restrict_privileged is true, we also enforce that only superusers and |
| 7504 | * members of the pg_read_all_settings role can see GUC_SUPERUSER_ONLY |
| 7505 | * variables. This should only be passed as true in user-driven calls. |
| 7506 | * |
| 7507 | * The string is *not* allocated for modification and is really only |
| 7508 | * valid until the next call to configuration related functions. |
| 7509 | */ |
| 7510 | const char * |
| 7511 | GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged) |
| 7512 | { |
| 7513 | struct config_generic *record; |
| 7514 | static char buffer[256]; |
| 7515 | |
| 7516 | record = find_option(name, false, ERROR); |
| 7517 | if (record == NULL) |
| 7518 | { |
| 7519 | if (missing_ok) |
| 7520 | return NULL; |
| 7521 | ereport(ERROR, |
| 7522 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 7523 | errmsg("unrecognized configuration parameter \"%s\"" , |
| 7524 | name))); |
| 7525 | } |
| 7526 | if (restrict_privileged && |
| 7527 | (record->flags & GUC_SUPERUSER_ONLY) && |
| 7528 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
| 7529 | ereport(ERROR, |
| 7530 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 7531 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
| 7532 | name))); |
| 7533 | |
| 7534 | switch (record->vartype) |
| 7535 | { |
| 7536 | case PGC_BOOL: |
| 7537 | return *((struct config_bool *) record)->variable ? "on" : "off" ; |
| 7538 | |
| 7539 | case PGC_INT: |
| 7540 | snprintf(buffer, sizeof(buffer), "%d" , |
| 7541 | *((struct config_int *) record)->variable); |
| 7542 | return buffer; |
| 7543 | |
| 7544 | case PGC_REAL: |
| 7545 | snprintf(buffer, sizeof(buffer), "%g" , |
| 7546 | *((struct config_real *) record)->variable); |
| 7547 | return buffer; |
| 7548 | |
| 7549 | case PGC_STRING: |
| 7550 | return *((struct config_string *) record)->variable; |
| 7551 | |
| 7552 | case PGC_ENUM: |
| 7553 | return config_enum_lookup_by_value((struct config_enum *) record, |
| 7554 | *((struct config_enum *) record)->variable); |
| 7555 | } |
| 7556 | return NULL; |
| 7557 | } |
| 7558 | |
| 7559 | /* |
| 7560 | * Get the RESET value associated with the given option. |
| 7561 | * |
| 7562 | * Note: this is not re-entrant, due to use of static result buffer; |
| 7563 | * not to mention that a string variable could have its reset_val changed. |
| 7564 | * Beware of assuming the result value is good for very long. |
| 7565 | */ |
| 7566 | const char * |
| 7567 | GetConfigOptionResetString(const char *name) |
| 7568 | { |
| 7569 | struct config_generic *record; |
| 7570 | static char buffer[256]; |
| 7571 | |
| 7572 | record = find_option(name, false, ERROR); |
| 7573 | if (record == NULL) |
| 7574 | ereport(ERROR, |
| 7575 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 7576 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
| 7577 | if ((record->flags & GUC_SUPERUSER_ONLY) && |
| 7578 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
| 7579 | ereport(ERROR, |
| 7580 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 7581 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
| 7582 | name))); |
| 7583 | |
| 7584 | switch (record->vartype) |
| 7585 | { |
| 7586 | case PGC_BOOL: |
| 7587 | return ((struct config_bool *) record)->reset_val ? "on" : "off" ; |
| 7588 | |
| 7589 | case PGC_INT: |
| 7590 | snprintf(buffer, sizeof(buffer), "%d" , |
| 7591 | ((struct config_int *) record)->reset_val); |
| 7592 | return buffer; |
| 7593 | |
| 7594 | case PGC_REAL: |
| 7595 | snprintf(buffer, sizeof(buffer), "%g" , |
| 7596 | ((struct config_real *) record)->reset_val); |
| 7597 | return buffer; |
| 7598 | |
| 7599 | case PGC_STRING: |
| 7600 | return ((struct config_string *) record)->reset_val; |
| 7601 | |
| 7602 | case PGC_ENUM: |
| 7603 | return config_enum_lookup_by_value((struct config_enum *) record, |
| 7604 | ((struct config_enum *) record)->reset_val); |
| 7605 | } |
| 7606 | return NULL; |
| 7607 | } |
| 7608 | |
| 7609 | /* |
| 7610 | * Get the GUC flags associated with the given option. |
| 7611 | * |
| 7612 | * If the option doesn't exist, return 0 if missing_ok is true, |
| 7613 | * otherwise throw an ereport and don't return. |
| 7614 | */ |
| 7615 | int |
| 7616 | GetConfigOptionFlags(const char *name, bool missing_ok) |
| 7617 | { |
| 7618 | struct config_generic *record; |
| 7619 | |
| 7620 | record = find_option(name, false, WARNING); |
| 7621 | if (record == NULL) |
| 7622 | { |
| 7623 | if (missing_ok) |
| 7624 | return 0; |
| 7625 | ereport(ERROR, |
| 7626 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 7627 | errmsg("unrecognized configuration parameter \"%s\"" , |
| 7628 | name))); |
| 7629 | } |
| 7630 | return record->flags; |
| 7631 | } |
| 7632 | |
| 7633 | |
| 7634 | /* |
| 7635 | * flatten_set_variable_args |
| 7636 | * Given a parsenode List as emitted by the grammar for SET, |
| 7637 | * convert to the flat string representation used by GUC. |
| 7638 | * |
| 7639 | * We need to be told the name of the variable the args are for, because |
| 7640 | * the flattening rules vary (ugh). |
| 7641 | * |
| 7642 | * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise |
| 7643 | * a palloc'd string. |
| 7644 | */ |
| 7645 | static char * |
| 7646 | flatten_set_variable_args(const char *name, List *args) |
| 7647 | { |
| 7648 | struct config_generic *record; |
| 7649 | int flags; |
| 7650 | StringInfoData buf; |
| 7651 | ListCell *l; |
| 7652 | |
| 7653 | /* Fast path if just DEFAULT */ |
| 7654 | if (args == NIL) |
| 7655 | return NULL; |
| 7656 | |
| 7657 | /* |
| 7658 | * Get flags for the variable; if it's not known, use default flags. |
| 7659 | * (Caller might throw error later, but not our business to do so here.) |
| 7660 | */ |
| 7661 | record = find_option(name, false, WARNING); |
| 7662 | if (record) |
| 7663 | flags = record->flags; |
| 7664 | else |
| 7665 | flags = 0; |
| 7666 | |
| 7667 | /* Complain if list input and non-list variable */ |
| 7668 | if ((flags & GUC_LIST_INPUT) == 0 && |
| 7669 | list_length(args) != 1) |
| 7670 | ereport(ERROR, |
| 7671 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 7672 | errmsg("SET %s takes only one argument" , name))); |
| 7673 | |
| 7674 | initStringInfo(&buf); |
| 7675 | |
| 7676 | /* |
| 7677 | * Each list member may be a plain A_Const node, or an A_Const within a |
| 7678 | * TypeCast; the latter case is supported only for ConstInterval arguments |
| 7679 | * (for SET TIME ZONE). |
| 7680 | */ |
| 7681 | foreach(l, args) |
| 7682 | { |
| 7683 | Node *arg = (Node *) lfirst(l); |
| 7684 | char *val; |
| 7685 | TypeName *typeName = NULL; |
| 7686 | A_Const *con; |
| 7687 | |
| 7688 | if (l != list_head(args)) |
| 7689 | appendStringInfoString(&buf, ", " ); |
| 7690 | |
| 7691 | if (IsA(arg, TypeCast)) |
| 7692 | { |
| 7693 | TypeCast *tc = (TypeCast *) arg; |
| 7694 | |
| 7695 | arg = tc->arg; |
| 7696 | typeName = tc->typeName; |
| 7697 | } |
| 7698 | |
| 7699 | if (!IsA(arg, A_Const)) |
| 7700 | elog(ERROR, "unrecognized node type: %d" , (int) nodeTag(arg)); |
| 7701 | con = (A_Const *) arg; |
| 7702 | |
| 7703 | switch (nodeTag(&con->val)) |
| 7704 | { |
| 7705 | case T_Integer: |
| 7706 | appendStringInfo(&buf, "%d" , intVal(&con->val)); |
| 7707 | break; |
| 7708 | case T_Float: |
| 7709 | /* represented as a string, so just copy it */ |
| 7710 | appendStringInfoString(&buf, strVal(&con->val)); |
| 7711 | break; |
| 7712 | case T_String: |
| 7713 | val = strVal(&con->val); |
| 7714 | if (typeName != NULL) |
| 7715 | { |
| 7716 | /* |
| 7717 | * Must be a ConstInterval argument for TIME ZONE. Coerce |
| 7718 | * to interval and back to normalize the value and account |
| 7719 | * for any typmod. |
| 7720 | */ |
| 7721 | Oid typoid; |
| 7722 | int32 typmod; |
| 7723 | Datum interval; |
| 7724 | char *intervalout; |
| 7725 | |
| 7726 | typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod); |
| 7727 | Assert(typoid == INTERVALOID); |
| 7728 | |
| 7729 | interval = |
| 7730 | DirectFunctionCall3(interval_in, |
| 7731 | CStringGetDatum(val), |
| 7732 | ObjectIdGetDatum(InvalidOid), |
| 7733 | Int32GetDatum(typmod)); |
| 7734 | |
| 7735 | intervalout = |
| 7736 | DatumGetCString(DirectFunctionCall1(interval_out, |
| 7737 | interval)); |
| 7738 | appendStringInfo(&buf, "INTERVAL '%s'" , intervalout); |
| 7739 | } |
| 7740 | else |
| 7741 | { |
| 7742 | /* |
| 7743 | * Plain string literal or identifier. For quote mode, |
| 7744 | * quote it if it's not a vanilla identifier. |
| 7745 | */ |
| 7746 | if (flags & GUC_LIST_QUOTE) |
| 7747 | appendStringInfoString(&buf, quote_identifier(val)); |
| 7748 | else |
| 7749 | appendStringInfoString(&buf, val); |
| 7750 | } |
| 7751 | break; |
| 7752 | default: |
| 7753 | elog(ERROR, "unrecognized node type: %d" , |
| 7754 | (int) nodeTag(&con->val)); |
| 7755 | break; |
| 7756 | } |
| 7757 | } |
| 7758 | |
| 7759 | return buf.data; |
| 7760 | } |
| 7761 | |
| 7762 | /* |
| 7763 | * Write updated configuration parameter values into a temporary file. |
| 7764 | * This function traverses the list of parameters and quotes the string |
| 7765 | * values before writing them. |
| 7766 | */ |
| 7767 | static void |
| 7768 | write_auto_conf_file(int fd, const char *filename, ConfigVariable *head) |
| 7769 | { |
| 7770 | StringInfoData buf; |
| 7771 | ConfigVariable *item; |
| 7772 | |
| 7773 | initStringInfo(&buf); |
| 7774 | |
| 7775 | /* Emit file header containing warning comment */ |
| 7776 | appendStringInfoString(&buf, "# Do not edit this file manually!\n" ); |
| 7777 | appendStringInfoString(&buf, "# It will be overwritten by the ALTER SYSTEM command.\n" ); |
| 7778 | |
| 7779 | errno = 0; |
| 7780 | if (write(fd, buf.data, buf.len) != buf.len) |
| 7781 | { |
| 7782 | /* if write didn't set errno, assume problem is no disk space */ |
| 7783 | if (errno == 0) |
| 7784 | errno = ENOSPC; |
| 7785 | ereport(ERROR, |
| 7786 | (errcode_for_file_access(), |
| 7787 | errmsg("could not write to file \"%s\": %m" , filename))); |
| 7788 | } |
| 7789 | |
| 7790 | /* Emit each parameter, properly quoting the value */ |
| 7791 | for (item = head; item != NULL; item = item->next) |
| 7792 | { |
| 7793 | char *escaped; |
| 7794 | |
| 7795 | resetStringInfo(&buf); |
| 7796 | |
| 7797 | appendStringInfoString(&buf, item->name); |
| 7798 | appendStringInfoString(&buf, " = '" ); |
| 7799 | |
| 7800 | escaped = escape_single_quotes_ascii(item->value); |
| 7801 | if (!escaped) |
| 7802 | ereport(ERROR, |
| 7803 | (errcode(ERRCODE_OUT_OF_MEMORY), |
| 7804 | errmsg("out of memory" ))); |
| 7805 | appendStringInfoString(&buf, escaped); |
| 7806 | free(escaped); |
| 7807 | |
| 7808 | appendStringInfoString(&buf, "'\n" ); |
| 7809 | |
| 7810 | errno = 0; |
| 7811 | if (write(fd, buf.data, buf.len) != buf.len) |
| 7812 | { |
| 7813 | /* if write didn't set errno, assume problem is no disk space */ |
| 7814 | if (errno == 0) |
| 7815 | errno = ENOSPC; |
| 7816 | ereport(ERROR, |
| 7817 | (errcode_for_file_access(), |
| 7818 | errmsg("could not write to file \"%s\": %m" , filename))); |
| 7819 | } |
| 7820 | } |
| 7821 | |
| 7822 | /* fsync before considering the write to be successful */ |
| 7823 | if (pg_fsync(fd) != 0) |
| 7824 | ereport(ERROR, |
| 7825 | (errcode_for_file_access(), |
| 7826 | errmsg("could not fsync file \"%s\": %m" , filename))); |
| 7827 | |
| 7828 | pfree(buf.data); |
| 7829 | } |
| 7830 | |
| 7831 | /* |
| 7832 | * Update the given list of configuration parameters, adding, replacing |
| 7833 | * or deleting the entry for item "name" (delete if "value" == NULL). |
| 7834 | */ |
| 7835 | static void |
| 7836 | replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, |
| 7837 | const char *name, const char *value) |
| 7838 | { |
| 7839 | ConfigVariable *item, |
| 7840 | *next, |
| 7841 | *prev = NULL; |
| 7842 | |
| 7843 | /* |
| 7844 | * Remove any existing match(es) for "name". Normally there'd be at most |
| 7845 | * one, but if external tools have modified the config file, there could |
| 7846 | * be more. |
| 7847 | */ |
| 7848 | for (item = *head_p; item != NULL; item = next) |
| 7849 | { |
| 7850 | next = item->next; |
| 7851 | if (guc_name_compare(item->name, name) == 0) |
| 7852 | { |
| 7853 | /* found a match, delete it */ |
| 7854 | if (prev) |
| 7855 | prev->next = next; |
| 7856 | else |
| 7857 | *head_p = next; |
| 7858 | if (next == NULL) |
| 7859 | *tail_p = prev; |
| 7860 | |
| 7861 | pfree(item->name); |
| 7862 | pfree(item->value); |
| 7863 | pfree(item->filename); |
| 7864 | pfree(item); |
| 7865 | } |
| 7866 | else |
| 7867 | prev = item; |
| 7868 | } |
| 7869 | |
| 7870 | /* Done if we're trying to delete it */ |
| 7871 | if (value == NULL) |
| 7872 | return; |
| 7873 | |
| 7874 | /* OK, append a new entry */ |
| 7875 | item = palloc(sizeof *item); |
| 7876 | item->name = pstrdup(name); |
| 7877 | item->value = pstrdup(value); |
| 7878 | item->errmsg = NULL; |
| 7879 | item->filename = pstrdup("" ); /* new item has no location */ |
| 7880 | item->sourceline = 0; |
| 7881 | item->ignore = false; |
| 7882 | item->applied = false; |
| 7883 | item->next = NULL; |
| 7884 | |
| 7885 | if (*head_p == NULL) |
| 7886 | *head_p = item; |
| 7887 | else |
| 7888 | (*tail_p)->next = item; |
| 7889 | *tail_p = item; |
| 7890 | } |
| 7891 | |
| 7892 | |
| 7893 | /* |
| 7894 | * Execute ALTER SYSTEM statement. |
| 7895 | * |
| 7896 | * Read the old PG_AUTOCONF_FILENAME file, merge in the new variable value, |
| 7897 | * and write out an updated file. If the command is ALTER SYSTEM RESET ALL, |
| 7898 | * we can skip reading the old file and just write an empty file. |
| 7899 | * |
| 7900 | * An LWLock is used to serialize updates of the configuration file. |
| 7901 | * |
| 7902 | * In case of an error, we leave the original automatic |
| 7903 | * configuration file (PG_AUTOCONF_FILENAME) intact. |
| 7904 | */ |
| 7905 | void |
| 7906 | AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) |
| 7907 | { |
| 7908 | char *name; |
| 7909 | char *value; |
| 7910 | bool resetall = false; |
| 7911 | ConfigVariable *head = NULL; |
| 7912 | ConfigVariable *tail = NULL; |
| 7913 | volatile int Tmpfd; |
| 7914 | char AutoConfFileName[MAXPGPATH]; |
| 7915 | char AutoConfTmpFileName[MAXPGPATH]; |
| 7916 | |
| 7917 | if (!superuser()) |
| 7918 | ereport(ERROR, |
| 7919 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 7920 | (errmsg("must be superuser to execute ALTER SYSTEM command" )))); |
| 7921 | |
| 7922 | /* |
| 7923 | * Extract statement arguments |
| 7924 | */ |
| 7925 | name = altersysstmt->setstmt->name; |
| 7926 | |
| 7927 | switch (altersysstmt->setstmt->kind) |
| 7928 | { |
| 7929 | case VAR_SET_VALUE: |
| 7930 | value = ExtractSetVariableArgs(altersysstmt->setstmt); |
| 7931 | break; |
| 7932 | |
| 7933 | case VAR_SET_DEFAULT: |
| 7934 | case VAR_RESET: |
| 7935 | value = NULL; |
| 7936 | break; |
| 7937 | |
| 7938 | case VAR_RESET_ALL: |
| 7939 | value = NULL; |
| 7940 | resetall = true; |
| 7941 | break; |
| 7942 | |
| 7943 | default: |
| 7944 | elog(ERROR, "unrecognized alter system stmt type: %d" , |
| 7945 | altersysstmt->setstmt->kind); |
| 7946 | break; |
| 7947 | } |
| 7948 | |
| 7949 | /* |
| 7950 | * Unless it's RESET_ALL, validate the target variable and value |
| 7951 | */ |
| 7952 | if (!resetall) |
| 7953 | { |
| 7954 | struct config_generic *record; |
| 7955 | |
| 7956 | record = find_option(name, false, ERROR); |
| 7957 | if (record == NULL) |
| 7958 | ereport(ERROR, |
| 7959 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 7960 | errmsg("unrecognized configuration parameter \"%s\"" , |
| 7961 | name))); |
| 7962 | |
| 7963 | /* |
| 7964 | * Don't allow parameters that can't be set in configuration files to |
| 7965 | * be set in PG_AUTOCONF_FILENAME file. |
| 7966 | */ |
| 7967 | if ((record->context == PGC_INTERNAL) || |
| 7968 | (record->flags & GUC_DISALLOW_IN_FILE) || |
| 7969 | (record->flags & GUC_DISALLOW_IN_AUTO_FILE)) |
| 7970 | ereport(ERROR, |
| 7971 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
| 7972 | errmsg("parameter \"%s\" cannot be changed" , |
| 7973 | name))); |
| 7974 | |
| 7975 | /* |
| 7976 | * If a value is specified, verify that it's sane. |
| 7977 | */ |
| 7978 | if (value) |
| 7979 | { |
| 7980 | union config_var_val newval; |
| 7981 | void * = NULL; |
| 7982 | |
| 7983 | /* Check that it's acceptable for the indicated parameter */ |
| 7984 | if (!parse_and_validate_value(record, name, value, |
| 7985 | PGC_S_FILE, ERROR, |
| 7986 | &newval, &newextra)) |
| 7987 | ereport(ERROR, |
| 7988 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 7989 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 7990 | name, value))); |
| 7991 | |
| 7992 | if (record->vartype == PGC_STRING && newval.stringval != NULL) |
| 7993 | free(newval.stringval); |
| 7994 | if (newextra) |
| 7995 | free(newextra); |
| 7996 | |
| 7997 | /* |
| 7998 | * We must also reject values containing newlines, because the |
| 7999 | * grammar for config files doesn't support embedded newlines in |
| 8000 | * string literals. |
| 8001 | */ |
| 8002 | if (strchr(value, '\n')) |
| 8003 | ereport(ERROR, |
| 8004 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 8005 | errmsg("parameter value for ALTER SYSTEM must not contain a newline" ))); |
| 8006 | } |
| 8007 | } |
| 8008 | |
| 8009 | /* |
| 8010 | * PG_AUTOCONF_FILENAME and its corresponding temporary file are always in |
| 8011 | * the data directory, so we can reference them by simple relative paths. |
| 8012 | */ |
| 8013 | snprintf(AutoConfFileName, sizeof(AutoConfFileName), "%s" , |
| 8014 | PG_AUTOCONF_FILENAME); |
| 8015 | snprintf(AutoConfTmpFileName, sizeof(AutoConfTmpFileName), "%s.%s" , |
| 8016 | AutoConfFileName, |
| 8017 | "tmp" ); |
| 8018 | |
| 8019 | /* |
| 8020 | * Only one backend is allowed to operate on PG_AUTOCONF_FILENAME at a |
| 8021 | * time. Use AutoFileLock to ensure that. We must hold the lock while |
| 8022 | * reading the old file contents. |
| 8023 | */ |
| 8024 | LWLockAcquire(AutoFileLock, LW_EXCLUSIVE); |
| 8025 | |
| 8026 | /* |
| 8027 | * If we're going to reset everything, then no need to open or parse the |
| 8028 | * old file. We'll just write out an empty list. |
| 8029 | */ |
| 8030 | if (!resetall) |
| 8031 | { |
| 8032 | struct stat st; |
| 8033 | |
| 8034 | if (stat(AutoConfFileName, &st) == 0) |
| 8035 | { |
| 8036 | /* open old file PG_AUTOCONF_FILENAME */ |
| 8037 | FILE *infile; |
| 8038 | |
| 8039 | infile = AllocateFile(AutoConfFileName, "r" ); |
| 8040 | if (infile == NULL) |
| 8041 | ereport(ERROR, |
| 8042 | (errcode_for_file_access(), |
| 8043 | errmsg("could not open file \"%s\": %m" , |
| 8044 | AutoConfFileName))); |
| 8045 | |
| 8046 | /* parse it */ |
| 8047 | if (!ParseConfigFp(infile, AutoConfFileName, 0, LOG, &head, &tail)) |
| 8048 | ereport(ERROR, |
| 8049 | (errcode(ERRCODE_CONFIG_FILE_ERROR), |
| 8050 | errmsg("could not parse contents of file \"%s\"" , |
| 8051 | AutoConfFileName))); |
| 8052 | |
| 8053 | FreeFile(infile); |
| 8054 | } |
| 8055 | |
| 8056 | /* |
| 8057 | * Now, replace any existing entry with the new value, or add it if |
| 8058 | * not present. |
| 8059 | */ |
| 8060 | replace_auto_config_value(&head, &tail, name, value); |
| 8061 | } |
| 8062 | |
| 8063 | /* |
| 8064 | * To ensure crash safety, first write the new file data to a temp file, |
| 8065 | * then atomically rename it into place. |
| 8066 | * |
| 8067 | * If there is a temp file left over due to a previous crash, it's okay to |
| 8068 | * truncate and reuse it. |
| 8069 | */ |
| 8070 | Tmpfd = BasicOpenFile(AutoConfTmpFileName, |
| 8071 | O_CREAT | O_RDWR | O_TRUNC); |
| 8072 | if (Tmpfd < 0) |
| 8073 | ereport(ERROR, |
| 8074 | (errcode_for_file_access(), |
| 8075 | errmsg("could not open file \"%s\": %m" , |
| 8076 | AutoConfTmpFileName))); |
| 8077 | |
| 8078 | /* |
| 8079 | * Use a TRY block to clean up the file if we fail. Since we need a TRY |
| 8080 | * block anyway, OK to use BasicOpenFile rather than OpenTransientFile. |
| 8081 | */ |
| 8082 | PG_TRY(); |
| 8083 | { |
| 8084 | /* Write and sync the new contents to the temporary file */ |
| 8085 | write_auto_conf_file(Tmpfd, AutoConfTmpFileName, head); |
| 8086 | |
| 8087 | /* Close before renaming; may be required on some platforms */ |
| 8088 | close(Tmpfd); |
| 8089 | Tmpfd = -1; |
| 8090 | |
| 8091 | /* |
| 8092 | * As the rename is atomic operation, if any problem occurs after this |
| 8093 | * at worst it can lose the parameters set by last ALTER SYSTEM |
| 8094 | * command. |
| 8095 | */ |
| 8096 | durable_rename(AutoConfTmpFileName, AutoConfFileName, ERROR); |
| 8097 | } |
| 8098 | PG_CATCH(); |
| 8099 | { |
| 8100 | /* Close file first, else unlink might fail on some platforms */ |
| 8101 | if (Tmpfd >= 0) |
| 8102 | close(Tmpfd); |
| 8103 | |
| 8104 | /* Unlink, but ignore any error */ |
| 8105 | (void) unlink(AutoConfTmpFileName); |
| 8106 | |
| 8107 | PG_RE_THROW(); |
| 8108 | } |
| 8109 | PG_END_TRY(); |
| 8110 | |
| 8111 | FreeConfigVariables(head); |
| 8112 | |
| 8113 | LWLockRelease(AutoFileLock); |
| 8114 | } |
| 8115 | |
| 8116 | /* |
| 8117 | * SET command |
| 8118 | */ |
| 8119 | void |
| 8120 | ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) |
| 8121 | { |
| 8122 | GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET; |
| 8123 | |
| 8124 | /* |
| 8125 | * Workers synchronize these parameters at the start of the parallel |
| 8126 | * operation; then, we block SET during the operation. |
| 8127 | */ |
| 8128 | if (IsInParallelMode()) |
| 8129 | ereport(ERROR, |
| 8130 | (errcode(ERRCODE_INVALID_TRANSACTION_STATE), |
| 8131 | errmsg("cannot set parameters during a parallel operation" ))); |
| 8132 | |
| 8133 | switch (stmt->kind) |
| 8134 | { |
| 8135 | case VAR_SET_VALUE: |
| 8136 | case VAR_SET_CURRENT: |
| 8137 | if (stmt->is_local) |
| 8138 | WarnNoTransactionBlock(isTopLevel, "SET LOCAL" ); |
| 8139 | (void) set_config_option(stmt->name, |
| 8140 | ExtractSetVariableArgs(stmt), |
| 8141 | (superuser() ? PGC_SUSET : PGC_USERSET), |
| 8142 | PGC_S_SESSION, |
| 8143 | action, true, 0, false); |
| 8144 | break; |
| 8145 | case VAR_SET_MULTI: |
| 8146 | |
| 8147 | /* |
| 8148 | * Special-case SQL syntaxes. The TRANSACTION and SESSION |
| 8149 | * CHARACTERISTICS cases effectively set more than one variable |
| 8150 | * per statement. TRANSACTION SNAPSHOT only takes one argument, |
| 8151 | * but we put it here anyway since it's a special case and not |
| 8152 | * related to any GUC variable. |
| 8153 | */ |
| 8154 | if (strcmp(stmt->name, "TRANSACTION" ) == 0) |
| 8155 | { |
| 8156 | ListCell *head; |
| 8157 | |
| 8158 | WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION" ); |
| 8159 | |
| 8160 | foreach(head, stmt->args) |
| 8161 | { |
| 8162 | DefElem *item = (DefElem *) lfirst(head); |
| 8163 | |
| 8164 | if (strcmp(item->defname, "transaction_isolation" ) == 0) |
| 8165 | SetPGVariable("transaction_isolation" , |
| 8166 | list_make1(item->arg), stmt->is_local); |
| 8167 | else if (strcmp(item->defname, "transaction_read_only" ) == 0) |
| 8168 | SetPGVariable("transaction_read_only" , |
| 8169 | list_make1(item->arg), stmt->is_local); |
| 8170 | else if (strcmp(item->defname, "transaction_deferrable" ) == 0) |
| 8171 | SetPGVariable("transaction_deferrable" , |
| 8172 | list_make1(item->arg), stmt->is_local); |
| 8173 | else |
| 8174 | elog(ERROR, "unexpected SET TRANSACTION element: %s" , |
| 8175 | item->defname); |
| 8176 | } |
| 8177 | } |
| 8178 | else if (strcmp(stmt->name, "SESSION CHARACTERISTICS" ) == 0) |
| 8179 | { |
| 8180 | ListCell *head; |
| 8181 | |
| 8182 | foreach(head, stmt->args) |
| 8183 | { |
| 8184 | DefElem *item = (DefElem *) lfirst(head); |
| 8185 | |
| 8186 | if (strcmp(item->defname, "transaction_isolation" ) == 0) |
| 8187 | SetPGVariable("default_transaction_isolation" , |
| 8188 | list_make1(item->arg), stmt->is_local); |
| 8189 | else if (strcmp(item->defname, "transaction_read_only" ) == 0) |
| 8190 | SetPGVariable("default_transaction_read_only" , |
| 8191 | list_make1(item->arg), stmt->is_local); |
| 8192 | else if (strcmp(item->defname, "transaction_deferrable" ) == 0) |
| 8193 | SetPGVariable("default_transaction_deferrable" , |
| 8194 | list_make1(item->arg), stmt->is_local); |
| 8195 | else |
| 8196 | elog(ERROR, "unexpected SET SESSION element: %s" , |
| 8197 | item->defname); |
| 8198 | } |
| 8199 | } |
| 8200 | else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT" ) == 0) |
| 8201 | { |
| 8202 | A_Const *con = linitial_node(A_Const, stmt->args); |
| 8203 | |
| 8204 | if (stmt->is_local) |
| 8205 | ereport(ERROR, |
| 8206 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 8207 | errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented" ))); |
| 8208 | |
| 8209 | WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION" ); |
| 8210 | Assert(nodeTag(&con->val) == T_String); |
| 8211 | ImportSnapshot(strVal(&con->val)); |
| 8212 | } |
| 8213 | else |
| 8214 | elog(ERROR, "unexpected SET MULTI element: %s" , |
| 8215 | stmt->name); |
| 8216 | break; |
| 8217 | case VAR_SET_DEFAULT: |
| 8218 | if (stmt->is_local) |
| 8219 | WarnNoTransactionBlock(isTopLevel, "SET LOCAL" ); |
| 8220 | /* fall through */ |
| 8221 | case VAR_RESET: |
| 8222 | if (strcmp(stmt->name, "transaction_isolation" ) == 0) |
| 8223 | WarnNoTransactionBlock(isTopLevel, "RESET TRANSACTION" ); |
| 8224 | |
| 8225 | (void) set_config_option(stmt->name, |
| 8226 | NULL, |
| 8227 | (superuser() ? PGC_SUSET : PGC_USERSET), |
| 8228 | PGC_S_SESSION, |
| 8229 | action, true, 0, false); |
| 8230 | break; |
| 8231 | case VAR_RESET_ALL: |
| 8232 | ResetAllOptions(); |
| 8233 | break; |
| 8234 | } |
| 8235 | } |
| 8236 | |
| 8237 | /* |
| 8238 | * Get the value to assign for a VariableSetStmt, or NULL if it's RESET. |
| 8239 | * The result is palloc'd. |
| 8240 | * |
| 8241 | * This is exported for use by actions such as ALTER ROLE SET. |
| 8242 | */ |
| 8243 | char * |
| 8244 | (VariableSetStmt *stmt) |
| 8245 | { |
| 8246 | switch (stmt->kind) |
| 8247 | { |
| 8248 | case VAR_SET_VALUE: |
| 8249 | return flatten_set_variable_args(stmt->name, stmt->args); |
| 8250 | case VAR_SET_CURRENT: |
| 8251 | return GetConfigOptionByName(stmt->name, NULL, false); |
| 8252 | default: |
| 8253 | return NULL; |
| 8254 | } |
| 8255 | } |
| 8256 | |
| 8257 | /* |
| 8258 | * SetPGVariable - SET command exported as an easily-C-callable function. |
| 8259 | * |
| 8260 | * This provides access to SET TO value, as well as SET TO DEFAULT (expressed |
| 8261 | * by passing args == NIL), but not SET FROM CURRENT functionality. |
| 8262 | */ |
| 8263 | void |
| 8264 | SetPGVariable(const char *name, List *args, bool is_local) |
| 8265 | { |
| 8266 | char *argstring = flatten_set_variable_args(name, args); |
| 8267 | |
| 8268 | /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */ |
| 8269 | (void) set_config_option(name, |
| 8270 | argstring, |
| 8271 | (superuser() ? PGC_SUSET : PGC_USERSET), |
| 8272 | PGC_S_SESSION, |
| 8273 | is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET, |
| 8274 | true, 0, false); |
| 8275 | } |
| 8276 | |
| 8277 | /* |
| 8278 | * SET command wrapped as a SQL callable function. |
| 8279 | */ |
| 8280 | Datum |
| 8281 | set_config_by_name(PG_FUNCTION_ARGS) |
| 8282 | { |
| 8283 | char *name; |
| 8284 | char *value; |
| 8285 | char *new_value; |
| 8286 | bool is_local; |
| 8287 | |
| 8288 | if (PG_ARGISNULL(0)) |
| 8289 | ereport(ERROR, |
| 8290 | (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 8291 | errmsg("SET requires parameter name" ))); |
| 8292 | |
| 8293 | /* Get the GUC variable name */ |
| 8294 | name = TextDatumGetCString(PG_GETARG_DATUM(0)); |
| 8295 | |
| 8296 | /* Get the desired value or set to NULL for a reset request */ |
| 8297 | if (PG_ARGISNULL(1)) |
| 8298 | value = NULL; |
| 8299 | else |
| 8300 | value = TextDatumGetCString(PG_GETARG_DATUM(1)); |
| 8301 | |
| 8302 | /* |
| 8303 | * Get the desired state of is_local. Default to false if provided value |
| 8304 | * is NULL |
| 8305 | */ |
| 8306 | if (PG_ARGISNULL(2)) |
| 8307 | is_local = false; |
| 8308 | else |
| 8309 | is_local = PG_GETARG_BOOL(2); |
| 8310 | |
| 8311 | /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */ |
| 8312 | (void) set_config_option(name, |
| 8313 | value, |
| 8314 | (superuser() ? PGC_SUSET : PGC_USERSET), |
| 8315 | PGC_S_SESSION, |
| 8316 | is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET, |
| 8317 | true, 0, false); |
| 8318 | |
| 8319 | /* get the new current value */ |
| 8320 | new_value = GetConfigOptionByName(name, NULL, false); |
| 8321 | |
| 8322 | /* Convert return string to text */ |
| 8323 | PG_RETURN_TEXT_P(cstring_to_text(new_value)); |
| 8324 | } |
| 8325 | |
| 8326 | |
| 8327 | /* |
| 8328 | * Common code for DefineCustomXXXVariable subroutines: allocate the |
| 8329 | * new variable's config struct and fill in generic fields. |
| 8330 | */ |
| 8331 | static struct config_generic * |
| 8332 | init_custom_variable(const char *name, |
| 8333 | const char *short_desc, |
| 8334 | const char *long_desc, |
| 8335 | GucContext context, |
| 8336 | int flags, |
| 8337 | enum config_type type, |
| 8338 | size_t sz) |
| 8339 | { |
| 8340 | struct config_generic *gen; |
| 8341 | |
| 8342 | /* |
| 8343 | * Only allow custom PGC_POSTMASTER variables to be created during shared |
| 8344 | * library preload; any later than that, we can't ensure that the value |
| 8345 | * doesn't change after startup. This is a fatal elog if it happens; just |
| 8346 | * erroring out isn't safe because we don't know what the calling loadable |
| 8347 | * module might already have hooked into. |
| 8348 | */ |
| 8349 | if (context == PGC_POSTMASTER && |
| 8350 | !process_shared_preload_libraries_in_progress) |
| 8351 | elog(FATAL, "cannot create PGC_POSTMASTER variables after startup" ); |
| 8352 | |
| 8353 | /* |
| 8354 | * We can't support custom GUC_LIST_QUOTE variables, because the wrong |
| 8355 | * things would happen if such a variable were set or pg_dump'd when the |
| 8356 | * defining extension isn't loaded. Again, treat this as fatal because |
| 8357 | * the loadable module may be partly initialized already. |
| 8358 | */ |
| 8359 | if (flags & GUC_LIST_QUOTE) |
| 8360 | elog(FATAL, "extensions cannot define GUC_LIST_QUOTE variables" ); |
| 8361 | |
| 8362 | /* |
| 8363 | * Before pljava commit 398f3b876ed402bdaec8bc804f29e2be95c75139 |
| 8364 | * (2015-12-15), two of that module's PGC_USERSET variables facilitated |
| 8365 | * trivial escalation to superuser privileges. Restrict the variables to |
| 8366 | * protect sites that have yet to upgrade pljava. |
| 8367 | */ |
| 8368 | if (context == PGC_USERSET && |
| 8369 | (strcmp(name, "pljava.classpath" ) == 0 || |
| 8370 | strcmp(name, "pljava.vmoptions" ) == 0)) |
| 8371 | context = PGC_SUSET; |
| 8372 | |
| 8373 | gen = (struct config_generic *) guc_malloc(ERROR, sz); |
| 8374 | memset(gen, 0, sz); |
| 8375 | |
| 8376 | gen->name = guc_strdup(ERROR, name); |
| 8377 | gen->context = context; |
| 8378 | gen->group = CUSTOM_OPTIONS; |
| 8379 | gen->short_desc = short_desc; |
| 8380 | gen->long_desc = long_desc; |
| 8381 | gen->flags = flags; |
| 8382 | gen->vartype = type; |
| 8383 | |
| 8384 | return gen; |
| 8385 | } |
| 8386 | |
| 8387 | /* |
| 8388 | * Common code for DefineCustomXXXVariable subroutines: insert the new |
| 8389 | * variable into the GUC variable array, replacing any placeholder. |
| 8390 | */ |
| 8391 | static void |
| 8392 | define_custom_variable(struct config_generic *variable) |
| 8393 | { |
| 8394 | const char *name = variable->name; |
| 8395 | const char **nameAddr = &name; |
| 8396 | struct config_string *pHolder; |
| 8397 | struct config_generic **res; |
| 8398 | |
| 8399 | /* |
| 8400 | * See if there's a placeholder by the same name. |
| 8401 | */ |
| 8402 | res = (struct config_generic **) bsearch((void *) &nameAddr, |
| 8403 | (void *) guc_variables, |
| 8404 | num_guc_variables, |
| 8405 | sizeof(struct config_generic *), |
| 8406 | guc_var_compare); |
| 8407 | if (res == NULL) |
| 8408 | { |
| 8409 | /* |
| 8410 | * No placeholder to replace, so we can just add it ... but first, |
| 8411 | * make sure it's initialized to its default value. |
| 8412 | */ |
| 8413 | InitializeOneGUCOption(variable); |
| 8414 | add_guc_variable(variable, ERROR); |
| 8415 | return; |
| 8416 | } |
| 8417 | |
| 8418 | /* |
| 8419 | * This better be a placeholder |
| 8420 | */ |
| 8421 | if (((*res)->flags & GUC_CUSTOM_PLACEHOLDER) == 0) |
| 8422 | ereport(ERROR, |
| 8423 | (errcode(ERRCODE_INTERNAL_ERROR), |
| 8424 | errmsg("attempt to redefine parameter \"%s\"" , name))); |
| 8425 | |
| 8426 | Assert((*res)->vartype == PGC_STRING); |
| 8427 | pHolder = (struct config_string *) (*res); |
| 8428 | |
| 8429 | /* |
| 8430 | * First, set the variable to its default value. We must do this even |
| 8431 | * though we intend to immediately apply a new value, since it's possible |
| 8432 | * that the new value is invalid. |
| 8433 | */ |
| 8434 | InitializeOneGUCOption(variable); |
| 8435 | |
| 8436 | /* |
| 8437 | * Replace the placeholder. We aren't changing the name, so no re-sorting |
| 8438 | * is necessary |
| 8439 | */ |
| 8440 | *res = variable; |
| 8441 | |
| 8442 | /* |
| 8443 | * Assign the string value(s) stored in the placeholder to the real |
| 8444 | * variable. Essentially, we need to duplicate all the active and stacked |
| 8445 | * values, but with appropriate validation and datatype adjustment. |
| 8446 | * |
| 8447 | * If an assignment fails, we report a WARNING and keep going. We don't |
| 8448 | * want to throw ERROR for bad values, because it'd bollix the add-on |
| 8449 | * module that's presumably halfway through getting loaded. In such cases |
| 8450 | * the default or previous state will become active instead. |
| 8451 | */ |
| 8452 | |
| 8453 | /* First, apply the reset value if any */ |
| 8454 | if (pHolder->reset_val) |
| 8455 | (void) set_config_option(name, pHolder->reset_val, |
| 8456 | pHolder->gen.reset_scontext, |
| 8457 | pHolder->gen.reset_source, |
| 8458 | GUC_ACTION_SET, true, WARNING, false); |
| 8459 | /* That should not have resulted in stacking anything */ |
| 8460 | Assert(variable->stack == NULL); |
| 8461 | |
| 8462 | /* Now, apply current and stacked values, in the order they were stacked */ |
| 8463 | reapply_stacked_values(variable, pHolder, pHolder->gen.stack, |
| 8464 | *(pHolder->variable), |
| 8465 | pHolder->gen.scontext, pHolder->gen.source); |
| 8466 | |
| 8467 | /* Also copy over any saved source-location information */ |
| 8468 | if (pHolder->gen.sourcefile) |
| 8469 | set_config_sourcefile(name, pHolder->gen.sourcefile, |
| 8470 | pHolder->gen.sourceline); |
| 8471 | |
| 8472 | /* |
| 8473 | * Free up as much as we conveniently can of the placeholder structure. |
| 8474 | * (This neglects any stack items, so it's possible for some memory to be |
| 8475 | * leaked. Since this can only happen once per session per variable, it |
| 8476 | * doesn't seem worth spending much code on.) |
| 8477 | */ |
| 8478 | set_string_field(pHolder, pHolder->variable, NULL); |
| 8479 | set_string_field(pHolder, &pHolder->reset_val, NULL); |
| 8480 | |
| 8481 | free(pHolder); |
| 8482 | } |
| 8483 | |
| 8484 | /* |
| 8485 | * Recursive subroutine for define_custom_variable: reapply non-reset values |
| 8486 | * |
| 8487 | * We recurse so that the values are applied in the same order as originally. |
| 8488 | * At each recursion level, apply the upper-level value (passed in) in the |
| 8489 | * fashion implied by the stack entry. |
| 8490 | */ |
| 8491 | static void |
| 8492 | reapply_stacked_values(struct config_generic *variable, |
| 8493 | struct config_string *pHolder, |
| 8494 | GucStack *stack, |
| 8495 | const char *curvalue, |
| 8496 | GucContext curscontext, GucSource cursource) |
| 8497 | { |
| 8498 | const char *name = variable->name; |
| 8499 | GucStack *oldvarstack = variable->stack; |
| 8500 | |
| 8501 | if (stack != NULL) |
| 8502 | { |
| 8503 | /* First, recurse, so that stack items are processed bottom to top */ |
| 8504 | reapply_stacked_values(variable, pHolder, stack->prev, |
| 8505 | stack->prior.val.stringval, |
| 8506 | stack->scontext, stack->source); |
| 8507 | |
| 8508 | /* See how to apply the passed-in value */ |
| 8509 | switch (stack->state) |
| 8510 | { |
| 8511 | case GUC_SAVE: |
| 8512 | (void) set_config_option(name, curvalue, |
| 8513 | curscontext, cursource, |
| 8514 | GUC_ACTION_SAVE, true, |
| 8515 | WARNING, false); |
| 8516 | break; |
| 8517 | |
| 8518 | case GUC_SET: |
| 8519 | (void) set_config_option(name, curvalue, |
| 8520 | curscontext, cursource, |
| 8521 | GUC_ACTION_SET, true, |
| 8522 | WARNING, false); |
| 8523 | break; |
| 8524 | |
| 8525 | case GUC_LOCAL: |
| 8526 | (void) set_config_option(name, curvalue, |
| 8527 | curscontext, cursource, |
| 8528 | GUC_ACTION_LOCAL, true, |
| 8529 | WARNING, false); |
| 8530 | break; |
| 8531 | |
| 8532 | case GUC_SET_LOCAL: |
| 8533 | /* first, apply the masked value as SET */ |
| 8534 | (void) set_config_option(name, stack->masked.val.stringval, |
| 8535 | stack->masked_scontext, PGC_S_SESSION, |
| 8536 | GUC_ACTION_SET, true, |
| 8537 | WARNING, false); |
| 8538 | /* then apply the current value as LOCAL */ |
| 8539 | (void) set_config_option(name, curvalue, |
| 8540 | curscontext, cursource, |
| 8541 | GUC_ACTION_LOCAL, true, |
| 8542 | WARNING, false); |
| 8543 | break; |
| 8544 | } |
| 8545 | |
| 8546 | /* If we successfully made a stack entry, adjust its nest level */ |
| 8547 | if (variable->stack != oldvarstack) |
| 8548 | variable->stack->nest_level = stack->nest_level; |
| 8549 | } |
| 8550 | else |
| 8551 | { |
| 8552 | /* |
| 8553 | * We are at the end of the stack. If the active/previous value is |
| 8554 | * different from the reset value, it must represent a previously |
| 8555 | * committed session value. Apply it, and then drop the stack entry |
| 8556 | * that set_config_option will have created under the impression that |
| 8557 | * this is to be just a transactional assignment. (We leak the stack |
| 8558 | * entry.) |
| 8559 | */ |
| 8560 | if (curvalue != pHolder->reset_val || |
| 8561 | curscontext != pHolder->gen.reset_scontext || |
| 8562 | cursource != pHolder->gen.reset_source) |
| 8563 | { |
| 8564 | (void) set_config_option(name, curvalue, |
| 8565 | curscontext, cursource, |
| 8566 | GUC_ACTION_SET, true, WARNING, false); |
| 8567 | variable->stack = NULL; |
| 8568 | } |
| 8569 | } |
| 8570 | } |
| 8571 | |
| 8572 | void |
| 8573 | DefineCustomBoolVariable(const char *name, |
| 8574 | const char *short_desc, |
| 8575 | const char *long_desc, |
| 8576 | bool *valueAddr, |
| 8577 | bool bootValue, |
| 8578 | GucContext context, |
| 8579 | int flags, |
| 8580 | GucBoolCheckHook check_hook, |
| 8581 | GucBoolAssignHook assign_hook, |
| 8582 | GucShowHook show_hook) |
| 8583 | { |
| 8584 | struct config_bool *var; |
| 8585 | |
| 8586 | var = (struct config_bool *) |
| 8587 | init_custom_variable(name, short_desc, long_desc, context, flags, |
| 8588 | PGC_BOOL, sizeof(struct config_bool)); |
| 8589 | var->variable = valueAddr; |
| 8590 | var->boot_val = bootValue; |
| 8591 | var->reset_val = bootValue; |
| 8592 | var->check_hook = check_hook; |
| 8593 | var->assign_hook = assign_hook; |
| 8594 | var->show_hook = show_hook; |
| 8595 | define_custom_variable(&var->gen); |
| 8596 | } |
| 8597 | |
| 8598 | void |
| 8599 | DefineCustomIntVariable(const char *name, |
| 8600 | const char *short_desc, |
| 8601 | const char *long_desc, |
| 8602 | int *valueAddr, |
| 8603 | int bootValue, |
| 8604 | int minValue, |
| 8605 | int maxValue, |
| 8606 | GucContext context, |
| 8607 | int flags, |
| 8608 | GucIntCheckHook check_hook, |
| 8609 | GucIntAssignHook assign_hook, |
| 8610 | GucShowHook show_hook) |
| 8611 | { |
| 8612 | struct config_int *var; |
| 8613 | |
| 8614 | var = (struct config_int *) |
| 8615 | init_custom_variable(name, short_desc, long_desc, context, flags, |
| 8616 | PGC_INT, sizeof(struct config_int)); |
| 8617 | var->variable = valueAddr; |
| 8618 | var->boot_val = bootValue; |
| 8619 | var->reset_val = bootValue; |
| 8620 | var->min = minValue; |
| 8621 | var->max = maxValue; |
| 8622 | var->check_hook = check_hook; |
| 8623 | var->assign_hook = assign_hook; |
| 8624 | var->show_hook = show_hook; |
| 8625 | define_custom_variable(&var->gen); |
| 8626 | } |
| 8627 | |
| 8628 | void |
| 8629 | DefineCustomRealVariable(const char *name, |
| 8630 | const char *short_desc, |
| 8631 | const char *long_desc, |
| 8632 | double *valueAddr, |
| 8633 | double bootValue, |
| 8634 | double minValue, |
| 8635 | double maxValue, |
| 8636 | GucContext context, |
| 8637 | int flags, |
| 8638 | GucRealCheckHook check_hook, |
| 8639 | GucRealAssignHook assign_hook, |
| 8640 | GucShowHook show_hook) |
| 8641 | { |
| 8642 | struct config_real *var; |
| 8643 | |
| 8644 | var = (struct config_real *) |
| 8645 | init_custom_variable(name, short_desc, long_desc, context, flags, |
| 8646 | PGC_REAL, sizeof(struct config_real)); |
| 8647 | var->variable = valueAddr; |
| 8648 | var->boot_val = bootValue; |
| 8649 | var->reset_val = bootValue; |
| 8650 | var->min = minValue; |
| 8651 | var->max = maxValue; |
| 8652 | var->check_hook = check_hook; |
| 8653 | var->assign_hook = assign_hook; |
| 8654 | var->show_hook = show_hook; |
| 8655 | define_custom_variable(&var->gen); |
| 8656 | } |
| 8657 | |
| 8658 | void |
| 8659 | DefineCustomStringVariable(const char *name, |
| 8660 | const char *short_desc, |
| 8661 | const char *long_desc, |
| 8662 | char **valueAddr, |
| 8663 | const char *bootValue, |
| 8664 | GucContext context, |
| 8665 | int flags, |
| 8666 | GucStringCheckHook check_hook, |
| 8667 | GucStringAssignHook assign_hook, |
| 8668 | GucShowHook show_hook) |
| 8669 | { |
| 8670 | struct config_string *var; |
| 8671 | |
| 8672 | var = (struct config_string *) |
| 8673 | init_custom_variable(name, short_desc, long_desc, context, flags, |
| 8674 | PGC_STRING, sizeof(struct config_string)); |
| 8675 | var->variable = valueAddr; |
| 8676 | var->boot_val = bootValue; |
| 8677 | var->check_hook = check_hook; |
| 8678 | var->assign_hook = assign_hook; |
| 8679 | var->show_hook = show_hook; |
| 8680 | define_custom_variable(&var->gen); |
| 8681 | } |
| 8682 | |
| 8683 | void |
| 8684 | (const char *name, |
| 8685 | const char *short_desc, |
| 8686 | const char *long_desc, |
| 8687 | int *valueAddr, |
| 8688 | int bootValue, |
| 8689 | const struct config_enum_entry *options, |
| 8690 | GucContext context, |
| 8691 | int flags, |
| 8692 | GucEnumCheckHook check_hook, |
| 8693 | GucEnumAssignHook assign_hook, |
| 8694 | GucShowHook show_hook) |
| 8695 | { |
| 8696 | struct config_enum *var; |
| 8697 | |
| 8698 | var = (struct config_enum *) |
| 8699 | init_custom_variable(name, short_desc, long_desc, context, flags, |
| 8700 | PGC_ENUM, sizeof(struct config_enum)); |
| 8701 | var->variable = valueAddr; |
| 8702 | var->boot_val = bootValue; |
| 8703 | var->reset_val = bootValue; |
| 8704 | var->options = options; |
| 8705 | var->check_hook = check_hook; |
| 8706 | var->assign_hook = assign_hook; |
| 8707 | var->show_hook = show_hook; |
| 8708 | define_custom_variable(&var->gen); |
| 8709 | } |
| 8710 | |
| 8711 | void |
| 8712 | EmitWarningsOnPlaceholders(const char *className) |
| 8713 | { |
| 8714 | int classLen = strlen(className); |
| 8715 | int i; |
| 8716 | |
| 8717 | for (i = 0; i < num_guc_variables; i++) |
| 8718 | { |
| 8719 | struct config_generic *var = guc_variables[i]; |
| 8720 | |
| 8721 | if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 && |
| 8722 | strncmp(className, var->name, classLen) == 0 && |
| 8723 | var->name[classLen] == GUC_QUALIFIER_SEPARATOR) |
| 8724 | { |
| 8725 | ereport(WARNING, |
| 8726 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 8727 | errmsg("unrecognized configuration parameter \"%s\"" , |
| 8728 | var->name))); |
| 8729 | } |
| 8730 | } |
| 8731 | } |
| 8732 | |
| 8733 | |
| 8734 | /* |
| 8735 | * SHOW command |
| 8736 | */ |
| 8737 | void |
| 8738 | GetPGVariable(const char *name, DestReceiver *dest) |
| 8739 | { |
| 8740 | if (guc_name_compare(name, "all" ) == 0) |
| 8741 | ShowAllGUCConfig(dest); |
| 8742 | else |
| 8743 | ShowGUCConfigOption(name, dest); |
| 8744 | } |
| 8745 | |
| 8746 | TupleDesc |
| 8747 | GetPGVariableResultDesc(const char *name) |
| 8748 | { |
| 8749 | TupleDesc tupdesc; |
| 8750 | |
| 8751 | if (guc_name_compare(name, "all" ) == 0) |
| 8752 | { |
| 8753 | /* need a tuple descriptor representing three TEXT columns */ |
| 8754 | tupdesc = CreateTemplateTupleDesc(3); |
| 8755 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name" , |
| 8756 | TEXTOID, -1, 0); |
| 8757 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting" , |
| 8758 | TEXTOID, -1, 0); |
| 8759 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description" , |
| 8760 | TEXTOID, -1, 0); |
| 8761 | } |
| 8762 | else |
| 8763 | { |
| 8764 | const char *varname; |
| 8765 | |
| 8766 | /* Get the canonical spelling of name */ |
| 8767 | (void) GetConfigOptionByName(name, &varname, false); |
| 8768 | |
| 8769 | /* need a tuple descriptor representing a single TEXT column */ |
| 8770 | tupdesc = CreateTemplateTupleDesc(1); |
| 8771 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, |
| 8772 | TEXTOID, -1, 0); |
| 8773 | } |
| 8774 | return tupdesc; |
| 8775 | } |
| 8776 | |
| 8777 | |
| 8778 | /* |
| 8779 | * SHOW command |
| 8780 | */ |
| 8781 | static void |
| 8782 | ShowGUCConfigOption(const char *name, DestReceiver *dest) |
| 8783 | { |
| 8784 | TupOutputState *tstate; |
| 8785 | TupleDesc tupdesc; |
| 8786 | const char *varname; |
| 8787 | char *value; |
| 8788 | |
| 8789 | /* Get the value and canonical spelling of name */ |
| 8790 | value = GetConfigOptionByName(name, &varname, false); |
| 8791 | |
| 8792 | /* need a tuple descriptor representing a single TEXT column */ |
| 8793 | tupdesc = CreateTemplateTupleDesc(1); |
| 8794 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname, |
| 8795 | TEXTOID, -1, 0); |
| 8796 | |
| 8797 | /* prepare for projection of tuples */ |
| 8798 | tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); |
| 8799 | |
| 8800 | /* Send it */ |
| 8801 | do_text_output_oneline(tstate, value); |
| 8802 | |
| 8803 | end_tup_output(tstate); |
| 8804 | } |
| 8805 | |
| 8806 | /* |
| 8807 | * SHOW ALL command |
| 8808 | */ |
| 8809 | static void |
| 8810 | ShowAllGUCConfig(DestReceiver *dest) |
| 8811 | { |
| 8812 | int i; |
| 8813 | TupOutputState *tstate; |
| 8814 | TupleDesc tupdesc; |
| 8815 | Datum values[3]; |
| 8816 | bool isnull[3] = {false, false, false}; |
| 8817 | |
| 8818 | /* need a tuple descriptor representing three TEXT columns */ |
| 8819 | tupdesc = CreateTemplateTupleDesc(3); |
| 8820 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "name" , |
| 8821 | TEXTOID, -1, 0); |
| 8822 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting" , |
| 8823 | TEXTOID, -1, 0); |
| 8824 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description" , |
| 8825 | TEXTOID, -1, 0); |
| 8826 | |
| 8827 | /* prepare for projection of tuples */ |
| 8828 | tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); |
| 8829 | |
| 8830 | for (i = 0; i < num_guc_variables; i++) |
| 8831 | { |
| 8832 | struct config_generic *conf = guc_variables[i]; |
| 8833 | char *setting; |
| 8834 | |
| 8835 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
| 8836 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
| 8837 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
| 8838 | continue; |
| 8839 | |
| 8840 | /* assign to the values array */ |
| 8841 | values[0] = PointerGetDatum(cstring_to_text(conf->name)); |
| 8842 | |
| 8843 | setting = _ShowOption(conf, true); |
| 8844 | if (setting) |
| 8845 | { |
| 8846 | values[1] = PointerGetDatum(cstring_to_text(setting)); |
| 8847 | isnull[1] = false; |
| 8848 | } |
| 8849 | else |
| 8850 | { |
| 8851 | values[1] = PointerGetDatum(NULL); |
| 8852 | isnull[1] = true; |
| 8853 | } |
| 8854 | |
| 8855 | values[2] = PointerGetDatum(cstring_to_text(conf->short_desc)); |
| 8856 | |
| 8857 | /* send it to dest */ |
| 8858 | do_tup_output(tstate, values, isnull); |
| 8859 | |
| 8860 | /* clean up */ |
| 8861 | pfree(DatumGetPointer(values[0])); |
| 8862 | if (setting) |
| 8863 | { |
| 8864 | pfree(setting); |
| 8865 | pfree(DatumGetPointer(values[1])); |
| 8866 | } |
| 8867 | pfree(DatumGetPointer(values[2])); |
| 8868 | } |
| 8869 | |
| 8870 | end_tup_output(tstate); |
| 8871 | } |
| 8872 | |
| 8873 | /* |
| 8874 | * Returns an array of modified GUC options to show in EXPLAIN. Only options |
| 8875 | * related to query planning (marked with GUC_EXPLAIN), with values different |
| 8876 | * from built-in defaults. |
| 8877 | */ |
| 8878 | struct config_generic ** |
| 8879 | get_explain_guc_options(int *num) |
| 8880 | { |
| 8881 | int i; |
| 8882 | struct config_generic **result; |
| 8883 | |
| 8884 | *num = 0; |
| 8885 | |
| 8886 | /* |
| 8887 | * Allocate enough space to fit all GUC_EXPLAIN options. We may not need |
| 8888 | * all the space, but there are fairly few such options so we don't waste |
| 8889 | * a lot of memory. |
| 8890 | */ |
| 8891 | result = palloc(sizeof(struct config_generic *) * num_guc_explain_variables); |
| 8892 | |
| 8893 | for (i = 0; i < num_guc_variables; i++) |
| 8894 | { |
| 8895 | bool modified; |
| 8896 | struct config_generic *conf = guc_variables[i]; |
| 8897 | |
| 8898 | /* return only options visible to the user */ |
| 8899 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
| 8900 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
| 8901 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
| 8902 | continue; |
| 8903 | |
| 8904 | /* only parameters explicitly marked for inclusion in explain */ |
| 8905 | if (!(conf->flags & GUC_EXPLAIN)) |
| 8906 | continue; |
| 8907 | |
| 8908 | /* return only options that were modified (w.r.t. config file) */ |
| 8909 | modified = false; |
| 8910 | |
| 8911 | switch (conf->vartype) |
| 8912 | { |
| 8913 | case PGC_BOOL: |
| 8914 | { |
| 8915 | struct config_bool *lconf = (struct config_bool *) conf; |
| 8916 | |
| 8917 | modified = (lconf->boot_val != *(lconf->variable)); |
| 8918 | } |
| 8919 | break; |
| 8920 | |
| 8921 | case PGC_INT: |
| 8922 | { |
| 8923 | struct config_int *lconf = (struct config_int *) conf; |
| 8924 | |
| 8925 | modified = (lconf->boot_val != *(lconf->variable)); |
| 8926 | } |
| 8927 | break; |
| 8928 | |
| 8929 | case PGC_REAL: |
| 8930 | { |
| 8931 | struct config_real *lconf = (struct config_real *) conf; |
| 8932 | |
| 8933 | modified = (lconf->boot_val != *(lconf->variable)); |
| 8934 | } |
| 8935 | break; |
| 8936 | |
| 8937 | case PGC_STRING: |
| 8938 | { |
| 8939 | struct config_string *lconf = (struct config_string *) conf; |
| 8940 | |
| 8941 | modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0); |
| 8942 | } |
| 8943 | break; |
| 8944 | |
| 8945 | case PGC_ENUM: |
| 8946 | { |
| 8947 | struct config_enum *lconf = (struct config_enum *) conf; |
| 8948 | |
| 8949 | modified = (lconf->boot_val != *(lconf->variable)); |
| 8950 | } |
| 8951 | break; |
| 8952 | |
| 8953 | default: |
| 8954 | elog(ERROR, "unexpected GUC type: %d" , conf->vartype); |
| 8955 | } |
| 8956 | |
| 8957 | /* skip GUC variables that match the built-in default */ |
| 8958 | if (!modified) |
| 8959 | continue; |
| 8960 | |
| 8961 | /* assign to the values array */ |
| 8962 | result[*num] = conf; |
| 8963 | *num = *num + 1; |
| 8964 | |
| 8965 | Assert(*num <= num_guc_explain_variables); |
| 8966 | } |
| 8967 | |
| 8968 | return result; |
| 8969 | } |
| 8970 | |
| 8971 | /* |
| 8972 | * Return GUC variable value by name; optionally return canonical form of |
| 8973 | * name. If the GUC is unset, then throw an error unless missing_ok is true, |
| 8974 | * in which case return NULL. Return value is palloc'd (but *varname isn't). |
| 8975 | */ |
| 8976 | char * |
| 8977 | GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) |
| 8978 | { |
| 8979 | struct config_generic *record; |
| 8980 | |
| 8981 | record = find_option(name, false, ERROR); |
| 8982 | if (record == NULL) |
| 8983 | { |
| 8984 | if (missing_ok) |
| 8985 | { |
| 8986 | if (varname) |
| 8987 | *varname = NULL; |
| 8988 | return NULL; |
| 8989 | } |
| 8990 | |
| 8991 | ereport(ERROR, |
| 8992 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 8993 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
| 8994 | } |
| 8995 | |
| 8996 | if ((record->flags & GUC_SUPERUSER_ONLY) && |
| 8997 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
| 8998 | ereport(ERROR, |
| 8999 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 9000 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
| 9001 | name))); |
| 9002 | |
| 9003 | if (varname) |
| 9004 | *varname = record->name; |
| 9005 | |
| 9006 | return _ShowOption(record, true); |
| 9007 | } |
| 9008 | |
| 9009 | /* |
| 9010 | * Return GUC variable value by variable number; optionally return canonical |
| 9011 | * form of name. Return value is palloc'd. |
| 9012 | */ |
| 9013 | void |
| 9014 | GetConfigOptionByNum(int varnum, const char **values, bool *noshow) |
| 9015 | { |
| 9016 | char buffer[256]; |
| 9017 | struct config_generic *conf; |
| 9018 | |
| 9019 | /* check requested variable number valid */ |
| 9020 | Assert((varnum >= 0) && (varnum < num_guc_variables)); |
| 9021 | |
| 9022 | conf = guc_variables[varnum]; |
| 9023 | |
| 9024 | if (noshow) |
| 9025 | { |
| 9026 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
| 9027 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
| 9028 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
| 9029 | *noshow = true; |
| 9030 | else |
| 9031 | *noshow = false; |
| 9032 | } |
| 9033 | |
| 9034 | /* first get the generic attributes */ |
| 9035 | |
| 9036 | /* name */ |
| 9037 | values[0] = conf->name; |
| 9038 | |
| 9039 | /* setting: use _ShowOption in order to avoid duplicating the logic */ |
| 9040 | values[1] = _ShowOption(conf, false); |
| 9041 | |
| 9042 | /* unit, if any (NULL is fine) */ |
| 9043 | values[2] = get_config_unit_name(conf->flags); |
| 9044 | |
| 9045 | /* group */ |
| 9046 | values[3] = _(config_group_names[conf->group]); |
| 9047 | |
| 9048 | /* short_desc */ |
| 9049 | values[4] = _(conf->short_desc); |
| 9050 | |
| 9051 | /* extra_desc */ |
| 9052 | values[5] = _(conf->long_desc); |
| 9053 | |
| 9054 | /* context */ |
| 9055 | values[6] = GucContext_Names[conf->context]; |
| 9056 | |
| 9057 | /* vartype */ |
| 9058 | values[7] = config_type_names[conf->vartype]; |
| 9059 | |
| 9060 | /* source */ |
| 9061 | values[8] = GucSource_Names[conf->source]; |
| 9062 | |
| 9063 | /* now get the type specific attributes */ |
| 9064 | switch (conf->vartype) |
| 9065 | { |
| 9066 | case PGC_BOOL: |
| 9067 | { |
| 9068 | struct config_bool *lconf = (struct config_bool *) conf; |
| 9069 | |
| 9070 | /* min_val */ |
| 9071 | values[9] = NULL; |
| 9072 | |
| 9073 | /* max_val */ |
| 9074 | values[10] = NULL; |
| 9075 | |
| 9076 | /* enumvals */ |
| 9077 | values[11] = NULL; |
| 9078 | |
| 9079 | /* boot_val */ |
| 9080 | values[12] = pstrdup(lconf->boot_val ? "on" : "off" ); |
| 9081 | |
| 9082 | /* reset_val */ |
| 9083 | values[13] = pstrdup(lconf->reset_val ? "on" : "off" ); |
| 9084 | } |
| 9085 | break; |
| 9086 | |
| 9087 | case PGC_INT: |
| 9088 | { |
| 9089 | struct config_int *lconf = (struct config_int *) conf; |
| 9090 | |
| 9091 | /* min_val */ |
| 9092 | snprintf(buffer, sizeof(buffer), "%d" , lconf->min); |
| 9093 | values[9] = pstrdup(buffer); |
| 9094 | |
| 9095 | /* max_val */ |
| 9096 | snprintf(buffer, sizeof(buffer), "%d" , lconf->max); |
| 9097 | values[10] = pstrdup(buffer); |
| 9098 | |
| 9099 | /* enumvals */ |
| 9100 | values[11] = NULL; |
| 9101 | |
| 9102 | /* boot_val */ |
| 9103 | snprintf(buffer, sizeof(buffer), "%d" , lconf->boot_val); |
| 9104 | values[12] = pstrdup(buffer); |
| 9105 | |
| 9106 | /* reset_val */ |
| 9107 | snprintf(buffer, sizeof(buffer), "%d" , lconf->reset_val); |
| 9108 | values[13] = pstrdup(buffer); |
| 9109 | } |
| 9110 | break; |
| 9111 | |
| 9112 | case PGC_REAL: |
| 9113 | { |
| 9114 | struct config_real *lconf = (struct config_real *) conf; |
| 9115 | |
| 9116 | /* min_val */ |
| 9117 | snprintf(buffer, sizeof(buffer), "%g" , lconf->min); |
| 9118 | values[9] = pstrdup(buffer); |
| 9119 | |
| 9120 | /* max_val */ |
| 9121 | snprintf(buffer, sizeof(buffer), "%g" , lconf->max); |
| 9122 | values[10] = pstrdup(buffer); |
| 9123 | |
| 9124 | /* enumvals */ |
| 9125 | values[11] = NULL; |
| 9126 | |
| 9127 | /* boot_val */ |
| 9128 | snprintf(buffer, sizeof(buffer), "%g" , lconf->boot_val); |
| 9129 | values[12] = pstrdup(buffer); |
| 9130 | |
| 9131 | /* reset_val */ |
| 9132 | snprintf(buffer, sizeof(buffer), "%g" , lconf->reset_val); |
| 9133 | values[13] = pstrdup(buffer); |
| 9134 | } |
| 9135 | break; |
| 9136 | |
| 9137 | case PGC_STRING: |
| 9138 | { |
| 9139 | struct config_string *lconf = (struct config_string *) conf; |
| 9140 | |
| 9141 | /* min_val */ |
| 9142 | values[9] = NULL; |
| 9143 | |
| 9144 | /* max_val */ |
| 9145 | values[10] = NULL; |
| 9146 | |
| 9147 | /* enumvals */ |
| 9148 | values[11] = NULL; |
| 9149 | |
| 9150 | /* boot_val */ |
| 9151 | if (lconf->boot_val == NULL) |
| 9152 | values[12] = NULL; |
| 9153 | else |
| 9154 | values[12] = pstrdup(lconf->boot_val); |
| 9155 | |
| 9156 | /* reset_val */ |
| 9157 | if (lconf->reset_val == NULL) |
| 9158 | values[13] = NULL; |
| 9159 | else |
| 9160 | values[13] = pstrdup(lconf->reset_val); |
| 9161 | } |
| 9162 | break; |
| 9163 | |
| 9164 | case PGC_ENUM: |
| 9165 | { |
| 9166 | struct config_enum *lconf = (struct config_enum *) conf; |
| 9167 | |
| 9168 | /* min_val */ |
| 9169 | values[9] = NULL; |
| 9170 | |
| 9171 | /* max_val */ |
| 9172 | values[10] = NULL; |
| 9173 | |
| 9174 | /* enumvals */ |
| 9175 | |
| 9176 | /* |
| 9177 | * NOTE! enumvals with double quotes in them are not |
| 9178 | * supported! |
| 9179 | */ |
| 9180 | values[11] = config_enum_get_options((struct config_enum *) conf, |
| 9181 | "{\"" , "\"}" , "\",\"" ); |
| 9182 | |
| 9183 | /* boot_val */ |
| 9184 | values[12] = pstrdup(config_enum_lookup_by_value(lconf, |
| 9185 | lconf->boot_val)); |
| 9186 | |
| 9187 | /* reset_val */ |
| 9188 | values[13] = pstrdup(config_enum_lookup_by_value(lconf, |
| 9189 | lconf->reset_val)); |
| 9190 | } |
| 9191 | break; |
| 9192 | |
| 9193 | default: |
| 9194 | { |
| 9195 | /* |
| 9196 | * should never get here, but in case we do, set 'em to NULL |
| 9197 | */ |
| 9198 | |
| 9199 | /* min_val */ |
| 9200 | values[9] = NULL; |
| 9201 | |
| 9202 | /* max_val */ |
| 9203 | values[10] = NULL; |
| 9204 | |
| 9205 | /* enumvals */ |
| 9206 | values[11] = NULL; |
| 9207 | |
| 9208 | /* boot_val */ |
| 9209 | values[12] = NULL; |
| 9210 | |
| 9211 | /* reset_val */ |
| 9212 | values[13] = NULL; |
| 9213 | } |
| 9214 | break; |
| 9215 | } |
| 9216 | |
| 9217 | /* |
| 9218 | * If the setting came from a config file, set the source location. For |
| 9219 | * security reasons, we don't show source file/line number for |
| 9220 | * insufficiently-privileged users. |
| 9221 | */ |
| 9222 | if (conf->source == PGC_S_FILE && |
| 9223 | is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
| 9224 | { |
| 9225 | values[14] = conf->sourcefile; |
| 9226 | snprintf(buffer, sizeof(buffer), "%d" , conf->sourceline); |
| 9227 | values[15] = pstrdup(buffer); |
| 9228 | } |
| 9229 | else |
| 9230 | { |
| 9231 | values[14] = NULL; |
| 9232 | values[15] = NULL; |
| 9233 | } |
| 9234 | |
| 9235 | values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f" ; |
| 9236 | } |
| 9237 | |
| 9238 | /* |
| 9239 | * Return the total number of GUC variables |
| 9240 | */ |
| 9241 | int |
| 9242 | GetNumConfigOptions(void) |
| 9243 | { |
| 9244 | return num_guc_variables; |
| 9245 | } |
| 9246 | |
| 9247 | /* |
| 9248 | * show_config_by_name - equiv to SHOW X command but implemented as |
| 9249 | * a function. |
| 9250 | */ |
| 9251 | Datum |
| 9252 | show_config_by_name(PG_FUNCTION_ARGS) |
| 9253 | { |
| 9254 | char *varname = TextDatumGetCString(PG_GETARG_DATUM(0)); |
| 9255 | char *varval; |
| 9256 | |
| 9257 | /* Get the value */ |
| 9258 | varval = GetConfigOptionByName(varname, NULL, false); |
| 9259 | |
| 9260 | /* Convert to text */ |
| 9261 | PG_RETURN_TEXT_P(cstring_to_text(varval)); |
| 9262 | } |
| 9263 | |
| 9264 | /* |
| 9265 | * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as |
| 9266 | * a function. If X does not exist, suppress the error and just return NULL |
| 9267 | * if missing_ok is true. |
| 9268 | */ |
| 9269 | Datum |
| 9270 | show_config_by_name_missing_ok(PG_FUNCTION_ARGS) |
| 9271 | { |
| 9272 | char *varname = TextDatumGetCString(PG_GETARG_DATUM(0)); |
| 9273 | bool missing_ok = PG_GETARG_BOOL(1); |
| 9274 | char *varval; |
| 9275 | |
| 9276 | /* Get the value */ |
| 9277 | varval = GetConfigOptionByName(varname, NULL, missing_ok); |
| 9278 | |
| 9279 | /* return NULL if no such variable */ |
| 9280 | if (varval == NULL) |
| 9281 | PG_RETURN_NULL(); |
| 9282 | |
| 9283 | /* Convert to text */ |
| 9284 | PG_RETURN_TEXT_P(cstring_to_text(varval)); |
| 9285 | } |
| 9286 | |
| 9287 | /* |
| 9288 | * show_all_settings - equiv to SHOW ALL command but implemented as |
| 9289 | * a Table Function. |
| 9290 | */ |
| 9291 | #define NUM_PG_SETTINGS_ATTS 17 |
| 9292 | |
| 9293 | Datum |
| 9294 | show_all_settings(PG_FUNCTION_ARGS) |
| 9295 | { |
| 9296 | FuncCallContext *funcctx; |
| 9297 | TupleDesc tupdesc; |
| 9298 | int call_cntr; |
| 9299 | int max_calls; |
| 9300 | AttInMetadata *attinmeta; |
| 9301 | MemoryContext oldcontext; |
| 9302 | |
| 9303 | /* stuff done only on the first call of the function */ |
| 9304 | if (SRF_IS_FIRSTCALL()) |
| 9305 | { |
| 9306 | /* create a function context for cross-call persistence */ |
| 9307 | funcctx = SRF_FIRSTCALL_INIT(); |
| 9308 | |
| 9309 | /* |
| 9310 | * switch to memory context appropriate for multiple function calls |
| 9311 | */ |
| 9312 | oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); |
| 9313 | |
| 9314 | /* |
| 9315 | * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns |
| 9316 | * of the appropriate types |
| 9317 | */ |
| 9318 | tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS); |
| 9319 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name" , |
| 9320 | TEXTOID, -1, 0); |
| 9321 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting" , |
| 9322 | TEXTOID, -1, 0); |
| 9323 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit" , |
| 9324 | TEXTOID, -1, 0); |
| 9325 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category" , |
| 9326 | TEXTOID, -1, 0); |
| 9327 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc" , |
| 9328 | TEXTOID, -1, 0); |
| 9329 | TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc" , |
| 9330 | TEXTOID, -1, 0); |
| 9331 | TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context" , |
| 9332 | TEXTOID, -1, 0); |
| 9333 | TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype" , |
| 9334 | TEXTOID, -1, 0); |
| 9335 | TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source" , |
| 9336 | TEXTOID, -1, 0); |
| 9337 | TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val" , |
| 9338 | TEXTOID, -1, 0); |
| 9339 | TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val" , |
| 9340 | TEXTOID, -1, 0); |
| 9341 | TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals" , |
| 9342 | TEXTARRAYOID, -1, 0); |
| 9343 | TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val" , |
| 9344 | TEXTOID, -1, 0); |
| 9345 | TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val" , |
| 9346 | TEXTOID, -1, 0); |
| 9347 | TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile" , |
| 9348 | TEXTOID, -1, 0); |
| 9349 | TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline" , |
| 9350 | INT4OID, -1, 0); |
| 9351 | TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart" , |
| 9352 | BOOLOID, -1, 0); |
| 9353 | |
| 9354 | /* |
| 9355 | * Generate attribute metadata needed later to produce tuples from raw |
| 9356 | * C strings |
| 9357 | */ |
| 9358 | attinmeta = TupleDescGetAttInMetadata(tupdesc); |
| 9359 | funcctx->attinmeta = attinmeta; |
| 9360 | |
| 9361 | /* total number of tuples to be returned */ |
| 9362 | funcctx->max_calls = GetNumConfigOptions(); |
| 9363 | |
| 9364 | MemoryContextSwitchTo(oldcontext); |
| 9365 | } |
| 9366 | |
| 9367 | /* stuff done on every call of the function */ |
| 9368 | funcctx = SRF_PERCALL_SETUP(); |
| 9369 | |
| 9370 | call_cntr = funcctx->call_cntr; |
| 9371 | max_calls = funcctx->max_calls; |
| 9372 | attinmeta = funcctx->attinmeta; |
| 9373 | |
| 9374 | if (call_cntr < max_calls) /* do when there is more left to send */ |
| 9375 | { |
| 9376 | char *values[NUM_PG_SETTINGS_ATTS]; |
| 9377 | bool noshow; |
| 9378 | HeapTuple tuple; |
| 9379 | Datum result; |
| 9380 | |
| 9381 | /* |
| 9382 | * Get the next visible GUC variable name and value |
| 9383 | */ |
| 9384 | do |
| 9385 | { |
| 9386 | GetConfigOptionByNum(call_cntr, (const char **) values, &noshow); |
| 9387 | if (noshow) |
| 9388 | { |
| 9389 | /* bump the counter and get the next config setting */ |
| 9390 | call_cntr = ++funcctx->call_cntr; |
| 9391 | |
| 9392 | /* make sure we haven't gone too far now */ |
| 9393 | if (call_cntr >= max_calls) |
| 9394 | SRF_RETURN_DONE(funcctx); |
| 9395 | } |
| 9396 | } while (noshow); |
| 9397 | |
| 9398 | /* build a tuple */ |
| 9399 | tuple = BuildTupleFromCStrings(attinmeta, values); |
| 9400 | |
| 9401 | /* make the tuple into a datum */ |
| 9402 | result = HeapTupleGetDatum(tuple); |
| 9403 | |
| 9404 | SRF_RETURN_NEXT(funcctx, result); |
| 9405 | } |
| 9406 | else |
| 9407 | { |
| 9408 | /* do when there is no more left */ |
| 9409 | SRF_RETURN_DONE(funcctx); |
| 9410 | } |
| 9411 | } |
| 9412 | |
| 9413 | /* |
| 9414 | * show_all_file_settings |
| 9415 | * |
| 9416 | * Returns a table of all parameter settings in all configuration files |
| 9417 | * which includes the config file pathname, the line number, a sequence number |
| 9418 | * indicating the order in which the settings were encountered, the parameter |
| 9419 | * name and value, a bool showing if the value could be applied, and possibly |
| 9420 | * an associated error message. (For problems such as syntax errors, the |
| 9421 | * parameter name/value might be NULL.) |
| 9422 | * |
| 9423 | * Note: no filtering is done here, instead we depend on the GRANT system |
| 9424 | * to prevent unprivileged users from accessing this function or the view |
| 9425 | * built on top of it. |
| 9426 | */ |
| 9427 | Datum |
| 9428 | show_all_file_settings(PG_FUNCTION_ARGS) |
| 9429 | { |
| 9430 | #define NUM_PG_FILE_SETTINGS_ATTS 7 |
| 9431 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
| 9432 | TupleDesc tupdesc; |
| 9433 | Tuplestorestate *tupstore; |
| 9434 | ConfigVariable *conf; |
| 9435 | int seqno; |
| 9436 | MemoryContext per_query_ctx; |
| 9437 | MemoryContext oldcontext; |
| 9438 | |
| 9439 | /* Check to see if caller supports us returning a tuplestore */ |
| 9440 | if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) |
| 9441 | ereport(ERROR, |
| 9442 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 9443 | errmsg("set-valued function called in context that cannot accept a set" ))); |
| 9444 | if (!(rsinfo->allowedModes & SFRM_Materialize)) |
| 9445 | ereport(ERROR, |
| 9446 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 9447 | errmsg("materialize mode required, but it is not " \ |
| 9448 | "allowed in this context" ))); |
| 9449 | |
| 9450 | /* Scan the config files using current context as workspace */ |
| 9451 | conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3); |
| 9452 | |
| 9453 | /* Switch into long-lived context to construct returned data structures */ |
| 9454 | per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; |
| 9455 | oldcontext = MemoryContextSwitchTo(per_query_ctx); |
| 9456 | |
| 9457 | /* Build a tuple descriptor for our result type */ |
| 9458 | tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS); |
| 9459 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile" , |
| 9460 | TEXTOID, -1, 0); |
| 9461 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline" , |
| 9462 | INT4OID, -1, 0); |
| 9463 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno" , |
| 9464 | INT4OID, -1, 0); |
| 9465 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name" , |
| 9466 | TEXTOID, -1, 0); |
| 9467 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting" , |
| 9468 | TEXTOID, -1, 0); |
| 9469 | TupleDescInitEntry(tupdesc, (AttrNumber) 6, "applied" , |
| 9470 | BOOLOID, -1, 0); |
| 9471 | TupleDescInitEntry(tupdesc, (AttrNumber) 7, "error" , |
| 9472 | TEXTOID, -1, 0); |
| 9473 | |
| 9474 | /* Build a tuplestore to return our results in */ |
| 9475 | tupstore = tuplestore_begin_heap(true, false, work_mem); |
| 9476 | rsinfo->returnMode = SFRM_Materialize; |
| 9477 | rsinfo->setResult = tupstore; |
| 9478 | rsinfo->setDesc = tupdesc; |
| 9479 | |
| 9480 | /* The rest can be done in short-lived context */ |
| 9481 | MemoryContextSwitchTo(oldcontext); |
| 9482 | |
| 9483 | /* Process the results and create a tuplestore */ |
| 9484 | for (seqno = 1; conf != NULL; conf = conf->next, seqno++) |
| 9485 | { |
| 9486 | Datum values[NUM_PG_FILE_SETTINGS_ATTS]; |
| 9487 | bool nulls[NUM_PG_FILE_SETTINGS_ATTS]; |
| 9488 | |
| 9489 | memset(values, 0, sizeof(values)); |
| 9490 | memset(nulls, 0, sizeof(nulls)); |
| 9491 | |
| 9492 | /* sourcefile */ |
| 9493 | if (conf->filename) |
| 9494 | values[0] = PointerGetDatum(cstring_to_text(conf->filename)); |
| 9495 | else |
| 9496 | nulls[0] = true; |
| 9497 | |
| 9498 | /* sourceline (not meaningful if no sourcefile) */ |
| 9499 | if (conf->filename) |
| 9500 | values[1] = Int32GetDatum(conf->sourceline); |
| 9501 | else |
| 9502 | nulls[1] = true; |
| 9503 | |
| 9504 | /* seqno */ |
| 9505 | values[2] = Int32GetDatum(seqno); |
| 9506 | |
| 9507 | /* name */ |
| 9508 | if (conf->name) |
| 9509 | values[3] = PointerGetDatum(cstring_to_text(conf->name)); |
| 9510 | else |
| 9511 | nulls[3] = true; |
| 9512 | |
| 9513 | /* setting */ |
| 9514 | if (conf->value) |
| 9515 | values[4] = PointerGetDatum(cstring_to_text(conf->value)); |
| 9516 | else |
| 9517 | nulls[4] = true; |
| 9518 | |
| 9519 | /* applied */ |
| 9520 | values[5] = BoolGetDatum(conf->applied); |
| 9521 | |
| 9522 | /* error */ |
| 9523 | if (conf->errmsg) |
| 9524 | values[6] = PointerGetDatum(cstring_to_text(conf->errmsg)); |
| 9525 | else |
| 9526 | nulls[6] = true; |
| 9527 | |
| 9528 | /* shove row into tuplestore */ |
| 9529 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); |
| 9530 | } |
| 9531 | |
| 9532 | tuplestore_donestoring(tupstore); |
| 9533 | |
| 9534 | return (Datum) 0; |
| 9535 | } |
| 9536 | |
| 9537 | static char * |
| 9538 | _ShowOption(struct config_generic *record, bool use_units) |
| 9539 | { |
| 9540 | char buffer[256]; |
| 9541 | const char *val; |
| 9542 | |
| 9543 | switch (record->vartype) |
| 9544 | { |
| 9545 | case PGC_BOOL: |
| 9546 | { |
| 9547 | struct config_bool *conf = (struct config_bool *) record; |
| 9548 | |
| 9549 | if (conf->show_hook) |
| 9550 | val = conf->show_hook(); |
| 9551 | else |
| 9552 | val = *conf->variable ? "on" : "off" ; |
| 9553 | } |
| 9554 | break; |
| 9555 | |
| 9556 | case PGC_INT: |
| 9557 | { |
| 9558 | struct config_int *conf = (struct config_int *) record; |
| 9559 | |
| 9560 | if (conf->show_hook) |
| 9561 | val = conf->show_hook(); |
| 9562 | else |
| 9563 | { |
| 9564 | /* |
| 9565 | * Use int64 arithmetic to avoid overflows in units |
| 9566 | * conversion. |
| 9567 | */ |
| 9568 | int64 result = *conf->variable; |
| 9569 | const char *unit; |
| 9570 | |
| 9571 | if (use_units && result > 0 && (record->flags & GUC_UNIT)) |
| 9572 | convert_int_from_base_unit(result, |
| 9573 | record->flags & GUC_UNIT, |
| 9574 | &result, &unit); |
| 9575 | else |
| 9576 | unit = "" ; |
| 9577 | |
| 9578 | snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s" , |
| 9579 | result, unit); |
| 9580 | val = buffer; |
| 9581 | } |
| 9582 | } |
| 9583 | break; |
| 9584 | |
| 9585 | case PGC_REAL: |
| 9586 | { |
| 9587 | struct config_real *conf = (struct config_real *) record; |
| 9588 | |
| 9589 | if (conf->show_hook) |
| 9590 | val = conf->show_hook(); |
| 9591 | else |
| 9592 | { |
| 9593 | double result = *conf->variable; |
| 9594 | const char *unit; |
| 9595 | |
| 9596 | if (use_units && result > 0 && (record->flags & GUC_UNIT)) |
| 9597 | convert_real_from_base_unit(result, |
| 9598 | record->flags & GUC_UNIT, |
| 9599 | &result, &unit); |
| 9600 | else |
| 9601 | unit = "" ; |
| 9602 | |
| 9603 | snprintf(buffer, sizeof(buffer), "%g%s" , |
| 9604 | result, unit); |
| 9605 | val = buffer; |
| 9606 | } |
| 9607 | } |
| 9608 | break; |
| 9609 | |
| 9610 | case PGC_STRING: |
| 9611 | { |
| 9612 | struct config_string *conf = (struct config_string *) record; |
| 9613 | |
| 9614 | if (conf->show_hook) |
| 9615 | val = conf->show_hook(); |
| 9616 | else if (*conf->variable && **conf->variable) |
| 9617 | val = *conf->variable; |
| 9618 | else |
| 9619 | val = "" ; |
| 9620 | } |
| 9621 | break; |
| 9622 | |
| 9623 | case PGC_ENUM: |
| 9624 | { |
| 9625 | struct config_enum *conf = (struct config_enum *) record; |
| 9626 | |
| 9627 | if (conf->show_hook) |
| 9628 | val = conf->show_hook(); |
| 9629 | else |
| 9630 | val = config_enum_lookup_by_value(conf, *conf->variable); |
| 9631 | } |
| 9632 | break; |
| 9633 | |
| 9634 | default: |
| 9635 | /* just to keep compiler quiet */ |
| 9636 | val = "???" ; |
| 9637 | break; |
| 9638 | } |
| 9639 | |
| 9640 | return pstrdup(val); |
| 9641 | } |
| 9642 | |
| 9643 | |
| 9644 | #ifdef EXEC_BACKEND |
| 9645 | |
| 9646 | /* |
| 9647 | * These routines dump out all non-default GUC options into a binary |
| 9648 | * file that is read by all exec'ed backends. The format is: |
| 9649 | * |
| 9650 | * variable name, string, null terminated |
| 9651 | * variable value, string, null terminated |
| 9652 | * variable sourcefile, string, null terminated (empty if none) |
| 9653 | * variable sourceline, integer |
| 9654 | * variable source, integer |
| 9655 | * variable scontext, integer |
| 9656 | */ |
| 9657 | static void |
| 9658 | write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) |
| 9659 | { |
| 9660 | if (gconf->source == PGC_S_DEFAULT) |
| 9661 | return; |
| 9662 | |
| 9663 | fprintf(fp, "%s" , gconf->name); |
| 9664 | fputc(0, fp); |
| 9665 | |
| 9666 | switch (gconf->vartype) |
| 9667 | { |
| 9668 | case PGC_BOOL: |
| 9669 | { |
| 9670 | struct config_bool *conf = (struct config_bool *) gconf; |
| 9671 | |
| 9672 | if (*conf->variable) |
| 9673 | fprintf(fp, "true" ); |
| 9674 | else |
| 9675 | fprintf(fp, "false" ); |
| 9676 | } |
| 9677 | break; |
| 9678 | |
| 9679 | case PGC_INT: |
| 9680 | { |
| 9681 | struct config_int *conf = (struct config_int *) gconf; |
| 9682 | |
| 9683 | fprintf(fp, "%d" , *conf->variable); |
| 9684 | } |
| 9685 | break; |
| 9686 | |
| 9687 | case PGC_REAL: |
| 9688 | { |
| 9689 | struct config_real *conf = (struct config_real *) gconf; |
| 9690 | |
| 9691 | fprintf(fp, "%.17g" , *conf->variable); |
| 9692 | } |
| 9693 | break; |
| 9694 | |
| 9695 | case PGC_STRING: |
| 9696 | { |
| 9697 | struct config_string *conf = (struct config_string *) gconf; |
| 9698 | |
| 9699 | fprintf(fp, "%s" , *conf->variable); |
| 9700 | } |
| 9701 | break; |
| 9702 | |
| 9703 | case PGC_ENUM: |
| 9704 | { |
| 9705 | struct config_enum *conf = (struct config_enum *) gconf; |
| 9706 | |
| 9707 | fprintf(fp, "%s" , |
| 9708 | config_enum_lookup_by_value(conf, *conf->variable)); |
| 9709 | } |
| 9710 | break; |
| 9711 | } |
| 9712 | |
| 9713 | fputc(0, fp); |
| 9714 | |
| 9715 | if (gconf->sourcefile) |
| 9716 | fprintf(fp, "%s" , gconf->sourcefile); |
| 9717 | fputc(0, fp); |
| 9718 | |
| 9719 | fwrite(&gconf->sourceline, 1, sizeof(gconf->sourceline), fp); |
| 9720 | fwrite(&gconf->source, 1, sizeof(gconf->source), fp); |
| 9721 | fwrite(&gconf->scontext, 1, sizeof(gconf->scontext), fp); |
| 9722 | } |
| 9723 | |
| 9724 | void |
| 9725 | write_nondefault_variables(GucContext context) |
| 9726 | { |
| 9727 | int elevel; |
| 9728 | FILE *fp; |
| 9729 | int i; |
| 9730 | |
| 9731 | Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP); |
| 9732 | |
| 9733 | elevel = (context == PGC_SIGHUP) ? LOG : ERROR; |
| 9734 | |
| 9735 | /* |
| 9736 | * Open file |
| 9737 | */ |
| 9738 | fp = AllocateFile(CONFIG_EXEC_PARAMS_NEW, "w" ); |
| 9739 | if (!fp) |
| 9740 | { |
| 9741 | ereport(elevel, |
| 9742 | (errcode_for_file_access(), |
| 9743 | errmsg("could not write to file \"%s\": %m" , |
| 9744 | CONFIG_EXEC_PARAMS_NEW))); |
| 9745 | return; |
| 9746 | } |
| 9747 | |
| 9748 | for (i = 0; i < num_guc_variables; i++) |
| 9749 | { |
| 9750 | write_one_nondefault_variable(fp, guc_variables[i]); |
| 9751 | } |
| 9752 | |
| 9753 | if (FreeFile(fp)) |
| 9754 | { |
| 9755 | ereport(elevel, |
| 9756 | (errcode_for_file_access(), |
| 9757 | errmsg("could not write to file \"%s\": %m" , |
| 9758 | CONFIG_EXEC_PARAMS_NEW))); |
| 9759 | return; |
| 9760 | } |
| 9761 | |
| 9762 | /* |
| 9763 | * Put new file in place. This could delay on Win32, but we don't hold |
| 9764 | * any exclusive locks. |
| 9765 | */ |
| 9766 | rename(CONFIG_EXEC_PARAMS_NEW, CONFIG_EXEC_PARAMS); |
| 9767 | } |
| 9768 | |
| 9769 | |
| 9770 | /* |
| 9771 | * Read string, including null byte from file |
| 9772 | * |
| 9773 | * Return NULL on EOF and nothing read |
| 9774 | */ |
| 9775 | static char * |
| 9776 | read_string_with_null(FILE *fp) |
| 9777 | { |
| 9778 | int i = 0, |
| 9779 | ch, |
| 9780 | maxlen = 256; |
| 9781 | char *str = NULL; |
| 9782 | |
| 9783 | do |
| 9784 | { |
| 9785 | if ((ch = fgetc(fp)) == EOF) |
| 9786 | { |
| 9787 | if (i == 0) |
| 9788 | return NULL; |
| 9789 | else |
| 9790 | elog(FATAL, "invalid format of exec config params file" ); |
| 9791 | } |
| 9792 | if (i == 0) |
| 9793 | str = guc_malloc(FATAL, maxlen); |
| 9794 | else if (i == maxlen) |
| 9795 | str = guc_realloc(FATAL, str, maxlen *= 2); |
| 9796 | str[i++] = ch; |
| 9797 | } while (ch != 0); |
| 9798 | |
| 9799 | return str; |
| 9800 | } |
| 9801 | |
| 9802 | |
| 9803 | /* |
| 9804 | * This routine loads a previous postmaster dump of its non-default |
| 9805 | * settings. |
| 9806 | */ |
| 9807 | void |
| 9808 | read_nondefault_variables(void) |
| 9809 | { |
| 9810 | FILE *fp; |
| 9811 | char *varname, |
| 9812 | *varvalue, |
| 9813 | *varsourcefile; |
| 9814 | int varsourceline; |
| 9815 | GucSource varsource; |
| 9816 | GucContext varscontext; |
| 9817 | |
| 9818 | /* |
| 9819 | * Assert that PGC_BACKEND/PGC_SU_BACKEND case in set_config_option() will |
| 9820 | * do the right thing. |
| 9821 | */ |
| 9822 | Assert(IsInitProcessingMode()); |
| 9823 | |
| 9824 | /* |
| 9825 | * Open file |
| 9826 | */ |
| 9827 | fp = AllocateFile(CONFIG_EXEC_PARAMS, "r" ); |
| 9828 | if (!fp) |
| 9829 | { |
| 9830 | /* File not found is fine */ |
| 9831 | if (errno != ENOENT) |
| 9832 | ereport(FATAL, |
| 9833 | (errcode_for_file_access(), |
| 9834 | errmsg("could not read from file \"%s\": %m" , |
| 9835 | CONFIG_EXEC_PARAMS))); |
| 9836 | return; |
| 9837 | } |
| 9838 | |
| 9839 | for (;;) |
| 9840 | { |
| 9841 | struct config_generic *record; |
| 9842 | |
| 9843 | if ((varname = read_string_with_null(fp)) == NULL) |
| 9844 | break; |
| 9845 | |
| 9846 | if ((record = find_option(varname, true, FATAL)) == NULL) |
| 9847 | elog(FATAL, "failed to locate variable \"%s\" in exec config params file" , varname); |
| 9848 | |
| 9849 | if ((varvalue = read_string_with_null(fp)) == NULL) |
| 9850 | elog(FATAL, "invalid format of exec config params file" ); |
| 9851 | if ((varsourcefile = read_string_with_null(fp)) == NULL) |
| 9852 | elog(FATAL, "invalid format of exec config params file" ); |
| 9853 | if (fread(&varsourceline, 1, sizeof(varsourceline), fp) != sizeof(varsourceline)) |
| 9854 | elog(FATAL, "invalid format of exec config params file" ); |
| 9855 | if (fread(&varsource, 1, sizeof(varsource), fp) != sizeof(varsource)) |
| 9856 | elog(FATAL, "invalid format of exec config params file" ); |
| 9857 | if (fread(&varscontext, 1, sizeof(varscontext), fp) != sizeof(varscontext)) |
| 9858 | elog(FATAL, "invalid format of exec config params file" ); |
| 9859 | |
| 9860 | (void) set_config_option(varname, varvalue, |
| 9861 | varscontext, varsource, |
| 9862 | GUC_ACTION_SET, true, 0, true); |
| 9863 | if (varsourcefile[0]) |
| 9864 | set_config_sourcefile(varname, varsourcefile, varsourceline); |
| 9865 | |
| 9866 | free(varname); |
| 9867 | free(varvalue); |
| 9868 | free(varsourcefile); |
| 9869 | } |
| 9870 | |
| 9871 | FreeFile(fp); |
| 9872 | } |
| 9873 | #endif /* EXEC_BACKEND */ |
| 9874 | |
| 9875 | /* |
| 9876 | * can_skip_gucvar: |
| 9877 | * When serializing, determine whether to skip this GUC. When restoring, the |
| 9878 | * negation of this test determines whether to restore the compiled-in default |
| 9879 | * value before processing serialized values. |
| 9880 | * |
| 9881 | * A PGC_S_DEFAULT setting on the serialize side will typically match new |
| 9882 | * postmaster children, but that can be false when got_SIGHUP == true and the |
| 9883 | * pending configuration change modifies this setting. Nonetheless, we omit |
| 9884 | * PGC_S_DEFAULT settings from serialization and make up for that by restoring |
| 9885 | * defaults before applying serialized values. |
| 9886 | * |
| 9887 | * PGC_POSTMASTER variables always have the same value in every child of a |
| 9888 | * particular postmaster. Most PGC_INTERNAL variables are compile-time |
| 9889 | * constants; a few, like server_encoding and lc_ctype, are handled specially |
| 9890 | * outside the serialize/restore procedure. Therefore, SerializeGUCState() |
| 9891 | * never sends these, and RestoreGUCState() never changes them. |
| 9892 | * |
| 9893 | * Role is a special variable in the sense that its current value can be an |
| 9894 | * invalid value and there are multiple ways by which that can happen (like |
| 9895 | * after setting the role, someone drops it). So we handle it outside of |
| 9896 | * serialize/restore machinery. |
| 9897 | */ |
| 9898 | static bool |
| 9899 | can_skip_gucvar(struct config_generic *gconf) |
| 9900 | { |
| 9901 | return gconf->context == PGC_POSTMASTER || |
| 9902 | gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT || |
| 9903 | strcmp(gconf->name, "role" ) == 0; |
| 9904 | } |
| 9905 | |
| 9906 | /* |
| 9907 | * estimate_variable_size: |
| 9908 | * Compute space needed for dumping the given GUC variable. |
| 9909 | * |
| 9910 | * It's OK to overestimate, but not to underestimate. |
| 9911 | */ |
| 9912 | static Size |
| 9913 | estimate_variable_size(struct config_generic *gconf) |
| 9914 | { |
| 9915 | Size size; |
| 9916 | Size valsize = 0; |
| 9917 | |
| 9918 | if (can_skip_gucvar(gconf)) |
| 9919 | return 0; |
| 9920 | |
| 9921 | /* Name, plus trailing zero byte. */ |
| 9922 | size = strlen(gconf->name) + 1; |
| 9923 | |
| 9924 | /* Get the maximum display length of the GUC value. */ |
| 9925 | switch (gconf->vartype) |
| 9926 | { |
| 9927 | case PGC_BOOL: |
| 9928 | { |
| 9929 | valsize = 5; /* max(strlen('true'), strlen('false')) */ |
| 9930 | } |
| 9931 | break; |
| 9932 | |
| 9933 | case PGC_INT: |
| 9934 | { |
| 9935 | struct config_int *conf = (struct config_int *) gconf; |
| 9936 | |
| 9937 | /* |
| 9938 | * Instead of getting the exact display length, use max |
| 9939 | * length. Also reduce the max length for typical ranges of |
| 9940 | * small values. Maximum value is 2147483647, i.e. 10 chars. |
| 9941 | * Include one byte for sign. |
| 9942 | */ |
| 9943 | if (Abs(*conf->variable) < 1000) |
| 9944 | valsize = 3 + 1; |
| 9945 | else |
| 9946 | valsize = 10 + 1; |
| 9947 | } |
| 9948 | break; |
| 9949 | |
| 9950 | case PGC_REAL: |
| 9951 | { |
| 9952 | /* |
| 9953 | * We are going to print it with %e with REALTYPE_PRECISION |
| 9954 | * fractional digits. Account for sign, leading digit, |
| 9955 | * decimal point, and exponent with up to 3 digits. E.g. |
| 9956 | * -3.99329042340000021e+110 |
| 9957 | */ |
| 9958 | valsize = 1 + 1 + 1 + REALTYPE_PRECISION + 5; |
| 9959 | } |
| 9960 | break; |
| 9961 | |
| 9962 | case PGC_STRING: |
| 9963 | { |
| 9964 | struct config_string *conf = (struct config_string *) gconf; |
| 9965 | |
| 9966 | /* |
| 9967 | * If the value is NULL, we transmit it as an empty string. |
| 9968 | * Although this is not physically the same value, GUC |
| 9969 | * generally treats a NULL the same as empty string. |
| 9970 | */ |
| 9971 | if (*conf->variable) |
| 9972 | valsize = strlen(*conf->variable); |
| 9973 | else |
| 9974 | valsize = 0; |
| 9975 | } |
| 9976 | break; |
| 9977 | |
| 9978 | case PGC_ENUM: |
| 9979 | { |
| 9980 | struct config_enum *conf = (struct config_enum *) gconf; |
| 9981 | |
| 9982 | valsize = strlen(config_enum_lookup_by_value(conf, *conf->variable)); |
| 9983 | } |
| 9984 | break; |
| 9985 | } |
| 9986 | |
| 9987 | /* Allow space for terminating zero-byte for value */ |
| 9988 | size = add_size(size, valsize + 1); |
| 9989 | |
| 9990 | if (gconf->sourcefile) |
| 9991 | size = add_size(size, strlen(gconf->sourcefile)); |
| 9992 | |
| 9993 | /* Allow space for terminating zero-byte for sourcefile */ |
| 9994 | size = add_size(size, 1); |
| 9995 | |
| 9996 | /* Include line whenever file is nonempty. */ |
| 9997 | if (gconf->sourcefile && gconf->sourcefile[0]) |
| 9998 | size = add_size(size, sizeof(gconf->sourceline)); |
| 9999 | |
| 10000 | size = add_size(size, sizeof(gconf->source)); |
| 10001 | size = add_size(size, sizeof(gconf->scontext)); |
| 10002 | |
| 10003 | return size; |
| 10004 | } |
| 10005 | |
| 10006 | /* |
| 10007 | * EstimateGUCStateSpace: |
| 10008 | * Returns the size needed to store the GUC state for the current process |
| 10009 | */ |
| 10010 | Size |
| 10011 | EstimateGUCStateSpace(void) |
| 10012 | { |
| 10013 | Size size; |
| 10014 | int i; |
| 10015 | |
| 10016 | /* Add space reqd for saving the data size of the guc state */ |
| 10017 | size = sizeof(Size); |
| 10018 | |
| 10019 | /* Add up the space needed for each GUC variable */ |
| 10020 | for (i = 0; i < num_guc_variables; i++) |
| 10021 | size = add_size(size, |
| 10022 | estimate_variable_size(guc_variables[i])); |
| 10023 | |
| 10024 | return size; |
| 10025 | } |
| 10026 | |
| 10027 | /* |
| 10028 | * do_serialize: |
| 10029 | * Copies the formatted string into the destination. Moves ahead the |
| 10030 | * destination pointer, and decrements the maxbytes by that many bytes. If |
| 10031 | * maxbytes is not sufficient to copy the string, error out. |
| 10032 | */ |
| 10033 | static void |
| 10034 | do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) |
| 10035 | { |
| 10036 | va_list vargs; |
| 10037 | int n; |
| 10038 | |
| 10039 | if (*maxbytes <= 0) |
| 10040 | elog(ERROR, "not enough space to serialize GUC state" ); |
| 10041 | |
| 10042 | va_start(vargs, fmt); |
| 10043 | n = vsnprintf(*destptr, *maxbytes, fmt, vargs); |
| 10044 | va_end(vargs); |
| 10045 | |
| 10046 | if (n < 0) |
| 10047 | { |
| 10048 | /* Shouldn't happen. Better show errno description. */ |
| 10049 | elog(ERROR, "vsnprintf failed: %m with format string \"%s\"" , fmt); |
| 10050 | } |
| 10051 | if (n >= *maxbytes) |
| 10052 | { |
| 10053 | /* This shouldn't happen either, really. */ |
| 10054 | elog(ERROR, "not enough space to serialize GUC state" ); |
| 10055 | } |
| 10056 | |
| 10057 | /* Shift the destptr ahead of the null terminator */ |
| 10058 | *destptr += n + 1; |
| 10059 | *maxbytes -= n + 1; |
| 10060 | } |
| 10061 | |
| 10062 | /* Binary copy version of do_serialize() */ |
| 10063 | static void |
| 10064 | do_serialize_binary(char **destptr, Size *maxbytes, void *val, Size valsize) |
| 10065 | { |
| 10066 | if (valsize > *maxbytes) |
| 10067 | elog(ERROR, "not enough space to serialize GUC state" ); |
| 10068 | |
| 10069 | memcpy(*destptr, val, valsize); |
| 10070 | *destptr += valsize; |
| 10071 | *maxbytes -= valsize; |
| 10072 | } |
| 10073 | |
| 10074 | /* |
| 10075 | * serialize_variable: |
| 10076 | * Dumps name, value and other information of a GUC variable into destptr. |
| 10077 | */ |
| 10078 | static void |
| 10079 | serialize_variable(char **destptr, Size *maxbytes, |
| 10080 | struct config_generic *gconf) |
| 10081 | { |
| 10082 | if (can_skip_gucvar(gconf)) |
| 10083 | return; |
| 10084 | |
| 10085 | do_serialize(destptr, maxbytes, "%s" , gconf->name); |
| 10086 | |
| 10087 | switch (gconf->vartype) |
| 10088 | { |
| 10089 | case PGC_BOOL: |
| 10090 | { |
| 10091 | struct config_bool *conf = (struct config_bool *) gconf; |
| 10092 | |
| 10093 | do_serialize(destptr, maxbytes, |
| 10094 | (*conf->variable ? "true" : "false" )); |
| 10095 | } |
| 10096 | break; |
| 10097 | |
| 10098 | case PGC_INT: |
| 10099 | { |
| 10100 | struct config_int *conf = (struct config_int *) gconf; |
| 10101 | |
| 10102 | do_serialize(destptr, maxbytes, "%d" , *conf->variable); |
| 10103 | } |
| 10104 | break; |
| 10105 | |
| 10106 | case PGC_REAL: |
| 10107 | { |
| 10108 | struct config_real *conf = (struct config_real *) gconf; |
| 10109 | |
| 10110 | do_serialize(destptr, maxbytes, "%.*e" , |
| 10111 | REALTYPE_PRECISION, *conf->variable); |
| 10112 | } |
| 10113 | break; |
| 10114 | |
| 10115 | case PGC_STRING: |
| 10116 | { |
| 10117 | struct config_string *conf = (struct config_string *) gconf; |
| 10118 | |
| 10119 | /* NULL becomes empty string, see estimate_variable_size() */ |
| 10120 | do_serialize(destptr, maxbytes, "%s" , |
| 10121 | *conf->variable ? *conf->variable : "" ); |
| 10122 | } |
| 10123 | break; |
| 10124 | |
| 10125 | case PGC_ENUM: |
| 10126 | { |
| 10127 | struct config_enum *conf = (struct config_enum *) gconf; |
| 10128 | |
| 10129 | do_serialize(destptr, maxbytes, "%s" , |
| 10130 | config_enum_lookup_by_value(conf, *conf->variable)); |
| 10131 | } |
| 10132 | break; |
| 10133 | } |
| 10134 | |
| 10135 | do_serialize(destptr, maxbytes, "%s" , |
| 10136 | (gconf->sourcefile ? gconf->sourcefile : "" )); |
| 10137 | |
| 10138 | if (gconf->sourcefile && gconf->sourcefile[0]) |
| 10139 | do_serialize_binary(destptr, maxbytes, &gconf->sourceline, |
| 10140 | sizeof(gconf->sourceline)); |
| 10141 | |
| 10142 | do_serialize_binary(destptr, maxbytes, &gconf->source, |
| 10143 | sizeof(gconf->source)); |
| 10144 | do_serialize_binary(destptr, maxbytes, &gconf->scontext, |
| 10145 | sizeof(gconf->scontext)); |
| 10146 | } |
| 10147 | |
| 10148 | /* |
| 10149 | * SerializeGUCState: |
| 10150 | * Dumps the complete GUC state onto the memory location at start_address. |
| 10151 | */ |
| 10152 | void |
| 10153 | SerializeGUCState(Size maxsize, char *start_address) |
| 10154 | { |
| 10155 | char *curptr; |
| 10156 | Size actual_size; |
| 10157 | Size bytes_left; |
| 10158 | int i; |
| 10159 | |
| 10160 | /* Reserve space for saving the actual size of the guc state */ |
| 10161 | Assert(maxsize > sizeof(actual_size)); |
| 10162 | curptr = start_address + sizeof(actual_size); |
| 10163 | bytes_left = maxsize - sizeof(actual_size); |
| 10164 | |
| 10165 | for (i = 0; i < num_guc_variables; i++) |
| 10166 | serialize_variable(&curptr, &bytes_left, guc_variables[i]); |
| 10167 | |
| 10168 | /* Store actual size without assuming alignment of start_address. */ |
| 10169 | actual_size = maxsize - bytes_left - sizeof(actual_size); |
| 10170 | memcpy(start_address, &actual_size, sizeof(actual_size)); |
| 10171 | } |
| 10172 | |
| 10173 | /* |
| 10174 | * read_gucstate: |
| 10175 | * Actually it does not read anything, just returns the srcptr. But it does |
| 10176 | * move the srcptr past the terminating zero byte, so that the caller is ready |
| 10177 | * to read the next string. |
| 10178 | */ |
| 10179 | static char * |
| 10180 | read_gucstate(char **srcptr, char *srcend) |
| 10181 | { |
| 10182 | char *retptr = *srcptr; |
| 10183 | char *ptr; |
| 10184 | |
| 10185 | if (*srcptr >= srcend) |
| 10186 | elog(ERROR, "incomplete GUC state" ); |
| 10187 | |
| 10188 | /* The string variables are all null terminated */ |
| 10189 | for (ptr = *srcptr; ptr < srcend && *ptr != '\0'; ptr++) |
| 10190 | ; |
| 10191 | |
| 10192 | if (ptr >= srcend) |
| 10193 | elog(ERROR, "could not find null terminator in GUC state" ); |
| 10194 | |
| 10195 | /* Set the new position to the byte following the terminating NUL */ |
| 10196 | *srcptr = ptr + 1; |
| 10197 | |
| 10198 | return retptr; |
| 10199 | } |
| 10200 | |
| 10201 | /* Binary read version of read_gucstate(). Copies into dest */ |
| 10202 | static void |
| 10203 | read_gucstate_binary(char **srcptr, char *srcend, void *dest, Size size) |
| 10204 | { |
| 10205 | if (*srcptr + size > srcend) |
| 10206 | elog(ERROR, "incomplete GUC state" ); |
| 10207 | |
| 10208 | memcpy(dest, *srcptr, size); |
| 10209 | *srcptr += size; |
| 10210 | } |
| 10211 | |
| 10212 | /* |
| 10213 | * RestoreGUCState: |
| 10214 | * Reads the GUC state at the specified address and updates the GUCs with the |
| 10215 | * values read from the GUC state. |
| 10216 | */ |
| 10217 | void |
| 10218 | RestoreGUCState(void *gucstate) |
| 10219 | { |
| 10220 | char *varname, |
| 10221 | *varvalue, |
| 10222 | *varsourcefile; |
| 10223 | int varsourceline; |
| 10224 | GucSource varsource; |
| 10225 | GucContext varscontext; |
| 10226 | char *srcptr = (char *) gucstate; |
| 10227 | char *srcend; |
| 10228 | Size len; |
| 10229 | int i; |
| 10230 | |
| 10231 | /* See comment at can_skip_gucvar(). */ |
| 10232 | for (i = 0; i < num_guc_variables; i++) |
| 10233 | if (!can_skip_gucvar(guc_variables[i])) |
| 10234 | InitializeOneGUCOption(guc_variables[i]); |
| 10235 | |
| 10236 | /* First item is the length of the subsequent data */ |
| 10237 | memcpy(&len, gucstate, sizeof(len)); |
| 10238 | |
| 10239 | srcptr += sizeof(len); |
| 10240 | srcend = srcptr + len; |
| 10241 | |
| 10242 | while (srcptr < srcend) |
| 10243 | { |
| 10244 | int result; |
| 10245 | |
| 10246 | varname = read_gucstate(&srcptr, srcend); |
| 10247 | varvalue = read_gucstate(&srcptr, srcend); |
| 10248 | varsourcefile = read_gucstate(&srcptr, srcend); |
| 10249 | if (varsourcefile[0]) |
| 10250 | read_gucstate_binary(&srcptr, srcend, |
| 10251 | &varsourceline, sizeof(varsourceline)); |
| 10252 | else |
| 10253 | varsourceline = 0; |
| 10254 | read_gucstate_binary(&srcptr, srcend, |
| 10255 | &varsource, sizeof(varsource)); |
| 10256 | read_gucstate_binary(&srcptr, srcend, |
| 10257 | &varscontext, sizeof(varscontext)); |
| 10258 | |
| 10259 | result = set_config_option(varname, varvalue, varscontext, varsource, |
| 10260 | GUC_ACTION_SET, true, ERROR, true); |
| 10261 | if (result <= 0) |
| 10262 | ereport(ERROR, |
| 10263 | (errcode(ERRCODE_INTERNAL_ERROR), |
| 10264 | errmsg("parameter \"%s\" could not be set" , varname))); |
| 10265 | if (varsourcefile[0]) |
| 10266 | set_config_sourcefile(varname, varsourcefile, varsourceline); |
| 10267 | } |
| 10268 | } |
| 10269 | |
| 10270 | /* |
| 10271 | * A little "long argument" simulation, although not quite GNU |
| 10272 | * compliant. Takes a string of the form "some-option=some value" and |
| 10273 | * returns name = "some_option" and value = "some value" in malloc'ed |
| 10274 | * storage. Note that '-' is converted to '_' in the option name. If |
| 10275 | * there is no '=' in the input string then value will be NULL. |
| 10276 | */ |
| 10277 | void |
| 10278 | ParseLongOption(const char *string, char **name, char **value) |
| 10279 | { |
| 10280 | size_t equal_pos; |
| 10281 | char *cp; |
| 10282 | |
| 10283 | AssertArg(string); |
| 10284 | AssertArg(name); |
| 10285 | AssertArg(value); |
| 10286 | |
| 10287 | equal_pos = strcspn(string, "=" ); |
| 10288 | |
| 10289 | if (string[equal_pos] == '=') |
| 10290 | { |
| 10291 | *name = guc_malloc(FATAL, equal_pos + 1); |
| 10292 | strlcpy(*name, string, equal_pos + 1); |
| 10293 | |
| 10294 | *value = guc_strdup(FATAL, &string[equal_pos + 1]); |
| 10295 | } |
| 10296 | else |
| 10297 | { |
| 10298 | /* no equal sign in string */ |
| 10299 | *name = guc_strdup(FATAL, string); |
| 10300 | *value = NULL; |
| 10301 | } |
| 10302 | |
| 10303 | for (cp = *name; *cp; cp++) |
| 10304 | if (*cp == '-') |
| 10305 | *cp = '_'; |
| 10306 | } |
| 10307 | |
| 10308 | |
| 10309 | /* |
| 10310 | * Handle options fetched from pg_db_role_setting.setconfig, |
| 10311 | * pg_proc.proconfig, etc. Caller must specify proper context/source/action. |
| 10312 | * |
| 10313 | * The array parameter must be an array of TEXT (it must not be NULL). |
| 10314 | */ |
| 10315 | void |
| 10316 | ProcessGUCArray(ArrayType *array, |
| 10317 | GucContext context, GucSource source, GucAction action) |
| 10318 | { |
| 10319 | int i; |
| 10320 | |
| 10321 | Assert(array != NULL); |
| 10322 | Assert(ARR_ELEMTYPE(array) == TEXTOID); |
| 10323 | Assert(ARR_NDIM(array) == 1); |
| 10324 | Assert(ARR_LBOUND(array)[0] == 1); |
| 10325 | |
| 10326 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
| 10327 | { |
| 10328 | Datum d; |
| 10329 | bool isnull; |
| 10330 | char *s; |
| 10331 | char *name; |
| 10332 | char *value; |
| 10333 | |
| 10334 | d = array_ref(array, 1, &i, |
| 10335 | -1 /* varlenarray */ , |
| 10336 | -1 /* TEXT's typlen */ , |
| 10337 | false /* TEXT's typbyval */ , |
| 10338 | 'i' /* TEXT's typalign */ , |
| 10339 | &isnull); |
| 10340 | |
| 10341 | if (isnull) |
| 10342 | continue; |
| 10343 | |
| 10344 | s = TextDatumGetCString(d); |
| 10345 | |
| 10346 | ParseLongOption(s, &name, &value); |
| 10347 | if (!value) |
| 10348 | { |
| 10349 | ereport(WARNING, |
| 10350 | (errcode(ERRCODE_SYNTAX_ERROR), |
| 10351 | errmsg("could not parse setting for parameter \"%s\"" , |
| 10352 | name))); |
| 10353 | free(name); |
| 10354 | continue; |
| 10355 | } |
| 10356 | |
| 10357 | (void) set_config_option(name, value, |
| 10358 | context, source, |
| 10359 | action, true, 0, false); |
| 10360 | |
| 10361 | free(name); |
| 10362 | if (value) |
| 10363 | free(value); |
| 10364 | pfree(s); |
| 10365 | } |
| 10366 | } |
| 10367 | |
| 10368 | |
| 10369 | /* |
| 10370 | * Add an entry to an option array. The array parameter may be NULL |
| 10371 | * to indicate the current table entry is NULL. |
| 10372 | */ |
| 10373 | ArrayType * |
| 10374 | GUCArrayAdd(ArrayType *array, const char *name, const char *value) |
| 10375 | { |
| 10376 | struct config_generic *record; |
| 10377 | Datum datum; |
| 10378 | char *newval; |
| 10379 | ArrayType *a; |
| 10380 | |
| 10381 | Assert(name); |
| 10382 | Assert(value); |
| 10383 | |
| 10384 | /* test if the option is valid and we're allowed to set it */ |
| 10385 | (void) validate_option_array_item(name, value, false); |
| 10386 | |
| 10387 | /* normalize name (converts obsolete GUC names to modern spellings) */ |
| 10388 | record = find_option(name, false, WARNING); |
| 10389 | if (record) |
| 10390 | name = record->name; |
| 10391 | |
| 10392 | /* build new item for array */ |
| 10393 | newval = psprintf("%s=%s" , name, value); |
| 10394 | datum = CStringGetTextDatum(newval); |
| 10395 | |
| 10396 | if (array) |
| 10397 | { |
| 10398 | int index; |
| 10399 | bool isnull; |
| 10400 | int i; |
| 10401 | |
| 10402 | Assert(ARR_ELEMTYPE(array) == TEXTOID); |
| 10403 | Assert(ARR_NDIM(array) == 1); |
| 10404 | Assert(ARR_LBOUND(array)[0] == 1); |
| 10405 | |
| 10406 | index = ARR_DIMS(array)[0] + 1; /* add after end */ |
| 10407 | |
| 10408 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
| 10409 | { |
| 10410 | Datum d; |
| 10411 | char *current; |
| 10412 | |
| 10413 | d = array_ref(array, 1, &i, |
| 10414 | -1 /* varlenarray */ , |
| 10415 | -1 /* TEXT's typlen */ , |
| 10416 | false /* TEXT's typbyval */ , |
| 10417 | 'i' /* TEXT's typalign */ , |
| 10418 | &isnull); |
| 10419 | if (isnull) |
| 10420 | continue; |
| 10421 | current = TextDatumGetCString(d); |
| 10422 | |
| 10423 | /* check for match up through and including '=' */ |
| 10424 | if (strncmp(current, newval, strlen(name) + 1) == 0) |
| 10425 | { |
| 10426 | index = i; |
| 10427 | break; |
| 10428 | } |
| 10429 | } |
| 10430 | |
| 10431 | a = array_set(array, 1, &index, |
| 10432 | datum, |
| 10433 | false, |
| 10434 | -1 /* varlena array */ , |
| 10435 | -1 /* TEXT's typlen */ , |
| 10436 | false /* TEXT's typbyval */ , |
| 10437 | 'i' /* TEXT's typalign */ ); |
| 10438 | } |
| 10439 | else |
| 10440 | a = construct_array(&datum, 1, |
| 10441 | TEXTOID, |
| 10442 | -1, false, 'i'); |
| 10443 | |
| 10444 | return a; |
| 10445 | } |
| 10446 | |
| 10447 | |
| 10448 | /* |
| 10449 | * Delete an entry from an option array. The array parameter may be NULL |
| 10450 | * to indicate the current table entry is NULL. Also, if the return value |
| 10451 | * is NULL then a null should be stored. |
| 10452 | */ |
| 10453 | ArrayType * |
| 10454 | GUCArrayDelete(ArrayType *array, const char *name) |
| 10455 | { |
| 10456 | struct config_generic *record; |
| 10457 | ArrayType *newarray; |
| 10458 | int i; |
| 10459 | int index; |
| 10460 | |
| 10461 | Assert(name); |
| 10462 | |
| 10463 | /* test if the option is valid and we're allowed to set it */ |
| 10464 | (void) validate_option_array_item(name, NULL, false); |
| 10465 | |
| 10466 | /* normalize name (converts obsolete GUC names to modern spellings) */ |
| 10467 | record = find_option(name, false, WARNING); |
| 10468 | if (record) |
| 10469 | name = record->name; |
| 10470 | |
| 10471 | /* if array is currently null, then surely nothing to delete */ |
| 10472 | if (!array) |
| 10473 | return NULL; |
| 10474 | |
| 10475 | newarray = NULL; |
| 10476 | index = 1; |
| 10477 | |
| 10478 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
| 10479 | { |
| 10480 | Datum d; |
| 10481 | char *val; |
| 10482 | bool isnull; |
| 10483 | |
| 10484 | d = array_ref(array, 1, &i, |
| 10485 | -1 /* varlenarray */ , |
| 10486 | -1 /* TEXT's typlen */ , |
| 10487 | false /* TEXT's typbyval */ , |
| 10488 | 'i' /* TEXT's typalign */ , |
| 10489 | &isnull); |
| 10490 | if (isnull) |
| 10491 | continue; |
| 10492 | val = TextDatumGetCString(d); |
| 10493 | |
| 10494 | /* ignore entry if it's what we want to delete */ |
| 10495 | if (strncmp(val, name, strlen(name)) == 0 |
| 10496 | && val[strlen(name)] == '=') |
| 10497 | continue; |
| 10498 | |
| 10499 | /* else add it to the output array */ |
| 10500 | if (newarray) |
| 10501 | newarray = array_set(newarray, 1, &index, |
| 10502 | d, |
| 10503 | false, |
| 10504 | -1 /* varlenarray */ , |
| 10505 | -1 /* TEXT's typlen */ , |
| 10506 | false /* TEXT's typbyval */ , |
| 10507 | 'i' /* TEXT's typalign */ ); |
| 10508 | else |
| 10509 | newarray = construct_array(&d, 1, |
| 10510 | TEXTOID, |
| 10511 | -1, false, 'i'); |
| 10512 | |
| 10513 | index++; |
| 10514 | } |
| 10515 | |
| 10516 | return newarray; |
| 10517 | } |
| 10518 | |
| 10519 | |
| 10520 | /* |
| 10521 | * Given a GUC array, delete all settings from it that our permission |
| 10522 | * level allows: if superuser, delete them all; if regular user, only |
| 10523 | * those that are PGC_USERSET |
| 10524 | */ |
| 10525 | ArrayType * |
| 10526 | GUCArrayReset(ArrayType *array) |
| 10527 | { |
| 10528 | ArrayType *newarray; |
| 10529 | int i; |
| 10530 | int index; |
| 10531 | |
| 10532 | /* if array is currently null, nothing to do */ |
| 10533 | if (!array) |
| 10534 | return NULL; |
| 10535 | |
| 10536 | /* if we're superuser, we can delete everything, so just do it */ |
| 10537 | if (superuser()) |
| 10538 | return NULL; |
| 10539 | |
| 10540 | newarray = NULL; |
| 10541 | index = 1; |
| 10542 | |
| 10543 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
| 10544 | { |
| 10545 | Datum d; |
| 10546 | char *val; |
| 10547 | char *eqsgn; |
| 10548 | bool isnull; |
| 10549 | |
| 10550 | d = array_ref(array, 1, &i, |
| 10551 | -1 /* varlenarray */ , |
| 10552 | -1 /* TEXT's typlen */ , |
| 10553 | false /* TEXT's typbyval */ , |
| 10554 | 'i' /* TEXT's typalign */ , |
| 10555 | &isnull); |
| 10556 | if (isnull) |
| 10557 | continue; |
| 10558 | val = TextDatumGetCString(d); |
| 10559 | |
| 10560 | eqsgn = strchr(val, '='); |
| 10561 | *eqsgn = '\0'; |
| 10562 | |
| 10563 | /* skip if we have permission to delete it */ |
| 10564 | if (validate_option_array_item(val, NULL, true)) |
| 10565 | continue; |
| 10566 | |
| 10567 | /* else add it to the output array */ |
| 10568 | if (newarray) |
| 10569 | newarray = array_set(newarray, 1, &index, |
| 10570 | d, |
| 10571 | false, |
| 10572 | -1 /* varlenarray */ , |
| 10573 | -1 /* TEXT's typlen */ , |
| 10574 | false /* TEXT's typbyval */ , |
| 10575 | 'i' /* TEXT's typalign */ ); |
| 10576 | else |
| 10577 | newarray = construct_array(&d, 1, |
| 10578 | TEXTOID, |
| 10579 | -1, false, 'i'); |
| 10580 | |
| 10581 | index++; |
| 10582 | pfree(val); |
| 10583 | } |
| 10584 | |
| 10585 | return newarray; |
| 10586 | } |
| 10587 | |
| 10588 | /* |
| 10589 | * Validate a proposed option setting for GUCArrayAdd/Delete/Reset. |
| 10590 | * |
| 10591 | * name is the option name. value is the proposed value for the Add case, |
| 10592 | * or NULL for the Delete/Reset cases. If skipIfNoPermissions is true, it's |
| 10593 | * not an error to have no permissions to set the option. |
| 10594 | * |
| 10595 | * Returns true if OK, false if skipIfNoPermissions is true and user does not |
| 10596 | * have permission to change this option (all other error cases result in an |
| 10597 | * error being thrown). |
| 10598 | */ |
| 10599 | static bool |
| 10600 | validate_option_array_item(const char *name, const char *value, |
| 10601 | bool skipIfNoPermissions) |
| 10602 | |
| 10603 | { |
| 10604 | struct config_generic *gconf; |
| 10605 | |
| 10606 | /* |
| 10607 | * There are three cases to consider: |
| 10608 | * |
| 10609 | * name is a known GUC variable. Check the value normally, check |
| 10610 | * permissions normally (i.e., allow if variable is USERSET, or if it's |
| 10611 | * SUSET and user is superuser). |
| 10612 | * |
| 10613 | * name is not known, but exists or can be created as a placeholder (i.e., |
| 10614 | * it has a prefixed name). We allow this case if you're a superuser, |
| 10615 | * otherwise not. Superusers are assumed to know what they're doing. We |
| 10616 | * can't allow it for other users, because when the placeholder is |
| 10617 | * resolved it might turn out to be a SUSET variable; |
| 10618 | * define_custom_variable assumes we checked that. |
| 10619 | * |
| 10620 | * name is not known and can't be created as a placeholder. Throw error, |
| 10621 | * unless skipIfNoPermissions is true, in which case return false. |
| 10622 | */ |
| 10623 | gconf = find_option(name, true, WARNING); |
| 10624 | if (!gconf) |
| 10625 | { |
| 10626 | /* not known, failed to make a placeholder */ |
| 10627 | if (skipIfNoPermissions) |
| 10628 | return false; |
| 10629 | ereport(ERROR, |
| 10630 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
| 10631 | errmsg("unrecognized configuration parameter \"%s\"" , |
| 10632 | name))); |
| 10633 | } |
| 10634 | |
| 10635 | if (gconf->flags & GUC_CUSTOM_PLACEHOLDER) |
| 10636 | { |
| 10637 | /* |
| 10638 | * We cannot do any meaningful check on the value, so only permissions |
| 10639 | * are useful to check. |
| 10640 | */ |
| 10641 | if (superuser()) |
| 10642 | return true; |
| 10643 | if (skipIfNoPermissions) |
| 10644 | return false; |
| 10645 | ereport(ERROR, |
| 10646 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 10647 | errmsg("permission denied to set parameter \"%s\"" , name))); |
| 10648 | } |
| 10649 | |
| 10650 | /* manual permissions check so we can avoid an error being thrown */ |
| 10651 | if (gconf->context == PGC_USERSET) |
| 10652 | /* ok */ ; |
| 10653 | else if (gconf->context == PGC_SUSET && superuser()) |
| 10654 | /* ok */ ; |
| 10655 | else if (skipIfNoPermissions) |
| 10656 | return false; |
| 10657 | /* if a permissions error should be thrown, let set_config_option do it */ |
| 10658 | |
| 10659 | /* test for permissions and valid option value */ |
| 10660 | (void) set_config_option(name, value, |
| 10661 | superuser() ? PGC_SUSET : PGC_USERSET, |
| 10662 | PGC_S_TEST, GUC_ACTION_SET, false, 0, false); |
| 10663 | |
| 10664 | return true; |
| 10665 | } |
| 10666 | |
| 10667 | |
| 10668 | /* |
| 10669 | * Called by check_hooks that want to override the normal |
| 10670 | * ERRCODE_INVALID_PARAMETER_VALUE SQLSTATE for check hook failures. |
| 10671 | * |
| 10672 | * Note that GUC_check_errmsg() etc are just macros that result in a direct |
| 10673 | * assignment to the associated variables. That is ugly, but forced by the |
| 10674 | * limitations of C's macro mechanisms. |
| 10675 | */ |
| 10676 | void |
| 10677 | GUC_check_errcode(int sqlerrcode) |
| 10678 | { |
| 10679 | GUC_check_errcode_value = sqlerrcode; |
| 10680 | } |
| 10681 | |
| 10682 | |
| 10683 | /* |
| 10684 | * Convenience functions to manage calling a variable's check_hook. |
| 10685 | * These mostly take care of the protocol for letting check hooks supply |
| 10686 | * portions of the error report on failure. |
| 10687 | */ |
| 10688 | |
| 10689 | static bool |
| 10690 | call_bool_check_hook(struct config_bool *conf, bool *newval, void **, |
| 10691 | GucSource source, int elevel) |
| 10692 | { |
| 10693 | /* Quick success if no hook */ |
| 10694 | if (!conf->check_hook) |
| 10695 | return true; |
| 10696 | |
| 10697 | /* Reset variables that might be set by hook */ |
| 10698 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
| 10699 | GUC_check_errmsg_string = NULL; |
| 10700 | GUC_check_errdetail_string = NULL; |
| 10701 | GUC_check_errhint_string = NULL; |
| 10702 | |
| 10703 | if (!conf->check_hook(newval, extra, source)) |
| 10704 | { |
| 10705 | ereport(elevel, |
| 10706 | (errcode(GUC_check_errcode_value), |
| 10707 | GUC_check_errmsg_string ? |
| 10708 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
| 10709 | errmsg("invalid value for parameter \"%s\": %d" , |
| 10710 | conf->gen.name, (int) *newval), |
| 10711 | GUC_check_errdetail_string ? |
| 10712 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
| 10713 | GUC_check_errhint_string ? |
| 10714 | errhint("%s" , GUC_check_errhint_string) : 0)); |
| 10715 | /* Flush any strings created in ErrorContext */ |
| 10716 | FlushErrorState(); |
| 10717 | return false; |
| 10718 | } |
| 10719 | |
| 10720 | return true; |
| 10721 | } |
| 10722 | |
| 10723 | static bool |
| 10724 | call_int_check_hook(struct config_int *conf, int *newval, void **, |
| 10725 | GucSource source, int elevel) |
| 10726 | { |
| 10727 | /* Quick success if no hook */ |
| 10728 | if (!conf->check_hook) |
| 10729 | return true; |
| 10730 | |
| 10731 | /* Reset variables that might be set by hook */ |
| 10732 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
| 10733 | GUC_check_errmsg_string = NULL; |
| 10734 | GUC_check_errdetail_string = NULL; |
| 10735 | GUC_check_errhint_string = NULL; |
| 10736 | |
| 10737 | if (!conf->check_hook(newval, extra, source)) |
| 10738 | { |
| 10739 | ereport(elevel, |
| 10740 | (errcode(GUC_check_errcode_value), |
| 10741 | GUC_check_errmsg_string ? |
| 10742 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
| 10743 | errmsg("invalid value for parameter \"%s\": %d" , |
| 10744 | conf->gen.name, *newval), |
| 10745 | GUC_check_errdetail_string ? |
| 10746 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
| 10747 | GUC_check_errhint_string ? |
| 10748 | errhint("%s" , GUC_check_errhint_string) : 0)); |
| 10749 | /* Flush any strings created in ErrorContext */ |
| 10750 | FlushErrorState(); |
| 10751 | return false; |
| 10752 | } |
| 10753 | |
| 10754 | return true; |
| 10755 | } |
| 10756 | |
| 10757 | static bool |
| 10758 | call_real_check_hook(struct config_real *conf, double *newval, void **, |
| 10759 | GucSource source, int elevel) |
| 10760 | { |
| 10761 | /* Quick success if no hook */ |
| 10762 | if (!conf->check_hook) |
| 10763 | return true; |
| 10764 | |
| 10765 | /* Reset variables that might be set by hook */ |
| 10766 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
| 10767 | GUC_check_errmsg_string = NULL; |
| 10768 | GUC_check_errdetail_string = NULL; |
| 10769 | GUC_check_errhint_string = NULL; |
| 10770 | |
| 10771 | if (!conf->check_hook(newval, extra, source)) |
| 10772 | { |
| 10773 | ereport(elevel, |
| 10774 | (errcode(GUC_check_errcode_value), |
| 10775 | GUC_check_errmsg_string ? |
| 10776 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
| 10777 | errmsg("invalid value for parameter \"%s\": %g" , |
| 10778 | conf->gen.name, *newval), |
| 10779 | GUC_check_errdetail_string ? |
| 10780 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
| 10781 | GUC_check_errhint_string ? |
| 10782 | errhint("%s" , GUC_check_errhint_string) : 0)); |
| 10783 | /* Flush any strings created in ErrorContext */ |
| 10784 | FlushErrorState(); |
| 10785 | return false; |
| 10786 | } |
| 10787 | |
| 10788 | return true; |
| 10789 | } |
| 10790 | |
| 10791 | static bool |
| 10792 | call_string_check_hook(struct config_string *conf, char **newval, void **, |
| 10793 | GucSource source, int elevel) |
| 10794 | { |
| 10795 | /* Quick success if no hook */ |
| 10796 | if (!conf->check_hook) |
| 10797 | return true; |
| 10798 | |
| 10799 | /* Reset variables that might be set by hook */ |
| 10800 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
| 10801 | GUC_check_errmsg_string = NULL; |
| 10802 | GUC_check_errdetail_string = NULL; |
| 10803 | GUC_check_errhint_string = NULL; |
| 10804 | |
| 10805 | if (!conf->check_hook(newval, extra, source)) |
| 10806 | { |
| 10807 | ereport(elevel, |
| 10808 | (errcode(GUC_check_errcode_value), |
| 10809 | GUC_check_errmsg_string ? |
| 10810 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
| 10811 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 10812 | conf->gen.name, *newval ? *newval : "" ), |
| 10813 | GUC_check_errdetail_string ? |
| 10814 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
| 10815 | GUC_check_errhint_string ? |
| 10816 | errhint("%s" , GUC_check_errhint_string) : 0)); |
| 10817 | /* Flush any strings created in ErrorContext */ |
| 10818 | FlushErrorState(); |
| 10819 | return false; |
| 10820 | } |
| 10821 | |
| 10822 | return true; |
| 10823 | } |
| 10824 | |
| 10825 | static bool |
| 10826 | call_enum_check_hook(struct config_enum *conf, int *newval, void **, |
| 10827 | GucSource source, int elevel) |
| 10828 | { |
| 10829 | /* Quick success if no hook */ |
| 10830 | if (!conf->check_hook) |
| 10831 | return true; |
| 10832 | |
| 10833 | /* Reset variables that might be set by hook */ |
| 10834 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
| 10835 | GUC_check_errmsg_string = NULL; |
| 10836 | GUC_check_errdetail_string = NULL; |
| 10837 | GUC_check_errhint_string = NULL; |
| 10838 | |
| 10839 | if (!conf->check_hook(newval, extra, source)) |
| 10840 | { |
| 10841 | ereport(elevel, |
| 10842 | (errcode(GUC_check_errcode_value), |
| 10843 | GUC_check_errmsg_string ? |
| 10844 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
| 10845 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
| 10846 | conf->gen.name, |
| 10847 | config_enum_lookup_by_value(conf, *newval)), |
| 10848 | GUC_check_errdetail_string ? |
| 10849 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
| 10850 | GUC_check_errhint_string ? |
| 10851 | errhint("%s" , GUC_check_errhint_string) : 0)); |
| 10852 | /* Flush any strings created in ErrorContext */ |
| 10853 | FlushErrorState(); |
| 10854 | return false; |
| 10855 | } |
| 10856 | |
| 10857 | return true; |
| 10858 | } |
| 10859 | |
| 10860 | |
| 10861 | /* |
| 10862 | * check_hook, assign_hook and show_hook subroutines |
| 10863 | */ |
| 10864 | |
| 10865 | static bool |
| 10866 | check_wal_consistency_checking(char **newval, void **, GucSource source) |
| 10867 | { |
| 10868 | char *rawstring; |
| 10869 | List *elemlist; |
| 10870 | ListCell *l; |
| 10871 | bool newwalconsistency[RM_MAX_ID + 1]; |
| 10872 | |
| 10873 | /* Initialize the array */ |
| 10874 | MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool)); |
| 10875 | |
| 10876 | /* Need a modifiable copy of string */ |
| 10877 | rawstring = pstrdup(*newval); |
| 10878 | |
| 10879 | /* Parse string into list of identifiers */ |
| 10880 | if (!SplitIdentifierString(rawstring, ',', &elemlist)) |
| 10881 | { |
| 10882 | /* syntax error in list */ |
| 10883 | GUC_check_errdetail("List syntax is invalid." ); |
| 10884 | pfree(rawstring); |
| 10885 | list_free(elemlist); |
| 10886 | return false; |
| 10887 | } |
| 10888 | |
| 10889 | foreach(l, elemlist) |
| 10890 | { |
| 10891 | char *tok = (char *) lfirst(l); |
| 10892 | bool found = false; |
| 10893 | RmgrId rmid; |
| 10894 | |
| 10895 | /* Check for 'all'. */ |
| 10896 | if (pg_strcasecmp(tok, "all" ) == 0) |
| 10897 | { |
| 10898 | for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 10899 | if (RmgrTable[rmid].rm_mask != NULL) |
| 10900 | newwalconsistency[rmid] = true; |
| 10901 | found = true; |
| 10902 | } |
| 10903 | else |
| 10904 | { |
| 10905 | /* |
| 10906 | * Check if the token matches with any individual resource |
| 10907 | * manager. |
| 10908 | */ |
| 10909 | for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
| 10910 | { |
| 10911 | if (pg_strcasecmp(tok, RmgrTable[rmid].rm_name) == 0 && |
| 10912 | RmgrTable[rmid].rm_mask != NULL) |
| 10913 | { |
| 10914 | newwalconsistency[rmid] = true; |
| 10915 | found = true; |
| 10916 | } |
| 10917 | } |
| 10918 | } |
| 10919 | |
| 10920 | /* If a valid resource manager is found, check for the next one. */ |
| 10921 | if (!found) |
| 10922 | { |
| 10923 | GUC_check_errdetail("Unrecognized key word: \"%s\"." , tok); |
| 10924 | pfree(rawstring); |
| 10925 | list_free(elemlist); |
| 10926 | return false; |
| 10927 | } |
| 10928 | } |
| 10929 | |
| 10930 | pfree(rawstring); |
| 10931 | list_free(elemlist); |
| 10932 | |
| 10933 | /* assign new value */ |
| 10934 | *extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool)); |
| 10935 | memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool)); |
| 10936 | return true; |
| 10937 | } |
| 10938 | |
| 10939 | static void |
| 10940 | assign_wal_consistency_checking(const char *newval, void *) |
| 10941 | { |
| 10942 | wal_consistency_checking = (bool *) extra; |
| 10943 | } |
| 10944 | |
| 10945 | static bool |
| 10946 | check_log_destination(char **newval, void **, GucSource source) |
| 10947 | { |
| 10948 | char *rawstring; |
| 10949 | List *elemlist; |
| 10950 | ListCell *l; |
| 10951 | int newlogdest = 0; |
| 10952 | int *; |
| 10953 | |
| 10954 | /* Need a modifiable copy of string */ |
| 10955 | rawstring = pstrdup(*newval); |
| 10956 | |
| 10957 | /* Parse string into list of identifiers */ |
| 10958 | if (!SplitIdentifierString(rawstring, ',', &elemlist)) |
| 10959 | { |
| 10960 | /* syntax error in list */ |
| 10961 | GUC_check_errdetail("List syntax is invalid." ); |
| 10962 | pfree(rawstring); |
| 10963 | list_free(elemlist); |
| 10964 | return false; |
| 10965 | } |
| 10966 | |
| 10967 | foreach(l, elemlist) |
| 10968 | { |
| 10969 | char *tok = (char *) lfirst(l); |
| 10970 | |
| 10971 | if (pg_strcasecmp(tok, "stderr" ) == 0) |
| 10972 | newlogdest |= LOG_DESTINATION_STDERR; |
| 10973 | else if (pg_strcasecmp(tok, "csvlog" ) == 0) |
| 10974 | newlogdest |= LOG_DESTINATION_CSVLOG; |
| 10975 | #ifdef HAVE_SYSLOG |
| 10976 | else if (pg_strcasecmp(tok, "syslog" ) == 0) |
| 10977 | newlogdest |= LOG_DESTINATION_SYSLOG; |
| 10978 | #endif |
| 10979 | #ifdef WIN32 |
| 10980 | else if (pg_strcasecmp(tok, "eventlog" ) == 0) |
| 10981 | newlogdest |= LOG_DESTINATION_EVENTLOG; |
| 10982 | #endif |
| 10983 | else |
| 10984 | { |
| 10985 | GUC_check_errdetail("Unrecognized key word: \"%s\"." , tok); |
| 10986 | pfree(rawstring); |
| 10987 | list_free(elemlist); |
| 10988 | return false; |
| 10989 | } |
| 10990 | } |
| 10991 | |
| 10992 | pfree(rawstring); |
| 10993 | list_free(elemlist); |
| 10994 | |
| 10995 | myextra = (int *) guc_malloc(ERROR, sizeof(int)); |
| 10996 | *myextra = newlogdest; |
| 10997 | *extra = (void *) myextra; |
| 10998 | |
| 10999 | return true; |
| 11000 | } |
| 11001 | |
| 11002 | static void |
| 11003 | assign_log_destination(const char *newval, void *) |
| 11004 | { |
| 11005 | Log_destination = *((int *) extra); |
| 11006 | } |
| 11007 | |
| 11008 | static void |
| 11009 | assign_syslog_facility(int newval, void *) |
| 11010 | { |
| 11011 | #ifdef HAVE_SYSLOG |
| 11012 | set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres" , |
| 11013 | newval); |
| 11014 | #endif |
| 11015 | /* Without syslog support, just ignore it */ |
| 11016 | } |
| 11017 | |
| 11018 | static void |
| 11019 | assign_syslog_ident(const char *newval, void *) |
| 11020 | { |
| 11021 | #ifdef HAVE_SYSLOG |
| 11022 | set_syslog_parameters(newval, syslog_facility); |
| 11023 | #endif |
| 11024 | /* Without syslog support, it will always be set to "none", so ignore */ |
| 11025 | } |
| 11026 | |
| 11027 | |
| 11028 | static void |
| 11029 | assign_session_replication_role(int newval, void *) |
| 11030 | { |
| 11031 | /* |
| 11032 | * Must flush the plan cache when changing replication role; but don't |
| 11033 | * flush unnecessarily. |
| 11034 | */ |
| 11035 | if (SessionReplicationRole != newval) |
| 11036 | ResetPlanCache(); |
| 11037 | } |
| 11038 | |
| 11039 | static bool |
| 11040 | check_temp_buffers(int *newval, void **, GucSource source) |
| 11041 | { |
| 11042 | /* |
| 11043 | * Once local buffers have been initialized, it's too late to change this. |
| 11044 | */ |
| 11045 | if (NLocBuffer && NLocBuffer != *newval) |
| 11046 | { |
| 11047 | GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session." ); |
| 11048 | return false; |
| 11049 | } |
| 11050 | return true; |
| 11051 | } |
| 11052 | |
| 11053 | static bool |
| 11054 | check_bonjour(bool *newval, void **, GucSource source) |
| 11055 | { |
| 11056 | #ifndef USE_BONJOUR |
| 11057 | if (*newval) |
| 11058 | { |
| 11059 | GUC_check_errmsg("Bonjour is not supported by this build" ); |
| 11060 | return false; |
| 11061 | } |
| 11062 | #endif |
| 11063 | return true; |
| 11064 | } |
| 11065 | |
| 11066 | static bool |
| 11067 | check_ssl(bool *newval, void **, GucSource source) |
| 11068 | { |
| 11069 | #ifndef USE_SSL |
| 11070 | if (*newval) |
| 11071 | { |
| 11072 | GUC_check_errmsg("SSL is not supported by this build" ); |
| 11073 | return false; |
| 11074 | } |
| 11075 | #endif |
| 11076 | return true; |
| 11077 | } |
| 11078 | |
| 11079 | static bool |
| 11080 | check_stage_log_stats(bool *newval, void **, GucSource source) |
| 11081 | { |
| 11082 | if (*newval && log_statement_stats) |
| 11083 | { |
| 11084 | GUC_check_errdetail("Cannot enable parameter when \"log_statement_stats\" is true." ); |
| 11085 | return false; |
| 11086 | } |
| 11087 | return true; |
| 11088 | } |
| 11089 | |
| 11090 | static bool |
| 11091 | check_log_stats(bool *newval, void **, GucSource source) |
| 11092 | { |
| 11093 | if (*newval && |
| 11094 | (log_parser_stats || log_planner_stats || log_executor_stats)) |
| 11095 | { |
| 11096 | GUC_check_errdetail("Cannot enable \"log_statement_stats\" when " |
| 11097 | "\"log_parser_stats\", \"log_planner_stats\", " |
| 11098 | "or \"log_executor_stats\" is true." ); |
| 11099 | return false; |
| 11100 | } |
| 11101 | return true; |
| 11102 | } |
| 11103 | |
| 11104 | static bool |
| 11105 | check_canonical_path(char **newval, void **, GucSource source) |
| 11106 | { |
| 11107 | /* |
| 11108 | * Since canonicalize_path never enlarges the string, we can just modify |
| 11109 | * newval in-place. But watch out for NULL, which is the default value |
| 11110 | * for external_pid_file. |
| 11111 | */ |
| 11112 | if (*newval) |
| 11113 | canonicalize_path(*newval); |
| 11114 | return true; |
| 11115 | } |
| 11116 | |
| 11117 | static bool |
| 11118 | check_timezone_abbreviations(char **newval, void **, GucSource source) |
| 11119 | { |
| 11120 | /* |
| 11121 | * The boot_val given above for timezone_abbreviations is NULL. When we |
| 11122 | * see this we just do nothing. If this value isn't overridden from the |
| 11123 | * config file then pg_timezone_abbrev_initialize() will eventually |
| 11124 | * replace it with "Default". This hack has two purposes: to avoid |
| 11125 | * wasting cycles loading values that might soon be overridden from the |
| 11126 | * config file, and to avoid trying to read the timezone abbrev files |
| 11127 | * during InitializeGUCOptions(). The latter doesn't work in an |
| 11128 | * EXEC_BACKEND subprocess because my_exec_path hasn't been set yet and so |
| 11129 | * we can't locate PGSHAREDIR. |
| 11130 | */ |
| 11131 | if (*newval == NULL) |
| 11132 | { |
| 11133 | Assert(source == PGC_S_DEFAULT); |
| 11134 | return true; |
| 11135 | } |
| 11136 | |
| 11137 | /* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */ |
| 11138 | *extra = load_tzoffsets(*newval); |
| 11139 | |
| 11140 | /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */ |
| 11141 | if (!*extra) |
| 11142 | return false; |
| 11143 | |
| 11144 | return true; |
| 11145 | } |
| 11146 | |
| 11147 | static void |
| 11148 | assign_timezone_abbreviations(const char *newval, void *) |
| 11149 | { |
| 11150 | /* Do nothing for the boot_val default of NULL */ |
| 11151 | if (!extra) |
| 11152 | return; |
| 11153 | |
| 11154 | InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra); |
| 11155 | } |
| 11156 | |
| 11157 | /* |
| 11158 | * pg_timezone_abbrev_initialize --- set default value if not done already |
| 11159 | * |
| 11160 | * This is called after initial loading of postgresql.conf. If no |
| 11161 | * timezone_abbreviations setting was found therein, select default. |
| 11162 | * If a non-default value is already installed, nothing will happen. |
| 11163 | * |
| 11164 | * This can also be called from ProcessConfigFile to establish the default |
| 11165 | * value after a postgresql.conf entry for it is removed. |
| 11166 | */ |
| 11167 | static void |
| 11168 | pg_timezone_abbrev_initialize(void) |
| 11169 | { |
| 11170 | SetConfigOption("timezone_abbreviations" , "Default" , |
| 11171 | PGC_POSTMASTER, PGC_S_DYNAMIC_DEFAULT); |
| 11172 | } |
| 11173 | |
| 11174 | static const char * |
| 11175 | show_archive_command(void) |
| 11176 | { |
| 11177 | if (XLogArchivingActive()) |
| 11178 | return XLogArchiveCommand; |
| 11179 | else |
| 11180 | return "(disabled)" ; |
| 11181 | } |
| 11182 | |
| 11183 | static void |
| 11184 | assign_tcp_keepalives_idle(int newval, void *) |
| 11185 | { |
| 11186 | /* |
| 11187 | * The kernel API provides no way to test a value without setting it; and |
| 11188 | * once we set it we might fail to unset it. So there seems little point |
| 11189 | * in fully implementing the check-then-assign GUC API for these |
| 11190 | * variables. Instead we just do the assignment on demand. pqcomm.c |
| 11191 | * reports any problems via elog(LOG). |
| 11192 | * |
| 11193 | * This approach means that the GUC value might have little to do with the |
| 11194 | * actual kernel value, so we use a show_hook that retrieves the kernel |
| 11195 | * value rather than trusting GUC's copy. |
| 11196 | */ |
| 11197 | (void) pq_setkeepalivesidle(newval, MyProcPort); |
| 11198 | } |
| 11199 | |
| 11200 | static const char * |
| 11201 | show_tcp_keepalives_idle(void) |
| 11202 | { |
| 11203 | /* See comments in assign_tcp_keepalives_idle */ |
| 11204 | static char nbuf[16]; |
| 11205 | |
| 11206 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivesidle(MyProcPort)); |
| 11207 | return nbuf; |
| 11208 | } |
| 11209 | |
| 11210 | static void |
| 11211 | assign_tcp_keepalives_interval(int newval, void *) |
| 11212 | { |
| 11213 | /* See comments in assign_tcp_keepalives_idle */ |
| 11214 | (void) pq_setkeepalivesinterval(newval, MyProcPort); |
| 11215 | } |
| 11216 | |
| 11217 | static const char * |
| 11218 | show_tcp_keepalives_interval(void) |
| 11219 | { |
| 11220 | /* See comments in assign_tcp_keepalives_idle */ |
| 11221 | static char nbuf[16]; |
| 11222 | |
| 11223 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivesinterval(MyProcPort)); |
| 11224 | return nbuf; |
| 11225 | } |
| 11226 | |
| 11227 | static void |
| 11228 | assign_tcp_keepalives_count(int newval, void *) |
| 11229 | { |
| 11230 | /* See comments in assign_tcp_keepalives_idle */ |
| 11231 | (void) pq_setkeepalivescount(newval, MyProcPort); |
| 11232 | } |
| 11233 | |
| 11234 | static const char * |
| 11235 | show_tcp_keepalives_count(void) |
| 11236 | { |
| 11237 | /* See comments in assign_tcp_keepalives_idle */ |
| 11238 | static char nbuf[16]; |
| 11239 | |
| 11240 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivescount(MyProcPort)); |
| 11241 | return nbuf; |
| 11242 | } |
| 11243 | |
| 11244 | static void |
| 11245 | assign_tcp_user_timeout(int newval, void *) |
| 11246 | { |
| 11247 | /* See comments in assign_tcp_keepalives_idle */ |
| 11248 | (void) pq_settcpusertimeout(newval, MyProcPort); |
| 11249 | } |
| 11250 | |
| 11251 | static const char * |
| 11252 | show_tcp_user_timeout(void) |
| 11253 | { |
| 11254 | /* See comments in assign_tcp_keepalives_idle */ |
| 11255 | static char nbuf[16]; |
| 11256 | |
| 11257 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_gettcpusertimeout(MyProcPort)); |
| 11258 | return nbuf; |
| 11259 | } |
| 11260 | |
| 11261 | static bool |
| 11262 | check_maxconnections(int *newval, void **, GucSource source) |
| 11263 | { |
| 11264 | if (*newval + autovacuum_max_workers + 1 + |
| 11265 | max_worker_processes + max_wal_senders > MAX_BACKENDS) |
| 11266 | return false; |
| 11267 | return true; |
| 11268 | } |
| 11269 | |
| 11270 | static bool |
| 11271 | check_autovacuum_max_workers(int *newval, void **, GucSource source) |
| 11272 | { |
| 11273 | if (MaxConnections + *newval + 1 + |
| 11274 | max_worker_processes + max_wal_senders > MAX_BACKENDS) |
| 11275 | return false; |
| 11276 | return true; |
| 11277 | } |
| 11278 | |
| 11279 | static bool |
| 11280 | check_max_wal_senders(int *newval, void **, GucSource source) |
| 11281 | { |
| 11282 | if (MaxConnections + autovacuum_max_workers + 1 + |
| 11283 | max_worker_processes + *newval > MAX_BACKENDS) |
| 11284 | return false; |
| 11285 | return true; |
| 11286 | } |
| 11287 | |
| 11288 | static bool |
| 11289 | check_autovacuum_work_mem(int *newval, void **, GucSource source) |
| 11290 | { |
| 11291 | /* |
| 11292 | * -1 indicates fallback. |
| 11293 | * |
| 11294 | * If we haven't yet changed the boot_val default of -1, just let it be. |
| 11295 | * Autovacuum will look to maintenance_work_mem instead. |
| 11296 | */ |
| 11297 | if (*newval == -1) |
| 11298 | return true; |
| 11299 | |
| 11300 | /* |
| 11301 | * We clamp manually-set values to at least 1MB. Since |
| 11302 | * maintenance_work_mem is always set to at least this value, do the same |
| 11303 | * here. |
| 11304 | */ |
| 11305 | if (*newval < 1024) |
| 11306 | *newval = 1024; |
| 11307 | |
| 11308 | return true; |
| 11309 | } |
| 11310 | |
| 11311 | static bool |
| 11312 | check_max_worker_processes(int *newval, void **, GucSource source) |
| 11313 | { |
| 11314 | if (MaxConnections + autovacuum_max_workers + 1 + |
| 11315 | *newval + max_wal_senders > MAX_BACKENDS) |
| 11316 | return false; |
| 11317 | return true; |
| 11318 | } |
| 11319 | |
| 11320 | static bool |
| 11321 | check_effective_io_concurrency(int *newval, void **, GucSource source) |
| 11322 | { |
| 11323 | #ifdef USE_PREFETCH |
| 11324 | double new_prefetch_pages; |
| 11325 | |
| 11326 | if (ComputeIoConcurrency(*newval, &new_prefetch_pages)) |
| 11327 | { |
| 11328 | int * = (int *) guc_malloc(ERROR, sizeof(int)); |
| 11329 | |
| 11330 | *myextra = (int) rint(new_prefetch_pages); |
| 11331 | *extra = (void *) myextra; |
| 11332 | |
| 11333 | return true; |
| 11334 | } |
| 11335 | else |
| 11336 | return false; |
| 11337 | #else |
| 11338 | if (*newval != 0) |
| 11339 | { |
| 11340 | GUC_check_errdetail("effective_io_concurrency must be set to 0 on platforms that lack posix_fadvise()." ); |
| 11341 | return false; |
| 11342 | } |
| 11343 | return true; |
| 11344 | #endif /* USE_PREFETCH */ |
| 11345 | } |
| 11346 | |
| 11347 | static void |
| 11348 | assign_effective_io_concurrency(int newval, void *) |
| 11349 | { |
| 11350 | #ifdef USE_PREFETCH |
| 11351 | target_prefetch_pages = *((int *) extra); |
| 11352 | #endif /* USE_PREFETCH */ |
| 11353 | } |
| 11354 | |
| 11355 | static void |
| 11356 | assign_pgstat_temp_directory(const char *newval, void *) |
| 11357 | { |
| 11358 | /* check_canonical_path already canonicalized newval for us */ |
| 11359 | char *dname; |
| 11360 | char *tname; |
| 11361 | char *fname; |
| 11362 | |
| 11363 | /* directory */ |
| 11364 | dname = guc_malloc(ERROR, strlen(newval) + 1); /* runtime dir */ |
| 11365 | sprintf(dname, "%s" , newval); |
| 11366 | |
| 11367 | /* global stats */ |
| 11368 | tname = guc_malloc(ERROR, strlen(newval) + 12); /* /global.tmp */ |
| 11369 | sprintf(tname, "%s/global.tmp" , newval); |
| 11370 | fname = guc_malloc(ERROR, strlen(newval) + 13); /* /global.stat */ |
| 11371 | sprintf(fname, "%s/global.stat" , newval); |
| 11372 | |
| 11373 | if (pgstat_stat_directory) |
| 11374 | free(pgstat_stat_directory); |
| 11375 | pgstat_stat_directory = dname; |
| 11376 | if (pgstat_stat_tmpname) |
| 11377 | free(pgstat_stat_tmpname); |
| 11378 | pgstat_stat_tmpname = tname; |
| 11379 | if (pgstat_stat_filename) |
| 11380 | free(pgstat_stat_filename); |
| 11381 | pgstat_stat_filename = fname; |
| 11382 | } |
| 11383 | |
| 11384 | static bool |
| 11385 | check_application_name(char **newval, void **, GucSource source) |
| 11386 | { |
| 11387 | /* Only allow clean ASCII chars in the application name */ |
| 11388 | pg_clean_ascii(*newval); |
| 11389 | |
| 11390 | return true; |
| 11391 | } |
| 11392 | |
| 11393 | static void |
| 11394 | assign_application_name(const char *newval, void *) |
| 11395 | { |
| 11396 | /* Update the pg_stat_activity view */ |
| 11397 | pgstat_report_appname(newval); |
| 11398 | } |
| 11399 | |
| 11400 | static bool |
| 11401 | check_cluster_name(char **newval, void **, GucSource source) |
| 11402 | { |
| 11403 | /* Only allow clean ASCII chars in the cluster name */ |
| 11404 | pg_clean_ascii(*newval); |
| 11405 | |
| 11406 | return true; |
| 11407 | } |
| 11408 | |
| 11409 | static const char * |
| 11410 | show_unix_socket_permissions(void) |
| 11411 | { |
| 11412 | static char buf[12]; |
| 11413 | |
| 11414 | snprintf(buf, sizeof(buf), "%04o" , Unix_socket_permissions); |
| 11415 | return buf; |
| 11416 | } |
| 11417 | |
| 11418 | static const char * |
| 11419 | show_log_file_mode(void) |
| 11420 | { |
| 11421 | static char buf[12]; |
| 11422 | |
| 11423 | snprintf(buf, sizeof(buf), "%04o" , Log_file_mode); |
| 11424 | return buf; |
| 11425 | } |
| 11426 | |
| 11427 | static const char * |
| 11428 | show_data_directory_mode(void) |
| 11429 | { |
| 11430 | static char buf[12]; |
| 11431 | |
| 11432 | snprintf(buf, sizeof(buf), "%04o" , data_directory_mode); |
| 11433 | return buf; |
| 11434 | } |
| 11435 | |
| 11436 | static bool |
| 11437 | check_recovery_target_timeline(char **newval, void **, GucSource source) |
| 11438 | { |
| 11439 | RecoveryTargetTimeLineGoal rttg; |
| 11440 | RecoveryTargetTimeLineGoal *; |
| 11441 | |
| 11442 | if (strcmp(*newval, "current" ) == 0) |
| 11443 | rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE; |
| 11444 | else if (strcmp(*newval, "latest" ) == 0) |
| 11445 | rttg = RECOVERY_TARGET_TIMELINE_LATEST; |
| 11446 | else |
| 11447 | { |
| 11448 | rttg = RECOVERY_TARGET_TIMELINE_NUMERIC; |
| 11449 | |
| 11450 | errno = 0; |
| 11451 | strtoul(*newval, NULL, 0); |
| 11452 | if (errno == EINVAL || errno == ERANGE) |
| 11453 | { |
| 11454 | GUC_check_errdetail("recovery_target_timeline is not a valid number." ); |
| 11455 | return false; |
| 11456 | } |
| 11457 | } |
| 11458 | |
| 11459 | myextra = (RecoveryTargetTimeLineGoal *) guc_malloc(ERROR, sizeof(RecoveryTargetTimeLineGoal)); |
| 11460 | *myextra = rttg; |
| 11461 | *extra = (void *) myextra; |
| 11462 | |
| 11463 | return true; |
| 11464 | } |
| 11465 | |
| 11466 | static void |
| 11467 | assign_recovery_target_timeline(const char *newval, void *) |
| 11468 | { |
| 11469 | recoveryTargetTimeLineGoal = *((RecoveryTargetTimeLineGoal *) extra); |
| 11470 | if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC) |
| 11471 | recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0); |
| 11472 | else |
| 11473 | recoveryTargetTLIRequested = 0; |
| 11474 | } |
| 11475 | |
| 11476 | /* |
| 11477 | * Recovery target settings: Only one of the several recovery_target* settings |
| 11478 | * may be set. Setting a second one results in an error. The global variable |
| 11479 | * recoveryTarget tracks which kind of recovery target was chosen. Other |
| 11480 | * variables store the actual target value (for example a string or a xid). |
| 11481 | * The assign functions of the parameters check whether a competing parameter |
| 11482 | * was already set. But we want to allow setting the same parameter multiple |
| 11483 | * times. We also want to allow unsetting a parameter and setting a different |
| 11484 | * one, so we unset recoveryTarget when the parameter is set to an empty |
| 11485 | * string. |
| 11486 | */ |
| 11487 | |
| 11488 | static void |
| 11489 | pg_attribute_noreturn() |
| 11490 | error_multiple_recovery_targets(void) |
| 11491 | { |
| 11492 | ereport(ERROR, |
| 11493 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 11494 | errmsg("multiple recovery targets specified" ), |
| 11495 | errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set." ))); |
| 11496 | } |
| 11497 | |
| 11498 | static bool |
| 11499 | check_recovery_target(char **newval, void **, GucSource source) |
| 11500 | { |
| 11501 | if (strcmp(*newval, "immediate" ) != 0 && strcmp(*newval, "" ) != 0) |
| 11502 | { |
| 11503 | GUC_check_errdetail("The only allowed value is \"immediate\"." ); |
| 11504 | return false; |
| 11505 | } |
| 11506 | return true; |
| 11507 | } |
| 11508 | |
| 11509 | static void |
| 11510 | assign_recovery_target(const char *newval, void *) |
| 11511 | { |
| 11512 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
| 11513 | recoveryTarget != RECOVERY_TARGET_IMMEDIATE) |
| 11514 | error_multiple_recovery_targets(); |
| 11515 | |
| 11516 | if (newval && strcmp(newval, "" ) != 0) |
| 11517 | recoveryTarget = RECOVERY_TARGET_IMMEDIATE; |
| 11518 | else |
| 11519 | recoveryTarget = RECOVERY_TARGET_UNSET; |
| 11520 | } |
| 11521 | |
| 11522 | static bool |
| 11523 | check_recovery_target_xid(char **newval, void **, GucSource source) |
| 11524 | { |
| 11525 | if (strcmp(*newval, "" ) != 0) |
| 11526 | { |
| 11527 | TransactionId xid; |
| 11528 | TransactionId *; |
| 11529 | |
| 11530 | errno = 0; |
| 11531 | xid = (TransactionId) strtoul(*newval, NULL, 0); |
| 11532 | if (errno == EINVAL || errno == ERANGE) |
| 11533 | return false; |
| 11534 | |
| 11535 | myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId)); |
| 11536 | *myextra = xid; |
| 11537 | *extra = (void *) myextra; |
| 11538 | } |
| 11539 | return true; |
| 11540 | } |
| 11541 | |
| 11542 | static void |
| 11543 | assign_recovery_target_xid(const char *newval, void *) |
| 11544 | { |
| 11545 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
| 11546 | recoveryTarget != RECOVERY_TARGET_XID) |
| 11547 | error_multiple_recovery_targets(); |
| 11548 | |
| 11549 | if (newval && strcmp(newval, "" ) != 0) |
| 11550 | { |
| 11551 | recoveryTarget = RECOVERY_TARGET_XID; |
| 11552 | recoveryTargetXid = *((TransactionId *) extra); |
| 11553 | } |
| 11554 | else |
| 11555 | recoveryTarget = RECOVERY_TARGET_UNSET; |
| 11556 | } |
| 11557 | |
| 11558 | /* |
| 11559 | * The interpretation of the recovery_target_time string can depend on the |
| 11560 | * time zone setting, so we need to wait until after all GUC processing is |
| 11561 | * done before we can do the final parsing of the string. This check function |
| 11562 | * only does a parsing pass to catch syntax errors, but we store the string |
| 11563 | * and parse it again when we need to use it. |
| 11564 | */ |
| 11565 | static bool |
| 11566 | check_recovery_target_time(char **newval, void **, GucSource source) |
| 11567 | { |
| 11568 | if (strcmp(*newval, "" ) != 0) |
| 11569 | { |
| 11570 | /* reject some special values */ |
| 11571 | if (strcmp(*newval, "now" ) == 0 || |
| 11572 | strcmp(*newval, "today" ) == 0 || |
| 11573 | strcmp(*newval, "tomorrow" ) == 0 || |
| 11574 | strcmp(*newval, "yesterday" ) == 0) |
| 11575 | { |
| 11576 | return false; |
| 11577 | } |
| 11578 | |
| 11579 | /* |
| 11580 | * parse timestamp value (see also timestamptz_in()) |
| 11581 | */ |
| 11582 | { |
| 11583 | char *str = *newval; |
| 11584 | fsec_t fsec; |
| 11585 | struct pg_tm tt, |
| 11586 | *tm = &tt; |
| 11587 | int tz; |
| 11588 | int dtype; |
| 11589 | int nf; |
| 11590 | int dterr; |
| 11591 | char *field[MAXDATEFIELDS]; |
| 11592 | int ftype[MAXDATEFIELDS]; |
| 11593 | char workbuf[MAXDATELEN + MAXDATEFIELDS]; |
| 11594 | TimestampTz timestamp; |
| 11595 | |
| 11596 | dterr = ParseDateTime(str, workbuf, sizeof(workbuf), |
| 11597 | field, ftype, MAXDATEFIELDS, &nf); |
| 11598 | if (dterr == 0) |
| 11599 | dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); |
| 11600 | if (dterr != 0) |
| 11601 | return false; |
| 11602 | if (dtype != DTK_DATE) |
| 11603 | return false; |
| 11604 | |
| 11605 | if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) |
| 11606 | { |
| 11607 | GUC_check_errdetail("timestamp out of range: \"%s\"" , str); |
| 11608 | return false; |
| 11609 | } |
| 11610 | } |
| 11611 | } |
| 11612 | return true; |
| 11613 | } |
| 11614 | |
| 11615 | static void |
| 11616 | assign_recovery_target_time(const char *newval, void *) |
| 11617 | { |
| 11618 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
| 11619 | recoveryTarget != RECOVERY_TARGET_TIME) |
| 11620 | error_multiple_recovery_targets(); |
| 11621 | |
| 11622 | if (newval && strcmp(newval, "" ) != 0) |
| 11623 | recoveryTarget = RECOVERY_TARGET_TIME; |
| 11624 | else |
| 11625 | recoveryTarget = RECOVERY_TARGET_UNSET; |
| 11626 | } |
| 11627 | |
| 11628 | static bool |
| 11629 | check_recovery_target_name(char **newval, void **, GucSource source) |
| 11630 | { |
| 11631 | /* Use the value of newval directly */ |
| 11632 | if (strlen(*newval) >= MAXFNAMELEN) |
| 11633 | { |
| 11634 | GUC_check_errdetail("%s is too long (maximum %d characters)." , |
| 11635 | "recovery_target_name" , MAXFNAMELEN - 1); |
| 11636 | return false; |
| 11637 | } |
| 11638 | return true; |
| 11639 | } |
| 11640 | |
| 11641 | static void |
| 11642 | assign_recovery_target_name(const char *newval, void *) |
| 11643 | { |
| 11644 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
| 11645 | recoveryTarget != RECOVERY_TARGET_NAME) |
| 11646 | error_multiple_recovery_targets(); |
| 11647 | |
| 11648 | if (newval && strcmp(newval, "" ) != 0) |
| 11649 | { |
| 11650 | recoveryTarget = RECOVERY_TARGET_NAME; |
| 11651 | recoveryTargetName = newval; |
| 11652 | } |
| 11653 | else |
| 11654 | recoveryTarget = RECOVERY_TARGET_UNSET; |
| 11655 | } |
| 11656 | |
| 11657 | static bool |
| 11658 | check_recovery_target_lsn(char **newval, void **, GucSource source) |
| 11659 | { |
| 11660 | if (strcmp(*newval, "" ) != 0) |
| 11661 | { |
| 11662 | XLogRecPtr lsn; |
| 11663 | XLogRecPtr *; |
| 11664 | bool have_error = false; |
| 11665 | |
| 11666 | lsn = pg_lsn_in_internal(*newval, &have_error); |
| 11667 | if (have_error) |
| 11668 | return false; |
| 11669 | |
| 11670 | myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr)); |
| 11671 | *myextra = lsn; |
| 11672 | *extra = (void *) myextra; |
| 11673 | } |
| 11674 | return true; |
| 11675 | } |
| 11676 | |
| 11677 | static void |
| 11678 | assign_recovery_target_lsn(const char *newval, void *) |
| 11679 | { |
| 11680 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
| 11681 | recoveryTarget != RECOVERY_TARGET_LSN) |
| 11682 | error_multiple_recovery_targets(); |
| 11683 | |
| 11684 | if (newval && strcmp(newval, "" ) != 0) |
| 11685 | { |
| 11686 | recoveryTarget = RECOVERY_TARGET_LSN; |
| 11687 | recoveryTargetLSN = *((XLogRecPtr *) extra); |
| 11688 | } |
| 11689 | else |
| 11690 | recoveryTarget = RECOVERY_TARGET_UNSET; |
| 11691 | } |
| 11692 | |
| 11693 | static bool |
| 11694 | check_primary_slot_name(char **newval, void **, GucSource source) |
| 11695 | { |
| 11696 | if (*newval && strcmp(*newval, "" ) != 0 && |
| 11697 | !ReplicationSlotValidateName(*newval, WARNING)) |
| 11698 | return false; |
| 11699 | |
| 11700 | return true; |
| 11701 | } |
| 11702 | |
| 11703 | static bool |
| 11704 | check_default_with_oids(bool *newval, void **, GucSource source) |
| 11705 | { |
| 11706 | if (*newval) |
| 11707 | { |
| 11708 | /* check the GUC's definition for an explanation */ |
| 11709 | GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED); |
| 11710 | GUC_check_errmsg("tables declared WITH OIDS are not supported" ); |
| 11711 | |
| 11712 | return false; |
| 11713 | } |
| 11714 | |
| 11715 | return true; |
| 11716 | } |
| 11717 | |
| 11718 | #include "guc-file.c" |
| 11719 | |