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-2020, 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 "catalog/storage.h"
40 #include "commands/async.h"
41 #include "commands/prepare.h"
42 #include "commands/trigger.h"
43 #include "commands/user.h"
44 #include "commands/vacuum.h"
45 #include "commands/variable.h"
46 #include "common/string.h"
47 #include "funcapi.h"
48 #include "jit/jit.h"
49 #include "libpq/auth.h"
50 #include "libpq/libpq.h"
51 #include "libpq/pqformat.h"
52 #include "miscadmin.h"
53 #include "optimizer/cost.h"
54 #include "optimizer/geqo.h"
55 #include "optimizer/optimizer.h"
56 #include "optimizer/paths.h"
57 #include "optimizer/planmain.h"
58 #include "parser/parse_expr.h"
59 #include "parser/parse_type.h"
60 #include "parser/parser.h"
61 #include "parser/scansup.h"
62 #include "pgstat.h"
63 #include "postmaster/autovacuum.h"
64 #include "postmaster/bgworker_internals.h"
65 #include "postmaster/bgwriter.h"
66 #include "postmaster/postmaster.h"
67 #include "postmaster/syslogger.h"
68 #include "postmaster/walwriter.h"
69 #include "replication/logicallauncher.h"
70 #include "replication/reorderbuffer.h"
71 #include "replication/slot.h"
72 #include "replication/syncrep.h"
73 #include "replication/walreceiver.h"
74 #include "replication/walsender.h"
75 #include "storage/bufmgr.h"
76 #include "storage/dsm_impl.h"
77 #include "storage/fd.h"
78 #include "storage/large_object.h"
79 #include "storage/pg_shmem.h"
80 #include "storage/predicate.h"
81 #include "storage/proc.h"
82 #include "storage/standby.h"
83 #include "tcop/tcopprot.h"
84 #include "tsearch/ts_cache.h"
85 #include "utils/acl.h"
86 #include "utils/builtins.h"
87 #include "utils/bytea.h"
88 #include "utils/float.h"
89 #include "utils/guc_tables.h"
90 #include "utils/memutils.h"
91 #include "utils/pg_locale.h"
92 #include "utils/pg_lsn.h"
93 #include "utils/plancache.h"
94 #include "utils/portal.h"
95 #include "utils/ps_status.h"
96 #include "utils/rls.h"
97 #include "utils/snapmgr.h"
98 #include "utils/tzparser.h"
99 #include "utils/varlena.h"
100 #include "utils/xml.h"
101 
102 #ifndef PG_KRB_SRVTAB
103 #define PG_KRB_SRVTAB ""
104 #endif
105 
106 #define CONFIG_FILENAME "postgresql.conf"
107 #define HBA_FILENAME	"pg_hba.conf"
108 #define IDENT_FILENAME	"pg_ident.conf"
109 
110 #ifdef EXEC_BACKEND
111 #define CONFIG_EXEC_PARAMS "global/config_exec_params"
112 #define CONFIG_EXEC_PARAMS_NEW "global/config_exec_params.new"
113 #endif
114 
115 /*
116  * Precision with which REAL type guc values are to be printed for GUC
117  * serialization.
118  */
119 #define REALTYPE_PRECISION 17
120 
121 /* XXX these should appear in other modules' header files */
122 extern bool Log_disconnections;
123 extern int	CommitDelay;
124 extern int	CommitSiblings;
125 extern char *default_tablespace;
126 extern char *temp_tablespaces;
127 extern bool ignore_checksum_failure;
128 extern bool ignore_invalid_pages;
129 extern bool synchronize_seqscans;
130 
131 #ifdef TRACE_SYNCSCAN
132 extern bool trace_syncscan;
133 #endif
134 #ifdef DEBUG_BOUNDED_SORT
135 extern bool optimize_bounded_sort;
136 #endif
137 
138 static int	GUC_check_errcode_value;
139 
140 /* global variables for check hook support */
141 char	   *GUC_check_errmsg_string;
142 char	   *GUC_check_errdetail_string;
143 char	   *GUC_check_errhint_string;
144 
145 static void do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) pg_attribute_printf(3, 4);
146 
147 static void set_config_sourcefile(const char *name, char *sourcefile,
148 								  int sourceline);
149 static bool call_bool_check_hook(struct config_bool *conf, bool *newval,
150 								 void **extra, GucSource source, int elevel);
151 static bool call_int_check_hook(struct config_int *conf, int *newval,
152 								void **extra, GucSource source, int elevel);
153 static bool call_real_check_hook(struct config_real *conf, double *newval,
154 								 void **extra, GucSource source, int elevel);
155 static bool call_string_check_hook(struct config_string *conf, char **newval,
156 								   void **extra, GucSource source, int elevel);
157 static bool call_enum_check_hook(struct config_enum *conf, int *newval,
158 								 void **extra, GucSource source, int elevel);
159 
160 static bool check_log_destination(char **newval, void **extra, GucSource source);
161 static void assign_log_destination(const char *newval, void *extra);
162 
163 static bool check_wal_consistency_checking(char **newval, void **extra,
164 										   GucSource source);
165 static void assign_wal_consistency_checking(const char *newval, void *extra);
166 
167 #ifdef HAVE_SYSLOG
168 static int	syslog_facility = LOG_LOCAL0;
169 #else
170 static int	syslog_facility = 0;
171 #endif
172 
173 static void assign_syslog_facility(int newval, void *extra);
174 static void assign_syslog_ident(const char *newval, void *extra);
175 static void assign_session_replication_role(int newval, void *extra);
176 static bool check_temp_buffers(int *newval, void **extra, GucSource source);
177 static bool check_bonjour(bool *newval, void **extra, GucSource source);
178 static bool check_ssl(bool *newval, void **extra, GucSource source);
179 static bool check_stage_log_stats(bool *newval, void **extra, GucSource source);
180 static bool check_log_stats(bool *newval, void **extra, GucSource source);
181 static bool check_canonical_path(char **newval, void **extra, GucSource source);
182 static bool check_timezone_abbreviations(char **newval, void **extra, GucSource source);
183 static void assign_timezone_abbreviations(const char *newval, void *extra);
184 static void pg_timezone_abbrev_initialize(void);
185 static const char *show_archive_command(void);
186 static void assign_tcp_keepalives_idle(int newval, void *extra);
187 static void assign_tcp_keepalives_interval(int newval, void *extra);
188 static void assign_tcp_keepalives_count(int newval, void *extra);
189 static void assign_tcp_user_timeout(int newval, void *extra);
190 static const char *show_tcp_keepalives_idle(void);
191 static const char *show_tcp_keepalives_interval(void);
192 static const char *show_tcp_keepalives_count(void);
193 static const char *show_tcp_user_timeout(void);
194 static bool check_maxconnections(int *newval, void **extra, GucSource source);
195 static bool check_max_worker_processes(int *newval, void **extra, GucSource source);
196 static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
197 static bool check_max_wal_senders(int *newval, void **extra, GucSource source);
198 static bool check_autovacuum_work_mem(int *newval, void **extra, GucSource source);
199 static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source);
200 static bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source);
201 static void assign_pgstat_temp_directory(const char *newval, void *extra);
202 static bool check_application_name(char **newval, void **extra, GucSource source);
203 static void assign_application_name(const char *newval, void *extra);
204 static bool check_cluster_name(char **newval, void **extra, GucSource source);
205 static const char *show_unix_socket_permissions(void);
206 static const char *show_log_file_mode(void);
207 static const char *show_data_directory_mode(void);
208 static bool check_backtrace_functions(char **newval, void **extra, GucSource source);
209 static void assign_backtrace_functions(const char *newval, void *extra);
210 static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
211 static void assign_recovery_target_timeline(const char *newval, void *extra);
212 static bool check_recovery_target(char **newval, void **extra, GucSource source);
213 static void assign_recovery_target(const char *newval, void *extra);
214 static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
215 static void assign_recovery_target_xid(const char *newval, void *extra);
216 static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
217 static void assign_recovery_target_time(const char *newval, void *extra);
218 static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
219 static void assign_recovery_target_name(const char *newval, void *extra);
220 static bool check_recovery_target_lsn(char **newval, void **extra, GucSource source);
221 static void assign_recovery_target_lsn(const char *newval, void *extra);
222 static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
223 static bool check_default_with_oids(bool *newval, void **extra, GucSource source);
224 
225 /* Private functions in guc-file.l that need to be called from guc.c */
226 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
227 												 bool applySettings, int elevel);
228 
229 
230 /*
231  * Options for enum values defined in this module.
232  *
233  * NOTE! Option values may not contain double quotes!
234  */
235 
236 static const struct config_enum_entry bytea_output_options[] = {
237 	{"escape", BYTEA_OUTPUT_ESCAPE, false},
238 	{"hex", BYTEA_OUTPUT_HEX, false},
239 	{NULL, 0, false}
240 };
241 
242 StaticAssertDecl(lengthof(bytea_output_options) == (BYTEA_OUTPUT_HEX + 2),
243 				 "array length mismatch");
244 
245 /*
246  * We have different sets for client and server message level options because
247  * they sort slightly different (see "log" level), and because "fatal"/"panic"
248  * aren't sensible for client_min_messages.
249  */
250 static const struct config_enum_entry client_message_level_options[] = {
251 	{"debug5", DEBUG5, false},
252 	{"debug4", DEBUG4, false},
253 	{"debug3", DEBUG3, false},
254 	{"debug2", DEBUG2, false},
255 	{"debug1", DEBUG1, false},
256 	{"debug", DEBUG2, true},
257 	{"log", LOG, false},
258 	{"info", INFO, true},
259 	{"notice", NOTICE, false},
260 	{"warning", WARNING, false},
261 	{"error", ERROR, false},
262 	{NULL, 0, false}
263 };
264 
265 static const struct config_enum_entry server_message_level_options[] = {
266 	{"debug5", DEBUG5, false},
267 	{"debug4", DEBUG4, false},
268 	{"debug3", DEBUG3, false},
269 	{"debug2", DEBUG2, false},
270 	{"debug1", DEBUG1, false},
271 	{"debug", DEBUG2, true},
272 	{"info", INFO, false},
273 	{"notice", NOTICE, false},
274 	{"warning", WARNING, false},
275 	{"error", ERROR, false},
276 	{"log", LOG, false},
277 	{"fatal", FATAL, false},
278 	{"panic", PANIC, false},
279 	{NULL, 0, false}
280 };
281 
282 static const struct config_enum_entry intervalstyle_options[] = {
283 	{"postgres", INTSTYLE_POSTGRES, false},
284 	{"postgres_verbose", INTSTYLE_POSTGRES_VERBOSE, false},
285 	{"sql_standard", INTSTYLE_SQL_STANDARD, false},
286 	{"iso_8601", INTSTYLE_ISO_8601, false},
287 	{NULL, 0, false}
288 };
289 
290 StaticAssertDecl(lengthof(intervalstyle_options) == (INTSTYLE_ISO_8601 + 2),
291 				 "array length mismatch");
292 
293 static const struct config_enum_entry log_error_verbosity_options[] = {
294 	{"terse", PGERROR_TERSE, false},
295 	{"default", PGERROR_DEFAULT, false},
296 	{"verbose", PGERROR_VERBOSE, false},
297 	{NULL, 0, false}
298 };
299 
300 StaticAssertDecl(lengthof(log_error_verbosity_options) == (PGERROR_VERBOSE + 2),
301 				 "array length mismatch");
302 
303 static const struct config_enum_entry log_statement_options[] = {
304 	{"none", LOGSTMT_NONE, false},
305 	{"ddl", LOGSTMT_DDL, false},
306 	{"mod", LOGSTMT_MOD, false},
307 	{"all", LOGSTMT_ALL, false},
308 	{NULL, 0, false}
309 };
310 
311 StaticAssertDecl(lengthof(log_statement_options) == (LOGSTMT_ALL + 2),
312 				 "array length mismatch");
313 
314 static const struct config_enum_entry isolation_level_options[] = {
315 	{"serializable", XACT_SERIALIZABLE, false},
316 	{"repeatable read", XACT_REPEATABLE_READ, false},
317 	{"read committed", XACT_READ_COMMITTED, false},
318 	{"read uncommitted", XACT_READ_UNCOMMITTED, false},
319 	{NULL, 0}
320 };
321 
322 static const struct config_enum_entry session_replication_role_options[] = {
323 	{"origin", SESSION_REPLICATION_ROLE_ORIGIN, false},
324 	{"replica", SESSION_REPLICATION_ROLE_REPLICA, false},
325 	{"local", SESSION_REPLICATION_ROLE_LOCAL, false},
326 	{NULL, 0, false}
327 };
328 
329 StaticAssertDecl(lengthof(session_replication_role_options) == (SESSION_REPLICATION_ROLE_LOCAL + 2),
330 				 "array length mismatch");
331 
332 static const struct config_enum_entry syslog_facility_options[] = {
333 #ifdef HAVE_SYSLOG
334 	{"local0", LOG_LOCAL0, false},
335 	{"local1", LOG_LOCAL1, false},
336 	{"local2", LOG_LOCAL2, false},
337 	{"local3", LOG_LOCAL3, false},
338 	{"local4", LOG_LOCAL4, false},
339 	{"local5", LOG_LOCAL5, false},
340 	{"local6", LOG_LOCAL6, false},
341 	{"local7", LOG_LOCAL7, false},
342 #else
343 	{"none", 0, false},
344 #endif
345 	{NULL, 0}
346 };
347 
348 static const struct config_enum_entry track_function_options[] = {
349 	{"none", TRACK_FUNC_OFF, false},
350 	{"pl", TRACK_FUNC_PL, false},
351 	{"all", TRACK_FUNC_ALL, false},
352 	{NULL, 0, false}
353 };
354 
355 StaticAssertDecl(lengthof(track_function_options) == (TRACK_FUNC_ALL + 2),
356 				 "array length mismatch");
357 
358 static const struct config_enum_entry xmlbinary_options[] = {
359 	{"base64", XMLBINARY_BASE64, false},
360 	{"hex", XMLBINARY_HEX, false},
361 	{NULL, 0, false}
362 };
363 
364 StaticAssertDecl(lengthof(xmlbinary_options) == (XMLBINARY_HEX + 2),
365 				 "array length mismatch");
366 
367 static const struct config_enum_entry xmloption_options[] = {
368 	{"content", XMLOPTION_CONTENT, false},
369 	{"document", XMLOPTION_DOCUMENT, false},
370 	{NULL, 0, false}
371 };
372 
373 StaticAssertDecl(lengthof(xmloption_options) == (XMLOPTION_CONTENT + 2),
374 				 "array length mismatch");
375 
376 /*
377  * Although only "on", "off", and "safe_encoding" are documented, we
378  * accept all the likely variants of "on" and "off".
379  */
380 static const struct config_enum_entry backslash_quote_options[] = {
381 	{"safe_encoding", BACKSLASH_QUOTE_SAFE_ENCODING, false},
382 	{"on", BACKSLASH_QUOTE_ON, false},
383 	{"off", BACKSLASH_QUOTE_OFF, false},
384 	{"true", BACKSLASH_QUOTE_ON, true},
385 	{"false", BACKSLASH_QUOTE_OFF, true},
386 	{"yes", BACKSLASH_QUOTE_ON, true},
387 	{"no", BACKSLASH_QUOTE_OFF, true},
388 	{"1", BACKSLASH_QUOTE_ON, true},
389 	{"0", BACKSLASH_QUOTE_OFF, true},
390 	{NULL, 0, false}
391 };
392 
393 /*
394  * Although only "on", "off", and "partition" are documented, we
395  * accept all the likely variants of "on" and "off".
396  */
397 static const struct config_enum_entry constraint_exclusion_options[] = {
398 	{"partition", CONSTRAINT_EXCLUSION_PARTITION, false},
399 	{"on", CONSTRAINT_EXCLUSION_ON, false},
400 	{"off", CONSTRAINT_EXCLUSION_OFF, false},
401 	{"true", CONSTRAINT_EXCLUSION_ON, true},
402 	{"false", CONSTRAINT_EXCLUSION_OFF, true},
403 	{"yes", CONSTRAINT_EXCLUSION_ON, true},
404 	{"no", CONSTRAINT_EXCLUSION_OFF, true},
405 	{"1", CONSTRAINT_EXCLUSION_ON, true},
406 	{"0", CONSTRAINT_EXCLUSION_OFF, true},
407 	{NULL, 0, false}
408 };
409 
410 /*
411  * Although only "on", "off", "remote_apply", "remote_write", and "local" are
412  * documented, we accept all the likely variants of "on" and "off".
413  */
414 static const struct config_enum_entry synchronous_commit_options[] = {
415 	{"local", SYNCHRONOUS_COMMIT_LOCAL_FLUSH, false},
416 	{"remote_write", SYNCHRONOUS_COMMIT_REMOTE_WRITE, false},
417 	{"remote_apply", SYNCHRONOUS_COMMIT_REMOTE_APPLY, false},
418 	{"on", SYNCHRONOUS_COMMIT_ON, false},
419 	{"off", SYNCHRONOUS_COMMIT_OFF, false},
420 	{"true", SYNCHRONOUS_COMMIT_ON, true},
421 	{"false", SYNCHRONOUS_COMMIT_OFF, true},
422 	{"yes", SYNCHRONOUS_COMMIT_ON, true},
423 	{"no", SYNCHRONOUS_COMMIT_OFF, true},
424 	{"1", SYNCHRONOUS_COMMIT_ON, true},
425 	{"0", SYNCHRONOUS_COMMIT_OFF, true},
426 	{NULL, 0, false}
427 };
428 
429 /*
430  * Although only "on", "off", "try" are documented, we accept all the likely
431  * variants of "on" and "off".
432  */
433 static const struct config_enum_entry huge_pages_options[] = {
434 	{"off", HUGE_PAGES_OFF, false},
435 	{"on", HUGE_PAGES_ON, false},
436 	{"try", HUGE_PAGES_TRY, false},
437 	{"true", HUGE_PAGES_ON, true},
438 	{"false", HUGE_PAGES_OFF, true},
439 	{"yes", HUGE_PAGES_ON, true},
440 	{"no", HUGE_PAGES_OFF, true},
441 	{"1", HUGE_PAGES_ON, true},
442 	{"0", HUGE_PAGES_OFF, true},
443 	{NULL, 0, false}
444 };
445 
446 static const struct config_enum_entry force_parallel_mode_options[] = {
447 	{"off", FORCE_PARALLEL_OFF, false},
448 	{"on", FORCE_PARALLEL_ON, false},
449 	{"regress", FORCE_PARALLEL_REGRESS, false},
450 	{"true", FORCE_PARALLEL_ON, true},
451 	{"false", FORCE_PARALLEL_OFF, true},
452 	{"yes", FORCE_PARALLEL_ON, true},
453 	{"no", FORCE_PARALLEL_OFF, true},
454 	{"1", FORCE_PARALLEL_ON, true},
455 	{"0", FORCE_PARALLEL_OFF, true},
456 	{NULL, 0, false}
457 };
458 
459 static const struct config_enum_entry plan_cache_mode_options[] = {
460 	{"auto", PLAN_CACHE_MODE_AUTO, false},
461 	{"force_generic_plan", PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, false},
462 	{"force_custom_plan", PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, false},
463 	{NULL, 0, false}
464 };
465 
466 /*
467  * password_encryption used to be a boolean, so accept all the likely
468  * variants of "on", too. "off" used to store passwords in plaintext,
469  * but we don't support that anymore.
470  */
471 static const struct config_enum_entry password_encryption_options[] = {
472 	{"md5", PASSWORD_TYPE_MD5, false},
473 	{"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false},
474 	{"on", PASSWORD_TYPE_MD5, true},
475 	{"true", PASSWORD_TYPE_MD5, true},
476 	{"yes", PASSWORD_TYPE_MD5, true},
477 	{"1", PASSWORD_TYPE_MD5, true},
478 	{NULL, 0, false}
479 };
480 
481 const struct config_enum_entry ssl_protocol_versions_info[] = {
482 	{"", PG_TLS_ANY, false},
483 	{"TLSv1", PG_TLS1_VERSION, false},
484 	{"TLSv1.1", PG_TLS1_1_VERSION, false},
485 	{"TLSv1.2", PG_TLS1_2_VERSION, false},
486 	{"TLSv1.3", PG_TLS1_3_VERSION, false},
487 	{NULL, 0, false}
488 };
489 
490 StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2),
491 				 "array length mismatch");
492 
493 static struct config_enum_entry shared_memory_options[] = {
494 #ifndef WIN32
495 	{"sysv", SHMEM_TYPE_SYSV, false},
496 #endif
497 #ifndef EXEC_BACKEND
498 	{"mmap", SHMEM_TYPE_MMAP, false},
499 #endif
500 #ifdef WIN32
501 	{"windows", SHMEM_TYPE_WINDOWS, false},
502 #endif
503 	{NULL, 0, false}
504 };
505 
506 /*
507  * Options for enum values stored in other modules
508  */
509 extern const struct config_enum_entry wal_level_options[];
510 extern const struct config_enum_entry archive_mode_options[];
511 extern const struct config_enum_entry recovery_target_action_options[];
512 extern const struct config_enum_entry sync_method_options[];
513 extern const struct config_enum_entry dynamic_shared_memory_options[];
514 
515 /*
516  * GUC option variables that are exported from this module
517  */
518 bool		log_duration = false;
519 bool		Debug_print_plan = false;
520 bool		Debug_print_parse = false;
521 bool		Debug_print_rewritten = false;
522 bool		Debug_pretty_print = true;
523 
524 bool		log_parser_stats = false;
525 bool		log_planner_stats = false;
526 bool		log_executor_stats = false;
527 bool		log_statement_stats = false;	/* this is sort of all three above
528 											 * together */
529 bool		log_btree_build_stats = false;
530 char	   *event_source;
531 
532 bool		row_security;
533 bool		check_function_bodies = true;
534 
535 /*
536  * This GUC exists solely for backward compatibility, check its definition for
537  * details.
538  */
539 bool		default_with_oids = false;
540 bool		session_auth_is_superuser;
541 
542 int			log_min_error_statement = ERROR;
543 int			log_min_messages = WARNING;
544 int			client_min_messages = NOTICE;
545 int			log_min_duration_sample = -1;
546 int			log_min_duration_statement = -1;
547 int			log_parameter_max_length = -1;
548 int			log_parameter_max_length_on_error = 0;
549 int			log_temp_files = -1;
550 double		log_statement_sample_rate = 1.0;
551 double		log_xact_sample_rate = 0;
552 int			trace_recovery_messages = LOG;
553 char	   *backtrace_functions;
554 char	   *backtrace_symbol_list;
555 
556 int			temp_file_limit = -1;
557 
558 int			num_temp_buffers = 1024;
559 
560 char	   *cluster_name = "";
561 char	   *ConfigFileName;
562 char	   *HbaFileName;
563 char	   *IdentFileName;
564 char	   *external_pid_file;
565 
566 char	   *pgstat_temp_directory;
567 
568 char	   *application_name;
569 
570 int			tcp_keepalives_idle;
571 int			tcp_keepalives_interval;
572 int			tcp_keepalives_count;
573 int			tcp_user_timeout;
574 
575 /*
576  * SSL renegotiation was been removed in PostgreSQL 9.5, but we tolerate it
577  * being set to zero (meaning never renegotiate) for backward compatibility.
578  * This avoids breaking compatibility with clients that have never supported
579  * renegotiation and therefore always try to zero it.
580  */
581 int			ssl_renegotiation_limit;
582 
583 /*
584  * This really belongs in pg_shmem.c, but is defined here so that it doesn't
585  * need to be duplicated in all the different implementations of pg_shmem.c.
586  */
587 int			huge_pages;
588 
589 /*
590  * These variables are all dummies that don't do anything, except in some
591  * cases provide the value for SHOW to display.  The real state is elsewhere
592  * and is kept in sync by assign_hooks.
593  */
594 static char *syslog_ident_str;
595 static double phony_random_seed;
596 static char *client_encoding_string;
597 static char *datestyle_string;
598 static char *locale_collate;
599 static char *locale_ctype;
600 static char *server_encoding_string;
601 static char *server_version_string;
602 static int	server_version_num;
603 static char *timezone_string;
604 static char *log_timezone_string;
605 static char *timezone_abbreviations_string;
606 static char *data_directory;
607 static char *session_authorization_string;
608 static int	max_function_args;
609 static int	max_index_keys;
610 static int	max_identifier_length;
611 static int	block_size;
612 static int	segment_size;
613 static int	wal_block_size;
614 static bool data_checksums;
615 static bool integer_datetimes;
616 static bool assert_enabled;
617 static char *recovery_target_timeline_string;
618 static char *recovery_target_string;
619 static char *recovery_target_xid_string;
620 static char *recovery_target_name_string;
621 static char *recovery_target_lsn_string;
622 
623 
624 /* should be static, but commands/variable.c needs to get at this */
625 char	   *role_string;
626 
627 
628 /*
629  * Displayable names for context types (enum GucContext)
630  *
631  * Note: these strings are deliberately not localized.
632  */
633 const char *const GucContext_Names[] =
634 {
635 	 /* PGC_INTERNAL */ "internal",
636 	 /* PGC_POSTMASTER */ "postmaster",
637 	 /* PGC_SIGHUP */ "sighup",
638 	 /* PGC_SU_BACKEND */ "superuser-backend",
639 	 /* PGC_BACKEND */ "backend",
640 	 /* PGC_SUSET */ "superuser",
641 	 /* PGC_USERSET */ "user"
642 };
643 
644 StaticAssertDecl(lengthof(GucContext_Names) == (PGC_USERSET + 1),
645 				 "array length mismatch");
646 
647 /*
648  * Displayable names for source types (enum GucSource)
649  *
650  * Note: these strings are deliberately not localized.
651  */
652 const char *const GucSource_Names[] =
653 {
654 	 /* PGC_S_DEFAULT */ "default",
655 	 /* PGC_S_DYNAMIC_DEFAULT */ "default",
656 	 /* PGC_S_ENV_VAR */ "environment variable",
657 	 /* PGC_S_FILE */ "configuration file",
658 	 /* PGC_S_ARGV */ "command line",
659 	 /* PGC_S_GLOBAL */ "global",
660 	 /* PGC_S_DATABASE */ "database",
661 	 /* PGC_S_USER */ "user",
662 	 /* PGC_S_DATABASE_USER */ "database user",
663 	 /* PGC_S_CLIENT */ "client",
664 	 /* PGC_S_OVERRIDE */ "override",
665 	 /* PGC_S_INTERACTIVE */ "interactive",
666 	 /* PGC_S_TEST */ "test",
667 	 /* PGC_S_SESSION */ "session"
668 };
669 
670 StaticAssertDecl(lengthof(GucSource_Names) == (PGC_S_SESSION + 1),
671 				 "array length mismatch");
672 
673 /*
674  * Displayable names for the groupings defined in enum config_group
675  */
676 const char *const config_group_names[] =
677 {
678 	/* UNGROUPED */
679 	gettext_noop("Ungrouped"),
680 	/* FILE_LOCATIONS */
681 	gettext_noop("File Locations"),
682 	/* CONN_AUTH */
683 	gettext_noop("Connections and Authentication"),
684 	/* CONN_AUTH_SETTINGS */
685 	gettext_noop("Connections and Authentication / Connection Settings"),
686 	/* CONN_AUTH_AUTH */
687 	gettext_noop("Connections and Authentication / Authentication"),
688 	/* CONN_AUTH_SSL */
689 	gettext_noop("Connections and Authentication / SSL"),
690 	/* RESOURCES */
691 	gettext_noop("Resource Usage"),
692 	/* RESOURCES_MEM */
693 	gettext_noop("Resource Usage / Memory"),
694 	/* RESOURCES_DISK */
695 	gettext_noop("Resource Usage / Disk"),
696 	/* RESOURCES_KERNEL */
697 	gettext_noop("Resource Usage / Kernel Resources"),
698 	/* RESOURCES_VACUUM_DELAY */
699 	gettext_noop("Resource Usage / Cost-Based Vacuum Delay"),
700 	/* RESOURCES_BGWRITER */
701 	gettext_noop("Resource Usage / Background Writer"),
702 	/* RESOURCES_ASYNCHRONOUS */
703 	gettext_noop("Resource Usage / Asynchronous Behavior"),
704 	/* WAL */
705 	gettext_noop("Write-Ahead Log"),
706 	/* WAL_SETTINGS */
707 	gettext_noop("Write-Ahead Log / Settings"),
708 	/* WAL_CHECKPOINTS */
709 	gettext_noop("Write-Ahead Log / Checkpoints"),
710 	/* WAL_ARCHIVING */
711 	gettext_noop("Write-Ahead Log / Archiving"),
712 	/* WAL_ARCHIVE_RECOVERY */
713 	gettext_noop("Write-Ahead Log / Archive Recovery"),
714 	/* WAL_RECOVERY_TARGET */
715 	gettext_noop("Write-Ahead Log / Recovery Target"),
716 	/* REPLICATION */
717 	gettext_noop("Replication"),
718 	/* REPLICATION_SENDING */
719 	gettext_noop("Replication / Sending Servers"),
720 	/* REPLICATION_MASTER */
721 	gettext_noop("Replication / Master Server"),
722 	/* REPLICATION_STANDBY */
723 	gettext_noop("Replication / Standby Servers"),
724 	/* REPLICATION_SUBSCRIBERS */
725 	gettext_noop("Replication / Subscribers"),
726 	/* QUERY_TUNING */
727 	gettext_noop("Query Tuning"),
728 	/* QUERY_TUNING_METHOD */
729 	gettext_noop("Query Tuning / Planner Method Configuration"),
730 	/* QUERY_TUNING_COST */
731 	gettext_noop("Query Tuning / Planner Cost Constants"),
732 	/* QUERY_TUNING_GEQO */
733 	gettext_noop("Query Tuning / Genetic Query Optimizer"),
734 	/* QUERY_TUNING_OTHER */
735 	gettext_noop("Query Tuning / Other Planner Options"),
736 	/* LOGGING */
737 	gettext_noop("Reporting and Logging"),
738 	/* LOGGING_WHERE */
739 	gettext_noop("Reporting and Logging / Where to Log"),
740 	/* LOGGING_WHEN */
741 	gettext_noop("Reporting and Logging / When to Log"),
742 	/* LOGGING_WHAT */
743 	gettext_noop("Reporting and Logging / What to Log"),
744 	/* PROCESS_TITLE */
745 	gettext_noop("Process Title"),
746 	/* STATS */
747 	gettext_noop("Statistics"),
748 	/* STATS_MONITORING */
749 	gettext_noop("Statistics / Monitoring"),
750 	/* STATS_COLLECTOR */
751 	gettext_noop("Statistics / Query and Index Statistics Collector"),
752 	/* AUTOVACUUM */
753 	gettext_noop("Autovacuum"),
754 	/* CLIENT_CONN */
755 	gettext_noop("Client Connection Defaults"),
756 	/* CLIENT_CONN_STATEMENT */
757 	gettext_noop("Client Connection Defaults / Statement Behavior"),
758 	/* CLIENT_CONN_LOCALE */
759 	gettext_noop("Client Connection Defaults / Locale and Formatting"),
760 	/* CLIENT_CONN_PRELOAD */
761 	gettext_noop("Client Connection Defaults / Shared Library Preloading"),
762 	/* CLIENT_CONN_OTHER */
763 	gettext_noop("Client Connection Defaults / Other Defaults"),
764 	/* LOCK_MANAGEMENT */
765 	gettext_noop("Lock Management"),
766 	/* COMPAT_OPTIONS */
767 	gettext_noop("Version and Platform Compatibility"),
768 	/* COMPAT_OPTIONS_PREVIOUS */
769 	gettext_noop("Version and Platform Compatibility / Previous PostgreSQL Versions"),
770 	/* COMPAT_OPTIONS_CLIENT */
771 	gettext_noop("Version and Platform Compatibility / Other Platforms and Clients"),
772 	/* ERROR_HANDLING */
773 	gettext_noop("Error Handling"),
774 	/* PRESET_OPTIONS */
775 	gettext_noop("Preset Options"),
776 	/* CUSTOM_OPTIONS */
777 	gettext_noop("Customized Options"),
778 	/* DEVELOPER_OPTIONS */
779 	gettext_noop("Developer Options"),
780 	/* help_config wants this array to be null-terminated */
781 	NULL
782 };
783 
784 StaticAssertDecl(lengthof(config_group_names) == (DEVELOPER_OPTIONS + 2),
785 				 "array length mismatch");
786 
787 /*
788  * Displayable names for GUC variable types (enum config_type)
789  *
790  * Note: these strings are deliberately not localized.
791  */
792 const char *const config_type_names[] =
793 {
794 	 /* PGC_BOOL */ "bool",
795 	 /* PGC_INT */ "integer",
796 	 /* PGC_REAL */ "real",
797 	 /* PGC_STRING */ "string",
798 	 /* PGC_ENUM */ "enum"
799 };
800 
801 StaticAssertDecl(lengthof(config_type_names) == (PGC_ENUM + 1),
802 				 "array length mismatch");
803 
804 /*
805  * Unit conversion tables.
806  *
807  * There are two tables, one for memory units, and another for time units.
808  * For each supported conversion from one unit to another, we have an entry
809  * in the table.
810  *
811  * To keep things simple, and to avoid possible roundoff error,
812  * conversions are never chained.  There needs to be a direct conversion
813  * between all units (of the same type).
814  *
815  * The conversions for each base unit must be kept in order from greatest to
816  * smallest human-friendly unit; convert_xxx_from_base_unit() rely on that.
817  * (The order of the base-unit groups does not matter.)
818  */
819 #define MAX_UNIT_LEN		3	/* length of longest recognized unit string */
820 
821 typedef struct
822 {
823 	char		unit[MAX_UNIT_LEN + 1]; /* unit, as a string, like "kB" or
824 										 * "min" */
825 	int			base_unit;		/* GUC_UNIT_XXX */
826 	double		multiplier;		/* Factor for converting unit -> base_unit */
827 } unit_conversion;
828 
829 /* Ensure that the constants in the tables don't overflow or underflow */
830 #if BLCKSZ < 1024 || BLCKSZ > (1024*1024)
831 #error BLCKSZ must be between 1KB and 1MB
832 #endif
833 #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024)
834 #error XLOG_BLCKSZ must be between 1KB and 1MB
835 #endif
836 
837 static const char *memory_units_hint = gettext_noop("Valid units for this parameter are \"B\", \"kB\", \"MB\", \"GB\", and \"TB\".");
838 
839 static const unit_conversion memory_unit_conversion_table[] =
840 {
841 	{"TB", GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0 * 1024.0},
842 	{"GB", GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0},
843 	{"MB", GUC_UNIT_BYTE, 1024.0 * 1024.0},
844 	{"kB", GUC_UNIT_BYTE, 1024.0},
845 	{"B", GUC_UNIT_BYTE, 1.0},
846 
847 	{"TB", GUC_UNIT_KB, 1024.0 * 1024.0 * 1024.0},
848 	{"GB", GUC_UNIT_KB, 1024.0 * 1024.0},
849 	{"MB", GUC_UNIT_KB, 1024.0},
850 	{"kB", GUC_UNIT_KB, 1.0},
851 	{"B", GUC_UNIT_KB, 1.0 / 1024.0},
852 
853 	{"TB", GUC_UNIT_MB, 1024.0 * 1024.0},
854 	{"GB", GUC_UNIT_MB, 1024.0},
855 	{"MB", GUC_UNIT_MB, 1.0},
856 	{"kB", GUC_UNIT_MB, 1.0 / 1024.0},
857 	{"B", GUC_UNIT_MB, 1.0 / (1024.0 * 1024.0)},
858 
859 	{"TB", GUC_UNIT_BLOCKS, (1024.0 * 1024.0 * 1024.0) / (BLCKSZ / 1024)},
860 	{"GB", GUC_UNIT_BLOCKS, (1024.0 * 1024.0) / (BLCKSZ / 1024)},
861 	{"MB", GUC_UNIT_BLOCKS, 1024.0 / (BLCKSZ / 1024)},
862 	{"kB", GUC_UNIT_BLOCKS, 1.0 / (BLCKSZ / 1024)},
863 	{"B", GUC_UNIT_BLOCKS, 1.0 / BLCKSZ},
864 
865 	{"TB", GUC_UNIT_XBLOCKS, (1024.0 * 1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)},
866 	{"GB", GUC_UNIT_XBLOCKS, (1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)},
867 	{"MB", GUC_UNIT_XBLOCKS, 1024.0 / (XLOG_BLCKSZ / 1024)},
868 	{"kB", GUC_UNIT_XBLOCKS, 1.0 / (XLOG_BLCKSZ / 1024)},
869 	{"B", GUC_UNIT_XBLOCKS, 1.0 / XLOG_BLCKSZ},
870 
871 	{""}						/* end of table marker */
872 };
873 
874 static const char *time_units_hint = gettext_noop("Valid units for this parameter are \"us\", \"ms\", \"s\", \"min\", \"h\", and \"d\".");
875 
876 static const unit_conversion time_unit_conversion_table[] =
877 {
878 	{"d", GUC_UNIT_MS, 1000 * 60 * 60 * 24},
879 	{"h", GUC_UNIT_MS, 1000 * 60 * 60},
880 	{"min", GUC_UNIT_MS, 1000 * 60},
881 	{"s", GUC_UNIT_MS, 1000},
882 	{"ms", GUC_UNIT_MS, 1},
883 	{"us", GUC_UNIT_MS, 1.0 / 1000},
884 
885 	{"d", GUC_UNIT_S, 60 * 60 * 24},
886 	{"h", GUC_UNIT_S, 60 * 60},
887 	{"min", GUC_UNIT_S, 60},
888 	{"s", GUC_UNIT_S, 1},
889 	{"ms", GUC_UNIT_S, 1.0 / 1000},
890 	{"us", GUC_UNIT_S, 1.0 / (1000 * 1000)},
891 
892 	{"d", GUC_UNIT_MIN, 60 * 24},
893 	{"h", GUC_UNIT_MIN, 60},
894 	{"min", GUC_UNIT_MIN, 1},
895 	{"s", GUC_UNIT_MIN, 1.0 / 60},
896 	{"ms", GUC_UNIT_MIN, 1.0 / (1000 * 60)},
897 	{"us", GUC_UNIT_MIN, 1.0 / (1000 * 1000 * 60)},
898 
899 	{""}						/* end of table marker */
900 };
901 
902 /*
903  * Contents of GUC tables
904  *
905  * See src/backend/utils/misc/README for design notes.
906  *
907  * TO ADD AN OPTION:
908  *
909  * 1. Declare a global variable of type bool, int, double, or char*
910  *	  and make use of it.
911  *
912  * 2. Decide at what times it's safe to set the option. See guc.h for
913  *	  details.
914  *
915  * 3. Decide on a name, a default value, upper and lower bounds (if
916  *	  applicable), etc.
917  *
918  * 4. Add a record below.
919  *
920  * 5. Add it to src/backend/utils/misc/postgresql.conf.sample, if
921  *	  appropriate.
922  *
923  * 6. Don't forget to document the option (at least in config.sgml).
924  *
925  * 7. If it's a new GUC_LIST_QUOTE option, you must add it to
926  *	  variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c.
927  */
928 
929 
930 /******** option records follow ********/
931 
932 static struct config_bool ConfigureNamesBool[] =
933 {
934 	{
935 		{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
936 			gettext_noop("Enables the planner's use of sequential-scan plans."),
937 			NULL,
938 			GUC_EXPLAIN
939 		},
940 		&enable_seqscan,
941 		true,
942 		NULL, NULL, NULL
943 	},
944 	{
945 		{"enable_indexscan", PGC_USERSET, QUERY_TUNING_METHOD,
946 			gettext_noop("Enables the planner's use of index-scan plans."),
947 			NULL,
948 			GUC_EXPLAIN
949 		},
950 		&enable_indexscan,
951 		true,
952 		NULL, NULL, NULL
953 	},
954 	{
955 		{"enable_indexonlyscan", PGC_USERSET, QUERY_TUNING_METHOD,
956 			gettext_noop("Enables the planner's use of index-only-scan plans."),
957 			NULL,
958 			GUC_EXPLAIN
959 		},
960 		&enable_indexonlyscan,
961 		true,
962 		NULL, NULL, NULL
963 	},
964 	{
965 		{"enable_bitmapscan", PGC_USERSET, QUERY_TUNING_METHOD,
966 			gettext_noop("Enables the planner's use of bitmap-scan plans."),
967 			NULL,
968 			GUC_EXPLAIN
969 		},
970 		&enable_bitmapscan,
971 		true,
972 		NULL, NULL, NULL
973 	},
974 	{
975 		{"enable_tidscan", PGC_USERSET, QUERY_TUNING_METHOD,
976 			gettext_noop("Enables the planner's use of TID scan plans."),
977 			NULL,
978 			GUC_EXPLAIN
979 		},
980 		&enable_tidscan,
981 		true,
982 		NULL, NULL, NULL
983 	},
984 	{
985 		{"enable_sort", PGC_USERSET, QUERY_TUNING_METHOD,
986 			gettext_noop("Enables the planner's use of explicit sort steps."),
987 			NULL,
988 			GUC_EXPLAIN
989 		},
990 		&enable_sort,
991 		true,
992 		NULL, NULL, NULL
993 	},
994 	{
995 		{"enable_incremental_sort", PGC_USERSET, QUERY_TUNING_METHOD,
996 			gettext_noop("Enables the planner's use of incremental sort steps."),
997 			NULL
998 		},
999 		&enable_incremental_sort,
1000 		true,
1001 		NULL, NULL, NULL
1002 	},
1003 	{
1004 		{"enable_hashagg", PGC_USERSET, QUERY_TUNING_METHOD,
1005 			gettext_noop("Enables the planner's use of hashed aggregation plans."),
1006 			NULL,
1007 			GUC_EXPLAIN
1008 		},
1009 		&enable_hashagg,
1010 		true,
1011 		NULL, NULL, NULL
1012 	},
1013 	{
1014 		{"enable_material", PGC_USERSET, QUERY_TUNING_METHOD,
1015 			gettext_noop("Enables the planner's use of materialization."),
1016 			NULL,
1017 			GUC_EXPLAIN
1018 		},
1019 		&enable_material,
1020 		true,
1021 		NULL, NULL, NULL
1022 	},
1023 	{
1024 		{"enable_nestloop", PGC_USERSET, QUERY_TUNING_METHOD,
1025 			gettext_noop("Enables the planner's use of nested-loop join plans."),
1026 			NULL,
1027 			GUC_EXPLAIN
1028 		},
1029 		&enable_nestloop,
1030 		true,
1031 		NULL, NULL, NULL
1032 	},
1033 	{
1034 		{"enable_mergejoin", PGC_USERSET, QUERY_TUNING_METHOD,
1035 			gettext_noop("Enables the planner's use of merge join plans."),
1036 			NULL,
1037 			GUC_EXPLAIN
1038 		},
1039 		&enable_mergejoin,
1040 		true,
1041 		NULL, NULL, NULL
1042 	},
1043 	{
1044 		{"enable_hashjoin", PGC_USERSET, QUERY_TUNING_METHOD,
1045 			gettext_noop("Enables the planner's use of hash join plans."),
1046 			NULL,
1047 			GUC_EXPLAIN
1048 		},
1049 		&enable_hashjoin,
1050 		true,
1051 		NULL, NULL, NULL
1052 	},
1053 	{
1054 		{"enable_gathermerge", PGC_USERSET, QUERY_TUNING_METHOD,
1055 			gettext_noop("Enables the planner's use of gather merge plans."),
1056 			NULL,
1057 			GUC_EXPLAIN
1058 		},
1059 		&enable_gathermerge,
1060 		true,
1061 		NULL, NULL, NULL
1062 	},
1063 	{
1064 		{"enable_partitionwise_join", PGC_USERSET, QUERY_TUNING_METHOD,
1065 			gettext_noop("Enables partitionwise join."),
1066 			NULL,
1067 			GUC_EXPLAIN
1068 		},
1069 		&enable_partitionwise_join,
1070 		false,
1071 		NULL, NULL, NULL
1072 	},
1073 	{
1074 		{"enable_partitionwise_aggregate", PGC_USERSET, QUERY_TUNING_METHOD,
1075 			gettext_noop("Enables partitionwise aggregation and grouping."),
1076 			NULL,
1077 			GUC_EXPLAIN
1078 		},
1079 		&enable_partitionwise_aggregate,
1080 		false,
1081 		NULL, NULL, NULL
1082 	},
1083 	{
1084 		{"enable_parallel_append", PGC_USERSET, QUERY_TUNING_METHOD,
1085 			gettext_noop("Enables the planner's use of parallel append plans."),
1086 			NULL,
1087 			GUC_EXPLAIN
1088 		},
1089 		&enable_parallel_append,
1090 		true,
1091 		NULL, NULL, NULL
1092 	},
1093 	{
1094 		{"enable_parallel_hash", PGC_USERSET, QUERY_TUNING_METHOD,
1095 			gettext_noop("Enables the planner's use of parallel hash plans."),
1096 			NULL,
1097 			GUC_EXPLAIN
1098 		},
1099 		&enable_parallel_hash,
1100 		true,
1101 		NULL, NULL, NULL
1102 	},
1103 	{
1104 		{"enable_partition_pruning", PGC_USERSET, QUERY_TUNING_METHOD,
1105 			gettext_noop("Enables plan-time and run-time partition pruning."),
1106 			gettext_noop("Allows the query planner and executor to compare partition "
1107 						 "bounds to conditions in the query to determine which "
1108 						 "partitions must be scanned."),
1109 			GUC_EXPLAIN
1110 		},
1111 		&enable_partition_pruning,
1112 		true,
1113 		NULL, NULL, NULL
1114 	},
1115 	{
1116 		{"geqo", PGC_USERSET, QUERY_TUNING_GEQO,
1117 			gettext_noop("Enables genetic query optimization."),
1118 			gettext_noop("This algorithm attempts to do planning without "
1119 						 "exhaustive searching."),
1120 			GUC_EXPLAIN
1121 		},
1122 		&enable_geqo,
1123 		true,
1124 		NULL, NULL, NULL
1125 	},
1126 	{
1127 		/* Not for general use --- used by SET SESSION AUTHORIZATION */
1128 		{"is_superuser", PGC_INTERNAL, UNGROUPED,
1129 			gettext_noop("Shows whether the current user is a superuser."),
1130 			NULL,
1131 			GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1132 		},
1133 		&session_auth_is_superuser,
1134 		false,
1135 		NULL, NULL, NULL
1136 	},
1137 	{
1138 		{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
1139 			gettext_noop("Enables advertising the server via Bonjour."),
1140 			NULL
1141 		},
1142 		&enable_bonjour,
1143 		false,
1144 		check_bonjour, NULL, NULL
1145 	},
1146 	{
1147 		{"track_commit_timestamp", PGC_POSTMASTER, REPLICATION,
1148 			gettext_noop("Collects transaction commit time."),
1149 			NULL
1150 		},
1151 		&track_commit_timestamp,
1152 		false,
1153 		NULL, NULL, NULL
1154 	},
1155 	{
1156 		{"ssl", PGC_SIGHUP, CONN_AUTH_SSL,
1157 			gettext_noop("Enables SSL connections."),
1158 			NULL
1159 		},
1160 		&EnableSSL,
1161 		false,
1162 		check_ssl, NULL, NULL
1163 	},
1164 	{
1165 		{"ssl_passphrase_command_supports_reload", PGC_SIGHUP, CONN_AUTH_SSL,
1166 			gettext_noop("Also use ssl_passphrase_command during server reload."),
1167 			NULL
1168 		},
1169 		&ssl_passphrase_command_supports_reload,
1170 		false,
1171 		NULL, NULL, NULL
1172 	},
1173 	{
1174 		{"ssl_prefer_server_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
1175 			gettext_noop("Give priority to server ciphersuite order."),
1176 			NULL
1177 		},
1178 		&SSLPreferServerCiphers,
1179 		true,
1180 		NULL, NULL, NULL
1181 	},
1182 	{
1183 		{"fsync", PGC_SIGHUP, WAL_SETTINGS,
1184 			gettext_noop("Forces synchronization of updates to disk."),
1185 			gettext_noop("The server will use the fsync() system call in several places to make "
1186 						 "sure that updates are physically written to disk. This insures "
1187 						 "that a database cluster will recover to a consistent state after "
1188 						 "an operating system or hardware crash.")
1189 		},
1190 		&enableFsync,
1191 		true,
1192 		NULL, NULL, NULL
1193 	},
1194 	{
1195 		{"ignore_checksum_failure", PGC_SUSET, DEVELOPER_OPTIONS,
1196 			gettext_noop("Continues processing after a checksum failure."),
1197 			gettext_noop("Detection of a checksum failure normally causes PostgreSQL to "
1198 						 "report an error, aborting the current transaction. Setting "
1199 						 "ignore_checksum_failure to true causes the system to ignore the failure "
1200 						 "(but still report a warning), and continue processing. This "
1201 						 "behavior could cause crashes or other serious problems. Only "
1202 						 "has an effect if checksums are enabled."),
1203 			GUC_NOT_IN_SAMPLE
1204 		},
1205 		&ignore_checksum_failure,
1206 		false,
1207 		NULL, NULL, NULL
1208 	},
1209 	{
1210 		{"zero_damaged_pages", PGC_SUSET, DEVELOPER_OPTIONS,
1211 			gettext_noop("Continues processing past damaged page headers."),
1212 			gettext_noop("Detection of a damaged page header normally causes PostgreSQL to "
1213 						 "report an error, aborting the current transaction. Setting "
1214 						 "zero_damaged_pages to true causes the system to instead report a "
1215 						 "warning, zero out the damaged page, and continue processing. This "
1216 						 "behavior will destroy data, namely all the rows on the damaged page."),
1217 			GUC_NOT_IN_SAMPLE
1218 		},
1219 		&zero_damaged_pages,
1220 		false,
1221 		NULL, NULL, NULL
1222 	},
1223 	{
1224 		{"ignore_invalid_pages", PGC_POSTMASTER, DEVELOPER_OPTIONS,
1225 			gettext_noop("Continues recovery after an invalid pages failure."),
1226 			gettext_noop("Detection of WAL records having references to "
1227 						 "invalid pages during recovery causes PostgreSQL to "
1228 						 "raise a PANIC-level error, aborting the recovery. "
1229 						 "Setting ignore_invalid_pages to true causes "
1230 						 "the system to ignore invalid page references "
1231 						 "in WAL records (but still report a warning), "
1232 						 "and continue recovery. This behavior may cause "
1233 						 "crashes, data loss, propagate or hide corruption, "
1234 						 "or other serious problems. Only has an effect "
1235 						 "during recovery or in standby mode."),
1236 			GUC_NOT_IN_SAMPLE
1237 		},
1238 		&ignore_invalid_pages,
1239 		false,
1240 		NULL, NULL, NULL
1241 	},
1242 	{
1243 		{"full_page_writes", PGC_SIGHUP, WAL_SETTINGS,
1244 			gettext_noop("Writes full pages to WAL when first modified after a checkpoint."),
1245 			gettext_noop("A page write in process during an operating system crash might be "
1246 						 "only partially written to disk.  During recovery, the row changes "
1247 						 "stored in WAL are not enough to recover.  This option writes "
1248 						 "pages when first modified after a checkpoint to WAL so full recovery "
1249 						 "is possible.")
1250 		},
1251 		&fullPageWrites,
1252 		true,
1253 		NULL, NULL, NULL
1254 	},
1255 
1256 	{
1257 		{"wal_log_hints", PGC_POSTMASTER, WAL_SETTINGS,
1258 			gettext_noop("Writes full pages to WAL when first modified after a checkpoint, even for a non-critical modification."),
1259 			NULL
1260 		},
1261 		&wal_log_hints,
1262 		false,
1263 		NULL, NULL, NULL
1264 	},
1265 
1266 	{
1267 		{"wal_compression", PGC_SUSET, WAL_SETTINGS,
1268 			gettext_noop("Compresses full-page writes written in WAL file."),
1269 			NULL
1270 		},
1271 		&wal_compression,
1272 		false,
1273 		NULL, NULL, NULL
1274 	},
1275 
1276 	{
1277 		{"wal_init_zero", PGC_SUSET, WAL_SETTINGS,
1278 			gettext_noop("Writes zeroes to new WAL files before first use."),
1279 			NULL
1280 		},
1281 		&wal_init_zero,
1282 		true,
1283 		NULL, NULL, NULL
1284 	},
1285 
1286 	{
1287 		{"wal_recycle", PGC_SUSET, WAL_SETTINGS,
1288 			gettext_noop("Recycles WAL files by renaming them."),
1289 			NULL
1290 		},
1291 		&wal_recycle,
1292 		true,
1293 		NULL, NULL, NULL
1294 	},
1295 
1296 	{
1297 		{"log_checkpoints", PGC_SIGHUP, LOGGING_WHAT,
1298 			gettext_noop("Logs each checkpoint."),
1299 			NULL
1300 		},
1301 		&log_checkpoints,
1302 		false,
1303 		NULL, NULL, NULL
1304 	},
1305 	{
1306 		{"log_connections", PGC_SU_BACKEND, LOGGING_WHAT,
1307 			gettext_noop("Logs each successful connection."),
1308 			NULL
1309 		},
1310 		&Log_connections,
1311 		false,
1312 		NULL, NULL, NULL
1313 	},
1314 	{
1315 		{"log_disconnections", PGC_SU_BACKEND, LOGGING_WHAT,
1316 			gettext_noop("Logs end of a session, including duration."),
1317 			NULL
1318 		},
1319 		&Log_disconnections,
1320 		false,
1321 		NULL, NULL, NULL
1322 	},
1323 	{
1324 		{"log_replication_commands", PGC_SUSET, LOGGING_WHAT,
1325 			gettext_noop("Logs each replication command."),
1326 			NULL
1327 		},
1328 		&log_replication_commands,
1329 		false,
1330 		NULL, NULL, NULL
1331 	},
1332 	{
1333 		{"debug_assertions", PGC_INTERNAL, PRESET_OPTIONS,
1334 			gettext_noop("Shows whether the running server has assertion checks enabled."),
1335 			NULL,
1336 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1337 		},
1338 		&assert_enabled,
1339 #ifdef USE_ASSERT_CHECKING
1340 		true,
1341 #else
1342 		false,
1343 #endif
1344 		NULL, NULL, NULL
1345 	},
1346 
1347 	{
1348 		{"exit_on_error", PGC_USERSET, ERROR_HANDLING_OPTIONS,
1349 			gettext_noop("Terminate session on any error."),
1350 			NULL
1351 		},
1352 		&ExitOnAnyError,
1353 		false,
1354 		NULL, NULL, NULL
1355 	},
1356 	{
1357 		{"restart_after_crash", PGC_SIGHUP, ERROR_HANDLING_OPTIONS,
1358 			gettext_noop("Reinitialize server after backend crash."),
1359 			NULL
1360 		},
1361 		&restart_after_crash,
1362 		true,
1363 		NULL, NULL, NULL
1364 	},
1365 
1366 	{
1367 		{"log_duration", PGC_SUSET, LOGGING_WHAT,
1368 			gettext_noop("Logs the duration of each completed SQL statement."),
1369 			NULL
1370 		},
1371 		&log_duration,
1372 		false,
1373 		NULL, NULL, NULL
1374 	},
1375 	{
1376 		{"debug_print_parse", PGC_USERSET, LOGGING_WHAT,
1377 			gettext_noop("Logs each query's parse tree."),
1378 			NULL
1379 		},
1380 		&Debug_print_parse,
1381 		false,
1382 		NULL, NULL, NULL
1383 	},
1384 	{
1385 		{"debug_print_rewritten", PGC_USERSET, LOGGING_WHAT,
1386 			gettext_noop("Logs each query's rewritten parse tree."),
1387 			NULL
1388 		},
1389 		&Debug_print_rewritten,
1390 		false,
1391 		NULL, NULL, NULL
1392 	},
1393 	{
1394 		{"debug_print_plan", PGC_USERSET, LOGGING_WHAT,
1395 			gettext_noop("Logs each query's execution plan."),
1396 			NULL
1397 		},
1398 		&Debug_print_plan,
1399 		false,
1400 		NULL, NULL, NULL
1401 	},
1402 	{
1403 		{"debug_pretty_print", PGC_USERSET, LOGGING_WHAT,
1404 			gettext_noop("Indents parse and plan tree displays."),
1405 			NULL
1406 		},
1407 		&Debug_pretty_print,
1408 		true,
1409 		NULL, NULL, NULL
1410 	},
1411 	{
1412 		{"log_parser_stats", PGC_SUSET, STATS_MONITORING,
1413 			gettext_noop("Writes parser performance statistics to the server log."),
1414 			NULL
1415 		},
1416 		&log_parser_stats,
1417 		false,
1418 		check_stage_log_stats, NULL, NULL
1419 	},
1420 	{
1421 		{"log_planner_stats", PGC_SUSET, STATS_MONITORING,
1422 			gettext_noop("Writes planner performance statistics to the server log."),
1423 			NULL
1424 		},
1425 		&log_planner_stats,
1426 		false,
1427 		check_stage_log_stats, NULL, NULL
1428 	},
1429 	{
1430 		{"log_executor_stats", PGC_SUSET, STATS_MONITORING,
1431 			gettext_noop("Writes executor performance statistics to the server log."),
1432 			NULL
1433 		},
1434 		&log_executor_stats,
1435 		false,
1436 		check_stage_log_stats, NULL, NULL
1437 	},
1438 	{
1439 		{"log_statement_stats", PGC_SUSET, STATS_MONITORING,
1440 			gettext_noop("Writes cumulative performance statistics to the server log."),
1441 			NULL
1442 		},
1443 		&log_statement_stats,
1444 		false,
1445 		check_log_stats, NULL, NULL
1446 	},
1447 #ifdef BTREE_BUILD_STATS
1448 	{
1449 		{"log_btree_build_stats", PGC_SUSET, DEVELOPER_OPTIONS,
1450 			gettext_noop("Logs system resource usage statistics (memory and CPU) on various B-tree operations."),
1451 			NULL,
1452 			GUC_NOT_IN_SAMPLE
1453 		},
1454 		&log_btree_build_stats,
1455 		false,
1456 		NULL, NULL, NULL
1457 	},
1458 #endif
1459 
1460 	{
1461 		{"track_activities", PGC_SUSET, STATS_COLLECTOR,
1462 			gettext_noop("Collects information about executing commands."),
1463 			gettext_noop("Enables the collection of information on the currently "
1464 						 "executing command of each session, along with "
1465 						 "the time at which that command began execution.")
1466 		},
1467 		&pgstat_track_activities,
1468 		true,
1469 		NULL, NULL, NULL
1470 	},
1471 	{
1472 		{"track_counts", PGC_SUSET, STATS_COLLECTOR,
1473 			gettext_noop("Collects statistics on database activity."),
1474 			NULL
1475 		},
1476 		&pgstat_track_counts,
1477 		true,
1478 		NULL, NULL, NULL
1479 	},
1480 	{
1481 		{"track_io_timing", PGC_SUSET, STATS_COLLECTOR,
1482 			gettext_noop("Collects timing statistics for database I/O activity."),
1483 			NULL
1484 		},
1485 		&track_io_timing,
1486 		false,
1487 		NULL, NULL, NULL
1488 	},
1489 
1490 	{
1491 		{"update_process_title", PGC_SUSET, PROCESS_TITLE,
1492 			gettext_noop("Updates the process title to show the active SQL command."),
1493 			gettext_noop("Enables updating of the process title every time a new SQL command is received by the server.")
1494 		},
1495 		&update_process_title,
1496 #ifdef WIN32
1497 		false,
1498 #else
1499 		true,
1500 #endif
1501 		NULL, NULL, NULL
1502 	},
1503 
1504 	{
1505 		{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
1506 			gettext_noop("Starts the autovacuum subprocess."),
1507 			NULL
1508 		},
1509 		&autovacuum_start_daemon,
1510 		true,
1511 		NULL, NULL, NULL
1512 	},
1513 
1514 	{
1515 		{"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
1516 			gettext_noop("Generates debugging output for LISTEN and NOTIFY."),
1517 			NULL,
1518 			GUC_NOT_IN_SAMPLE
1519 		},
1520 		&Trace_notify,
1521 		false,
1522 		NULL, NULL, NULL
1523 	},
1524 
1525 #ifdef LOCK_DEBUG
1526 	{
1527 		{"trace_locks", PGC_SUSET, DEVELOPER_OPTIONS,
1528 			gettext_noop("Emits information about lock usage."),
1529 			NULL,
1530 			GUC_NOT_IN_SAMPLE
1531 		},
1532 		&Trace_locks,
1533 		false,
1534 		NULL, NULL, NULL
1535 	},
1536 	{
1537 		{"trace_userlocks", PGC_SUSET, DEVELOPER_OPTIONS,
1538 			gettext_noop("Emits information about user lock usage."),
1539 			NULL,
1540 			GUC_NOT_IN_SAMPLE
1541 		},
1542 		&Trace_userlocks,
1543 		false,
1544 		NULL, NULL, NULL
1545 	},
1546 	{
1547 		{"trace_lwlocks", PGC_SUSET, DEVELOPER_OPTIONS,
1548 			gettext_noop("Emits information about lightweight lock usage."),
1549 			NULL,
1550 			GUC_NOT_IN_SAMPLE
1551 		},
1552 		&Trace_lwlocks,
1553 		false,
1554 		NULL, NULL, NULL
1555 	},
1556 	{
1557 		{"debug_deadlocks", PGC_SUSET, DEVELOPER_OPTIONS,
1558 			gettext_noop("Dumps information about all current locks when a deadlock timeout occurs."),
1559 			NULL,
1560 			GUC_NOT_IN_SAMPLE
1561 		},
1562 		&Debug_deadlocks,
1563 		false,
1564 		NULL, NULL, NULL
1565 	},
1566 #endif
1567 
1568 	{
1569 		{"log_lock_waits", PGC_SUSET, LOGGING_WHAT,
1570 			gettext_noop("Logs long lock waits."),
1571 			NULL
1572 		},
1573 		&log_lock_waits,
1574 		false,
1575 		NULL, NULL, NULL
1576 	},
1577 
1578 	{
1579 		{"log_hostname", PGC_SIGHUP, LOGGING_WHAT,
1580 			gettext_noop("Logs the host name in the connection logs."),
1581 			gettext_noop("By default, connection logs only show the IP address "
1582 						 "of the connecting host. If you want them to show the host name you "
1583 						 "can turn this on, but depending on your host name resolution "
1584 						 "setup it might impose a non-negligible performance penalty.")
1585 		},
1586 		&log_hostname,
1587 		false,
1588 		NULL, NULL, NULL
1589 	},
1590 	{
1591 		{"transform_null_equals", PGC_USERSET, COMPAT_OPTIONS_CLIENT,
1592 			gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"."),
1593 			gettext_noop("When turned on, expressions of the form expr = NULL "
1594 						 "(or NULL = expr) are treated as expr IS NULL, that is, they "
1595 						 "return true if expr evaluates to the null value, and false "
1596 						 "otherwise. The correct behavior of expr = NULL is to always "
1597 						 "return null (unknown).")
1598 		},
1599 		&Transform_null_equals,
1600 		false,
1601 		NULL, NULL, NULL
1602 	},
1603 	{
1604 		{"db_user_namespace", PGC_SIGHUP, CONN_AUTH_AUTH,
1605 			gettext_noop("Enables per-database user names."),
1606 			NULL
1607 		},
1608 		&Db_user_namespace,
1609 		false,
1610 		NULL, NULL, NULL
1611 	},
1612 	{
1613 		{"default_transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
1614 			gettext_noop("Sets the default read-only status of new transactions."),
1615 			NULL
1616 		},
1617 		&DefaultXactReadOnly,
1618 		false,
1619 		NULL, NULL, NULL
1620 	},
1621 	{
1622 		{"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
1623 			gettext_noop("Sets the current transaction's read-only status."),
1624 			NULL,
1625 			GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1626 		},
1627 		&XactReadOnly,
1628 		false,
1629 		check_transaction_read_only, NULL, NULL
1630 	},
1631 	{
1632 		{"default_transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT,
1633 			gettext_noop("Sets the default deferrable status of new transactions."),
1634 			NULL
1635 		},
1636 		&DefaultXactDeferrable,
1637 		false,
1638 		NULL, NULL, NULL
1639 	},
1640 	{
1641 		{"transaction_deferrable", PGC_USERSET, CLIENT_CONN_STATEMENT,
1642 			gettext_noop("Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures."),
1643 			NULL,
1644 			GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1645 		},
1646 		&XactDeferrable,
1647 		false,
1648 		check_transaction_deferrable, NULL, NULL
1649 	},
1650 	{
1651 		{"row_security", PGC_USERSET, CLIENT_CONN_STATEMENT,
1652 			gettext_noop("Enable row security."),
1653 			gettext_noop("When enabled, row security will be applied to all users.")
1654 		},
1655 		&row_security,
1656 		true,
1657 		NULL, NULL, NULL
1658 	},
1659 	{
1660 		{"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
1661 			gettext_noop("Check function bodies during CREATE FUNCTION."),
1662 			NULL
1663 		},
1664 		&check_function_bodies,
1665 		true,
1666 		NULL, NULL, NULL
1667 	},
1668 	{
1669 		{"array_nulls", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1670 			gettext_noop("Enable input of NULL elements in arrays."),
1671 			gettext_noop("When turned on, unquoted NULL in an array input "
1672 						 "value means a null value; "
1673 						 "otherwise it is taken literally.")
1674 		},
1675 		&Array_nulls,
1676 		true,
1677 		NULL, NULL, NULL
1678 	},
1679 
1680 	/*
1681 	 * WITH OIDS support, and consequently default_with_oids, was removed in
1682 	 * PostgreSQL 12, but we tolerate the parameter being set to false to
1683 	 * avoid unnecessarily breaking older dump files.
1684 	 */
1685 	{
1686 		{"default_with_oids", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1687 			gettext_noop("WITH OIDS is no longer supported; this can only be false."),
1688 			NULL,
1689 			GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE
1690 		},
1691 		&default_with_oids,
1692 		false,
1693 		check_default_with_oids, NULL, NULL
1694 	},
1695 	{
1696 		{"logging_collector", PGC_POSTMASTER, LOGGING_WHERE,
1697 			gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files."),
1698 			NULL
1699 		},
1700 		&Logging_collector,
1701 		false,
1702 		NULL, NULL, NULL
1703 	},
1704 	{
1705 		{"log_truncate_on_rotation", PGC_SIGHUP, LOGGING_WHERE,
1706 			gettext_noop("Truncate existing log files of same name during log rotation."),
1707 			NULL
1708 		},
1709 		&Log_truncate_on_rotation,
1710 		false,
1711 		NULL, NULL, NULL
1712 	},
1713 
1714 #ifdef TRACE_SORT
1715 	{
1716 		{"trace_sort", PGC_USERSET, DEVELOPER_OPTIONS,
1717 			gettext_noop("Emit information about resource usage in sorting."),
1718 			NULL,
1719 			GUC_NOT_IN_SAMPLE
1720 		},
1721 		&trace_sort,
1722 		false,
1723 		NULL, NULL, NULL
1724 	},
1725 #endif
1726 
1727 #ifdef TRACE_SYNCSCAN
1728 	/* this is undocumented because not exposed in a standard build */
1729 	{
1730 		{"trace_syncscan", PGC_USERSET, DEVELOPER_OPTIONS,
1731 			gettext_noop("Generate debugging output for synchronized scanning."),
1732 			NULL,
1733 			GUC_NOT_IN_SAMPLE
1734 		},
1735 		&trace_syncscan,
1736 		false,
1737 		NULL, NULL, NULL
1738 	},
1739 #endif
1740 
1741 #ifdef DEBUG_BOUNDED_SORT
1742 	/* this is undocumented because not exposed in a standard build */
1743 	{
1744 		{
1745 			"optimize_bounded_sort", PGC_USERSET, QUERY_TUNING_METHOD,
1746 			gettext_noop("Enable bounded sorting using heap sort."),
1747 			NULL,
1748 			GUC_NOT_IN_SAMPLE | GUC_EXPLAIN
1749 		},
1750 		&optimize_bounded_sort,
1751 		true,
1752 		NULL, NULL, NULL
1753 	},
1754 #endif
1755 
1756 #ifdef WAL_DEBUG
1757 	{
1758 		{"wal_debug", PGC_SUSET, DEVELOPER_OPTIONS,
1759 			gettext_noop("Emit WAL-related debugging output."),
1760 			NULL,
1761 			GUC_NOT_IN_SAMPLE
1762 		},
1763 		&XLOG_DEBUG,
1764 		false,
1765 		NULL, NULL, NULL
1766 	},
1767 #endif
1768 
1769 	{
1770 		{"integer_datetimes", PGC_INTERNAL, PRESET_OPTIONS,
1771 			gettext_noop("Datetimes are integer based."),
1772 			NULL,
1773 			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1774 		},
1775 		&integer_datetimes,
1776 		true,
1777 		NULL, NULL, NULL
1778 	},
1779 
1780 	{
1781 		{"krb_caseins_users", PGC_SIGHUP, CONN_AUTH_AUTH,
1782 			gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive."),
1783 			NULL
1784 		},
1785 		&pg_krb_caseins_users,
1786 		false,
1787 		NULL, NULL, NULL
1788 	},
1789 
1790 	{
1791 		{"escape_string_warning", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1792 			gettext_noop("Warn about backslash escapes in ordinary string literals."),
1793 			NULL
1794 		},
1795 		&escape_string_warning,
1796 		true,
1797 		NULL, NULL, NULL
1798 	},
1799 
1800 	{
1801 		{"standard_conforming_strings", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1802 			gettext_noop("Causes '...' strings to treat backslashes literally."),
1803 			NULL,
1804 			GUC_REPORT
1805 		},
1806 		&standard_conforming_strings,
1807 		true,
1808 		NULL, NULL, NULL
1809 	},
1810 
1811 	{
1812 		{"synchronize_seqscans", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1813 			gettext_noop("Enable synchronized sequential scans."),
1814 			NULL
1815 		},
1816 		&synchronize_seqscans,
1817 		true,
1818 		NULL, NULL, NULL
1819 	},
1820 
1821 	{
1822 		{"recovery_target_inclusive", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
1823 			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
1824 			NULL
1825 		},
1826 		&recoveryTargetInclusive,
1827 		true,
1828 		NULL, NULL, NULL
1829 	},
1830 
1831 	{
1832 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
1833 			gettext_noop("Allows connections and queries during recovery."),
1834 			NULL
1835 		},
1836 		&EnableHotStandby,
1837 		true,
1838 		NULL, NULL, NULL
1839 	},
1840 
1841 	{
1842 		{"hot_standby_feedback", PGC_SIGHUP, REPLICATION_STANDBY,
1843 			gettext_noop("Allows feedback from a hot standby to the primary that will avoid query conflicts."),
1844 			NULL
1845 		},
1846 		&hot_standby_feedback,
1847 		false,
1848 		NULL, NULL, NULL
1849 	},
1850 
1851 	{
1852 		{"allow_system_table_mods", PGC_SUSET, DEVELOPER_OPTIONS,
1853 			gettext_noop("Allows modifications of the structure of system tables."),
1854 			NULL,
1855 			GUC_NOT_IN_SAMPLE
1856 		},
1857 		&allowSystemTableMods,
1858 		false,
1859 		NULL, NULL, NULL
1860 	},
1861 
1862 	{
1863 		{"ignore_system_indexes", PGC_BACKEND, DEVELOPER_OPTIONS,
1864 			gettext_noop("Disables reading from system indexes."),
1865 			gettext_noop("It does not prevent updating the indexes, so it is safe "
1866 						 "to use.  The worst consequence is slowness."),
1867 			GUC_NOT_IN_SAMPLE
1868 		},
1869 		&IgnoreSystemIndexes,
1870 		false,
1871 		NULL, NULL, NULL
1872 	},
1873 
1874 	{
1875 		{"lo_compat_privileges", PGC_SUSET, COMPAT_OPTIONS_PREVIOUS,
1876 			gettext_noop("Enables backward compatibility mode for privilege checks on large objects."),
1877 			gettext_noop("Skips privilege checks when reading or modifying large objects, "
1878 						 "for compatibility with PostgreSQL releases prior to 9.0.")
1879 		},
1880 		&lo_compat_privileges,
1881 		false,
1882 		NULL, NULL, NULL
1883 	},
1884 
1885 	{
1886 		{"operator_precedence_warning", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1887 			gettext_noop("Emit a warning for constructs that changed meaning since PostgreSQL 9.4."),
1888 			NULL,
1889 		},
1890 		&operator_precedence_warning,
1891 		false,
1892 		NULL, NULL, NULL
1893 	},
1894 
1895 	{
1896 		{"quote_all_identifiers", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
1897 			gettext_noop("When generating SQL fragments, quote all identifiers."),
1898 			NULL,
1899 		},
1900 		&quote_all_identifiers,
1901 		false,
1902 		NULL, NULL, NULL
1903 	},
1904 
1905 	{
1906 		{"data_checksums", PGC_INTERNAL, PRESET_OPTIONS,
1907 			gettext_noop("Shows whether data checksums are turned on for this cluster."),
1908 			NULL,
1909 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
1910 		},
1911 		&data_checksums,
1912 		false,
1913 		NULL, NULL, NULL
1914 	},
1915 
1916 	{
1917 		{"syslog_sequence_numbers", PGC_SIGHUP, LOGGING_WHERE,
1918 			gettext_noop("Add sequence number to syslog messages to avoid duplicate suppression."),
1919 			NULL
1920 		},
1921 		&syslog_sequence_numbers,
1922 		true,
1923 		NULL, NULL, NULL
1924 	},
1925 
1926 	{
1927 		{"syslog_split_messages", PGC_SIGHUP, LOGGING_WHERE,
1928 			gettext_noop("Split messages sent to syslog by lines and to fit into 1024 bytes."),
1929 			NULL
1930 		},
1931 		&syslog_split_messages,
1932 		true,
1933 		NULL, NULL, NULL
1934 	},
1935 
1936 	{
1937 		{"parallel_leader_participation", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
1938 			gettext_noop("Controls whether Gather and Gather Merge also run subplans."),
1939 			gettext_noop("Should gather nodes also run subplans, or just gather tuples?"),
1940 			GUC_EXPLAIN
1941 		},
1942 		&parallel_leader_participation,
1943 		true,
1944 		NULL, NULL, NULL
1945 	},
1946 
1947 	{
1948 		{"jit", PGC_USERSET, QUERY_TUNING_OTHER,
1949 			gettext_noop("Allow JIT compilation."),
1950 			NULL,
1951 			GUC_EXPLAIN
1952 		},
1953 		&jit_enabled,
1954 		true,
1955 		NULL, NULL, NULL
1956 	},
1957 
1958 	{
1959 		{"jit_debugging_support", PGC_SU_BACKEND, DEVELOPER_OPTIONS,
1960 			gettext_noop("Register JIT compiled function with debugger."),
1961 			NULL,
1962 			GUC_NOT_IN_SAMPLE
1963 		},
1964 		&jit_debugging_support,
1965 		false,
1966 
1967 		/*
1968 		 * This is not guaranteed to be available, but given it's a developer
1969 		 * oriented option, it doesn't seem worth adding code checking
1970 		 * availability.
1971 		 */
1972 		NULL, NULL, NULL
1973 	},
1974 
1975 	{
1976 		{"jit_dump_bitcode", PGC_SUSET, DEVELOPER_OPTIONS,
1977 			gettext_noop("Write out LLVM bitcode to facilitate JIT debugging."),
1978 			NULL,
1979 			GUC_NOT_IN_SAMPLE
1980 		},
1981 		&jit_dump_bitcode,
1982 		false,
1983 		NULL, NULL, NULL
1984 	},
1985 
1986 	{
1987 		{"jit_expressions", PGC_USERSET, DEVELOPER_OPTIONS,
1988 			gettext_noop("Allow JIT compilation of expressions."),
1989 			NULL,
1990 			GUC_NOT_IN_SAMPLE
1991 		},
1992 		&jit_expressions,
1993 		true,
1994 		NULL, NULL, NULL
1995 	},
1996 
1997 	{
1998 		{"jit_profiling_support", PGC_SU_BACKEND, DEVELOPER_OPTIONS,
1999 			gettext_noop("Register JIT compiled function with perf profiler."),
2000 			NULL,
2001 			GUC_NOT_IN_SAMPLE
2002 		},
2003 		&jit_profiling_support,
2004 		false,
2005 
2006 		/*
2007 		 * This is not guaranteed to be available, but given it's a developer
2008 		 * oriented option, it doesn't seem worth adding code checking
2009 		 * availability.
2010 		 */
2011 		NULL, NULL, NULL
2012 	},
2013 
2014 	{
2015 		{"jit_tuple_deforming", PGC_USERSET, DEVELOPER_OPTIONS,
2016 			gettext_noop("Allow JIT compilation of tuple deforming."),
2017 			NULL,
2018 			GUC_NOT_IN_SAMPLE
2019 		},
2020 		&jit_tuple_deforming,
2021 		true,
2022 		NULL, NULL, NULL
2023 	},
2024 
2025 	{
2026 		{"data_sync_retry", PGC_POSTMASTER, ERROR_HANDLING_OPTIONS,
2027 			gettext_noop("Whether to continue running after a failure to sync data files."),
2028 		},
2029 		&data_sync_retry,
2030 		false,
2031 		NULL, NULL, NULL
2032 	},
2033 
2034 	{
2035 		{"wal_receiver_create_temp_slot", PGC_SIGHUP, REPLICATION_STANDBY,
2036 			gettext_noop("Sets whether a WAL receiver should create a temporary replication slot if no permanent slot is configured."),
2037 		},
2038 		&wal_receiver_create_temp_slot,
2039 		false,
2040 		NULL, NULL, NULL
2041 	},
2042 
2043 	/* End-of-list marker */
2044 	{
2045 		{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
2046 	}
2047 };
2048 
2049 
2050 static struct config_int ConfigureNamesInt[] =
2051 {
2052 	{
2053 		{"archive_timeout", PGC_SIGHUP, WAL_ARCHIVING,
2054 			gettext_noop("Forces a switch to the next WAL file if a "
2055 						 "new file has not been started within N seconds."),
2056 			NULL,
2057 			GUC_UNIT_S
2058 		},
2059 		&XLogArchiveTimeout,
2060 		0, 0, INT_MAX / 2,
2061 		NULL, NULL, NULL
2062 	},
2063 	{
2064 		{"post_auth_delay", PGC_BACKEND, DEVELOPER_OPTIONS,
2065 			gettext_noop("Waits N seconds on connection startup after authentication."),
2066 			gettext_noop("This allows attaching a debugger to the process."),
2067 			GUC_NOT_IN_SAMPLE | GUC_UNIT_S
2068 		},
2069 		&PostAuthDelay,
2070 		0, 0, INT_MAX / 1000000,
2071 		NULL, NULL, NULL
2072 	},
2073 	{
2074 		{"default_statistics_target", PGC_USERSET, QUERY_TUNING_OTHER,
2075 			gettext_noop("Sets the default statistics target."),
2076 			gettext_noop("This applies to table columns that have not had a "
2077 						 "column-specific target set via ALTER TABLE SET STATISTICS.")
2078 		},
2079 		&default_statistics_target,
2080 		100, 1, 10000,
2081 		NULL, NULL, NULL
2082 	},
2083 	{
2084 		{"from_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
2085 			gettext_noop("Sets the FROM-list size beyond which subqueries "
2086 						 "are not collapsed."),
2087 			gettext_noop("The planner will merge subqueries into upper "
2088 						 "queries if the resulting FROM list would have no more than "
2089 						 "this many items."),
2090 			GUC_EXPLAIN
2091 		},
2092 		&from_collapse_limit,
2093 		8, 1, INT_MAX,
2094 		NULL, NULL, NULL
2095 	},
2096 	{
2097 		{"join_collapse_limit", PGC_USERSET, QUERY_TUNING_OTHER,
2098 			gettext_noop("Sets the FROM-list size beyond which JOIN "
2099 						 "constructs are not flattened."),
2100 			gettext_noop("The planner will flatten explicit JOIN "
2101 						 "constructs into lists of FROM items whenever a "
2102 						 "list of no more than this many items would result."),
2103 			GUC_EXPLAIN
2104 		},
2105 		&join_collapse_limit,
2106 		8, 1, INT_MAX,
2107 		NULL, NULL, NULL
2108 	},
2109 	{
2110 		{"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO,
2111 			gettext_noop("Sets the threshold of FROM items beyond which GEQO is used."),
2112 			NULL,
2113 			GUC_EXPLAIN
2114 		},
2115 		&geqo_threshold,
2116 		12, 2, INT_MAX,
2117 		NULL, NULL, NULL
2118 	},
2119 	{
2120 		{"geqo_effort", PGC_USERSET, QUERY_TUNING_GEQO,
2121 			gettext_noop("GEQO: effort is used to set the default for other GEQO parameters."),
2122 			NULL,
2123 			GUC_EXPLAIN
2124 		},
2125 		&Geqo_effort,
2126 		DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT,
2127 		NULL, NULL, NULL
2128 	},
2129 	{
2130 		{"geqo_pool_size", PGC_USERSET, QUERY_TUNING_GEQO,
2131 			gettext_noop("GEQO: number of individuals in the population."),
2132 			gettext_noop("Zero selects a suitable default value."),
2133 			GUC_EXPLAIN
2134 		},
2135 		&Geqo_pool_size,
2136 		0, 0, INT_MAX,
2137 		NULL, NULL, NULL
2138 	},
2139 	{
2140 		{"geqo_generations", PGC_USERSET, QUERY_TUNING_GEQO,
2141 			gettext_noop("GEQO: number of iterations of the algorithm."),
2142 			gettext_noop("Zero selects a suitable default value."),
2143 			GUC_EXPLAIN
2144 		},
2145 		&Geqo_generations,
2146 		0, 0, INT_MAX,
2147 		NULL, NULL, NULL
2148 	},
2149 
2150 	{
2151 		/* This is PGC_SUSET to prevent hiding from log_lock_waits. */
2152 		{"deadlock_timeout", PGC_SUSET, LOCK_MANAGEMENT,
2153 			gettext_noop("Sets the time to wait on a lock before checking for deadlock."),
2154 			NULL,
2155 			GUC_UNIT_MS
2156 		},
2157 		&DeadlockTimeout,
2158 		1000, 1, INT_MAX,
2159 		NULL, NULL, NULL
2160 	},
2161 
2162 	{
2163 		{"max_standby_archive_delay", PGC_SIGHUP, REPLICATION_STANDBY,
2164 			gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing archived WAL data."),
2165 			NULL,
2166 			GUC_UNIT_MS
2167 		},
2168 		&max_standby_archive_delay,
2169 		30 * 1000, -1, INT_MAX,
2170 		NULL, NULL, NULL
2171 	},
2172 
2173 	{
2174 		{"max_standby_streaming_delay", PGC_SIGHUP, REPLICATION_STANDBY,
2175 			gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing streamed WAL data."),
2176 			NULL,
2177 			GUC_UNIT_MS
2178 		},
2179 		&max_standby_streaming_delay,
2180 		30 * 1000, -1, INT_MAX,
2181 		NULL, NULL, NULL
2182 	},
2183 
2184 	{
2185 		{"recovery_min_apply_delay", PGC_SIGHUP, REPLICATION_STANDBY,
2186 			gettext_noop("Sets the minimum delay for applying changes during recovery."),
2187 			NULL,
2188 			GUC_UNIT_MS
2189 		},
2190 		&recovery_min_apply_delay,
2191 		0, 0, INT_MAX,
2192 		NULL, NULL, NULL
2193 	},
2194 
2195 	{
2196 		{"wal_receiver_status_interval", PGC_SIGHUP, REPLICATION_STANDBY,
2197 			gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server."),
2198 			NULL,
2199 			GUC_UNIT_S
2200 		},
2201 		&wal_receiver_status_interval,
2202 		10, 0, INT_MAX / 1000,
2203 		NULL, NULL, NULL
2204 	},
2205 
2206 	{
2207 		{"wal_receiver_timeout", PGC_SIGHUP, REPLICATION_STANDBY,
2208 			gettext_noop("Sets the maximum wait time to receive data from the sending server."),
2209 			NULL,
2210 			GUC_UNIT_MS
2211 		},
2212 		&wal_receiver_timeout,
2213 		60 * 1000, 0, INT_MAX,
2214 		NULL, NULL, NULL
2215 	},
2216 
2217 	{
2218 		{"max_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
2219 			gettext_noop("Sets the maximum number of concurrent connections."),
2220 			NULL
2221 		},
2222 		&MaxConnections,
2223 		100, 1, MAX_BACKENDS,
2224 		check_maxconnections, NULL, NULL
2225 	},
2226 
2227 	{
2228 		/* see max_connections */
2229 		{"superuser_reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
2230 			gettext_noop("Sets the number of connection slots reserved for superusers."),
2231 			NULL
2232 		},
2233 		&ReservedBackends,
2234 		3, 0, MAX_BACKENDS,
2235 		NULL, NULL, NULL
2236 	},
2237 
2238 	/*
2239 	 * We sometimes multiply the number of shared buffers by two without
2240 	 * checking for overflow, so we mustn't allow more than INT_MAX / 2.
2241 	 */
2242 	{
2243 		{"shared_buffers", PGC_POSTMASTER, RESOURCES_MEM,
2244 			gettext_noop("Sets the number of shared memory buffers used by the server."),
2245 			NULL,
2246 			GUC_UNIT_BLOCKS
2247 		},
2248 		&NBuffers,
2249 		1024, 16, INT_MAX / 2,
2250 		NULL, NULL, NULL
2251 	},
2252 
2253 	{
2254 		{"temp_buffers", PGC_USERSET, RESOURCES_MEM,
2255 			gettext_noop("Sets the maximum number of temporary buffers used by each session."),
2256 			NULL,
2257 			GUC_UNIT_BLOCKS | GUC_EXPLAIN
2258 		},
2259 		&num_temp_buffers,
2260 		1024, 100, INT_MAX / 2,
2261 		check_temp_buffers, NULL, NULL
2262 	},
2263 
2264 	{
2265 		{"port", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
2266 			gettext_noop("Sets the TCP port the server listens on."),
2267 			NULL
2268 		},
2269 		&PostPortNumber,
2270 		DEF_PGPORT, 1, 65535,
2271 		NULL, NULL, NULL
2272 	},
2273 
2274 	{
2275 		{"unix_socket_permissions", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
2276 			gettext_noop("Sets the access permissions of the Unix-domain socket."),
2277 			gettext_noop("Unix-domain sockets use the usual Unix file system "
2278 						 "permission set. The parameter value is expected "
2279 						 "to be a numeric mode specification in the form "
2280 						 "accepted by the chmod and umask system calls. "
2281 						 "(To use the customary octal format the number must "
2282 						 "start with a 0 (zero).)")
2283 		},
2284 		&Unix_socket_permissions,
2285 		0777, 0000, 0777,
2286 		NULL, NULL, show_unix_socket_permissions
2287 	},
2288 
2289 	{
2290 		{"log_file_mode", PGC_SIGHUP, LOGGING_WHERE,
2291 			gettext_noop("Sets the file permissions for log files."),
2292 			gettext_noop("The parameter value is expected "
2293 						 "to be a numeric mode specification in the form "
2294 						 "accepted by the chmod and umask system calls. "
2295 						 "(To use the customary octal format the number must "
2296 						 "start with a 0 (zero).)")
2297 		},
2298 		&Log_file_mode,
2299 		0600, 0000, 0777,
2300 		NULL, NULL, show_log_file_mode
2301 	},
2302 
2303 
2304 	{
2305 		{"data_directory_mode", PGC_INTERNAL, PRESET_OPTIONS,
2306 			gettext_noop("Mode of the data directory."),
2307 			gettext_noop("The parameter value is a numeric mode specification "
2308 						 "in the form accepted by the chmod and umask system "
2309 						 "calls. (To use the customary octal format the number "
2310 						 "must start with a 0 (zero).)"),
2311 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
2312 		},
2313 		&data_directory_mode,
2314 		0700, 0000, 0777,
2315 		NULL, NULL, show_data_directory_mode
2316 	},
2317 
2318 	{
2319 		{"work_mem", PGC_USERSET, RESOURCES_MEM,
2320 			gettext_noop("Sets the maximum memory to be used for query workspaces."),
2321 			gettext_noop("This much memory can be used by each internal "
2322 						 "sort operation and hash table before switching to "
2323 						 "temporary disk files."),
2324 			GUC_UNIT_KB | GUC_EXPLAIN
2325 		},
2326 		&work_mem,
2327 		4096, 64, MAX_KILOBYTES,
2328 		NULL, NULL, NULL
2329 	},
2330 
2331 	{
2332 		{"maintenance_work_mem", PGC_USERSET, RESOURCES_MEM,
2333 			gettext_noop("Sets the maximum memory to be used for maintenance operations."),
2334 			gettext_noop("This includes operations such as VACUUM and CREATE INDEX."),
2335 			GUC_UNIT_KB
2336 		},
2337 		&maintenance_work_mem,
2338 		65536, 1024, MAX_KILOBYTES,
2339 		NULL, NULL, NULL
2340 	},
2341 
2342 	{
2343 		{"logical_decoding_work_mem", PGC_USERSET, RESOURCES_MEM,
2344 			gettext_noop("Sets the maximum memory to be used for logical decoding."),
2345 			gettext_noop("This much memory can be used by each internal "
2346 						 "reorder buffer before spilling to disk."),
2347 			GUC_UNIT_KB
2348 		},
2349 		&logical_decoding_work_mem,
2350 		65536, 64, MAX_KILOBYTES,
2351 		NULL, NULL, NULL
2352 	},
2353 
2354 	/*
2355 	 * We use the hopefully-safely-small value of 100kB as the compiled-in
2356 	 * default for max_stack_depth.  InitializeGUCOptions will increase it if
2357 	 * possible, depending on the actual platform-specific stack limit.
2358 	 */
2359 	{
2360 		{"max_stack_depth", PGC_SUSET, RESOURCES_MEM,
2361 			gettext_noop("Sets the maximum stack depth, in kilobytes."),
2362 			NULL,
2363 			GUC_UNIT_KB
2364 		},
2365 		&max_stack_depth,
2366 		100, 100, MAX_KILOBYTES,
2367 		check_max_stack_depth, assign_max_stack_depth, NULL
2368 	},
2369 
2370 	{
2371 		{"temp_file_limit", PGC_SUSET, RESOURCES_DISK,
2372 			gettext_noop("Limits the total size of all temporary files used by each process."),
2373 			gettext_noop("-1 means no limit."),
2374 			GUC_UNIT_KB
2375 		},
2376 		&temp_file_limit,
2377 		-1, -1, INT_MAX,
2378 		NULL, NULL, NULL
2379 	},
2380 
2381 	{
2382 		{"vacuum_cost_page_hit", PGC_USERSET, RESOURCES_VACUUM_DELAY,
2383 			gettext_noop("Vacuum cost for a page found in the buffer cache."),
2384 			NULL
2385 		},
2386 		&VacuumCostPageHit,
2387 		1, 0, 10000,
2388 		NULL, NULL, NULL
2389 	},
2390 
2391 	{
2392 		{"vacuum_cost_page_miss", PGC_USERSET, RESOURCES_VACUUM_DELAY,
2393 			gettext_noop("Vacuum cost for a page not found in the buffer cache."),
2394 			NULL
2395 		},
2396 		&VacuumCostPageMiss,
2397 		10, 0, 10000,
2398 		NULL, NULL, NULL
2399 	},
2400 
2401 	{
2402 		{"vacuum_cost_page_dirty", PGC_USERSET, RESOURCES_VACUUM_DELAY,
2403 			gettext_noop("Vacuum cost for a page dirtied by vacuum."),
2404 			NULL
2405 		},
2406 		&VacuumCostPageDirty,
2407 		20, 0, 10000,
2408 		NULL, NULL, NULL
2409 	},
2410 
2411 	{
2412 		{"vacuum_cost_limit", PGC_USERSET, RESOURCES_VACUUM_DELAY,
2413 			gettext_noop("Vacuum cost amount available before napping."),
2414 			NULL
2415 		},
2416 		&VacuumCostLimit,
2417 		200, 1, 10000,
2418 		NULL, NULL, NULL
2419 	},
2420 
2421 	{
2422 		{"autovacuum_vacuum_cost_limit", PGC_SIGHUP, AUTOVACUUM,
2423 			gettext_noop("Vacuum cost amount available before napping, for autovacuum."),
2424 			NULL
2425 		},
2426 		&autovacuum_vac_cost_limit,
2427 		-1, -1, 10000,
2428 		NULL, NULL, NULL
2429 	},
2430 
2431 	{
2432 		{"max_files_per_process", PGC_POSTMASTER, RESOURCES_KERNEL,
2433 			gettext_noop("Sets the maximum number of simultaneously open files for each server process."),
2434 			NULL
2435 		},
2436 		&max_files_per_process,
2437 		1000, 64, INT_MAX,
2438 		NULL, NULL, NULL
2439 	},
2440 
2441 	/*
2442 	 * See also CheckRequiredParameterValues() if this parameter changes
2443 	 */
2444 	{
2445 		{"max_prepared_transactions", PGC_POSTMASTER, RESOURCES_MEM,
2446 			gettext_noop("Sets the maximum number of simultaneously prepared transactions."),
2447 			NULL
2448 		},
2449 		&max_prepared_xacts,
2450 		0, 0, MAX_BACKENDS,
2451 		NULL, NULL, NULL
2452 	},
2453 
2454 #ifdef LOCK_DEBUG
2455 	{
2456 		{"trace_lock_oidmin", PGC_SUSET, DEVELOPER_OPTIONS,
2457 			gettext_noop("Sets the minimum OID of tables for tracking locks."),
2458 			gettext_noop("Is used to avoid output on system tables."),
2459 			GUC_NOT_IN_SAMPLE
2460 		},
2461 		&Trace_lock_oidmin,
2462 		FirstNormalObjectId, 0, INT_MAX,
2463 		NULL, NULL, NULL
2464 	},
2465 	{
2466 		{"trace_lock_table", PGC_SUSET, DEVELOPER_OPTIONS,
2467 			gettext_noop("Sets the OID of the table with unconditionally lock tracing."),
2468 			NULL,
2469 			GUC_NOT_IN_SAMPLE
2470 		},
2471 		&Trace_lock_table,
2472 		0, 0, INT_MAX,
2473 		NULL, NULL, NULL
2474 	},
2475 #endif
2476 
2477 	{
2478 		{"statement_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
2479 			gettext_noop("Sets the maximum allowed duration of any statement."),
2480 			gettext_noop("A value of 0 turns off the timeout."),
2481 			GUC_UNIT_MS
2482 		},
2483 		&StatementTimeout,
2484 		0, 0, INT_MAX,
2485 		NULL, NULL, NULL
2486 	},
2487 
2488 	{
2489 		{"lock_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
2490 			gettext_noop("Sets the maximum allowed duration of any wait for a lock."),
2491 			gettext_noop("A value of 0 turns off the timeout."),
2492 			GUC_UNIT_MS
2493 		},
2494 		&LockTimeout,
2495 		0, 0, INT_MAX,
2496 		NULL, NULL, NULL
2497 	},
2498 
2499 	{
2500 		{"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
2501 			gettext_noop("Sets the maximum allowed duration of any idling transaction."),
2502 			gettext_noop("A value of 0 turns off the timeout."),
2503 			GUC_UNIT_MS
2504 		},
2505 		&IdleInTransactionSessionTimeout,
2506 		0, 0, INT_MAX,
2507 		NULL, NULL, NULL
2508 	},
2509 
2510 	{
2511 		{"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
2512 			gettext_noop("Minimum age at which VACUUM should freeze a table row."),
2513 			NULL
2514 		},
2515 		&vacuum_freeze_min_age,
2516 		50000000, 0, 1000000000,
2517 		NULL, NULL, NULL
2518 	},
2519 
2520 	{
2521 		{"vacuum_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
2522 			gettext_noop("Age at which VACUUM should scan whole table to freeze tuples."),
2523 			NULL
2524 		},
2525 		&vacuum_freeze_table_age,
2526 		150000000, 0, 2000000000,
2527 		NULL, NULL, NULL
2528 	},
2529 
2530 	{
2531 		{"vacuum_multixact_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
2532 			gettext_noop("Minimum age at which VACUUM should freeze a MultiXactId in a table row."),
2533 			NULL
2534 		},
2535 		&vacuum_multixact_freeze_min_age,
2536 		5000000, 0, 1000000000,
2537 		NULL, NULL, NULL
2538 	},
2539 
2540 	{
2541 		{"vacuum_multixact_freeze_table_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
2542 			gettext_noop("Multixact age at which VACUUM should scan whole table to freeze tuples."),
2543 			NULL
2544 		},
2545 		&vacuum_multixact_freeze_table_age,
2546 		150000000, 0, 2000000000,
2547 		NULL, NULL, NULL
2548 	},
2549 
2550 	{
2551 		{"vacuum_defer_cleanup_age", PGC_SIGHUP, REPLICATION_MASTER,
2552 			gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any."),
2553 			NULL
2554 		},
2555 		&vacuum_defer_cleanup_age,
2556 		0, 0, 1000000,
2557 		NULL, NULL, NULL
2558 	},
2559 
2560 	/*
2561 	 * See also CheckRequiredParameterValues() if this parameter changes
2562 	 */
2563 	{
2564 		{"max_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
2565 			gettext_noop("Sets the maximum number of locks per transaction."),
2566 			gettext_noop("The shared lock table is sized on the assumption that "
2567 						 "at most max_locks_per_transaction * max_connections distinct "
2568 						 "objects will need to be locked at any one time.")
2569 		},
2570 		&max_locks_per_xact,
2571 		64, 10, INT_MAX,
2572 		NULL, NULL, NULL
2573 	},
2574 
2575 	{
2576 		{"max_pred_locks_per_transaction", PGC_POSTMASTER, LOCK_MANAGEMENT,
2577 			gettext_noop("Sets the maximum number of predicate locks per transaction."),
2578 			gettext_noop("The shared predicate lock table is sized on the assumption that "
2579 						 "at most max_pred_locks_per_transaction * max_connections distinct "
2580 						 "objects will need to be locked at any one time.")
2581 		},
2582 		&max_predicate_locks_per_xact,
2583 		64, 10, INT_MAX,
2584 		NULL, NULL, NULL
2585 	},
2586 
2587 	{
2588 		{"max_pred_locks_per_relation", PGC_SIGHUP, LOCK_MANAGEMENT,
2589 			gettext_noop("Sets the maximum number of predicate-locked pages and tuples per relation."),
2590 			gettext_noop("If more than this total of pages and tuples in the same relation are locked "
2591 						 "by a connection, those locks are replaced by a relation-level lock.")
2592 		},
2593 		&max_predicate_locks_per_relation,
2594 		-2, INT_MIN, INT_MAX,
2595 		NULL, NULL, NULL
2596 	},
2597 
2598 	{
2599 		{"max_pred_locks_per_page", PGC_SIGHUP, LOCK_MANAGEMENT,
2600 			gettext_noop("Sets the maximum number of predicate-locked tuples per page."),
2601 			gettext_noop("If more than this number of tuples on the same page are locked "
2602 						 "by a connection, those locks are replaced by a page-level lock.")
2603 		},
2604 		&max_predicate_locks_per_page,
2605 		2, 0, INT_MAX,
2606 		NULL, NULL, NULL
2607 	},
2608 
2609 	{
2610 		{"authentication_timeout", PGC_SIGHUP, CONN_AUTH_AUTH,
2611 			gettext_noop("Sets the maximum allowed time to complete client authentication."),
2612 			NULL,
2613 			GUC_UNIT_S
2614 		},
2615 		&AuthenticationTimeout,
2616 		60, 1, 600,
2617 		NULL, NULL, NULL
2618 	},
2619 
2620 	{
2621 		/* Not for general use */
2622 		{"pre_auth_delay", PGC_SIGHUP, DEVELOPER_OPTIONS,
2623 			gettext_noop("Waits N seconds on connection startup before authentication."),
2624 			gettext_noop("This allows attaching a debugger to the process."),
2625 			GUC_NOT_IN_SAMPLE | GUC_UNIT_S
2626 		},
2627 		&PreAuthDelay,
2628 		0, 0, 60,
2629 		NULL, NULL, NULL
2630 	},
2631 
2632 	{
2633 		{"wal_keep_size", PGC_SIGHUP, REPLICATION_SENDING,
2634 			gettext_noop("Sets the size of WAL files held for standby servers."),
2635 			NULL,
2636 			GUC_UNIT_MB
2637 		},
2638 		&wal_keep_size_mb,
2639 		0, 0, MAX_KILOBYTES,
2640 		NULL, NULL, NULL
2641 	},
2642 
2643 	{
2644 		{"min_wal_size", PGC_SIGHUP, WAL_CHECKPOINTS,
2645 			gettext_noop("Sets the minimum size to shrink the WAL to."),
2646 			NULL,
2647 			GUC_UNIT_MB
2648 		},
2649 		&min_wal_size_mb,
2650 		DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
2651 		2, MAX_KILOBYTES,
2652 		NULL, NULL, NULL
2653 	},
2654 
2655 	{
2656 		{"max_wal_size", PGC_SIGHUP, WAL_CHECKPOINTS,
2657 			gettext_noop("Sets the WAL size that triggers a checkpoint."),
2658 			NULL,
2659 			GUC_UNIT_MB
2660 		},
2661 		&max_wal_size_mb,
2662 		DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)),
2663 		2, MAX_KILOBYTES,
2664 		NULL, assign_max_wal_size, NULL
2665 	},
2666 
2667 	{
2668 		{"checkpoint_timeout", PGC_SIGHUP, WAL_CHECKPOINTS,
2669 			gettext_noop("Sets the maximum time between automatic WAL checkpoints."),
2670 			NULL,
2671 			GUC_UNIT_S
2672 		},
2673 		&CheckPointTimeout,
2674 		300, 30, 86400,
2675 		NULL, NULL, NULL
2676 	},
2677 
2678 	{
2679 		{"checkpoint_warning", PGC_SIGHUP, WAL_CHECKPOINTS,
2680 			gettext_noop("Enables warnings if checkpoint segments are filled more "
2681 						 "frequently than this."),
2682 			gettext_noop("Write a message to the server log if checkpoints "
2683 						 "caused by the filling of checkpoint segment files happens more "
2684 						 "frequently than this number of seconds. Zero turns off the warning."),
2685 			GUC_UNIT_S
2686 		},
2687 		&CheckPointWarning,
2688 		30, 0, INT_MAX,
2689 		NULL, NULL, NULL
2690 	},
2691 
2692 	{
2693 		{"checkpoint_flush_after", PGC_SIGHUP, WAL_CHECKPOINTS,
2694 			gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
2695 			NULL,
2696 			GUC_UNIT_BLOCKS
2697 		},
2698 		&checkpoint_flush_after,
2699 		DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
2700 		NULL, NULL, NULL
2701 	},
2702 
2703 	{
2704 		{"wal_buffers", PGC_POSTMASTER, WAL_SETTINGS,
2705 			gettext_noop("Sets the number of disk-page buffers in shared memory for WAL."),
2706 			NULL,
2707 			GUC_UNIT_XBLOCKS
2708 		},
2709 		&XLOGbuffers,
2710 		-1, -1, (INT_MAX / XLOG_BLCKSZ),
2711 		check_wal_buffers, NULL, NULL
2712 	},
2713 
2714 	{
2715 		{"wal_writer_delay", PGC_SIGHUP, WAL_SETTINGS,
2716 			gettext_noop("Time between WAL flushes performed in the WAL writer."),
2717 			NULL,
2718 			GUC_UNIT_MS
2719 		},
2720 		&WalWriterDelay,
2721 		200, 1, 10000,
2722 		NULL, NULL, NULL
2723 	},
2724 
2725 	{
2726 		{"wal_writer_flush_after", PGC_SIGHUP, WAL_SETTINGS,
2727 			gettext_noop("Amount of WAL written out by WAL writer that triggers a flush."),
2728 			NULL,
2729 			GUC_UNIT_XBLOCKS
2730 		},
2731 		&WalWriterFlushAfter,
2732 		(1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
2733 		NULL, NULL, NULL
2734 	},
2735 
2736 	{
2737 		{"wal_skip_threshold", PGC_USERSET, WAL_SETTINGS,
2738 			gettext_noop("Size of new file to fsync instead of writing WAL."),
2739 			NULL,
2740 			GUC_UNIT_KB
2741 		},
2742 		&wal_skip_threshold,
2743 		2048, 0, MAX_KILOBYTES,
2744 		NULL, NULL, NULL
2745 	},
2746 
2747 	{
2748 		{"max_wal_senders", PGC_POSTMASTER, REPLICATION_SENDING,
2749 			gettext_noop("Sets the maximum number of simultaneously running WAL sender processes."),
2750 			NULL
2751 		},
2752 		&max_wal_senders,
2753 		10, 0, MAX_BACKENDS,
2754 		check_max_wal_senders, NULL, NULL
2755 	},
2756 
2757 	{
2758 		/* see max_wal_senders */
2759 		{"max_replication_slots", PGC_POSTMASTER, REPLICATION_SENDING,
2760 			gettext_noop("Sets the maximum number of simultaneously defined replication slots."),
2761 			NULL
2762 		},
2763 		&max_replication_slots,
2764 		10, 0, MAX_BACKENDS /* XXX? */ ,
2765 		NULL, NULL, NULL
2766 	},
2767 
2768 	{
2769 		{"max_slot_wal_keep_size", PGC_SIGHUP, REPLICATION_SENDING,
2770 			gettext_noop("Sets the maximum WAL size that can be reserved by replication slots."),
2771 			gettext_noop("Replication slots will be marked as failed, and segments released "
2772 						 "for deletion or recycling, if this much space is occupied by WAL "
2773 						 "on disk."),
2774 			GUC_UNIT_MB
2775 		},
2776 		&max_slot_wal_keep_size_mb,
2777 		-1, -1, MAX_KILOBYTES,
2778 		NULL, NULL, NULL
2779 	},
2780 
2781 	{
2782 		{"wal_sender_timeout", PGC_USERSET, REPLICATION_SENDING,
2783 			gettext_noop("Sets the maximum time to wait for WAL replication."),
2784 			NULL,
2785 			GUC_UNIT_MS
2786 		},
2787 		&wal_sender_timeout,
2788 		60 * 1000, 0, INT_MAX,
2789 		NULL, NULL, NULL
2790 	},
2791 
2792 	{
2793 		{"commit_delay", PGC_SUSET, WAL_SETTINGS,
2794 			gettext_noop("Sets the delay in microseconds between transaction commit and "
2795 						 "flushing WAL to disk."),
2796 			NULL
2797 			/* we have no microseconds designation, so can't supply units here */
2798 		},
2799 		&CommitDelay,
2800 		0, 0, 100000,
2801 		NULL, NULL, NULL
2802 	},
2803 
2804 	{
2805 		{"commit_siblings", PGC_USERSET, WAL_SETTINGS,
2806 			gettext_noop("Sets the minimum concurrent open transactions before performing "
2807 						 "commit_delay."),
2808 			NULL
2809 		},
2810 		&CommitSiblings,
2811 		5, 0, 1000,
2812 		NULL, NULL, NULL
2813 	},
2814 
2815 	{
2816 		{"extra_float_digits", PGC_USERSET, CLIENT_CONN_LOCALE,
2817 			gettext_noop("Sets the number of digits displayed for floating-point values."),
2818 			gettext_noop("This affects real, double precision, and geometric data types. "
2819 						 "A zero or negative parameter value is added to the standard "
2820 						 "number of digits (FLT_DIG or DBL_DIG as appropriate). "
2821 						 "Any value greater than zero selects precise output mode.")
2822 		},
2823 		&extra_float_digits,
2824 		1, -15, 3,
2825 		NULL, NULL, NULL
2826 	},
2827 
2828 	{
2829 		{"log_min_duration_sample", PGC_SUSET, LOGGING_WHEN,
2830 			gettext_noop("Sets the minimum execution time above which "
2831 						 "a sample of statements will be logged."
2832 						 " Sampling is determined by log_statement_sample_rate."),
2833 			gettext_noop("Zero logs a sample of all queries. -1 turns this feature off."),
2834 			GUC_UNIT_MS
2835 		},
2836 		&log_min_duration_sample,
2837 		-1, -1, INT_MAX,
2838 		NULL, NULL, NULL
2839 	},
2840 
2841 	{
2842 		{"log_min_duration_statement", PGC_SUSET, LOGGING_WHEN,
2843 			gettext_noop("Sets the minimum execution time above which "
2844 						 "all statements will be logged."),
2845 			gettext_noop("Zero prints all queries. -1 turns this feature off."),
2846 			GUC_UNIT_MS
2847 		},
2848 		&log_min_duration_statement,
2849 		-1, -1, INT_MAX,
2850 		NULL, NULL, NULL
2851 	},
2852 
2853 	{
2854 		{"log_autovacuum_min_duration", PGC_SIGHUP, LOGGING_WHAT,
2855 			gettext_noop("Sets the minimum execution time above which "
2856 						 "autovacuum actions will be logged."),
2857 			gettext_noop("Zero prints all actions. -1 turns autovacuum logging off."),
2858 			GUC_UNIT_MS
2859 		},
2860 		&Log_autovacuum_min_duration,
2861 		-1, -1, INT_MAX,
2862 		NULL, NULL, NULL
2863 	},
2864 
2865 	{
2866 		{"log_parameter_max_length", PGC_SUSET, LOGGING_WHAT,
2867 			gettext_noop("When logging statements, limit logged parameter values to first N bytes."),
2868 			gettext_noop("-1 to print values in full."),
2869 			GUC_UNIT_BYTE
2870 		},
2871 		&log_parameter_max_length,
2872 		-1, -1, INT_MAX / 2,
2873 		NULL, NULL, NULL
2874 	},
2875 
2876 	{
2877 		{"log_parameter_max_length_on_error", PGC_USERSET, LOGGING_WHAT,
2878 			gettext_noop("When reporting an error, limit logged parameter values to first N bytes."),
2879 			gettext_noop("-1 to print values in full."),
2880 			GUC_UNIT_BYTE
2881 		},
2882 		&log_parameter_max_length_on_error,
2883 		0, -1, INT_MAX / 2,
2884 		NULL, NULL, NULL
2885 	},
2886 
2887 	{
2888 		{"bgwriter_delay", PGC_SIGHUP, RESOURCES_BGWRITER,
2889 			gettext_noop("Background writer sleep time between rounds."),
2890 			NULL,
2891 			GUC_UNIT_MS
2892 		},
2893 		&BgWriterDelay,
2894 		200, 10, 10000,
2895 		NULL, NULL, NULL
2896 	},
2897 
2898 	{
2899 		{"bgwriter_lru_maxpages", PGC_SIGHUP, RESOURCES_BGWRITER,
2900 			gettext_noop("Background writer maximum number of LRU pages to flush per round."),
2901 			NULL
2902 		},
2903 		&bgwriter_lru_maxpages,
2904 		100, 0, INT_MAX / 2,	/* Same upper limit as shared_buffers */
2905 		NULL, NULL, NULL
2906 	},
2907 
2908 	{
2909 		{"bgwriter_flush_after", PGC_SIGHUP, RESOURCES_BGWRITER,
2910 			gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
2911 			NULL,
2912 			GUC_UNIT_BLOCKS
2913 		},
2914 		&bgwriter_flush_after,
2915 		DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
2916 		NULL, NULL, NULL
2917 	},
2918 
2919 	{
2920 		{"effective_io_concurrency",
2921 			PGC_USERSET,
2922 			RESOURCES_ASYNCHRONOUS,
2923 			gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem."),
2924 			NULL,
2925 			GUC_EXPLAIN
2926 		},
2927 		&effective_io_concurrency,
2928 #ifdef USE_PREFETCH
2929 		1,
2930 #else
2931 		0,
2932 #endif
2933 		0, MAX_IO_CONCURRENCY,
2934 		check_effective_io_concurrency, NULL, NULL
2935 	},
2936 
2937 	{
2938 		{"maintenance_io_concurrency",
2939 			PGC_USERSET,
2940 			RESOURCES_ASYNCHRONOUS,
2941 			gettext_noop("A variant of effective_io_concurrency that is used for maintenance work."),
2942 			NULL,
2943 			GUC_EXPLAIN
2944 		},
2945 		&maintenance_io_concurrency,
2946 #ifdef USE_PREFETCH
2947 		10,
2948 #else
2949 		0,
2950 #endif
2951 		0, MAX_IO_CONCURRENCY,
2952 		check_maintenance_io_concurrency, NULL, NULL
2953 	},
2954 
2955 	{
2956 		{"backend_flush_after", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
2957 			gettext_noop("Number of pages after which previously performed writes are flushed to disk."),
2958 			NULL,
2959 			GUC_UNIT_BLOCKS
2960 		},
2961 		&backend_flush_after,
2962 		DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES,
2963 		NULL, NULL, NULL
2964 	},
2965 
2966 	{
2967 		{"max_worker_processes",
2968 			PGC_POSTMASTER,
2969 			RESOURCES_ASYNCHRONOUS,
2970 			gettext_noop("Maximum number of concurrent worker processes."),
2971 			NULL,
2972 		},
2973 		&max_worker_processes,
2974 		8, 0, MAX_BACKENDS,
2975 		check_max_worker_processes, NULL, NULL
2976 	},
2977 
2978 	{
2979 		{"max_logical_replication_workers",
2980 			PGC_POSTMASTER,
2981 			REPLICATION_SUBSCRIBERS,
2982 			gettext_noop("Maximum number of logical replication worker processes."),
2983 			NULL,
2984 		},
2985 		&max_logical_replication_workers,
2986 		4, 0, MAX_BACKENDS,
2987 		NULL, NULL, NULL
2988 	},
2989 
2990 	{
2991 		{"max_sync_workers_per_subscription",
2992 			PGC_SIGHUP,
2993 			REPLICATION_SUBSCRIBERS,
2994 			gettext_noop("Maximum number of table synchronization workers per subscription."),
2995 			NULL,
2996 		},
2997 		&max_sync_workers_per_subscription,
2998 		2, 0, MAX_BACKENDS,
2999 		NULL, NULL, NULL
3000 	},
3001 
3002 	{
3003 		{"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
3004 			gettext_noop("Automatic log file rotation will occur after N minutes."),
3005 			NULL,
3006 			GUC_UNIT_MIN
3007 		},
3008 		&Log_RotationAge,
3009 		HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE,
3010 		NULL, NULL, NULL
3011 	},
3012 
3013 	{
3014 		{"log_rotation_size", PGC_SIGHUP, LOGGING_WHERE,
3015 			gettext_noop("Automatic log file rotation will occur after N kilobytes."),
3016 			NULL,
3017 			GUC_UNIT_KB
3018 		},
3019 		&Log_RotationSize,
3020 		10 * 1024, 0, INT_MAX / 1024,
3021 		NULL, NULL, NULL
3022 	},
3023 
3024 	{
3025 		{"max_function_args", PGC_INTERNAL, PRESET_OPTIONS,
3026 			gettext_noop("Shows the maximum number of function arguments."),
3027 			NULL,
3028 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3029 		},
3030 		&max_function_args,
3031 		FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS,
3032 		NULL, NULL, NULL
3033 	},
3034 
3035 	{
3036 		{"max_index_keys", PGC_INTERNAL, PRESET_OPTIONS,
3037 			gettext_noop("Shows the maximum number of index keys."),
3038 			NULL,
3039 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3040 		},
3041 		&max_index_keys,
3042 		INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS,
3043 		NULL, NULL, NULL
3044 	},
3045 
3046 	{
3047 		{"max_identifier_length", PGC_INTERNAL, PRESET_OPTIONS,
3048 			gettext_noop("Shows the maximum identifier length."),
3049 			NULL,
3050 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3051 		},
3052 		&max_identifier_length,
3053 		NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1,
3054 		NULL, NULL, NULL
3055 	},
3056 
3057 	{
3058 		{"block_size", PGC_INTERNAL, PRESET_OPTIONS,
3059 			gettext_noop("Shows the size of a disk block."),
3060 			NULL,
3061 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3062 		},
3063 		&block_size,
3064 		BLCKSZ, BLCKSZ, BLCKSZ,
3065 		NULL, NULL, NULL
3066 	},
3067 
3068 	{
3069 		{"segment_size", PGC_INTERNAL, PRESET_OPTIONS,
3070 			gettext_noop("Shows the number of pages per disk file."),
3071 			NULL,
3072 			GUC_UNIT_BLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3073 		},
3074 		&segment_size,
3075 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
3076 		NULL, NULL, NULL
3077 	},
3078 
3079 	{
3080 		{"wal_block_size", PGC_INTERNAL, PRESET_OPTIONS,
3081 			gettext_noop("Shows the block size in the write ahead log."),
3082 			NULL,
3083 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3084 		},
3085 		&wal_block_size,
3086 		XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ,
3087 		NULL, NULL, NULL
3088 	},
3089 
3090 	{
3091 		{"wal_retrieve_retry_interval", PGC_SIGHUP, REPLICATION_STANDBY,
3092 			gettext_noop("Sets the time to wait before retrying to retrieve WAL "
3093 						 "after a failed attempt."),
3094 			NULL,
3095 			GUC_UNIT_MS
3096 		},
3097 		&wal_retrieve_retry_interval,
3098 		5000, 1, INT_MAX,
3099 		NULL, NULL, NULL
3100 	},
3101 
3102 	{
3103 		{"wal_segment_size", PGC_INTERNAL, PRESET_OPTIONS,
3104 			gettext_noop("Shows the size of write ahead log segments."),
3105 			NULL,
3106 			GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3107 		},
3108 		&wal_segment_size,
3109 		DEFAULT_XLOG_SEG_SIZE,
3110 		WalSegMinSize,
3111 		WalSegMaxSize,
3112 		NULL, NULL, NULL
3113 	},
3114 
3115 	{
3116 		{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
3117 			gettext_noop("Time to sleep between autovacuum runs."),
3118 			NULL,
3119 			GUC_UNIT_S
3120 		},
3121 		&autovacuum_naptime,
3122 		60, 1, INT_MAX / 1000,
3123 		NULL, NULL, NULL
3124 	},
3125 	{
3126 		{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,
3127 			gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
3128 			NULL
3129 		},
3130 		&autovacuum_vac_thresh,
3131 		50, 0, INT_MAX,
3132 		NULL, NULL, NULL
3133 	},
3134 	{
3135 		{"autovacuum_vacuum_insert_threshold", PGC_SIGHUP, AUTOVACUUM,
3136 			gettext_noop("Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums."),
3137 			NULL
3138 		},
3139 		&autovacuum_vac_ins_thresh,
3140 		1000, -1, INT_MAX,
3141 		NULL, NULL, NULL
3142 	},
3143 	{
3144 		{"autovacuum_analyze_threshold", PGC_SIGHUP, AUTOVACUUM,
3145 			gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze."),
3146 			NULL
3147 		},
3148 		&autovacuum_anl_thresh,
3149 		50, 0, INT_MAX,
3150 		NULL, NULL, NULL
3151 	},
3152 	{
3153 		/* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
3154 		{"autovacuum_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
3155 			gettext_noop("Age at which to autovacuum a table to prevent transaction ID wraparound."),
3156 			NULL
3157 		},
3158 		&autovacuum_freeze_max_age,
3159 		/* see pg_resetwal if you change the upper-limit value */
3160 		200000000, 100000, 2000000000,
3161 		NULL, NULL, NULL
3162 	},
3163 	{
3164 		/* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */
3165 		{"autovacuum_multixact_freeze_max_age", PGC_POSTMASTER, AUTOVACUUM,
3166 			gettext_noop("Multixact age at which to autovacuum a table to prevent multixact wraparound."),
3167 			NULL
3168 		},
3169 		&autovacuum_multixact_freeze_max_age,
3170 		400000000, 10000, 2000000000,
3171 		NULL, NULL, NULL
3172 	},
3173 	{
3174 		/* see max_connections */
3175 		{"autovacuum_max_workers", PGC_POSTMASTER, AUTOVACUUM,
3176 			gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes."),
3177 			NULL
3178 		},
3179 		&autovacuum_max_workers,
3180 		3, 1, MAX_BACKENDS,
3181 		check_autovacuum_max_workers, NULL, NULL
3182 	},
3183 
3184 	{
3185 		{"max_parallel_maintenance_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
3186 			gettext_noop("Sets the maximum number of parallel processes per maintenance operation."),
3187 			NULL
3188 		},
3189 		&max_parallel_maintenance_workers,
3190 		2, 0, 1024,
3191 		NULL, NULL, NULL
3192 	},
3193 
3194 	{
3195 		{"max_parallel_workers_per_gather", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
3196 			gettext_noop("Sets the maximum number of parallel processes per executor node."),
3197 			NULL,
3198 			GUC_EXPLAIN
3199 		},
3200 		&max_parallel_workers_per_gather,
3201 		2, 0, MAX_PARALLEL_WORKER_LIMIT,
3202 		NULL, NULL, NULL
3203 	},
3204 
3205 	{
3206 		{"max_parallel_workers", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
3207 			gettext_noop("Sets the maximum number of parallel workers that can be active at one time."),
3208 			NULL,
3209 			GUC_EXPLAIN
3210 		},
3211 		&max_parallel_workers,
3212 		8, 0, MAX_PARALLEL_WORKER_LIMIT,
3213 		NULL, NULL, NULL
3214 	},
3215 
3216 	{
3217 		{"autovacuum_work_mem", PGC_SIGHUP, RESOURCES_MEM,
3218 			gettext_noop("Sets the maximum memory to be used by each autovacuum worker process."),
3219 			NULL,
3220 			GUC_UNIT_KB
3221 		},
3222 		&autovacuum_work_mem,
3223 		-1, -1, MAX_KILOBYTES,
3224 		check_autovacuum_work_mem, NULL, NULL
3225 	},
3226 
3227 	{
3228 		{"old_snapshot_threshold", PGC_POSTMASTER, RESOURCES_ASYNCHRONOUS,
3229 			gettext_noop("Time before a snapshot is too old to read pages changed after the snapshot was taken."),
3230 			gettext_noop("A value of -1 disables this feature."),
3231 			GUC_UNIT_MIN
3232 		},
3233 		&old_snapshot_threshold,
3234 		-1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60,
3235 		NULL, NULL, NULL
3236 	},
3237 
3238 	{
3239 		{"tcp_keepalives_idle", PGC_USERSET, CLIENT_CONN_OTHER,
3240 			gettext_noop("Time between issuing TCP keepalives."),
3241 			gettext_noop("A value of 0 uses the system default."),
3242 			GUC_UNIT_S
3243 		},
3244 		&tcp_keepalives_idle,
3245 		0, 0, INT_MAX,
3246 		NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle
3247 	},
3248 
3249 	{
3250 		{"tcp_keepalives_interval", PGC_USERSET, CLIENT_CONN_OTHER,
3251 			gettext_noop("Time between TCP keepalive retransmits."),
3252 			gettext_noop("A value of 0 uses the system default."),
3253 			GUC_UNIT_S
3254 		},
3255 		&tcp_keepalives_interval,
3256 		0, 0, INT_MAX,
3257 		NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval
3258 	},
3259 
3260 	{
3261 		{"ssl_renegotiation_limit", PGC_USERSET, CONN_AUTH_SSL,
3262 			gettext_noop("SSL renegotiation is no longer supported; this can only be 0."),
3263 			NULL,
3264 			GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE,
3265 		},
3266 		&ssl_renegotiation_limit,
3267 		0, 0, 0,
3268 		NULL, NULL, NULL
3269 	},
3270 
3271 	{
3272 		{"tcp_keepalives_count", PGC_USERSET, CLIENT_CONN_OTHER,
3273 			gettext_noop("Maximum number of TCP keepalive retransmits."),
3274 			gettext_noop("This controls the number of consecutive keepalive retransmits that can be "
3275 						 "lost before a connection is considered dead. A value of 0 uses the "
3276 						 "system default."),
3277 		},
3278 		&tcp_keepalives_count,
3279 		0, 0, INT_MAX,
3280 		NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count
3281 	},
3282 
3283 	{
3284 		{"gin_fuzzy_search_limit", PGC_USERSET, CLIENT_CONN_OTHER,
3285 			gettext_noop("Sets the maximum allowed result for exact search by GIN."),
3286 			NULL,
3287 			0
3288 		},
3289 		&GinFuzzySearchLimit,
3290 		0, 0, INT_MAX,
3291 		NULL, NULL, NULL
3292 	},
3293 
3294 	{
3295 		{"effective_cache_size", PGC_USERSET, QUERY_TUNING_COST,
3296 			gettext_noop("Sets the planner's assumption about the total size of the data caches."),
3297 			gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. "
3298 						 "This is measured in disk pages, which are normally 8 kB each."),
3299 			GUC_UNIT_BLOCKS | GUC_EXPLAIN,
3300 		},
3301 		&effective_cache_size,
3302 		DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX,
3303 		NULL, NULL, NULL
3304 	},
3305 
3306 	{
3307 		{"min_parallel_table_scan_size", PGC_USERSET, QUERY_TUNING_COST,
3308 			gettext_noop("Sets the minimum amount of table data for a parallel scan."),
3309 			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."),
3310 			GUC_UNIT_BLOCKS | GUC_EXPLAIN,
3311 		},
3312 		&min_parallel_table_scan_size,
3313 		(8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3,
3314 		NULL, NULL, NULL
3315 	},
3316 
3317 	{
3318 		{"min_parallel_index_scan_size", PGC_USERSET, QUERY_TUNING_COST,
3319 			gettext_noop("Sets the minimum amount of index data for a parallel scan."),
3320 			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."),
3321 			GUC_UNIT_BLOCKS | GUC_EXPLAIN,
3322 		},
3323 		&min_parallel_index_scan_size,
3324 		(512 * 1024) / BLCKSZ, 0, INT_MAX / 3,
3325 		NULL, NULL, NULL
3326 	},
3327 
3328 	{
3329 		/* Can't be set in postgresql.conf */
3330 		{"server_version_num", PGC_INTERNAL, PRESET_OPTIONS,
3331 			gettext_noop("Shows the server version as an integer."),
3332 			NULL,
3333 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3334 		},
3335 		&server_version_num,
3336 		PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM,
3337 		NULL, NULL, NULL
3338 	},
3339 
3340 	{
3341 		{"log_temp_files", PGC_SUSET, LOGGING_WHAT,
3342 			gettext_noop("Log the use of temporary files larger than this number of kilobytes."),
3343 			gettext_noop("Zero logs all files. The default is -1 (turning this feature off)."),
3344 			GUC_UNIT_KB
3345 		},
3346 		&log_temp_files,
3347 		-1, -1, INT_MAX,
3348 		NULL, NULL, NULL
3349 	},
3350 
3351 	{
3352 		{"track_activity_query_size", PGC_POSTMASTER, RESOURCES_MEM,
3353 			gettext_noop("Sets the size reserved for pg_stat_activity.query, in bytes."),
3354 			NULL,
3355 			GUC_UNIT_BYTE
3356 		},
3357 		&pgstat_track_activity_query_size,
3358 		1024, 100, 1048576,
3359 		NULL, NULL, NULL
3360 	},
3361 
3362 	{
3363 		{"gin_pending_list_limit", PGC_USERSET, CLIENT_CONN_STATEMENT,
3364 			gettext_noop("Sets the maximum size of the pending list for GIN index."),
3365 			NULL,
3366 			GUC_UNIT_KB
3367 		},
3368 		&gin_pending_list_limit,
3369 		4096, 64, MAX_KILOBYTES,
3370 		NULL, NULL, NULL
3371 	},
3372 
3373 	{
3374 		{"tcp_user_timeout", PGC_USERSET, CLIENT_CONN_OTHER,
3375 			gettext_noop("TCP user timeout."),
3376 			gettext_noop("A value of 0 uses the system default."),
3377 			GUC_UNIT_MS
3378 		},
3379 		&tcp_user_timeout,
3380 		0, 0, INT_MAX,
3381 		NULL, assign_tcp_user_timeout, show_tcp_user_timeout
3382 	},
3383 
3384 	/* End-of-list marker */
3385 	{
3386 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
3387 	}
3388 };
3389 
3390 
3391 static struct config_real ConfigureNamesReal[] =
3392 {
3393 	{
3394 		{"seq_page_cost", PGC_USERSET, QUERY_TUNING_COST,
3395 			gettext_noop("Sets the planner's estimate of the cost of a "
3396 						 "sequentially fetched disk page."),
3397 			NULL,
3398 			GUC_EXPLAIN
3399 		},
3400 		&seq_page_cost,
3401 		DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX,
3402 		NULL, NULL, NULL
3403 	},
3404 	{
3405 		{"random_page_cost", PGC_USERSET, QUERY_TUNING_COST,
3406 			gettext_noop("Sets the planner's estimate of the cost of a "
3407 						 "nonsequentially fetched disk page."),
3408 			NULL,
3409 			GUC_EXPLAIN
3410 		},
3411 		&random_page_cost,
3412 		DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX,
3413 		NULL, NULL, NULL
3414 	},
3415 	{
3416 		{"cpu_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
3417 			gettext_noop("Sets the planner's estimate of the cost of "
3418 						 "processing each tuple (row)."),
3419 			NULL,
3420 			GUC_EXPLAIN
3421 		},
3422 		&cpu_tuple_cost,
3423 		DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX,
3424 		NULL, NULL, NULL
3425 	},
3426 	{
3427 		{"cpu_index_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
3428 			gettext_noop("Sets the planner's estimate of the cost of "
3429 						 "processing each index entry during an index scan."),
3430 			NULL,
3431 			GUC_EXPLAIN
3432 		},
3433 		&cpu_index_tuple_cost,
3434 		DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX,
3435 		NULL, NULL, NULL
3436 	},
3437 	{
3438 		{"cpu_operator_cost", PGC_USERSET, QUERY_TUNING_COST,
3439 			gettext_noop("Sets the planner's estimate of the cost of "
3440 						 "processing each operator or function call."),
3441 			NULL,
3442 			GUC_EXPLAIN
3443 		},
3444 		&cpu_operator_cost,
3445 		DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX,
3446 		NULL, NULL, NULL
3447 	},
3448 	{
3449 		{"parallel_tuple_cost", PGC_USERSET, QUERY_TUNING_COST,
3450 			gettext_noop("Sets the planner's estimate of the cost of "
3451 						 "passing each tuple (row) from worker to master backend."),
3452 			NULL,
3453 			GUC_EXPLAIN
3454 		},
3455 		&parallel_tuple_cost,
3456 		DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX,
3457 		NULL, NULL, NULL
3458 	},
3459 	{
3460 		{"parallel_setup_cost", PGC_USERSET, QUERY_TUNING_COST,
3461 			gettext_noop("Sets the planner's estimate of the cost of "
3462 						 "starting up worker processes for parallel query."),
3463 			NULL,
3464 			GUC_EXPLAIN
3465 		},
3466 		&parallel_setup_cost,
3467 		DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX,
3468 		NULL, NULL, NULL
3469 	},
3470 
3471 	{
3472 		{"jit_above_cost", PGC_USERSET, QUERY_TUNING_COST,
3473 			gettext_noop("Perform JIT compilation if query is more expensive."),
3474 			gettext_noop("-1 disables JIT compilation."),
3475 			GUC_EXPLAIN
3476 		},
3477 		&jit_above_cost,
3478 		100000, -1, DBL_MAX,
3479 		NULL, NULL, NULL
3480 	},
3481 
3482 	{
3483 		{"jit_optimize_above_cost", PGC_USERSET, QUERY_TUNING_COST,
3484 			gettext_noop("Optimize JITed functions if query is more expensive."),
3485 			gettext_noop("-1 disables optimization."),
3486 			GUC_EXPLAIN
3487 		},
3488 		&jit_optimize_above_cost,
3489 		500000, -1, DBL_MAX,
3490 		NULL, NULL, NULL
3491 	},
3492 
3493 	{
3494 		{"jit_inline_above_cost", PGC_USERSET, QUERY_TUNING_COST,
3495 			gettext_noop("Perform JIT inlining if query is more expensive."),
3496 			gettext_noop("-1 disables inlining."),
3497 			GUC_EXPLAIN
3498 		},
3499 		&jit_inline_above_cost,
3500 		500000, -1, DBL_MAX,
3501 		NULL, NULL, NULL
3502 	},
3503 
3504 	{
3505 		{"cursor_tuple_fraction", PGC_USERSET, QUERY_TUNING_OTHER,
3506 			gettext_noop("Sets the planner's estimate of the fraction of "
3507 						 "a cursor's rows that will be retrieved."),
3508 			NULL,
3509 			GUC_EXPLAIN
3510 		},
3511 		&cursor_tuple_fraction,
3512 		DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0,
3513 		NULL, NULL, NULL
3514 	},
3515 
3516 	{
3517 		{"geqo_selection_bias", PGC_USERSET, QUERY_TUNING_GEQO,
3518 			gettext_noop("GEQO: selective pressure within the population."),
3519 			NULL,
3520 			GUC_EXPLAIN
3521 		},
3522 		&Geqo_selection_bias,
3523 		DEFAULT_GEQO_SELECTION_BIAS,
3524 		MIN_GEQO_SELECTION_BIAS, MAX_GEQO_SELECTION_BIAS,
3525 		NULL, NULL, NULL
3526 	},
3527 	{
3528 		{"geqo_seed", PGC_USERSET, QUERY_TUNING_GEQO,
3529 			gettext_noop("GEQO: seed for random path selection."),
3530 			NULL,
3531 			GUC_EXPLAIN
3532 		},
3533 		&Geqo_seed,
3534 		0.0, 0.0, 1.0,
3535 		NULL, NULL, NULL
3536 	},
3537 
3538 	{
3539 		{"hash_mem_multiplier", PGC_USERSET, RESOURCES_MEM,
3540 			gettext_noop("Multiple of work_mem to use for hash tables."),
3541 			NULL,
3542 			GUC_EXPLAIN
3543 		},
3544 		&hash_mem_multiplier,
3545 		1.0, 1.0, 1000.0,
3546 		NULL, NULL, NULL
3547 	},
3548 
3549 	{
3550 		{"bgwriter_lru_multiplier", PGC_SIGHUP, RESOURCES_BGWRITER,
3551 			gettext_noop("Multiple of the average buffer usage to free per round."),
3552 			NULL
3553 		},
3554 		&bgwriter_lru_multiplier,
3555 		2.0, 0.0, 10.0,
3556 		NULL, NULL, NULL
3557 	},
3558 
3559 	{
3560 		{"seed", PGC_USERSET, UNGROUPED,
3561 			gettext_noop("Sets the seed for random-number generation."),
3562 			NULL,
3563 			GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3564 		},
3565 		&phony_random_seed,
3566 		0.0, -1.0, 1.0,
3567 		check_random_seed, assign_random_seed, show_random_seed
3568 	},
3569 
3570 	{
3571 		{"vacuum_cost_delay", PGC_USERSET, RESOURCES_VACUUM_DELAY,
3572 			gettext_noop("Vacuum cost delay in milliseconds."),
3573 			NULL,
3574 			GUC_UNIT_MS
3575 		},
3576 		&VacuumCostDelay,
3577 		0, 0, 100,
3578 		NULL, NULL, NULL
3579 	},
3580 
3581 	{
3582 		{"autovacuum_vacuum_cost_delay", PGC_SIGHUP, AUTOVACUUM,
3583 			gettext_noop("Vacuum cost delay in milliseconds, for autovacuum."),
3584 			NULL,
3585 			GUC_UNIT_MS
3586 		},
3587 		&autovacuum_vac_cost_delay,
3588 		2, -1, 100,
3589 		NULL, NULL, NULL
3590 	},
3591 
3592 	{
3593 		{"autovacuum_vacuum_scale_factor", PGC_SIGHUP, AUTOVACUUM,
3594 			gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples."),
3595 			NULL
3596 		},
3597 		&autovacuum_vac_scale,
3598 		0.2, 0.0, 100.0,
3599 		NULL, NULL, NULL
3600 	},
3601 
3602 	{
3603 		{"autovacuum_vacuum_insert_scale_factor", PGC_SIGHUP, AUTOVACUUM,
3604 			gettext_noop("Number of tuple inserts prior to vacuum as a fraction of reltuples."),
3605 			NULL
3606 		},
3607 		&autovacuum_vac_ins_scale,
3608 		0.2, 0.0, 100.0,
3609 		NULL, NULL, NULL
3610 	},
3611 
3612 	{
3613 		{"autovacuum_analyze_scale_factor", PGC_SIGHUP, AUTOVACUUM,
3614 			gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples."),
3615 			NULL
3616 		},
3617 		&autovacuum_anl_scale,
3618 		0.1, 0.0, 100.0,
3619 		NULL, NULL, NULL
3620 	},
3621 
3622 	{
3623 		{"checkpoint_completion_target", PGC_SIGHUP, WAL_CHECKPOINTS,
3624 			gettext_noop("Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval."),
3625 			NULL
3626 		},
3627 		&CheckPointCompletionTarget,
3628 		0.5, 0.0, 1.0,
3629 		NULL, NULL, NULL
3630 	},
3631 
3632 	{
3633 		{"vacuum_cleanup_index_scale_factor", PGC_USERSET, CLIENT_CONN_STATEMENT,
3634 			gettext_noop("Number of tuple inserts prior to index cleanup as a fraction of reltuples."),
3635 			NULL
3636 		},
3637 		&vacuum_cleanup_index_scale_factor,
3638 		0.1, 0.0, 1e10,
3639 		NULL, NULL, NULL
3640 	},
3641 
3642 	{
3643 		{"log_statement_sample_rate", PGC_SUSET, LOGGING_WHEN,
3644 			gettext_noop("Fraction of statements exceeding log_min_duration_sample to be logged."),
3645 			gettext_noop("Use a value between 0.0 (never log) and 1.0 (always log).")
3646 		},
3647 		&log_statement_sample_rate,
3648 		1.0, 0.0, 1.0,
3649 		NULL, NULL, NULL
3650 	},
3651 
3652 	{
3653 		{"log_transaction_sample_rate", PGC_SUSET, LOGGING_WHEN,
3654 			gettext_noop("Set the fraction of transactions to log for new transactions."),
3655 			gettext_noop("Logs all statements from a fraction of transactions. "
3656 						 "Use a value between 0.0 (never log) and 1.0 (log all "
3657 						 "statements for all transactions).")
3658 		},
3659 		&log_xact_sample_rate,
3660 		0.0, 0.0, 1.0,
3661 		NULL, NULL, NULL
3662 	},
3663 
3664 	/* End-of-list marker */
3665 	{
3666 		{NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL
3667 	}
3668 };
3669 
3670 
3671 static struct config_string ConfigureNamesString[] =
3672 {
3673 	{
3674 		{"archive_command", PGC_SIGHUP, WAL_ARCHIVING,
3675 			gettext_noop("Sets the shell command that will be called to archive a WAL file."),
3676 			NULL
3677 		},
3678 		&XLogArchiveCommand,
3679 		"",
3680 		NULL, NULL, show_archive_command
3681 	},
3682 
3683 	{
3684 		{"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
3685 			gettext_noop("Sets the shell command that will be called to retrieve an archived WAL file."),
3686 			NULL
3687 		},
3688 		&recoveryRestoreCommand,
3689 		"",
3690 		NULL, NULL, NULL
3691 	},
3692 
3693 	{
3694 		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
3695 			gettext_noop("Sets the shell command that will be executed at every restart point."),
3696 			NULL
3697 		},
3698 		&archiveCleanupCommand,
3699 		"",
3700 		NULL, NULL, NULL
3701 	},
3702 
3703 	{
3704 		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
3705 			gettext_noop("Sets the shell command that will be executed once at the end of recovery."),
3706 			NULL
3707 		},
3708 		&recoveryEndCommand,
3709 		"",
3710 		NULL, NULL, NULL
3711 	},
3712 
3713 	{
3714 		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3715 			gettext_noop("Specifies the timeline to recover into."),
3716 			NULL
3717 		},
3718 		&recovery_target_timeline_string,
3719 		"latest",
3720 		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
3721 	},
3722 
3723 	{
3724 		{"recovery_target", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3725 			gettext_noop("Set to \"immediate\" to end recovery as soon as a consistent state is reached."),
3726 			NULL
3727 		},
3728 		&recovery_target_string,
3729 		"",
3730 		check_recovery_target, assign_recovery_target, NULL
3731 	},
3732 	{
3733 		{"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3734 			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
3735 			NULL
3736 		},
3737 		&recovery_target_xid_string,
3738 		"",
3739 		check_recovery_target_xid, assign_recovery_target_xid, NULL
3740 	},
3741 	{
3742 		{"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3743 			gettext_noop("Sets the time stamp up to which recovery will proceed."),
3744 			NULL
3745 		},
3746 		&recovery_target_time_string,
3747 		"",
3748 		check_recovery_target_time, assign_recovery_target_time, NULL
3749 	},
3750 	{
3751 		{"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3752 			gettext_noop("Sets the named restore point up to which recovery will proceed."),
3753 			NULL
3754 		},
3755 		&recovery_target_name_string,
3756 		"",
3757 		check_recovery_target_name, assign_recovery_target_name, NULL
3758 	},
3759 	{
3760 		{"recovery_target_lsn", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
3761 			gettext_noop("Sets the LSN of the write-ahead log location up to which recovery will proceed."),
3762 			NULL
3763 		},
3764 		&recovery_target_lsn_string,
3765 		"",
3766 		check_recovery_target_lsn, assign_recovery_target_lsn, NULL
3767 	},
3768 
3769 	{
3770 		{"promote_trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
3771 			gettext_noop("Specifies a file name whose presence ends recovery in the standby."),
3772 			NULL
3773 		},
3774 		&PromoteTriggerFile,
3775 		"",
3776 		NULL, NULL, NULL
3777 	},
3778 
3779 	{
3780 		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
3781 			gettext_noop("Sets the connection string to be used to connect to the sending server."),
3782 			NULL,
3783 			GUC_SUPERUSER_ONLY
3784 		},
3785 		&PrimaryConnInfo,
3786 		"",
3787 		NULL, NULL, NULL
3788 	},
3789 
3790 	{
3791 		{"primary_slot_name", PGC_SIGHUP, REPLICATION_STANDBY,
3792 			gettext_noop("Sets the name of the replication slot to use on the sending server."),
3793 			NULL
3794 		},
3795 		&PrimarySlotName,
3796 		"",
3797 		check_primary_slot_name, NULL, NULL
3798 	},
3799 
3800 	{
3801 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
3802 			gettext_noop("Sets the client's character set encoding."),
3803 			NULL,
3804 			GUC_IS_NAME | GUC_REPORT
3805 		},
3806 		&client_encoding_string,
3807 		"SQL_ASCII",
3808 		check_client_encoding, assign_client_encoding, NULL
3809 	},
3810 
3811 	{
3812 		{"log_line_prefix", PGC_SIGHUP, LOGGING_WHAT,
3813 			gettext_noop("Controls information prefixed to each log line."),
3814 			gettext_noop("If blank, no prefix is used.")
3815 		},
3816 		&Log_line_prefix,
3817 		"%m [%p] ",
3818 		NULL, NULL, NULL
3819 	},
3820 
3821 	{
3822 		{"log_timezone", PGC_SIGHUP, LOGGING_WHAT,
3823 			gettext_noop("Sets the time zone to use in log messages."),
3824 			NULL
3825 		},
3826 		&log_timezone_string,
3827 		"GMT",
3828 		check_log_timezone, assign_log_timezone, show_log_timezone
3829 	},
3830 
3831 	{
3832 		{"DateStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
3833 			gettext_noop("Sets the display format for date and time values."),
3834 			gettext_noop("Also controls interpretation of ambiguous "
3835 						 "date inputs."),
3836 			GUC_LIST_INPUT | GUC_REPORT
3837 		},
3838 		&datestyle_string,
3839 		"ISO, MDY",
3840 		check_datestyle, assign_datestyle, NULL
3841 	},
3842 
3843 	{
3844 		{"default_table_access_method", PGC_USERSET, CLIENT_CONN_STATEMENT,
3845 			gettext_noop("Sets the default table access method for new tables."),
3846 			NULL,
3847 			GUC_IS_NAME
3848 		},
3849 		&default_table_access_method,
3850 		DEFAULT_TABLE_ACCESS_METHOD,
3851 		check_default_table_access_method, NULL, NULL
3852 	},
3853 
3854 	{
3855 		{"default_tablespace", PGC_USERSET, CLIENT_CONN_STATEMENT,
3856 			gettext_noop("Sets the default tablespace to create tables and indexes in."),
3857 			gettext_noop("An empty string selects the database's default tablespace."),
3858 			GUC_IS_NAME
3859 		},
3860 		&default_tablespace,
3861 		"",
3862 		check_default_tablespace, NULL, NULL
3863 	},
3864 
3865 	{
3866 		{"temp_tablespaces", PGC_USERSET, CLIENT_CONN_STATEMENT,
3867 			gettext_noop("Sets the tablespace(s) to use for temporary tables and sort files."),
3868 			NULL,
3869 			GUC_LIST_INPUT | GUC_LIST_QUOTE
3870 		},
3871 		&temp_tablespaces,
3872 		"",
3873 		check_temp_tablespaces, assign_temp_tablespaces, NULL
3874 	},
3875 
3876 	{
3877 		{"dynamic_library_path", PGC_SUSET, CLIENT_CONN_OTHER,
3878 			gettext_noop("Sets the path for dynamically loadable modules."),
3879 			gettext_noop("If a dynamically loadable module needs to be opened and "
3880 						 "the specified name does not have a directory component (i.e., the "
3881 						 "name does not contain a slash), the system will search this path for "
3882 						 "the specified file."),
3883 			GUC_SUPERUSER_ONLY
3884 		},
3885 		&Dynamic_library_path,
3886 		"$libdir",
3887 		NULL, NULL, NULL
3888 	},
3889 
3890 	{
3891 		{"krb_server_keyfile", PGC_SIGHUP, CONN_AUTH_AUTH,
3892 			gettext_noop("Sets the location of the Kerberos server key file."),
3893 			NULL,
3894 			GUC_SUPERUSER_ONLY
3895 		},
3896 		&pg_krb_server_keyfile,
3897 		PG_KRB_SRVTAB,
3898 		NULL, NULL, NULL
3899 	},
3900 
3901 	{
3902 		{"bonjour_name", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
3903 			gettext_noop("Sets the Bonjour service name."),
3904 			NULL
3905 		},
3906 		&bonjour_name,
3907 		"",
3908 		NULL, NULL, NULL
3909 	},
3910 
3911 	/* See main.c about why defaults for LC_foo are not all alike */
3912 
3913 	{
3914 		{"lc_collate", PGC_INTERNAL, CLIENT_CONN_LOCALE,
3915 			gettext_noop("Shows the collation order locale."),
3916 			NULL,
3917 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3918 		},
3919 		&locale_collate,
3920 		"C",
3921 		NULL, NULL, NULL
3922 	},
3923 
3924 	{
3925 		{"lc_ctype", PGC_INTERNAL, CLIENT_CONN_LOCALE,
3926 			gettext_noop("Shows the character classification and case conversion locale."),
3927 			NULL,
3928 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
3929 		},
3930 		&locale_ctype,
3931 		"C",
3932 		NULL, NULL, NULL
3933 	},
3934 
3935 	{
3936 		{"lc_messages", PGC_SUSET, CLIENT_CONN_LOCALE,
3937 			gettext_noop("Sets the language in which messages are displayed."),
3938 			NULL
3939 		},
3940 		&locale_messages,
3941 		"",
3942 		check_locale_messages, assign_locale_messages, NULL
3943 	},
3944 
3945 	{
3946 		{"lc_monetary", PGC_USERSET, CLIENT_CONN_LOCALE,
3947 			gettext_noop("Sets the locale for formatting monetary amounts."),
3948 			NULL
3949 		},
3950 		&locale_monetary,
3951 		"C",
3952 		check_locale_monetary, assign_locale_monetary, NULL
3953 	},
3954 
3955 	{
3956 		{"lc_numeric", PGC_USERSET, CLIENT_CONN_LOCALE,
3957 			gettext_noop("Sets the locale for formatting numbers."),
3958 			NULL
3959 		},
3960 		&locale_numeric,
3961 		"C",
3962 		check_locale_numeric, assign_locale_numeric, NULL
3963 	},
3964 
3965 	{
3966 		{"lc_time", PGC_USERSET, CLIENT_CONN_LOCALE,
3967 			gettext_noop("Sets the locale for formatting date and time values."),
3968 			NULL
3969 		},
3970 		&locale_time,
3971 		"C",
3972 		check_locale_time, assign_locale_time, NULL
3973 	},
3974 
3975 	{
3976 		{"session_preload_libraries", PGC_SUSET, CLIENT_CONN_PRELOAD,
3977 			gettext_noop("Lists shared libraries to preload into each backend."),
3978 			NULL,
3979 			GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
3980 		},
3981 		&session_preload_libraries_string,
3982 		"",
3983 		NULL, NULL, NULL
3984 	},
3985 
3986 	{
3987 		{"shared_preload_libraries", PGC_POSTMASTER, CLIENT_CONN_PRELOAD,
3988 			gettext_noop("Lists shared libraries to preload into server."),
3989 			NULL,
3990 			GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
3991 		},
3992 		&shared_preload_libraries_string,
3993 		"",
3994 		NULL, NULL, NULL
3995 	},
3996 
3997 	{
3998 		{"local_preload_libraries", PGC_USERSET, CLIENT_CONN_PRELOAD,
3999 			gettext_noop("Lists unprivileged shared libraries to preload into each backend."),
4000 			NULL,
4001 			GUC_LIST_INPUT | GUC_LIST_QUOTE
4002 		},
4003 		&local_preload_libraries_string,
4004 		"",
4005 		NULL, NULL, NULL
4006 	},
4007 
4008 	{
4009 		{"search_path", PGC_USERSET, CLIENT_CONN_STATEMENT,
4010 			gettext_noop("Sets the schema search order for names that are not schema-qualified."),
4011 			NULL,
4012 			GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN
4013 		},
4014 		&namespace_search_path,
4015 		"\"$user\", public",
4016 		check_search_path, assign_search_path, NULL
4017 	},
4018 
4019 	{
4020 		/* Can't be set in postgresql.conf */
4021 		{"server_encoding", PGC_INTERNAL, CLIENT_CONN_LOCALE,
4022 			gettext_noop("Sets the server (database) character set encoding."),
4023 			NULL,
4024 			GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
4025 		},
4026 		&server_encoding_string,
4027 		"SQL_ASCII",
4028 		NULL, NULL, NULL
4029 	},
4030 
4031 	{
4032 		/* Can't be set in postgresql.conf */
4033 		{"server_version", PGC_INTERNAL, PRESET_OPTIONS,
4034 			gettext_noop("Shows the server version."),
4035 			NULL,
4036 			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
4037 		},
4038 		&server_version_string,
4039 		PG_VERSION,
4040 		NULL, NULL, NULL
4041 	},
4042 
4043 	{
4044 		/* Not for general use --- used by SET ROLE */
4045 		{"role", PGC_USERSET, UNGROUPED,
4046 			gettext_noop("Sets the current role."),
4047 			NULL,
4048 			GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST
4049 		},
4050 		&role_string,
4051 		"none",
4052 		check_role, assign_role, show_role
4053 	},
4054 
4055 	{
4056 		/* Not for general use --- used by SET SESSION AUTHORIZATION */
4057 		{"session_authorization", PGC_USERSET, UNGROUPED,
4058 			gettext_noop("Sets the session user name."),
4059 			NULL,
4060 			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
4061 		},
4062 		&session_authorization_string,
4063 		NULL,
4064 		check_session_authorization, assign_session_authorization, NULL
4065 	},
4066 
4067 	{
4068 		{"log_destination", PGC_SIGHUP, LOGGING_WHERE,
4069 			gettext_noop("Sets the destination for server log output."),
4070 			gettext_noop("Valid values are combinations of \"stderr\", "
4071 						 "\"syslog\", \"csvlog\", and \"eventlog\", "
4072 						 "depending on the platform."),
4073 			GUC_LIST_INPUT
4074 		},
4075 		&Log_destination_string,
4076 		"stderr",
4077 		check_log_destination, assign_log_destination, NULL
4078 	},
4079 	{
4080 		{"log_directory", PGC_SIGHUP, LOGGING_WHERE,
4081 			gettext_noop("Sets the destination directory for log files."),
4082 			gettext_noop("Can be specified as relative to the data directory "
4083 						 "or as absolute path."),
4084 			GUC_SUPERUSER_ONLY
4085 		},
4086 		&Log_directory,
4087 		"log",
4088 		check_canonical_path, NULL, NULL
4089 	},
4090 	{
4091 		{"log_filename", PGC_SIGHUP, LOGGING_WHERE,
4092 			gettext_noop("Sets the file name pattern for log files."),
4093 			NULL,
4094 			GUC_SUPERUSER_ONLY
4095 		},
4096 		&Log_filename,
4097 		"postgresql-%Y-%m-%d_%H%M%S.log",
4098 		NULL, NULL, NULL
4099 	},
4100 
4101 	{
4102 		{"syslog_ident", PGC_SIGHUP, LOGGING_WHERE,
4103 			gettext_noop("Sets the program name used to identify PostgreSQL "
4104 						 "messages in syslog."),
4105 			NULL
4106 		},
4107 		&syslog_ident_str,
4108 		"postgres",
4109 		NULL, assign_syslog_ident, NULL
4110 	},
4111 
4112 	{
4113 		{"event_source", PGC_POSTMASTER, LOGGING_WHERE,
4114 			gettext_noop("Sets the application name used to identify "
4115 						 "PostgreSQL messages in the event log."),
4116 			NULL
4117 		},
4118 		&event_source,
4119 		DEFAULT_EVENT_SOURCE,
4120 		NULL, NULL, NULL
4121 	},
4122 
4123 	{
4124 		{"TimeZone", PGC_USERSET, CLIENT_CONN_LOCALE,
4125 			gettext_noop("Sets the time zone for displaying and interpreting time stamps."),
4126 			NULL,
4127 			GUC_REPORT
4128 		},
4129 		&timezone_string,
4130 		"GMT",
4131 		check_timezone, assign_timezone, show_timezone
4132 	},
4133 	{
4134 		{"timezone_abbreviations", PGC_USERSET, CLIENT_CONN_LOCALE,
4135 			gettext_noop("Selects a file of time zone abbreviations."),
4136 			NULL
4137 		},
4138 		&timezone_abbreviations_string,
4139 		NULL,
4140 		check_timezone_abbreviations, assign_timezone_abbreviations, NULL
4141 	},
4142 
4143 	{
4144 		{"unix_socket_group", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
4145 			gettext_noop("Sets the owning group of the Unix-domain socket."),
4146 			gettext_noop("The owning user of the socket is always the user "
4147 						 "that starts the server.")
4148 		},
4149 		&Unix_socket_group,
4150 		"",
4151 		NULL, NULL, NULL
4152 	},
4153 
4154 	{
4155 		{"unix_socket_directories", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
4156 			gettext_noop("Sets the directories where Unix-domain sockets will be created."),
4157 			NULL,
4158 			GUC_SUPERUSER_ONLY
4159 		},
4160 		&Unix_socket_directories,
4161 #ifdef HAVE_UNIX_SOCKETS
4162 		DEFAULT_PGSOCKET_DIR,
4163 #else
4164 		"",
4165 #endif
4166 		NULL, NULL, NULL
4167 	},
4168 
4169 	{
4170 		{"listen_addresses", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
4171 			gettext_noop("Sets the host name or IP address(es) to listen to."),
4172 			NULL,
4173 			GUC_LIST_INPUT
4174 		},
4175 		&ListenAddresses,
4176 		"localhost",
4177 		NULL, NULL, NULL
4178 	},
4179 
4180 	{
4181 		/*
4182 		 * Can't be set by ALTER SYSTEM as it can lead to recursive definition
4183 		 * of data_directory.
4184 		 */
4185 		{"data_directory", PGC_POSTMASTER, FILE_LOCATIONS,
4186 			gettext_noop("Sets the server's data directory."),
4187 			NULL,
4188 			GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE
4189 		},
4190 		&data_directory,
4191 		NULL,
4192 		NULL, NULL, NULL
4193 	},
4194 
4195 	{
4196 		{"config_file", PGC_POSTMASTER, FILE_LOCATIONS,
4197 			gettext_noop("Sets the server's main configuration file."),
4198 			NULL,
4199 			GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY
4200 		},
4201 		&ConfigFileName,
4202 		NULL,
4203 		NULL, NULL, NULL
4204 	},
4205 
4206 	{
4207 		{"hba_file", PGC_POSTMASTER, FILE_LOCATIONS,
4208 			gettext_noop("Sets the server's \"hba\" configuration file."),
4209 			NULL,
4210 			GUC_SUPERUSER_ONLY
4211 		},
4212 		&HbaFileName,
4213 		NULL,
4214 		NULL, NULL, NULL
4215 	},
4216 
4217 	{
4218 		{"ident_file", PGC_POSTMASTER, FILE_LOCATIONS,
4219 			gettext_noop("Sets the server's \"ident\" configuration file."),
4220 			NULL,
4221 			GUC_SUPERUSER_ONLY
4222 		},
4223 		&IdentFileName,
4224 		NULL,
4225 		NULL, NULL, NULL
4226 	},
4227 
4228 	{
4229 		{"external_pid_file", PGC_POSTMASTER, FILE_LOCATIONS,
4230 			gettext_noop("Writes the postmaster PID to the specified file."),
4231 			NULL,
4232 			GUC_SUPERUSER_ONLY
4233 		},
4234 		&external_pid_file,
4235 		NULL,
4236 		check_canonical_path, NULL, NULL
4237 	},
4238 
4239 	{
4240 		{"ssl_library", PGC_INTERNAL, PRESET_OPTIONS,
4241 			gettext_noop("Name of the SSL library."),
4242 			NULL,
4243 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
4244 		},
4245 		&ssl_library,
4246 #ifdef USE_SSL
4247 		"OpenSSL",
4248 #else
4249 		"",
4250 #endif
4251 		NULL, NULL, NULL
4252 	},
4253 
4254 	{
4255 		{"ssl_cert_file", PGC_SIGHUP, CONN_AUTH_SSL,
4256 			gettext_noop("Location of the SSL server certificate file."),
4257 			NULL
4258 		},
4259 		&ssl_cert_file,
4260 		"server.crt",
4261 		NULL, NULL, NULL
4262 	},
4263 
4264 	{
4265 		{"ssl_key_file", PGC_SIGHUP, CONN_AUTH_SSL,
4266 			gettext_noop("Location of the SSL server private key file."),
4267 			NULL
4268 		},
4269 		&ssl_key_file,
4270 		"server.key",
4271 		NULL, NULL, NULL
4272 	},
4273 
4274 	{
4275 		{"ssl_ca_file", PGC_SIGHUP, CONN_AUTH_SSL,
4276 			gettext_noop("Location of the SSL certificate authority file."),
4277 			NULL
4278 		},
4279 		&ssl_ca_file,
4280 		"",
4281 		NULL, NULL, NULL
4282 	},
4283 
4284 	{
4285 		{"ssl_crl_file", PGC_SIGHUP, CONN_AUTH_SSL,
4286 			gettext_noop("Location of the SSL certificate revocation list file."),
4287 			NULL
4288 		},
4289 		&ssl_crl_file,
4290 		"",
4291 		NULL, NULL, NULL
4292 	},
4293 
4294 	{
4295 		{"stats_temp_directory", PGC_SIGHUP, STATS_COLLECTOR,
4296 			gettext_noop("Writes temporary statistics files to the specified directory."),
4297 			NULL,
4298 			GUC_SUPERUSER_ONLY
4299 		},
4300 		&pgstat_temp_directory,
4301 		PG_STAT_TMP_DIR,
4302 		check_canonical_path, assign_pgstat_temp_directory, NULL
4303 	},
4304 
4305 	{
4306 		{"synchronous_standby_names", PGC_SIGHUP, REPLICATION_MASTER,
4307 			gettext_noop("Number of synchronous standbys and list of names of potential synchronous ones."),
4308 			NULL,
4309 			GUC_LIST_INPUT
4310 		},
4311 		&SyncRepStandbyNames,
4312 		"",
4313 		check_synchronous_standby_names, assign_synchronous_standby_names, NULL
4314 	},
4315 
4316 	{
4317 		{"default_text_search_config", PGC_USERSET, CLIENT_CONN_LOCALE,
4318 			gettext_noop("Sets default text search configuration."),
4319 			NULL
4320 		},
4321 		&TSCurrentConfig,
4322 		"pg_catalog.simple",
4323 		check_TSCurrentConfig, assign_TSCurrentConfig, NULL
4324 	},
4325 
4326 	{
4327 		{"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SSL,
4328 			gettext_noop("Sets the list of allowed SSL ciphers."),
4329 			NULL,
4330 			GUC_SUPERUSER_ONLY
4331 		},
4332 		&SSLCipherSuites,
4333 #ifdef USE_OPENSSL
4334 		"HIGH:MEDIUM:+3DES:!aNULL",
4335 #else
4336 		"none",
4337 #endif
4338 		NULL, NULL, NULL
4339 	},
4340 
4341 	{
4342 		{"ssl_ecdh_curve", PGC_SIGHUP, CONN_AUTH_SSL,
4343 			gettext_noop("Sets the curve to use for ECDH."),
4344 			NULL,
4345 			GUC_SUPERUSER_ONLY
4346 		},
4347 		&SSLECDHCurve,
4348 #ifdef USE_SSL
4349 		"prime256v1",
4350 #else
4351 		"none",
4352 #endif
4353 		NULL, NULL, NULL
4354 	},
4355 
4356 	{
4357 		{"ssl_dh_params_file", PGC_SIGHUP, CONN_AUTH_SSL,
4358 			gettext_noop("Location of the SSL DH parameters file."),
4359 			NULL,
4360 			GUC_SUPERUSER_ONLY
4361 		},
4362 		&ssl_dh_params_file,
4363 		"",
4364 		NULL, NULL, NULL
4365 	},
4366 
4367 	{
4368 		{"ssl_passphrase_command", PGC_SIGHUP, CONN_AUTH_SSL,
4369 			gettext_noop("Command to obtain passphrases for SSL."),
4370 			NULL,
4371 			GUC_SUPERUSER_ONLY
4372 		},
4373 		&ssl_passphrase_command,
4374 		"",
4375 		NULL, NULL, NULL
4376 	},
4377 
4378 	{
4379 		{"application_name", PGC_USERSET, LOGGING_WHAT,
4380 			gettext_noop("Sets the application name to be reported in statistics and logs."),
4381 			NULL,
4382 			GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE
4383 		},
4384 		&application_name,
4385 		"",
4386 		check_application_name, assign_application_name, NULL
4387 	},
4388 
4389 	{
4390 		{"cluster_name", PGC_POSTMASTER, PROCESS_TITLE,
4391 			gettext_noop("Sets the name of the cluster, which is included in the process title."),
4392 			NULL,
4393 			GUC_IS_NAME
4394 		},
4395 		&cluster_name,
4396 		"",
4397 		check_cluster_name, NULL, NULL
4398 	},
4399 
4400 	{
4401 		{"wal_consistency_checking", PGC_SUSET, DEVELOPER_OPTIONS,
4402 			gettext_noop("Sets the WAL resource managers for which WAL consistency checks are done."),
4403 			gettext_noop("Full-page images will be logged for all data blocks and cross-checked against the results of WAL replay."),
4404 			GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE
4405 		},
4406 		&wal_consistency_checking_string,
4407 		"",
4408 		check_wal_consistency_checking, assign_wal_consistency_checking, NULL
4409 	},
4410 
4411 	{
4412 		{"jit_provider", PGC_POSTMASTER, CLIENT_CONN_PRELOAD,
4413 			gettext_noop("JIT provider to use."),
4414 			NULL,
4415 			GUC_SUPERUSER_ONLY
4416 		},
4417 		&jit_provider,
4418 		"llvmjit",
4419 		NULL, NULL, NULL
4420 	},
4421 
4422 	{
4423 		{"backtrace_functions", PGC_SUSET, DEVELOPER_OPTIONS,
4424 			gettext_noop("Log backtrace for errors in these functions."),
4425 			NULL,
4426 			GUC_NOT_IN_SAMPLE
4427 		},
4428 		&backtrace_functions,
4429 		"",
4430 		check_backtrace_functions, assign_backtrace_functions, NULL
4431 	},
4432 
4433 	/* End-of-list marker */
4434 	{
4435 		{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL
4436 	}
4437 };
4438 
4439 
4440 static struct config_enum ConfigureNamesEnum[] =
4441 {
4442 	{
4443 		{"backslash_quote", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
4444 			gettext_noop("Sets whether \"\\'\" is allowed in string literals."),
4445 			NULL
4446 		},
4447 		&backslash_quote,
4448 		BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options,
4449 		NULL, NULL, NULL
4450 	},
4451 
4452 	{
4453 		{"bytea_output", PGC_USERSET, CLIENT_CONN_STATEMENT,
4454 			gettext_noop("Sets the output format for bytea."),
4455 			NULL
4456 		},
4457 		&bytea_output,
4458 		BYTEA_OUTPUT_HEX, bytea_output_options,
4459 		NULL, NULL, NULL
4460 	},
4461 
4462 	{
4463 		{"client_min_messages", PGC_USERSET, CLIENT_CONN_STATEMENT,
4464 			gettext_noop("Sets the message levels that are sent to the client."),
4465 			gettext_noop("Each level includes all the levels that follow it. The later"
4466 						 " the level, the fewer messages are sent.")
4467 		},
4468 		&client_min_messages,
4469 		NOTICE, client_message_level_options,
4470 		NULL, NULL, NULL
4471 	},
4472 
4473 	{
4474 		{"constraint_exclusion", PGC_USERSET, QUERY_TUNING_OTHER,
4475 			gettext_noop("Enables the planner to use constraints to optimize queries."),
4476 			gettext_noop("Table scans will be skipped if their constraints"
4477 						 " guarantee that no rows match the query."),
4478 			GUC_EXPLAIN
4479 		},
4480 		&constraint_exclusion,
4481 		CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options,
4482 		NULL, NULL, NULL
4483 	},
4484 
4485 	{
4486 		{"default_transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
4487 			gettext_noop("Sets the transaction isolation level of each new transaction."),
4488 			NULL
4489 		},
4490 		&DefaultXactIsoLevel,
4491 		XACT_READ_COMMITTED, isolation_level_options,
4492 		NULL, NULL, NULL
4493 	},
4494 
4495 	{
4496 		{"transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
4497 			gettext_noop("Sets the current transaction's isolation level."),
4498 			NULL,
4499 			GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
4500 		},
4501 		&XactIsoLevel,
4502 		XACT_READ_COMMITTED, isolation_level_options,
4503 		check_XactIsoLevel, NULL, NULL
4504 	},
4505 
4506 	{
4507 		{"IntervalStyle", PGC_USERSET, CLIENT_CONN_LOCALE,
4508 			gettext_noop("Sets the display format for interval values."),
4509 			NULL,
4510 			GUC_REPORT
4511 		},
4512 		&IntervalStyle,
4513 		INTSTYLE_POSTGRES, intervalstyle_options,
4514 		NULL, NULL, NULL
4515 	},
4516 
4517 	{
4518 		{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
4519 			gettext_noop("Sets the verbosity of logged messages."),
4520 			NULL
4521 		},
4522 		&Log_error_verbosity,
4523 		PGERROR_DEFAULT, log_error_verbosity_options,
4524 		NULL, NULL, NULL
4525 	},
4526 
4527 	{
4528 		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
4529 			gettext_noop("Sets the message levels that are logged."),
4530 			gettext_noop("Each level includes all the levels that follow it. The later"
4531 						 " the level, the fewer messages are sent.")
4532 		},
4533 		&log_min_messages,
4534 		WARNING, server_message_level_options,
4535 		NULL, NULL, NULL
4536 	},
4537 
4538 	{
4539 		{"log_min_error_statement", PGC_SUSET, LOGGING_WHEN,
4540 			gettext_noop("Causes all statements generating error at or above this level to be logged."),
4541 			gettext_noop("Each level includes all the levels that follow it. The later"
4542 						 " the level, the fewer messages are sent.")
4543 		},
4544 		&log_min_error_statement,
4545 		ERROR, server_message_level_options,
4546 		NULL, NULL, NULL
4547 	},
4548 
4549 	{
4550 		{"log_statement", PGC_SUSET, LOGGING_WHAT,
4551 			gettext_noop("Sets the type of statements logged."),
4552 			NULL
4553 		},
4554 		&log_statement,
4555 		LOGSTMT_NONE, log_statement_options,
4556 		NULL, NULL, NULL
4557 	},
4558 
4559 	{
4560 		{"syslog_facility", PGC_SIGHUP, LOGGING_WHERE,
4561 			gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled."),
4562 			NULL
4563 		},
4564 		&syslog_facility,
4565 #ifdef HAVE_SYSLOG
4566 		LOG_LOCAL0,
4567 #else
4568 		0,
4569 #endif
4570 		syslog_facility_options,
4571 		NULL, assign_syslog_facility, NULL
4572 	},
4573 
4574 	{
4575 		{"session_replication_role", PGC_SUSET, CLIENT_CONN_STATEMENT,
4576 			gettext_noop("Sets the session's behavior for triggers and rewrite rules."),
4577 			NULL
4578 		},
4579 		&SessionReplicationRole,
4580 		SESSION_REPLICATION_ROLE_ORIGIN, session_replication_role_options,
4581 		NULL, assign_session_replication_role, NULL
4582 	},
4583 
4584 	{
4585 		{"synchronous_commit", PGC_USERSET, WAL_SETTINGS,
4586 			gettext_noop("Sets the current transaction's synchronization level."),
4587 			NULL
4588 		},
4589 		&synchronous_commit,
4590 		SYNCHRONOUS_COMMIT_ON, synchronous_commit_options,
4591 		NULL, assign_synchronous_commit, NULL
4592 	},
4593 
4594 	{
4595 		{"archive_mode", PGC_POSTMASTER, WAL_ARCHIVING,
4596 			gettext_noop("Allows archiving of WAL files using archive_command."),
4597 			NULL
4598 		},
4599 		&XLogArchiveMode,
4600 		ARCHIVE_MODE_OFF, archive_mode_options,
4601 		NULL, NULL, NULL
4602 	},
4603 
4604 	{
4605 		{"recovery_target_action", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
4606 			gettext_noop("Sets the action to perform upon reaching the recovery target."),
4607 			NULL
4608 		},
4609 		&recoveryTargetAction,
4610 		RECOVERY_TARGET_ACTION_PAUSE, recovery_target_action_options,
4611 		NULL, NULL, NULL
4612 	},
4613 
4614 	{
4615 		{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
4616 			gettext_noop("Enables logging of recovery-related debugging information."),
4617 			gettext_noop("Each level includes all the levels that follow it. The later"
4618 						 " the level, the fewer messages are sent.")
4619 		},
4620 		&trace_recovery_messages,
4621 
4622 		/*
4623 		 * client_message_level_options allows too many values, really, but
4624 		 * it's not worth having a separate options array for this.
4625 		 */
4626 		LOG, client_message_level_options,
4627 		NULL, NULL, NULL
4628 	},
4629 
4630 	{
4631 		{"track_functions", PGC_SUSET, STATS_COLLECTOR,
4632 			gettext_noop("Collects function-level statistics on database activity."),
4633 			NULL
4634 		},
4635 		&pgstat_track_functions,
4636 		TRACK_FUNC_OFF, track_function_options,
4637 		NULL, NULL, NULL
4638 	},
4639 
4640 	{
4641 		{"wal_level", PGC_POSTMASTER, WAL_SETTINGS,
4642 			gettext_noop("Set the level of information written to the WAL."),
4643 			NULL
4644 		},
4645 		&wal_level,
4646 		WAL_LEVEL_REPLICA, wal_level_options,
4647 		NULL, NULL, NULL
4648 	},
4649 
4650 	{
4651 		{"dynamic_shared_memory_type", PGC_POSTMASTER, RESOURCES_MEM,
4652 			gettext_noop("Selects the dynamic shared memory implementation used."),
4653 			NULL
4654 		},
4655 		&dynamic_shared_memory_type,
4656 		DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE, dynamic_shared_memory_options,
4657 		NULL, NULL, NULL
4658 	},
4659 
4660 	{
4661 		{"shared_memory_type", PGC_POSTMASTER, RESOURCES_MEM,
4662 			gettext_noop("Selects the shared memory implementation used for the main shared memory region."),
4663 			NULL
4664 		},
4665 		&shared_memory_type,
4666 		DEFAULT_SHARED_MEMORY_TYPE, shared_memory_options,
4667 		NULL, NULL, NULL
4668 	},
4669 
4670 	{
4671 		{"wal_sync_method", PGC_SIGHUP, WAL_SETTINGS,
4672 			gettext_noop("Selects the method used for forcing WAL updates to disk."),
4673 			NULL
4674 		},
4675 		&sync_method,
4676 		DEFAULT_SYNC_METHOD, sync_method_options,
4677 		NULL, assign_xlog_sync_method, NULL
4678 	},
4679 
4680 	{
4681 		{"xmlbinary", PGC_USERSET, CLIENT_CONN_STATEMENT,
4682 			gettext_noop("Sets how binary values are to be encoded in XML."),
4683 			NULL
4684 		},
4685 		&xmlbinary,
4686 		XMLBINARY_BASE64, xmlbinary_options,
4687 		NULL, NULL, NULL
4688 	},
4689 
4690 	{
4691 		{"xmloption", PGC_USERSET, CLIENT_CONN_STATEMENT,
4692 			gettext_noop("Sets whether XML data in implicit parsing and serialization "
4693 						 "operations is to be considered as documents or content fragments."),
4694 			NULL
4695 		},
4696 		&xmloption,
4697 		XMLOPTION_CONTENT, xmloption_options,
4698 		NULL, NULL, NULL
4699 	},
4700 
4701 	{
4702 		{"huge_pages", PGC_POSTMASTER, RESOURCES_MEM,
4703 			gettext_noop("Use of huge pages on Linux or Windows."),
4704 			NULL
4705 		},
4706 		&huge_pages,
4707 		HUGE_PAGES_TRY, huge_pages_options,
4708 		NULL, NULL, NULL
4709 	},
4710 
4711 	{
4712 		{"force_parallel_mode", PGC_USERSET, QUERY_TUNING_OTHER,
4713 			gettext_noop("Forces use of parallel query facilities."),
4714 			gettext_noop("If possible, run query using a parallel worker and with parallel restrictions."),
4715 			GUC_EXPLAIN
4716 		},
4717 		&force_parallel_mode,
4718 		FORCE_PARALLEL_OFF, force_parallel_mode_options,
4719 		NULL, NULL, NULL
4720 	},
4721 
4722 	{
4723 		{"password_encryption", PGC_USERSET, CONN_AUTH_AUTH,
4724 			gettext_noop("Chooses the algorithm for encrypting passwords."),
4725 			NULL
4726 		},
4727 		&Password_encryption,
4728 		PASSWORD_TYPE_MD5, password_encryption_options,
4729 		NULL, NULL, NULL
4730 	},
4731 
4732 	{
4733 		{"plan_cache_mode", PGC_USERSET, QUERY_TUNING_OTHER,
4734 			gettext_noop("Controls the planner's selection of custom or generic plan."),
4735 			gettext_noop("Prepared statements can have custom and generic plans, and the planner "
4736 						 "will attempt to choose which is better.  This can be set to override "
4737 						 "the default behavior."),
4738 			GUC_EXPLAIN
4739 		},
4740 		&plan_cache_mode,
4741 		PLAN_CACHE_MODE_AUTO, plan_cache_mode_options,
4742 		NULL, NULL, NULL
4743 	},
4744 
4745 	{
4746 		{"ssl_min_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
4747 			gettext_noop("Sets the minimum SSL/TLS protocol version to use."),
4748 			NULL,
4749 			GUC_SUPERUSER_ONLY
4750 		},
4751 		&ssl_min_protocol_version,
4752 		PG_TLS1_2_VERSION,
4753 		ssl_protocol_versions_info + 1, /* don't allow PG_TLS_ANY */
4754 		NULL, NULL, NULL
4755 	},
4756 
4757 	{
4758 		{"ssl_max_protocol_version", PGC_SIGHUP, CONN_AUTH_SSL,
4759 			gettext_noop("Sets the maximum SSL/TLS protocol version to use."),
4760 			NULL,
4761 			GUC_SUPERUSER_ONLY
4762 		},
4763 		&ssl_max_protocol_version,
4764 		PG_TLS_ANY,
4765 		ssl_protocol_versions_info,
4766 		NULL, NULL, NULL
4767 	},
4768 
4769 	/* End-of-list marker */
4770 	{
4771 		{NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL
4772 	}
4773 };
4774 
4775 /******** end of options list ********/
4776 
4777 
4778 /*
4779  * To allow continued support of obsolete names for GUC variables, we apply
4780  * the following mappings to any unrecognized name.  Note that an old name
4781  * should be mapped to a new one only if the new variable has very similar
4782  * semantics to the old.
4783  */
4784 static const char *const map_old_guc_names[] = {
4785 	"sort_mem", "work_mem",
4786 	"vacuum_mem", "maintenance_work_mem",
4787 	NULL
4788 };
4789 
4790 
4791 /*
4792  * Actual lookup of variables is done through this single, sorted array.
4793  */
4794 static struct config_generic **guc_variables;
4795 
4796 /* Current number of variables contained in the vector */
4797 static int	num_guc_variables;
4798 
4799 /* Vector capacity */
4800 static int	size_guc_variables;
4801 
4802 
4803 static bool guc_dirty;			/* true if need to do commit/abort work */
4804 
4805 static bool reporting_enabled;	/* true to enable GUC_REPORT */
4806 
4807 static int	GUCNestLevel = 0;	/* 1 when in main transaction */
4808 
4809 
4810 static int	guc_var_compare(const void *a, const void *b);
4811 static int	guc_name_compare(const char *namea, const char *nameb);
4812 static void InitializeGUCOptionsFromEnvironment(void);
4813 static void InitializeOneGUCOption(struct config_generic *gconf);
4814 static void push_old_value(struct config_generic *gconf, GucAction action);
4815 static void ReportGUCOption(struct config_generic *record);
4816 static void reapply_stacked_values(struct config_generic *variable,
4817 								   struct config_string *pHolder,
4818 								   GucStack *stack,
4819 								   const char *curvalue,
4820 								   GucContext curscontext, GucSource cursource);
4821 static void ShowGUCConfigOption(const char *name, DestReceiver *dest);
4822 static void ShowAllGUCConfig(DestReceiver *dest);
4823 static char *_ShowOption(struct config_generic *record, bool use_units);
4824 static bool validate_option_array_item(const char *name, const char *value,
4825 									   bool skipIfNoPermissions);
4826 static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p);
4827 static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
4828 									  const char *name, const char *value);
4829 
4830 
4831 /*
4832  * Some infrastructure for checking malloc/strdup/realloc calls
4833  */
4834 static void *
guc_malloc(int elevel,size_t size)4835 guc_malloc(int elevel, size_t size)
4836 {
4837 	void	   *data;
4838 
4839 	/* Avoid unportable behavior of malloc(0) */
4840 	if (size == 0)
4841 		size = 1;
4842 	data = malloc(size);
4843 	if (data == NULL)
4844 		ereport(elevel,
4845 				(errcode(ERRCODE_OUT_OF_MEMORY),
4846 				 errmsg("out of memory")));
4847 	return data;
4848 }
4849 
4850 static void *
guc_realloc(int elevel,void * old,size_t size)4851 guc_realloc(int elevel, void *old, size_t size)
4852 {
4853 	void	   *data;
4854 
4855 	/* Avoid unportable behavior of realloc(NULL, 0) */
4856 	if (old == NULL && size == 0)
4857 		size = 1;
4858 	data = realloc(old, size);
4859 	if (data == NULL)
4860 		ereport(elevel,
4861 				(errcode(ERRCODE_OUT_OF_MEMORY),
4862 				 errmsg("out of memory")));
4863 	return data;
4864 }
4865 
4866 static char *
guc_strdup(int elevel,const char * src)4867 guc_strdup(int elevel, const char *src)
4868 {
4869 	char	   *data;
4870 
4871 	data = strdup(src);
4872 	if (data == NULL)
4873 		ereport(elevel,
4874 				(errcode(ERRCODE_OUT_OF_MEMORY),
4875 				 errmsg("out of memory")));
4876 	return data;
4877 }
4878 
4879 
4880 /*
4881  * Detect whether strval is referenced anywhere in a GUC string item
4882  */
4883 static bool
string_field_used(struct config_string * conf,char * strval)4884 string_field_used(struct config_string *conf, char *strval)
4885 {
4886 	GucStack   *stack;
4887 
4888 	if (strval == *(conf->variable) ||
4889 		strval == conf->reset_val ||
4890 		strval == conf->boot_val)
4891 		return true;
4892 	for (stack = conf->gen.stack; stack; stack = stack->prev)
4893 	{
4894 		if (strval == stack->prior.val.stringval ||
4895 			strval == stack->masked.val.stringval)
4896 			return true;
4897 	}
4898 	return false;
4899 }
4900 
4901 /*
4902  * Support for assigning to a field of a string GUC item.  Free the prior
4903  * value if it's not referenced anywhere else in the item (including stacked
4904  * states).
4905  */
4906 static void
set_string_field(struct config_string * conf,char ** field,char * newval)4907 set_string_field(struct config_string *conf, char **field, char *newval)
4908 {
4909 	char	   *oldval = *field;
4910 
4911 	/* Do the assignment */
4912 	*field = newval;
4913 
4914 	/* Free old value if it's not NULL and isn't referenced anymore */
4915 	if (oldval && !string_field_used(conf, oldval))
4916 		free(oldval);
4917 }
4918 
4919 /*
4920  * Detect whether an "extra" struct is referenced anywhere in a GUC item
4921  */
4922 static bool
extra_field_used(struct config_generic * gconf,void * extra)4923 extra_field_used(struct config_generic *gconf, void *extra)
4924 {
4925 	GucStack   *stack;
4926 
4927 	if (extra == gconf->extra)
4928 		return true;
4929 	switch (gconf->vartype)
4930 	{
4931 		case PGC_BOOL:
4932 			if (extra == ((struct config_bool *) gconf)->reset_extra)
4933 				return true;
4934 			break;
4935 		case PGC_INT:
4936 			if (extra == ((struct config_int *) gconf)->reset_extra)
4937 				return true;
4938 			break;
4939 		case PGC_REAL:
4940 			if (extra == ((struct config_real *) gconf)->reset_extra)
4941 				return true;
4942 			break;
4943 		case PGC_STRING:
4944 			if (extra == ((struct config_string *) gconf)->reset_extra)
4945 				return true;
4946 			break;
4947 		case PGC_ENUM:
4948 			if (extra == ((struct config_enum *) gconf)->reset_extra)
4949 				return true;
4950 			break;
4951 	}
4952 	for (stack = gconf->stack; stack; stack = stack->prev)
4953 	{
4954 		if (extra == stack->prior.extra ||
4955 			extra == stack->masked.extra)
4956 			return true;
4957 	}
4958 
4959 	return false;
4960 }
4961 
4962 /*
4963  * Support for assigning to an "extra" field of a GUC item.  Free the prior
4964  * value if it's not referenced anywhere else in the item (including stacked
4965  * states).
4966  */
4967 static void
set_extra_field(struct config_generic * gconf,void ** field,void * newval)4968 set_extra_field(struct config_generic *gconf, void **field, void *newval)
4969 {
4970 	void	   *oldval = *field;
4971 
4972 	/* Do the assignment */
4973 	*field = newval;
4974 
4975 	/* Free old value if it's not NULL and isn't referenced anymore */
4976 	if (oldval && !extra_field_used(gconf, oldval))
4977 		free(oldval);
4978 }
4979 
4980 /*
4981  * Support for copying a variable's active value into a stack entry.
4982  * The "extra" field associated with the active value is copied, too.
4983  *
4984  * NB: be sure stringval and extra fields of a new stack entry are
4985  * initialized to NULL before this is used, else we'll try to free() them.
4986  */
4987 static void
set_stack_value(struct config_generic * gconf,config_var_value * val)4988 set_stack_value(struct config_generic *gconf, config_var_value *val)
4989 {
4990 	switch (gconf->vartype)
4991 	{
4992 		case PGC_BOOL:
4993 			val->val.boolval =
4994 				*((struct config_bool *) gconf)->variable;
4995 			break;
4996 		case PGC_INT:
4997 			val->val.intval =
4998 				*((struct config_int *) gconf)->variable;
4999 			break;
5000 		case PGC_REAL:
5001 			val->val.realval =
5002 				*((struct config_real *) gconf)->variable;
5003 			break;
5004 		case PGC_STRING:
5005 			set_string_field((struct config_string *) gconf,
5006 							 &(val->val.stringval),
5007 							 *((struct config_string *) gconf)->variable);
5008 			break;
5009 		case PGC_ENUM:
5010 			val->val.enumval =
5011 				*((struct config_enum *) gconf)->variable;
5012 			break;
5013 	}
5014 	set_extra_field(gconf, &(val->extra), gconf->extra);
5015 }
5016 
5017 /*
5018  * Support for discarding a no-longer-needed value in a stack entry.
5019  * The "extra" field associated with the stack entry is cleared, too.
5020  */
5021 static void
discard_stack_value(struct config_generic * gconf,config_var_value * val)5022 discard_stack_value(struct config_generic *gconf, config_var_value *val)
5023 {
5024 	switch (gconf->vartype)
5025 	{
5026 		case PGC_BOOL:
5027 		case PGC_INT:
5028 		case PGC_REAL:
5029 		case PGC_ENUM:
5030 			/* no need to do anything */
5031 			break;
5032 		case PGC_STRING:
5033 			set_string_field((struct config_string *) gconf,
5034 							 &(val->val.stringval),
5035 							 NULL);
5036 			break;
5037 	}
5038 	set_extra_field(gconf, &(val->extra), NULL);
5039 }
5040 
5041 
5042 /*
5043  * Fetch the sorted array pointer (exported for help_config.c's use ONLY)
5044  */
5045 struct config_generic **
get_guc_variables(void)5046 get_guc_variables(void)
5047 {
5048 	return guc_variables;
5049 }
5050 
5051 
5052 /*
5053  * Build the sorted array.  This is split out so that it could be
5054  * re-executed after startup (e.g., we could allow loadable modules to
5055  * add vars, and then we'd need to re-sort).
5056  */
5057 void
build_guc_variables(void)5058 build_guc_variables(void)
5059 {
5060 	int			size_vars;
5061 	int			num_vars = 0;
5062 	struct config_generic **guc_vars;
5063 	int			i;
5064 
5065 	for (i = 0; ConfigureNamesBool[i].gen.name; i++)
5066 	{
5067 		struct config_bool *conf = &ConfigureNamesBool[i];
5068 
5069 		/* Rather than requiring vartype to be filled in by hand, do this: */
5070 		conf->gen.vartype = PGC_BOOL;
5071 		num_vars++;
5072 	}
5073 
5074 	for (i = 0; ConfigureNamesInt[i].gen.name; i++)
5075 	{
5076 		struct config_int *conf = &ConfigureNamesInt[i];
5077 
5078 		conf->gen.vartype = PGC_INT;
5079 		num_vars++;
5080 	}
5081 
5082 	for (i = 0; ConfigureNamesReal[i].gen.name; i++)
5083 	{
5084 		struct config_real *conf = &ConfigureNamesReal[i];
5085 
5086 		conf->gen.vartype = PGC_REAL;
5087 		num_vars++;
5088 	}
5089 
5090 	for (i = 0; ConfigureNamesString[i].gen.name; i++)
5091 	{
5092 		struct config_string *conf = &ConfigureNamesString[i];
5093 
5094 		conf->gen.vartype = PGC_STRING;
5095 		num_vars++;
5096 	}
5097 
5098 	for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
5099 	{
5100 		struct config_enum *conf = &ConfigureNamesEnum[i];
5101 
5102 		conf->gen.vartype = PGC_ENUM;
5103 		num_vars++;
5104 	}
5105 
5106 	/*
5107 	 * Create table with 20% slack
5108 	 */
5109 	size_vars = num_vars + num_vars / 4;
5110 
5111 	guc_vars = (struct config_generic **)
5112 		guc_malloc(FATAL, size_vars * sizeof(struct config_generic *));
5113 
5114 	num_vars = 0;
5115 
5116 	for (i = 0; ConfigureNamesBool[i].gen.name; i++)
5117 		guc_vars[num_vars++] = &ConfigureNamesBool[i].gen;
5118 
5119 	for (i = 0; ConfigureNamesInt[i].gen.name; i++)
5120 		guc_vars[num_vars++] = &ConfigureNamesInt[i].gen;
5121 
5122 	for (i = 0; ConfigureNamesReal[i].gen.name; i++)
5123 		guc_vars[num_vars++] = &ConfigureNamesReal[i].gen;
5124 
5125 	for (i = 0; ConfigureNamesString[i].gen.name; i++)
5126 		guc_vars[num_vars++] = &ConfigureNamesString[i].gen;
5127 
5128 	for (i = 0; ConfigureNamesEnum[i].gen.name; i++)
5129 		guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen;
5130 
5131 	if (guc_variables)
5132 		free(guc_variables);
5133 	guc_variables = guc_vars;
5134 	num_guc_variables = num_vars;
5135 	size_guc_variables = size_vars;
5136 	qsort((void *) guc_variables, num_guc_variables,
5137 		  sizeof(struct config_generic *), guc_var_compare);
5138 }
5139 
5140 /*
5141  * Add a new GUC variable to the list of known variables. The
5142  * list is expanded if needed.
5143  */
5144 static bool
add_guc_variable(struct config_generic * var,int elevel)5145 add_guc_variable(struct config_generic *var, int elevel)
5146 {
5147 	if (num_guc_variables + 1 >= size_guc_variables)
5148 	{
5149 		/*
5150 		 * Increase the vector by 25%
5151 		 */
5152 		int			size_vars = size_guc_variables + size_guc_variables / 4;
5153 		struct config_generic **guc_vars;
5154 
5155 		if (size_vars == 0)
5156 		{
5157 			size_vars = 100;
5158 			guc_vars = (struct config_generic **)
5159 				guc_malloc(elevel, size_vars * sizeof(struct config_generic *));
5160 		}
5161 		else
5162 		{
5163 			guc_vars = (struct config_generic **)
5164 				guc_realloc(elevel, guc_variables, size_vars * sizeof(struct config_generic *));
5165 		}
5166 
5167 		if (guc_vars == NULL)
5168 			return false;		/* out of memory */
5169 
5170 		guc_variables = guc_vars;
5171 		size_guc_variables = size_vars;
5172 	}
5173 	guc_variables[num_guc_variables++] = var;
5174 	qsort((void *) guc_variables, num_guc_variables,
5175 		  sizeof(struct config_generic *), guc_var_compare);
5176 	return true;
5177 }
5178 
5179 /*
5180  * Create and add a placeholder variable for a custom variable name.
5181  */
5182 static struct config_generic *
add_placeholder_variable(const char * name,int elevel)5183 add_placeholder_variable(const char *name, int elevel)
5184 {
5185 	size_t		sz = sizeof(struct config_string) + sizeof(char *);
5186 	struct config_string *var;
5187 	struct config_generic *gen;
5188 
5189 	var = (struct config_string *) guc_malloc(elevel, sz);
5190 	if (var == NULL)
5191 		return NULL;
5192 	memset(var, 0, sz);
5193 	gen = &var->gen;
5194 
5195 	gen->name = guc_strdup(elevel, name);
5196 	if (gen->name == NULL)
5197 	{
5198 		free(var);
5199 		return NULL;
5200 	}
5201 
5202 	gen->context = PGC_USERSET;
5203 	gen->group = CUSTOM_OPTIONS;
5204 	gen->short_desc = "GUC placeholder variable";
5205 	gen->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER;
5206 	gen->vartype = PGC_STRING;
5207 
5208 	/*
5209 	 * The char* is allocated at the end of the struct since we have no
5210 	 * 'static' place to point to.  Note that the current value, as well as
5211 	 * the boot and reset values, start out NULL.
5212 	 */
5213 	var->variable = (char **) (var + 1);
5214 
5215 	if (!add_guc_variable((struct config_generic *) var, elevel))
5216 	{
5217 		free(unconstify(char *, gen->name));
5218 		free(var);
5219 		return NULL;
5220 	}
5221 
5222 	return gen;
5223 }
5224 
5225 /*
5226  * Look up option NAME.  If it exists, return a pointer to its record,
5227  * else return NULL.  If create_placeholders is true, we'll create a
5228  * placeholder record for a valid-looking custom variable name.
5229  */
5230 static struct config_generic *
find_option(const char * name,bool create_placeholders,int elevel)5231 find_option(const char *name, bool create_placeholders, int elevel)
5232 {
5233 	const char **key = &name;
5234 	struct config_generic **res;
5235 	int			i;
5236 
5237 	Assert(name);
5238 
5239 	/*
5240 	 * By equating const char ** with struct config_generic *, we are assuming
5241 	 * the name field is first in config_generic.
5242 	 */
5243 	res = (struct config_generic **) bsearch((void *) &key,
5244 											 (void *) guc_variables,
5245 											 num_guc_variables,
5246 											 sizeof(struct config_generic *),
5247 											 guc_var_compare);
5248 	if (res)
5249 		return *res;
5250 
5251 	/*
5252 	 * See if the name is an obsolete name for a variable.  We assume that the
5253 	 * set of supported old names is short enough that a brute-force search is
5254 	 * the best way.
5255 	 */
5256 	for (i = 0; map_old_guc_names[i] != NULL; i += 2)
5257 	{
5258 		if (guc_name_compare(name, map_old_guc_names[i]) == 0)
5259 			return find_option(map_old_guc_names[i + 1], false, elevel);
5260 	}
5261 
5262 	if (create_placeholders)
5263 	{
5264 		/*
5265 		 * Check if the name is qualified, and if so, add a placeholder.
5266 		 */
5267 		if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL)
5268 			return add_placeholder_variable(name, elevel);
5269 	}
5270 
5271 	/* Unknown name */
5272 	return NULL;
5273 }
5274 
5275 
5276 /*
5277  * comparator for qsorting and bsearching guc_variables array
5278  */
5279 static int
guc_var_compare(const void * a,const void * b)5280 guc_var_compare(const void *a, const void *b)
5281 {
5282 	const struct config_generic *confa = *(struct config_generic *const *) a;
5283 	const struct config_generic *confb = *(struct config_generic *const *) b;
5284 
5285 	return guc_name_compare(confa->name, confb->name);
5286 }
5287 
5288 /*
5289  * the bare comparison function for GUC names
5290  */
5291 static int
guc_name_compare(const char * namea,const char * nameb)5292 guc_name_compare(const char *namea, const char *nameb)
5293 {
5294 	/*
5295 	 * The temptation to use strcasecmp() here must be resisted, because the
5296 	 * array ordering has to remain stable across setlocale() calls. So, build
5297 	 * our own with a simple ASCII-only downcasing.
5298 	 */
5299 	while (*namea && *nameb)
5300 	{
5301 		char		cha = *namea++;
5302 		char		chb = *nameb++;
5303 
5304 		if (cha >= 'A' && cha <= 'Z')
5305 			cha += 'a' - 'A';
5306 		if (chb >= 'A' && chb <= 'Z')
5307 			chb += 'a' - 'A';
5308 		if (cha != chb)
5309 			return cha - chb;
5310 	}
5311 	if (*namea)
5312 		return 1;				/* a is longer */
5313 	if (*nameb)
5314 		return -1;				/* b is longer */
5315 	return 0;
5316 }
5317 
5318 
5319 /*
5320  * Initialize GUC options during program startup.
5321  *
5322  * Note that we cannot read the config file yet, since we have not yet
5323  * processed command-line switches.
5324  */
5325 void
InitializeGUCOptions(void)5326 InitializeGUCOptions(void)
5327 {
5328 	int			i;
5329 
5330 	/*
5331 	 * Before log_line_prefix could possibly receive a nonempty setting, make
5332 	 * sure that timezone processing is minimally alive (see elog.c).
5333 	 */
5334 	pg_timezone_initialize();
5335 
5336 	/*
5337 	 * Build sorted array of all GUC variables.
5338 	 */
5339 	build_guc_variables();
5340 
5341 	/*
5342 	 * Load all variables with their compiled-in defaults, and initialize
5343 	 * status fields as needed.
5344 	 */
5345 	for (i = 0; i < num_guc_variables; i++)
5346 	{
5347 		InitializeOneGUCOption(guc_variables[i]);
5348 	}
5349 
5350 	guc_dirty = false;
5351 
5352 	reporting_enabled = false;
5353 
5354 	/*
5355 	 * Prevent any attempt to override the transaction modes from
5356 	 * non-interactive sources.
5357 	 */
5358 	SetConfigOption("transaction_isolation", "read committed",
5359 					PGC_POSTMASTER, PGC_S_OVERRIDE);
5360 	SetConfigOption("transaction_read_only", "no",
5361 					PGC_POSTMASTER, PGC_S_OVERRIDE);
5362 	SetConfigOption("transaction_deferrable", "no",
5363 					PGC_POSTMASTER, PGC_S_OVERRIDE);
5364 
5365 	/*
5366 	 * For historical reasons, some GUC parameters can receive defaults from
5367 	 * environment variables.  Process those settings.
5368 	 */
5369 	InitializeGUCOptionsFromEnvironment();
5370 }
5371 
5372 /*
5373  * Assign any GUC values that can come from the server's environment.
5374  *
5375  * This is called from InitializeGUCOptions, and also from ProcessConfigFile
5376  * to deal with the possibility that a setting has been removed from
5377  * postgresql.conf and should now get a value from the environment.
5378  * (The latter is a kludge that should probably go away someday; if so,
5379  * fold this back into InitializeGUCOptions.)
5380  */
5381 static void
InitializeGUCOptionsFromEnvironment(void)5382 InitializeGUCOptionsFromEnvironment(void)
5383 {
5384 	char	   *env;
5385 	long		stack_rlimit;
5386 
5387 	env = getenv("PGPORT");
5388 	if (env != NULL)
5389 		SetConfigOption("port", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
5390 
5391 	env = getenv("PGDATESTYLE");
5392 	if (env != NULL)
5393 		SetConfigOption("datestyle", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
5394 
5395 	env = getenv("PGCLIENTENCODING");
5396 	if (env != NULL)
5397 		SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
5398 
5399 	/*
5400 	 * rlimit isn't exactly an "environment variable", but it behaves about
5401 	 * the same.  If we can identify the platform stack depth rlimit, increase
5402 	 * default stack depth setting up to whatever is safe (but at most 2MB).
5403 	 */
5404 	stack_rlimit = get_stack_depth_rlimit();
5405 	if (stack_rlimit > 0)
5406 	{
5407 		long		new_limit = (stack_rlimit - STACK_DEPTH_SLOP) / 1024L;
5408 
5409 		if (new_limit > 100)
5410 		{
5411 			char		limbuf[16];
5412 
5413 			new_limit = Min(new_limit, 2048);
5414 			sprintf(limbuf, "%ld", new_limit);
5415 			SetConfigOption("max_stack_depth", limbuf,
5416 							PGC_POSTMASTER, PGC_S_ENV_VAR);
5417 		}
5418 	}
5419 }
5420 
5421 /*
5422  * Initialize one GUC option variable to its compiled-in default.
5423  *
5424  * Note: the reason for calling check_hooks is not that we think the boot_val
5425  * might fail, but that the hooks might wish to compute an "extra" struct.
5426  */
5427 static void
InitializeOneGUCOption(struct config_generic * gconf)5428 InitializeOneGUCOption(struct config_generic *gconf)
5429 {
5430 	gconf->status = 0;
5431 	gconf->source = PGC_S_DEFAULT;
5432 	gconf->reset_source = PGC_S_DEFAULT;
5433 	gconf->scontext = PGC_INTERNAL;
5434 	gconf->reset_scontext = PGC_INTERNAL;
5435 	gconf->stack = NULL;
5436 	gconf->extra = NULL;
5437 	gconf->sourcefile = NULL;
5438 	gconf->sourceline = 0;
5439 
5440 	switch (gconf->vartype)
5441 	{
5442 		case PGC_BOOL:
5443 			{
5444 				struct config_bool *conf = (struct config_bool *) gconf;
5445 				bool		newval = conf->boot_val;
5446 				void	   *extra = NULL;
5447 
5448 				if (!call_bool_check_hook(conf, &newval, &extra,
5449 										  PGC_S_DEFAULT, LOG))
5450 					elog(FATAL, "failed to initialize %s to %d",
5451 						 conf->gen.name, (int) newval);
5452 				if (conf->assign_hook)
5453 					conf->assign_hook(newval, extra);
5454 				*conf->variable = conf->reset_val = newval;
5455 				conf->gen.extra = conf->reset_extra = extra;
5456 				break;
5457 			}
5458 		case PGC_INT:
5459 			{
5460 				struct config_int *conf = (struct config_int *) gconf;
5461 				int			newval = conf->boot_val;
5462 				void	   *extra = NULL;
5463 
5464 				Assert(newval >= conf->min);
5465 				Assert(newval <= conf->max);
5466 				if (!call_int_check_hook(conf, &newval, &extra,
5467 										 PGC_S_DEFAULT, LOG))
5468 					elog(FATAL, "failed to initialize %s to %d",
5469 						 conf->gen.name, newval);
5470 				if (conf->assign_hook)
5471 					conf->assign_hook(newval, extra);
5472 				*conf->variable = conf->reset_val = newval;
5473 				conf->gen.extra = conf->reset_extra = extra;
5474 				break;
5475 			}
5476 		case PGC_REAL:
5477 			{
5478 				struct config_real *conf = (struct config_real *) gconf;
5479 				double		newval = conf->boot_val;
5480 				void	   *extra = NULL;
5481 
5482 				Assert(newval >= conf->min);
5483 				Assert(newval <= conf->max);
5484 				if (!call_real_check_hook(conf, &newval, &extra,
5485 										  PGC_S_DEFAULT, LOG))
5486 					elog(FATAL, "failed to initialize %s to %g",
5487 						 conf->gen.name, newval);
5488 				if (conf->assign_hook)
5489 					conf->assign_hook(newval, extra);
5490 				*conf->variable = conf->reset_val = newval;
5491 				conf->gen.extra = conf->reset_extra = extra;
5492 				break;
5493 			}
5494 		case PGC_STRING:
5495 			{
5496 				struct config_string *conf = (struct config_string *) gconf;
5497 				char	   *newval;
5498 				void	   *extra = NULL;
5499 
5500 				/* non-NULL boot_val must always get strdup'd */
5501 				if (conf->boot_val != NULL)
5502 					newval = guc_strdup(FATAL, conf->boot_val);
5503 				else
5504 					newval = NULL;
5505 
5506 				if (!call_string_check_hook(conf, &newval, &extra,
5507 											PGC_S_DEFAULT, LOG))
5508 					elog(FATAL, "failed to initialize %s to \"%s\"",
5509 						 conf->gen.name, newval ? newval : "");
5510 				if (conf->assign_hook)
5511 					conf->assign_hook(newval, extra);
5512 				*conf->variable = conf->reset_val = newval;
5513 				conf->gen.extra = conf->reset_extra = extra;
5514 				break;
5515 			}
5516 		case PGC_ENUM:
5517 			{
5518 				struct config_enum *conf = (struct config_enum *) gconf;
5519 				int			newval = conf->boot_val;
5520 				void	   *extra = NULL;
5521 
5522 				if (!call_enum_check_hook(conf, &newval, &extra,
5523 										  PGC_S_DEFAULT, LOG))
5524 					elog(FATAL, "failed to initialize %s to %d",
5525 						 conf->gen.name, newval);
5526 				if (conf->assign_hook)
5527 					conf->assign_hook(newval, extra);
5528 				*conf->variable = conf->reset_val = newval;
5529 				conf->gen.extra = conf->reset_extra = extra;
5530 				break;
5531 			}
5532 	}
5533 }
5534 
5535 
5536 /*
5537  * Select the configuration files and data directory to be used, and
5538  * do the initial read of postgresql.conf.
5539  *
5540  * This is called after processing command-line switches.
5541  *		userDoption is the -D switch value if any (NULL if unspecified).
5542  *		progname is just for use in error messages.
5543  *
5544  * Returns true on success; on failure, prints a suitable error message
5545  * to stderr and returns false.
5546  */
5547 bool
SelectConfigFiles(const char * userDoption,const char * progname)5548 SelectConfigFiles(const char *userDoption, const char *progname)
5549 {
5550 	char	   *configdir;
5551 	char	   *fname;
5552 	struct stat stat_buf;
5553 
5554 	/* configdir is -D option, or $PGDATA if no -D */
5555 	if (userDoption)
5556 		configdir = make_absolute_path(userDoption);
5557 	else
5558 		configdir = make_absolute_path(getenv("PGDATA"));
5559 
5560 	if (configdir && stat(configdir, &stat_buf) != 0)
5561 	{
5562 		write_stderr("%s: could not access directory \"%s\": %s\n",
5563 					 progname,
5564 					 configdir,
5565 					 strerror(errno));
5566 		if (errno == ENOENT)
5567 			write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n");
5568 		return false;
5569 	}
5570 
5571 	/*
5572 	 * Find the configuration file: if config_file was specified on the
5573 	 * command line, use it, else use configdir/postgresql.conf.  In any case
5574 	 * ensure the result is an absolute path, so that it will be interpreted
5575 	 * the same way by future backends.
5576 	 */
5577 	if (ConfigFileName)
5578 		fname = make_absolute_path(ConfigFileName);
5579 	else if (configdir)
5580 	{
5581 		fname = guc_malloc(FATAL,
5582 						   strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
5583 		sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
5584 	}
5585 	else
5586 	{
5587 		write_stderr("%s does not know where to find the server configuration file.\n"
5588 					 "You must specify the --config-file or -D invocation "
5589 					 "option or set the PGDATA environment variable.\n",
5590 					 progname);
5591 		return false;
5592 	}
5593 
5594 	/*
5595 	 * Set the ConfigFileName GUC variable to its final value, ensuring that
5596 	 * it can't be overridden later.
5597 	 */
5598 	SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
5599 	free(fname);
5600 
5601 	/*
5602 	 * Now read the config file for the first time.
5603 	 */
5604 	if (stat(ConfigFileName, &stat_buf) != 0)
5605 	{
5606 		write_stderr("%s: could not access the server configuration file \"%s\": %s\n",
5607 					 progname, ConfigFileName, strerror(errno));
5608 		free(configdir);
5609 		return false;
5610 	}
5611 
5612 	/*
5613 	 * Read the configuration file for the first time.  This time only the
5614 	 * data_directory parameter is picked up to determine the data directory,
5615 	 * so that we can read the PG_AUTOCONF_FILENAME file next time.
5616 	 */
5617 	ProcessConfigFile(PGC_POSTMASTER);
5618 
5619 	/*
5620 	 * If the data_directory GUC variable has been set, use that as DataDir;
5621 	 * otherwise use configdir if set; else punt.
5622 	 *
5623 	 * Note: SetDataDir will copy and absolute-ize its argument, so we don't
5624 	 * have to.
5625 	 */
5626 	if (data_directory)
5627 		SetDataDir(data_directory);
5628 	else if (configdir)
5629 		SetDataDir(configdir);
5630 	else
5631 	{
5632 		write_stderr("%s does not know where to find the database system data.\n"
5633 					 "This can be specified as \"data_directory\" in \"%s\", "
5634 					 "or by the -D invocation option, or by the "
5635 					 "PGDATA environment variable.\n",
5636 					 progname, ConfigFileName);
5637 		return false;
5638 	}
5639 
5640 	/*
5641 	 * Reflect the final DataDir value back into the data_directory GUC var.
5642 	 * (If you are wondering why we don't just make them a single variable,
5643 	 * it's because the EXEC_BACKEND case needs DataDir to be transmitted to
5644 	 * child backends specially.  XXX is that still true?  Given that we now
5645 	 * chdir to DataDir, EXEC_BACKEND can read the config file without knowing
5646 	 * DataDir in advance.)
5647 	 */
5648 	SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
5649 
5650 	/*
5651 	 * Now read the config file a second time, allowing any settings in the
5652 	 * PG_AUTOCONF_FILENAME file to take effect.  (This is pretty ugly, but
5653 	 * since we have to determine the DataDir before we can find the autoconf
5654 	 * file, the alternatives seem worse.)
5655 	 */
5656 	ProcessConfigFile(PGC_POSTMASTER);
5657 
5658 	/*
5659 	 * If timezone_abbreviations wasn't set in the configuration file, install
5660 	 * the default value.  We do it this way because we can't safely install a
5661 	 * "real" value until my_exec_path is set, which may not have happened
5662 	 * when InitializeGUCOptions runs, so the bootstrap default value cannot
5663 	 * be the real desired default.
5664 	 */
5665 	pg_timezone_abbrev_initialize();
5666 
5667 	/*
5668 	 * Figure out where pg_hba.conf is, and make sure the path is absolute.
5669 	 */
5670 	if (HbaFileName)
5671 		fname = make_absolute_path(HbaFileName);
5672 	else if (configdir)
5673 	{
5674 		fname = guc_malloc(FATAL,
5675 						   strlen(configdir) + strlen(HBA_FILENAME) + 2);
5676 		sprintf(fname, "%s/%s", configdir, HBA_FILENAME);
5677 	}
5678 	else
5679 	{
5680 		write_stderr("%s does not know where to find the \"hba\" configuration file.\n"
5681 					 "This can be specified as \"hba_file\" in \"%s\", "
5682 					 "or by the -D invocation option, or by the "
5683 					 "PGDATA environment variable.\n",
5684 					 progname, ConfigFileName);
5685 		return false;
5686 	}
5687 	SetConfigOption("hba_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
5688 	free(fname);
5689 
5690 	/*
5691 	 * Likewise for pg_ident.conf.
5692 	 */
5693 	if (IdentFileName)
5694 		fname = make_absolute_path(IdentFileName);
5695 	else if (configdir)
5696 	{
5697 		fname = guc_malloc(FATAL,
5698 						   strlen(configdir) + strlen(IDENT_FILENAME) + 2);
5699 		sprintf(fname, "%s/%s", configdir, IDENT_FILENAME);
5700 	}
5701 	else
5702 	{
5703 		write_stderr("%s does not know where to find the \"ident\" configuration file.\n"
5704 					 "This can be specified as \"ident_file\" in \"%s\", "
5705 					 "or by the -D invocation option, or by the "
5706 					 "PGDATA environment variable.\n",
5707 					 progname, ConfigFileName);
5708 		return false;
5709 	}
5710 	SetConfigOption("ident_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);
5711 	free(fname);
5712 
5713 	free(configdir);
5714 
5715 	return true;
5716 }
5717 
5718 
5719 /*
5720  * Reset all options to their saved default values (implements RESET ALL)
5721  */
5722 void
ResetAllOptions(void)5723 ResetAllOptions(void)
5724 {
5725 	int			i;
5726 
5727 	for (i = 0; i < num_guc_variables; i++)
5728 	{
5729 		struct config_generic *gconf = guc_variables[i];
5730 
5731 		/* Don't reset non-SET-able values */
5732 		if (gconf->context != PGC_SUSET &&
5733 			gconf->context != PGC_USERSET)
5734 			continue;
5735 		/* Don't reset if special exclusion from RESET ALL */
5736 		if (gconf->flags & GUC_NO_RESET_ALL)
5737 			continue;
5738 		/* No need to reset if wasn't SET */
5739 		if (gconf->source <= PGC_S_OVERRIDE)
5740 			continue;
5741 
5742 		/* Save old value to support transaction abort */
5743 		push_old_value(gconf, GUC_ACTION_SET);
5744 
5745 		switch (gconf->vartype)
5746 		{
5747 			case PGC_BOOL:
5748 				{
5749 					struct config_bool *conf = (struct config_bool *) gconf;
5750 
5751 					if (conf->assign_hook)
5752 						conf->assign_hook(conf->reset_val,
5753 										  conf->reset_extra);
5754 					*conf->variable = conf->reset_val;
5755 					set_extra_field(&conf->gen, &conf->gen.extra,
5756 									conf->reset_extra);
5757 					break;
5758 				}
5759 			case PGC_INT:
5760 				{
5761 					struct config_int *conf = (struct config_int *) gconf;
5762 
5763 					if (conf->assign_hook)
5764 						conf->assign_hook(conf->reset_val,
5765 										  conf->reset_extra);
5766 					*conf->variable = conf->reset_val;
5767 					set_extra_field(&conf->gen, &conf->gen.extra,
5768 									conf->reset_extra);
5769 					break;
5770 				}
5771 			case PGC_REAL:
5772 				{
5773 					struct config_real *conf = (struct config_real *) gconf;
5774 
5775 					if (conf->assign_hook)
5776 						conf->assign_hook(conf->reset_val,
5777 										  conf->reset_extra);
5778 					*conf->variable = conf->reset_val;
5779 					set_extra_field(&conf->gen, &conf->gen.extra,
5780 									conf->reset_extra);
5781 					break;
5782 				}
5783 			case PGC_STRING:
5784 				{
5785 					struct config_string *conf = (struct config_string *) gconf;
5786 
5787 					if (conf->assign_hook)
5788 						conf->assign_hook(conf->reset_val,
5789 										  conf->reset_extra);
5790 					set_string_field(conf, conf->variable, conf->reset_val);
5791 					set_extra_field(&conf->gen, &conf->gen.extra,
5792 									conf->reset_extra);
5793 					break;
5794 				}
5795 			case PGC_ENUM:
5796 				{
5797 					struct config_enum *conf = (struct config_enum *) gconf;
5798 
5799 					if (conf->assign_hook)
5800 						conf->assign_hook(conf->reset_val,
5801 										  conf->reset_extra);
5802 					*conf->variable = conf->reset_val;
5803 					set_extra_field(&conf->gen, &conf->gen.extra,
5804 									conf->reset_extra);
5805 					break;
5806 				}
5807 		}
5808 
5809 		gconf->source = gconf->reset_source;
5810 		gconf->scontext = gconf->reset_scontext;
5811 
5812 		if (gconf->flags & GUC_REPORT)
5813 			ReportGUCOption(gconf);
5814 	}
5815 }
5816 
5817 
5818 /*
5819  * push_old_value
5820  *		Push previous state during transactional assignment to a GUC variable.
5821  */
5822 static void
push_old_value(struct config_generic * gconf,GucAction action)5823 push_old_value(struct config_generic *gconf, GucAction action)
5824 {
5825 	GucStack   *stack;
5826 
5827 	/* If we're not inside a nest level, do nothing */
5828 	if (GUCNestLevel == 0)
5829 		return;
5830 
5831 	/* Do we already have a stack entry of the current nest level? */
5832 	stack = gconf->stack;
5833 	if (stack && stack->nest_level >= GUCNestLevel)
5834 	{
5835 		/* Yes, so adjust its state if necessary */
5836 		Assert(stack->nest_level == GUCNestLevel);
5837 		switch (action)
5838 		{
5839 			case GUC_ACTION_SET:
5840 				/* SET overrides any prior action at same nest level */
5841 				if (stack->state == GUC_SET_LOCAL)
5842 				{
5843 					/* must discard old masked value */
5844 					discard_stack_value(gconf, &stack->masked);
5845 				}
5846 				stack->state = GUC_SET;
5847 				break;
5848 			case GUC_ACTION_LOCAL:
5849 				if (stack->state == GUC_SET)
5850 				{
5851 					/* SET followed by SET LOCAL, remember SET's value */
5852 					stack->masked_scontext = gconf->scontext;
5853 					set_stack_value(gconf, &stack->masked);
5854 					stack->state = GUC_SET_LOCAL;
5855 				}
5856 				/* in all other cases, no change to stack entry */
5857 				break;
5858 			case GUC_ACTION_SAVE:
5859 				/* Could only have a prior SAVE of same variable */
5860 				Assert(stack->state == GUC_SAVE);
5861 				break;
5862 		}
5863 		Assert(guc_dirty);		/* must be set already */
5864 		return;
5865 	}
5866 
5867 	/*
5868 	 * Push a new stack entry
5869 	 *
5870 	 * We keep all the stack entries in TopTransactionContext for simplicity.
5871 	 */
5872 	stack = (GucStack *) MemoryContextAllocZero(TopTransactionContext,
5873 												sizeof(GucStack));
5874 
5875 	stack->prev = gconf->stack;
5876 	stack->nest_level = GUCNestLevel;
5877 	switch (action)
5878 	{
5879 		case GUC_ACTION_SET:
5880 			stack->state = GUC_SET;
5881 			break;
5882 		case GUC_ACTION_LOCAL:
5883 			stack->state = GUC_LOCAL;
5884 			break;
5885 		case GUC_ACTION_SAVE:
5886 			stack->state = GUC_SAVE;
5887 			break;
5888 	}
5889 	stack->source = gconf->source;
5890 	stack->scontext = gconf->scontext;
5891 	set_stack_value(gconf, &stack->prior);
5892 
5893 	gconf->stack = stack;
5894 
5895 	/* Ensure we remember to pop at end of xact */
5896 	guc_dirty = true;
5897 }
5898 
5899 
5900 /*
5901  * Do GUC processing at main transaction start.
5902  */
5903 void
AtStart_GUC(void)5904 AtStart_GUC(void)
5905 {
5906 	/*
5907 	 * The nest level should be 0 between transactions; if it isn't, somebody
5908 	 * didn't call AtEOXact_GUC, or called it with the wrong nestLevel.  We
5909 	 * throw a warning but make no other effort to clean up.
5910 	 */
5911 	if (GUCNestLevel != 0)
5912 		elog(WARNING, "GUC nest level = %d at transaction start",
5913 			 GUCNestLevel);
5914 	GUCNestLevel = 1;
5915 }
5916 
5917 /*
5918  * Enter a new nesting level for GUC values.  This is called at subtransaction
5919  * start, and when entering a function that has proconfig settings, and in
5920  * some other places where we want to set GUC variables transiently.
5921  * NOTE we must not risk error here, else subtransaction start will be unhappy.
5922  */
5923 int
NewGUCNestLevel(void)5924 NewGUCNestLevel(void)
5925 {
5926 	return ++GUCNestLevel;
5927 }
5928 
5929 /*
5930  * Do GUC processing at transaction or subtransaction commit or abort, or
5931  * when exiting a function that has proconfig settings, or when undoing a
5932  * transient assignment to some GUC variables.  (The name is thus a bit of
5933  * a misnomer; perhaps it should be ExitGUCNestLevel or some such.)
5934  * During abort, we discard all GUC settings that were applied at nesting
5935  * levels >= nestLevel.  nestLevel == 1 corresponds to the main transaction.
5936  */
5937 void
AtEOXact_GUC(bool isCommit,int nestLevel)5938 AtEOXact_GUC(bool isCommit, int nestLevel)
5939 {
5940 	bool		still_dirty;
5941 	int			i;
5942 
5943 	/*
5944 	 * Note: it's possible to get here with GUCNestLevel == nestLevel-1 during
5945 	 * abort, if there is a failure during transaction start before
5946 	 * AtStart_GUC is called.
5947 	 */
5948 	Assert(nestLevel > 0 &&
5949 		   (nestLevel <= GUCNestLevel ||
5950 			(nestLevel == GUCNestLevel + 1 && !isCommit)));
5951 
5952 	/* Quick exit if nothing's changed in this transaction */
5953 	if (!guc_dirty)
5954 	{
5955 		GUCNestLevel = nestLevel - 1;
5956 		return;
5957 	}
5958 
5959 	still_dirty = false;
5960 	for (i = 0; i < num_guc_variables; i++)
5961 	{
5962 		struct config_generic *gconf = guc_variables[i];
5963 		GucStack   *stack;
5964 
5965 		/*
5966 		 * Process and pop each stack entry within the nest level. To simplify
5967 		 * fmgr_security_definer() and other places that use GUC_ACTION_SAVE,
5968 		 * we allow failure exit from code that uses a local nest level to be
5969 		 * recovered at the surrounding transaction or subtransaction abort;
5970 		 * so there could be more than one stack entry to pop.
5971 		 */
5972 		while ((stack = gconf->stack) != NULL &&
5973 			   stack->nest_level >= nestLevel)
5974 		{
5975 			GucStack   *prev = stack->prev;
5976 			bool		restorePrior = false;
5977 			bool		restoreMasked = false;
5978 			bool		changed;
5979 
5980 			/*
5981 			 * In this next bit, if we don't set either restorePrior or
5982 			 * restoreMasked, we must "discard" any unwanted fields of the
5983 			 * stack entries to avoid leaking memory.  If we do set one of
5984 			 * those flags, unused fields will be cleaned up after restoring.
5985 			 */
5986 			if (!isCommit)		/* if abort, always restore prior value */
5987 				restorePrior = true;
5988 			else if (stack->state == GUC_SAVE)
5989 				restorePrior = true;
5990 			else if (stack->nest_level == 1)
5991 			{
5992 				/* transaction commit */
5993 				if (stack->state == GUC_SET_LOCAL)
5994 					restoreMasked = true;
5995 				else if (stack->state == GUC_SET)
5996 				{
5997 					/* we keep the current active value */
5998 					discard_stack_value(gconf, &stack->prior);
5999 				}
6000 				else			/* must be GUC_LOCAL */
6001 					restorePrior = true;
6002 			}
6003 			else if (prev == NULL ||
6004 					 prev->nest_level < stack->nest_level - 1)
6005 			{
6006 				/* decrement entry's level and do not pop it */
6007 				stack->nest_level--;
6008 				continue;
6009 			}
6010 			else
6011 			{
6012 				/*
6013 				 * We have to merge this stack entry into prev. See README for
6014 				 * discussion of this bit.
6015 				 */
6016 				switch (stack->state)
6017 				{
6018 					case GUC_SAVE:
6019 						Assert(false);	/* can't get here */
6020 						break;
6021 
6022 					case GUC_SET:
6023 						/* next level always becomes SET */
6024 						discard_stack_value(gconf, &stack->prior);
6025 						if (prev->state == GUC_SET_LOCAL)
6026 							discard_stack_value(gconf, &prev->masked);
6027 						prev->state = GUC_SET;
6028 						break;
6029 
6030 					case GUC_LOCAL:
6031 						if (prev->state == GUC_SET)
6032 						{
6033 							/* LOCAL migrates down */
6034 							prev->masked_scontext = stack->scontext;
6035 							prev->masked = stack->prior;
6036 							prev->state = GUC_SET_LOCAL;
6037 						}
6038 						else
6039 						{
6040 							/* else just forget this stack level */
6041 							discard_stack_value(gconf, &stack->prior);
6042 						}
6043 						break;
6044 
6045 					case GUC_SET_LOCAL:
6046 						/* prior state at this level no longer wanted */
6047 						discard_stack_value(gconf, &stack->prior);
6048 						/* copy down the masked state */
6049 						prev->masked_scontext = stack->masked_scontext;
6050 						if (prev->state == GUC_SET_LOCAL)
6051 							discard_stack_value(gconf, &prev->masked);
6052 						prev->masked = stack->masked;
6053 						prev->state = GUC_SET_LOCAL;
6054 						break;
6055 				}
6056 			}
6057 
6058 			changed = false;
6059 
6060 			if (restorePrior || restoreMasked)
6061 			{
6062 				/* Perform appropriate restoration of the stacked value */
6063 				config_var_value newvalue;
6064 				GucSource	newsource;
6065 				GucContext	newscontext;
6066 
6067 				if (restoreMasked)
6068 				{
6069 					newvalue = stack->masked;
6070 					newsource = PGC_S_SESSION;
6071 					newscontext = stack->masked_scontext;
6072 				}
6073 				else
6074 				{
6075 					newvalue = stack->prior;
6076 					newsource = stack->source;
6077 					newscontext = stack->scontext;
6078 				}
6079 
6080 				switch (gconf->vartype)
6081 				{
6082 					case PGC_BOOL:
6083 						{
6084 							struct config_bool *conf = (struct config_bool *) gconf;
6085 							bool		newval = newvalue.val.boolval;
6086 							void	   *newextra = newvalue.extra;
6087 
6088 							if (*conf->variable != newval ||
6089 								conf->gen.extra != newextra)
6090 							{
6091 								if (conf->assign_hook)
6092 									conf->assign_hook(newval, newextra);
6093 								*conf->variable = newval;
6094 								set_extra_field(&conf->gen, &conf->gen.extra,
6095 												newextra);
6096 								changed = true;
6097 							}
6098 							break;
6099 						}
6100 					case PGC_INT:
6101 						{
6102 							struct config_int *conf = (struct config_int *) gconf;
6103 							int			newval = newvalue.val.intval;
6104 							void	   *newextra = newvalue.extra;
6105 
6106 							if (*conf->variable != newval ||
6107 								conf->gen.extra != newextra)
6108 							{
6109 								if (conf->assign_hook)
6110 									conf->assign_hook(newval, newextra);
6111 								*conf->variable = newval;
6112 								set_extra_field(&conf->gen, &conf->gen.extra,
6113 												newextra);
6114 								changed = true;
6115 							}
6116 							break;
6117 						}
6118 					case PGC_REAL:
6119 						{
6120 							struct config_real *conf = (struct config_real *) gconf;
6121 							double		newval = newvalue.val.realval;
6122 							void	   *newextra = newvalue.extra;
6123 
6124 							if (*conf->variable != newval ||
6125 								conf->gen.extra != newextra)
6126 							{
6127 								if (conf->assign_hook)
6128 									conf->assign_hook(newval, newextra);
6129 								*conf->variable = newval;
6130 								set_extra_field(&conf->gen, &conf->gen.extra,
6131 												newextra);
6132 								changed = true;
6133 							}
6134 							break;
6135 						}
6136 					case PGC_STRING:
6137 						{
6138 							struct config_string *conf = (struct config_string *) gconf;
6139 							char	   *newval = newvalue.val.stringval;
6140 							void	   *newextra = newvalue.extra;
6141 
6142 							if (*conf->variable != newval ||
6143 								conf->gen.extra != newextra)
6144 							{
6145 								if (conf->assign_hook)
6146 									conf->assign_hook(newval, newextra);
6147 								set_string_field(conf, conf->variable, newval);
6148 								set_extra_field(&conf->gen, &conf->gen.extra,
6149 												newextra);
6150 								changed = true;
6151 							}
6152 
6153 							/*
6154 							 * Release stacked values if not used anymore. We
6155 							 * could use discard_stack_value() here, but since
6156 							 * we have type-specific code anyway, might as
6157 							 * well inline it.
6158 							 */
6159 							set_string_field(conf, &stack->prior.val.stringval, NULL);
6160 							set_string_field(conf, &stack->masked.val.stringval, NULL);
6161 							break;
6162 						}
6163 					case PGC_ENUM:
6164 						{
6165 							struct config_enum *conf = (struct config_enum *) gconf;
6166 							int			newval = newvalue.val.enumval;
6167 							void	   *newextra = newvalue.extra;
6168 
6169 							if (*conf->variable != newval ||
6170 								conf->gen.extra != newextra)
6171 							{
6172 								if (conf->assign_hook)
6173 									conf->assign_hook(newval, newextra);
6174 								*conf->variable = newval;
6175 								set_extra_field(&conf->gen, &conf->gen.extra,
6176 												newextra);
6177 								changed = true;
6178 							}
6179 							break;
6180 						}
6181 				}
6182 
6183 				/*
6184 				 * Release stacked extra values if not used anymore.
6185 				 */
6186 				set_extra_field(gconf, &(stack->prior.extra), NULL);
6187 				set_extra_field(gconf, &(stack->masked.extra), NULL);
6188 
6189 				/* And restore source information */
6190 				gconf->source = newsource;
6191 				gconf->scontext = newscontext;
6192 			}
6193 
6194 			/* Finish popping the state stack */
6195 			gconf->stack = prev;
6196 			pfree(stack);
6197 
6198 			/* Report new value if we changed it */
6199 			if (changed && (gconf->flags & GUC_REPORT))
6200 				ReportGUCOption(gconf);
6201 		}						/* end of stack-popping loop */
6202 
6203 		if (stack != NULL)
6204 			still_dirty = true;
6205 	}
6206 
6207 	/* If there are no remaining stack entries, we can reset guc_dirty */
6208 	guc_dirty = still_dirty;
6209 
6210 	/* Update nesting level */
6211 	GUCNestLevel = nestLevel - 1;
6212 }
6213 
6214 
6215 /*
6216  * Start up automatic reporting of changes to variables marked GUC_REPORT.
6217  * This is executed at completion of backend startup.
6218  */
6219 void
BeginReportingGUCOptions(void)6220 BeginReportingGUCOptions(void)
6221 {
6222 	int			i;
6223 
6224 	/*
6225 	 * Don't do anything unless talking to an interactive frontend of protocol
6226 	 * 3.0 or later.
6227 	 */
6228 	if (whereToSendOutput != DestRemote ||
6229 		PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
6230 		return;
6231 
6232 	reporting_enabled = true;
6233 
6234 	/* Transmit initial values of interesting variables */
6235 	for (i = 0; i < num_guc_variables; i++)
6236 	{
6237 		struct config_generic *conf = guc_variables[i];
6238 
6239 		if (conf->flags & GUC_REPORT)
6240 			ReportGUCOption(conf);
6241 	}
6242 }
6243 
6244 /*
6245  * ReportGUCOption: if appropriate, transmit option value to frontend
6246  */
6247 static void
ReportGUCOption(struct config_generic * record)6248 ReportGUCOption(struct config_generic *record)
6249 {
6250 	if (reporting_enabled && (record->flags & GUC_REPORT))
6251 	{
6252 		char	   *val = _ShowOption(record, false);
6253 		StringInfoData msgbuf;
6254 
6255 		pq_beginmessage(&msgbuf, 'S');
6256 		pq_sendstring(&msgbuf, record->name);
6257 		pq_sendstring(&msgbuf, val);
6258 		pq_endmessage(&msgbuf);
6259 
6260 		pfree(val);
6261 	}
6262 }
6263 
6264 /*
6265  * Convert a value from one of the human-friendly units ("kB", "min" etc.)
6266  * to the given base unit.  'value' and 'unit' are the input value and unit
6267  * to convert from (there can be trailing spaces in the unit string).
6268  * The converted value is stored in *base_value.
6269  * It's caller's responsibility to round off the converted value as necessary
6270  * and check for out-of-range.
6271  *
6272  * Returns true on success, false if the input unit is not recognized.
6273  */
6274 static bool
convert_to_base_unit(double value,const char * unit,int base_unit,double * base_value)6275 convert_to_base_unit(double value, const char *unit,
6276 					 int base_unit, double *base_value)
6277 {
6278 	char		unitstr[MAX_UNIT_LEN + 1];
6279 	int			unitlen;
6280 	const unit_conversion *table;
6281 	int			i;
6282 
6283 	/* extract unit string to compare to table entries */
6284 	unitlen = 0;
6285 	while (*unit != '\0' && !isspace((unsigned char) *unit) &&
6286 		   unitlen < MAX_UNIT_LEN)
6287 		unitstr[unitlen++] = *(unit++);
6288 	unitstr[unitlen] = '\0';
6289 	/* allow whitespace after unit */
6290 	while (isspace((unsigned char) *unit))
6291 		unit++;
6292 	if (*unit != '\0')
6293 		return false;			/* unit too long, or garbage after it */
6294 
6295 	/* now search the appropriate table */
6296 	if (base_unit & GUC_UNIT_MEMORY)
6297 		table = memory_unit_conversion_table;
6298 	else
6299 		table = time_unit_conversion_table;
6300 
6301 	for (i = 0; *table[i].unit; i++)
6302 	{
6303 		if (base_unit == table[i].base_unit &&
6304 			strcmp(unitstr, table[i].unit) == 0)
6305 		{
6306 			double		cvalue = value * table[i].multiplier;
6307 
6308 			/*
6309 			 * If the user gave a fractional value such as "30.1GB", round it
6310 			 * off to the nearest multiple of the next smaller unit, if there
6311 			 * is one.
6312 			 */
6313 			if (*table[i + 1].unit &&
6314 				base_unit == table[i + 1].base_unit)
6315 				cvalue = rint(cvalue / table[i + 1].multiplier) *
6316 					table[i + 1].multiplier;
6317 
6318 			*base_value = cvalue;
6319 			return true;
6320 		}
6321 	}
6322 	return false;
6323 }
6324 
6325 /*
6326  * Convert an integer value in some base unit to a human-friendly unit.
6327  *
6328  * The output unit is chosen so that it's the greatest unit that can represent
6329  * the value without loss.  For example, if the base unit is GUC_UNIT_KB, 1024
6330  * is converted to 1 MB, but 1025 is represented as 1025 kB.
6331  */
6332 static void
convert_int_from_base_unit(int64 base_value,int base_unit,int64 * value,const char ** unit)6333 convert_int_from_base_unit(int64 base_value, int base_unit,
6334 						   int64 *value, const char **unit)
6335 {
6336 	const unit_conversion *table;
6337 	int			i;
6338 
6339 	*unit = NULL;
6340 
6341 	if (base_unit & GUC_UNIT_MEMORY)
6342 		table = memory_unit_conversion_table;
6343 	else
6344 		table = time_unit_conversion_table;
6345 
6346 	for (i = 0; *table[i].unit; i++)
6347 	{
6348 		if (base_unit == table[i].base_unit)
6349 		{
6350 			/*
6351 			 * Accept the first conversion that divides the value evenly.  We
6352 			 * assume that the conversions for each base unit are ordered from
6353 			 * greatest unit to the smallest!
6354 			 */
6355 			if (table[i].multiplier <= 1.0 ||
6356 				base_value % (int64) table[i].multiplier == 0)
6357 			{
6358 				*value = (int64) rint(base_value / table[i].multiplier);
6359 				*unit = table[i].unit;
6360 				break;
6361 			}
6362 		}
6363 	}
6364 
6365 	Assert(*unit != NULL);
6366 }
6367 
6368 /*
6369  * Convert a floating-point value in some base unit to a human-friendly unit.
6370  *
6371  * Same as above, except we have to do the math a bit differently, and
6372  * there's a possibility that we don't find any exact divisor.
6373  */
6374 static void
convert_real_from_base_unit(double base_value,int base_unit,double * value,const char ** unit)6375 convert_real_from_base_unit(double base_value, int base_unit,
6376 							double *value, const char **unit)
6377 {
6378 	const unit_conversion *table;
6379 	int			i;
6380 
6381 	*unit = NULL;
6382 
6383 	if (base_unit & GUC_UNIT_MEMORY)
6384 		table = memory_unit_conversion_table;
6385 	else
6386 		table = time_unit_conversion_table;
6387 
6388 	for (i = 0; *table[i].unit; i++)
6389 	{
6390 		if (base_unit == table[i].base_unit)
6391 		{
6392 			/*
6393 			 * Accept the first conversion that divides the value evenly; or
6394 			 * if there is none, use the smallest (last) target unit.
6395 			 *
6396 			 * What we actually care about here is whether snprintf with "%g"
6397 			 * will print the value as an integer, so the obvious test of
6398 			 * "*value == rint(*value)" is too strict; roundoff error might
6399 			 * make us choose an unreasonably small unit.  As a compromise,
6400 			 * accept a divisor that is within 1e-8 of producing an integer.
6401 			 */
6402 			*value = base_value / table[i].multiplier;
6403 			*unit = table[i].unit;
6404 			if (*value > 0 &&
6405 				fabs((rint(*value) / *value) - 1.0) <= 1e-8)
6406 				break;
6407 		}
6408 	}
6409 
6410 	Assert(*unit != NULL);
6411 }
6412 
6413 /*
6414  * Return the name of a GUC's base unit (e.g. "ms") given its flags.
6415  * Return NULL if the GUC is unitless.
6416  */
6417 static const char *
get_config_unit_name(int flags)6418 get_config_unit_name(int flags)
6419 {
6420 	switch (flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME))
6421 	{
6422 		case 0:
6423 			return NULL;		/* GUC has no units */
6424 		case GUC_UNIT_BYTE:
6425 			return "B";
6426 		case GUC_UNIT_KB:
6427 			return "kB";
6428 		case GUC_UNIT_MB:
6429 			return "MB";
6430 		case GUC_UNIT_BLOCKS:
6431 			{
6432 				static char bbuf[8];
6433 
6434 				/* initialize if first time through */
6435 				if (bbuf[0] == '\0')
6436 					snprintf(bbuf, sizeof(bbuf), "%dkB", BLCKSZ / 1024);
6437 				return bbuf;
6438 			}
6439 		case GUC_UNIT_XBLOCKS:
6440 			{
6441 				static char xbuf[8];
6442 
6443 				/* initialize if first time through */
6444 				if (xbuf[0] == '\0')
6445 					snprintf(xbuf, sizeof(xbuf), "%dkB", XLOG_BLCKSZ / 1024);
6446 				return xbuf;
6447 			}
6448 		case GUC_UNIT_MS:
6449 			return "ms";
6450 		case GUC_UNIT_S:
6451 			return "s";
6452 		case GUC_UNIT_MIN:
6453 			return "min";
6454 		default:
6455 			elog(ERROR, "unrecognized GUC units value: %d",
6456 				 flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME));
6457 			return NULL;
6458 	}
6459 }
6460 
6461 
6462 /*
6463  * Try to parse value as an integer.  The accepted formats are the
6464  * usual decimal, octal, or hexadecimal formats, as well as floating-point
6465  * formats (which will be rounded to integer after any units conversion).
6466  * Optionally, the value can be followed by a unit name if "flags" indicates
6467  * a unit is allowed.
6468  *
6469  * If the string parses okay, return true, else false.
6470  * If okay and result is not NULL, return the value in *result.
6471  * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable
6472  * HINT message, or NULL if no hint provided.
6473  */
6474 bool
parse_int(const char * value,int * result,int flags,const char ** hintmsg)6475 parse_int(const char *value, int *result, int flags, const char **hintmsg)
6476 {
6477 	/*
6478 	 * We assume here that double is wide enough to represent any integer
6479 	 * value with adequate precision.
6480 	 */
6481 	double		val;
6482 	char	   *endptr;
6483 
6484 	/* To suppress compiler warnings, always set output params */
6485 	if (result)
6486 		*result = 0;
6487 	if (hintmsg)
6488 		*hintmsg = NULL;
6489 
6490 	/*
6491 	 * Try to parse as an integer (allowing octal or hex input).  If the
6492 	 * conversion stops at a decimal point or 'e', or overflows, re-parse as
6493 	 * float.  This should work fine as long as we have no unit names starting
6494 	 * with 'e'.  If we ever do, the test could be extended to check for a
6495 	 * sign or digit after 'e', but for now that's unnecessary.
6496 	 */
6497 	errno = 0;
6498 	val = strtol(value, &endptr, 0);
6499 	if (*endptr == '.' || *endptr == 'e' || *endptr == 'E' ||
6500 		errno == ERANGE)
6501 	{
6502 		errno = 0;
6503 		val = strtod(value, &endptr);
6504 	}
6505 
6506 	if (endptr == value || errno == ERANGE)
6507 		return false;			/* no HINT for these cases */
6508 
6509 	/* reject NaN (infinities will fail range check below) */
6510 	if (isnan(val))
6511 		return false;			/* treat same as syntax error; no HINT */
6512 
6513 	/* allow whitespace between number and unit */
6514 	while (isspace((unsigned char) *endptr))
6515 		endptr++;
6516 
6517 	/* Handle possible unit */
6518 	if (*endptr != '\0')
6519 	{
6520 		if ((flags & GUC_UNIT) == 0)
6521 			return false;		/* this setting does not accept a unit */
6522 
6523 		if (!convert_to_base_unit(val,
6524 								  endptr, (flags & GUC_UNIT),
6525 								  &val))
6526 		{
6527 			/* invalid unit, or garbage after the unit; set hint and fail. */
6528 			if (hintmsg)
6529 			{
6530 				if (flags & GUC_UNIT_MEMORY)
6531 					*hintmsg = memory_units_hint;
6532 				else
6533 					*hintmsg = time_units_hint;
6534 			}
6535 			return false;
6536 		}
6537 	}
6538 
6539 	/* Round to int, then check for overflow */
6540 	val = rint(val);
6541 
6542 	if (val > INT_MAX || val < INT_MIN)
6543 	{
6544 		if (hintmsg)
6545 			*hintmsg = gettext_noop("Value exceeds integer range.");
6546 		return false;
6547 	}
6548 
6549 	if (result)
6550 		*result = (int) val;
6551 	return true;
6552 }
6553 
6554 /*
6555  * Try to parse value as a floating point number in the usual format.
6556  * Optionally, the value can be followed by a unit name if "flags" indicates
6557  * a unit is allowed.
6558  *
6559  * If the string parses okay, return true, else false.
6560  * If okay and result is not NULL, return the value in *result.
6561  * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable
6562  * HINT message, or NULL if no hint provided.
6563  */
6564 bool
parse_real(const char * value,double * result,int flags,const char ** hintmsg)6565 parse_real(const char *value, double *result, int flags, const char **hintmsg)
6566 {
6567 	double		val;
6568 	char	   *endptr;
6569 
6570 	/* To suppress compiler warnings, always set output params */
6571 	if (result)
6572 		*result = 0;
6573 	if (hintmsg)
6574 		*hintmsg = NULL;
6575 
6576 	errno = 0;
6577 	val = strtod(value, &endptr);
6578 
6579 	if (endptr == value || errno == ERANGE)
6580 		return false;			/* no HINT for these cases */
6581 
6582 	/* reject NaN (infinities will fail range checks later) */
6583 	if (isnan(val))
6584 		return false;			/* treat same as syntax error; no HINT */
6585 
6586 	/* allow whitespace between number and unit */
6587 	while (isspace((unsigned char) *endptr))
6588 		endptr++;
6589 
6590 	/* Handle possible unit */
6591 	if (*endptr != '\0')
6592 	{
6593 		if ((flags & GUC_UNIT) == 0)
6594 			return false;		/* this setting does not accept a unit */
6595 
6596 		if (!convert_to_base_unit(val,
6597 								  endptr, (flags & GUC_UNIT),
6598 								  &val))
6599 		{
6600 			/* invalid unit, or garbage after the unit; set hint and fail. */
6601 			if (hintmsg)
6602 			{
6603 				if (flags & GUC_UNIT_MEMORY)
6604 					*hintmsg = memory_units_hint;
6605 				else
6606 					*hintmsg = time_units_hint;
6607 			}
6608 			return false;
6609 		}
6610 	}
6611 
6612 	if (result)
6613 		*result = val;
6614 	return true;
6615 }
6616 
6617 
6618 /*
6619  * Lookup the name for an enum option with the selected value.
6620  * Should only ever be called with known-valid values, so throws
6621  * an elog(ERROR) if the enum option is not found.
6622  *
6623  * The returned string is a pointer to static data and not
6624  * allocated for modification.
6625  */
6626 const char *
config_enum_lookup_by_value(struct config_enum * record,int val)6627 config_enum_lookup_by_value(struct config_enum *record, int val)
6628 {
6629 	const struct config_enum_entry *entry;
6630 
6631 	for (entry = record->options; entry && entry->name; entry++)
6632 	{
6633 		if (entry->val == val)
6634 			return entry->name;
6635 	}
6636 
6637 	elog(ERROR, "could not find enum option %d for %s",
6638 		 val, record->gen.name);
6639 	return NULL;				/* silence compiler */
6640 }
6641 
6642 
6643 /*
6644  * Lookup the value for an enum option with the selected name
6645  * (case-insensitive).
6646  * If the enum option is found, sets the retval value and returns
6647  * true. If it's not found, return false and retval is set to 0.
6648  */
6649 bool
config_enum_lookup_by_name(struct config_enum * record,const char * value,int * retval)6650 config_enum_lookup_by_name(struct config_enum *record, const char *value,
6651 						   int *retval)
6652 {
6653 	const struct config_enum_entry *entry;
6654 
6655 	for (entry = record->options; entry && entry->name; entry++)
6656 	{
6657 		if (pg_strcasecmp(value, entry->name) == 0)
6658 		{
6659 			*retval = entry->val;
6660 			return true;
6661 		}
6662 	}
6663 
6664 	*retval = 0;
6665 	return false;
6666 }
6667 
6668 
6669 /*
6670  * Return a list of all available options for an enum, excluding
6671  * hidden ones, separated by the given separator.
6672  * If prefix is non-NULL, it is added before the first enum value.
6673  * If suffix is non-NULL, it is added to the end of the string.
6674  */
6675 static char *
config_enum_get_options(struct config_enum * record,const char * prefix,const char * suffix,const char * separator)6676 config_enum_get_options(struct config_enum *record, const char *prefix,
6677 						const char *suffix, const char *separator)
6678 {
6679 	const struct config_enum_entry *entry;
6680 	StringInfoData retstr;
6681 	int			seplen;
6682 
6683 	initStringInfo(&retstr);
6684 	appendStringInfoString(&retstr, prefix);
6685 
6686 	seplen = strlen(separator);
6687 	for (entry = record->options; entry && entry->name; entry++)
6688 	{
6689 		if (!entry->hidden)
6690 		{
6691 			appendStringInfoString(&retstr, entry->name);
6692 			appendBinaryStringInfo(&retstr, separator, seplen);
6693 		}
6694 	}
6695 
6696 	/*
6697 	 * All the entries may have been hidden, leaving the string empty if no
6698 	 * prefix was given. This indicates a broken GUC setup, since there is no
6699 	 * use for an enum without any values, so we just check to make sure we
6700 	 * don't write to invalid memory instead of actually trying to do
6701 	 * something smart with it.
6702 	 */
6703 	if (retstr.len >= seplen)
6704 	{
6705 		/* Replace final separator */
6706 		retstr.data[retstr.len - seplen] = '\0';
6707 		retstr.len -= seplen;
6708 	}
6709 
6710 	appendStringInfoString(&retstr, suffix);
6711 
6712 	return retstr.data;
6713 }
6714 
6715 /*
6716  * Parse and validate a proposed value for the specified configuration
6717  * parameter.
6718  *
6719  * This does built-in checks (such as range limits for an integer parameter)
6720  * and also calls any check hook the parameter may have.
6721  *
6722  * record: GUC variable's info record
6723  * name: variable name (should match the record of course)
6724  * value: proposed value, as a string
6725  * source: identifies source of value (check hooks may need this)
6726  * elevel: level to log any error reports at
6727  * newval: on success, converted parameter value is returned here
6728  * newextra: on success, receives any "extra" data returned by check hook
6729  *	(caller must initialize *newextra to NULL)
6730  *
6731  * Returns true if OK, false if not (or throws error, if elevel >= ERROR)
6732  */
6733 static bool
parse_and_validate_value(struct config_generic * record,const char * name,const char * value,GucSource source,int elevel,union config_var_val * newval,void ** newextra)6734 parse_and_validate_value(struct config_generic *record,
6735 						 const char *name, const char *value,
6736 						 GucSource source, int elevel,
6737 						 union config_var_val *newval, void **newextra)
6738 {
6739 	switch (record->vartype)
6740 	{
6741 		case PGC_BOOL:
6742 			{
6743 				struct config_bool *conf = (struct config_bool *) record;
6744 
6745 				if (!parse_bool(value, &newval->boolval))
6746 				{
6747 					ereport(elevel,
6748 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6749 							 errmsg("parameter \"%s\" requires a Boolean value",
6750 									name)));
6751 					return false;
6752 				}
6753 
6754 				if (!call_bool_check_hook(conf, &newval->boolval, newextra,
6755 										  source, elevel))
6756 					return false;
6757 			}
6758 			break;
6759 		case PGC_INT:
6760 			{
6761 				struct config_int *conf = (struct config_int *) record;
6762 				const char *hintmsg;
6763 
6764 				if (!parse_int(value, &newval->intval,
6765 							   conf->gen.flags, &hintmsg))
6766 				{
6767 					ereport(elevel,
6768 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6769 							 errmsg("invalid value for parameter \"%s\": \"%s\"",
6770 									name, value),
6771 							 hintmsg ? errhint("%s", _(hintmsg)) : 0));
6772 					return false;
6773 				}
6774 
6775 				if (newval->intval < conf->min || newval->intval > conf->max)
6776 				{
6777 					const char *unit = get_config_unit_name(conf->gen.flags);
6778 
6779 					ereport(elevel,
6780 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6781 							 errmsg("%d%s%s is outside the valid range for parameter \"%s\" (%d .. %d)",
6782 									newval->intval,
6783 									unit ? " " : "",
6784 									unit ? unit : "",
6785 									name,
6786 									conf->min, conf->max)));
6787 					return false;
6788 				}
6789 
6790 				if (!call_int_check_hook(conf, &newval->intval, newextra,
6791 										 source, elevel))
6792 					return false;
6793 			}
6794 			break;
6795 		case PGC_REAL:
6796 			{
6797 				struct config_real *conf = (struct config_real *) record;
6798 				const char *hintmsg;
6799 
6800 				if (!parse_real(value, &newval->realval,
6801 								conf->gen.flags, &hintmsg))
6802 				{
6803 					ereport(elevel,
6804 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6805 							 errmsg("invalid value for parameter \"%s\": \"%s\"",
6806 									name, value),
6807 							 hintmsg ? errhint("%s", _(hintmsg)) : 0));
6808 					return false;
6809 				}
6810 
6811 				if (newval->realval < conf->min || newval->realval > conf->max)
6812 				{
6813 					const char *unit = get_config_unit_name(conf->gen.flags);
6814 
6815 					ereport(elevel,
6816 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6817 							 errmsg("%g%s%s is outside the valid range for parameter \"%s\" (%g .. %g)",
6818 									newval->realval,
6819 									unit ? " " : "",
6820 									unit ? unit : "",
6821 									name,
6822 									conf->min, conf->max)));
6823 					return false;
6824 				}
6825 
6826 				if (!call_real_check_hook(conf, &newval->realval, newextra,
6827 										  source, elevel))
6828 					return false;
6829 			}
6830 			break;
6831 		case PGC_STRING:
6832 			{
6833 				struct config_string *conf = (struct config_string *) record;
6834 
6835 				/*
6836 				 * The value passed by the caller could be transient, so we
6837 				 * always strdup it.
6838 				 */
6839 				newval->stringval = guc_strdup(elevel, value);
6840 				if (newval->stringval == NULL)
6841 					return false;
6842 
6843 				/*
6844 				 * The only built-in "parsing" check we have is to apply
6845 				 * truncation if GUC_IS_NAME.
6846 				 */
6847 				if (conf->gen.flags & GUC_IS_NAME)
6848 					truncate_identifier(newval->stringval,
6849 										strlen(newval->stringval),
6850 										true);
6851 
6852 				if (!call_string_check_hook(conf, &newval->stringval, newextra,
6853 											source, elevel))
6854 				{
6855 					free(newval->stringval);
6856 					newval->stringval = NULL;
6857 					return false;
6858 				}
6859 			}
6860 			break;
6861 		case PGC_ENUM:
6862 			{
6863 				struct config_enum *conf = (struct config_enum *) record;
6864 
6865 				if (!config_enum_lookup_by_name(conf, value, &newval->enumval))
6866 				{
6867 					char	   *hintmsg;
6868 
6869 					hintmsg = config_enum_get_options(conf,
6870 													  "Available values: ",
6871 													  ".", ", ");
6872 
6873 					ereport(elevel,
6874 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6875 							 errmsg("invalid value for parameter \"%s\": \"%s\"",
6876 									name, value),
6877 							 hintmsg ? errhint("%s", _(hintmsg)) : 0));
6878 
6879 					if (hintmsg)
6880 						pfree(hintmsg);
6881 					return false;
6882 				}
6883 
6884 				if (!call_enum_check_hook(conf, &newval->enumval, newextra,
6885 										  source, elevel))
6886 					return false;
6887 			}
6888 			break;
6889 	}
6890 
6891 	return true;
6892 }
6893 
6894 
6895 /*
6896  * Sets option `name' to given value.
6897  *
6898  * The value should be a string, which will be parsed and converted to
6899  * the appropriate data type.  The context and source parameters indicate
6900  * in which context this function is being called, so that it can apply the
6901  * access restrictions properly.
6902  *
6903  * If value is NULL, set the option to its default value (normally the
6904  * reset_val, but if source == PGC_S_DEFAULT we instead use the boot_val).
6905  *
6906  * action indicates whether to set the value globally in the session, locally
6907  * to the current top transaction, or just for the duration of a function call.
6908  *
6909  * If changeVal is false then don't really set the option but do all
6910  * the checks to see if it would work.
6911  *
6912  * elevel should normally be passed as zero, allowing this function to make
6913  * its standard choice of ereport level.  However some callers need to be
6914  * able to override that choice; they should pass the ereport level to use.
6915  *
6916  * Return value:
6917  *	+1: the value is valid and was successfully applied.
6918  *	0:	the name or value is invalid (but see below).
6919  *	-1: the value was not applied because of context, priority, or changeVal.
6920  *
6921  * If there is an error (non-existing option, invalid value) then an
6922  * ereport(ERROR) is thrown *unless* this is called for a source for which
6923  * we don't want an ERROR (currently, those are defaults, the config file,
6924  * and per-database or per-user settings, as well as callers who specify
6925  * a less-than-ERROR elevel).  In those cases we write a suitable error
6926  * message via ereport() and return 0.
6927  *
6928  * See also SetConfigOption for an external interface.
6929  */
6930 int
set_config_option(const char * name,const char * value,GucContext context,GucSource source,GucAction action,bool changeVal,int elevel,bool is_reload)6931 set_config_option(const char *name, const char *value,
6932 				  GucContext context, GucSource source,
6933 				  GucAction action, bool changeVal, int elevel,
6934 				  bool is_reload)
6935 {
6936 	struct config_generic *record;
6937 	union config_var_val newval_union;
6938 	void	   *newextra = NULL;
6939 	bool		prohibitValueChange = false;
6940 	bool		makeDefault;
6941 
6942 	if (elevel == 0)
6943 	{
6944 		if (source == PGC_S_DEFAULT || source == PGC_S_FILE)
6945 		{
6946 			/*
6947 			 * To avoid cluttering the log, only the postmaster bleats loudly
6948 			 * about problems with the config file.
6949 			 */
6950 			elevel = IsUnderPostmaster ? DEBUG3 : LOG;
6951 		}
6952 		else if (source == PGC_S_GLOBAL ||
6953 				 source == PGC_S_DATABASE ||
6954 				 source == PGC_S_USER ||
6955 				 source == PGC_S_DATABASE_USER)
6956 			elevel = WARNING;
6957 		else
6958 			elevel = ERROR;
6959 	}
6960 
6961 	/*
6962 	 * GUC_ACTION_SAVE changes are acceptable during a parallel operation,
6963 	 * because the current worker will also pop the change.  We're probably
6964 	 * dealing with a function having a proconfig entry.  Only the function's
6965 	 * body should observe the change, and peer workers do not share in the
6966 	 * execution of a function call started by this worker.
6967 	 *
6968 	 * Other changes might need to affect other workers, so forbid them.
6969 	 */
6970 	if (IsInParallelMode() && changeVal && action != GUC_ACTION_SAVE)
6971 		ereport(elevel,
6972 				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
6973 				 errmsg("cannot set parameters during a parallel operation")));
6974 
6975 	record = find_option(name, true, elevel);
6976 	if (record == NULL)
6977 	{
6978 		ereport(elevel,
6979 				(errcode(ERRCODE_UNDEFINED_OBJECT),
6980 				 errmsg("unrecognized configuration parameter \"%s\"", name)));
6981 		return 0;
6982 	}
6983 
6984 	/*
6985 	 * Check if the option can be set at this time. See guc.h for the precise
6986 	 * rules.
6987 	 */
6988 	switch (record->context)
6989 	{
6990 		case PGC_INTERNAL:
6991 			if (context != PGC_INTERNAL)
6992 			{
6993 				ereport(elevel,
6994 						(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
6995 						 errmsg("parameter \"%s\" cannot be changed",
6996 								name)));
6997 				return 0;
6998 			}
6999 			break;
7000 		case PGC_POSTMASTER:
7001 			if (context == PGC_SIGHUP)
7002 			{
7003 				/*
7004 				 * We are re-reading a PGC_POSTMASTER variable from
7005 				 * postgresql.conf.  We can't change the setting, so we should
7006 				 * give a warning if the DBA tries to change it.  However,
7007 				 * because of variant formats, canonicalization by check
7008 				 * hooks, etc, we can't just compare the given string directly
7009 				 * to what's stored.  Set a flag to check below after we have
7010 				 * the final storable value.
7011 				 */
7012 				prohibitValueChange = true;
7013 			}
7014 			else if (context != PGC_POSTMASTER)
7015 			{
7016 				ereport(elevel,
7017 						(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7018 						 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7019 								name)));
7020 				return 0;
7021 			}
7022 			break;
7023 		case PGC_SIGHUP:
7024 			if (context != PGC_SIGHUP && context != PGC_POSTMASTER)
7025 			{
7026 				ereport(elevel,
7027 						(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7028 						 errmsg("parameter \"%s\" cannot be changed now",
7029 								name)));
7030 				return 0;
7031 			}
7032 
7033 			/*
7034 			 * Hmm, the idea of the SIGHUP context is "ought to be global, but
7035 			 * can be changed after postmaster start". But there's nothing
7036 			 * that prevents a crafty administrator from sending SIGHUP
7037 			 * signals to individual backends only.
7038 			 */
7039 			break;
7040 		case PGC_SU_BACKEND:
7041 			/* Reject if we're connecting but user is not superuser */
7042 			if (context == PGC_BACKEND)
7043 			{
7044 				ereport(elevel,
7045 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7046 						 errmsg("permission denied to set parameter \"%s\"",
7047 								name)));
7048 				return 0;
7049 			}
7050 			/* fall through to process the same as PGC_BACKEND */
7051 			/* FALLTHROUGH */
7052 		case PGC_BACKEND:
7053 			if (context == PGC_SIGHUP)
7054 			{
7055 				/*
7056 				 * If a PGC_BACKEND or PGC_SU_BACKEND parameter is changed in
7057 				 * the config file, we want to accept the new value in the
7058 				 * postmaster (whence it will propagate to
7059 				 * subsequently-started backends), but ignore it in existing
7060 				 * backends.  This is a tad klugy, but necessary because we
7061 				 * don't re-read the config file during backend start.
7062 				 *
7063 				 * In EXEC_BACKEND builds, this works differently: we load all
7064 				 * non-default settings from the CONFIG_EXEC_PARAMS file
7065 				 * during backend start.  In that case we must accept
7066 				 * PGC_SIGHUP settings, so as to have the same value as if
7067 				 * we'd forked from the postmaster.  This can also happen when
7068 				 * using RestoreGUCState() within a background worker that
7069 				 * needs to have the same settings as the user backend that
7070 				 * started it. is_reload will be true when either situation
7071 				 * applies.
7072 				 */
7073 				if (IsUnderPostmaster && !is_reload)
7074 					return -1;
7075 			}
7076 			else if (context != PGC_POSTMASTER &&
7077 					 context != PGC_BACKEND &&
7078 					 context != PGC_SU_BACKEND &&
7079 					 source != PGC_S_CLIENT)
7080 			{
7081 				ereport(elevel,
7082 						(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7083 						 errmsg("parameter \"%s\" cannot be set after connection start",
7084 								name)));
7085 				return 0;
7086 			}
7087 			break;
7088 		case PGC_SUSET:
7089 			if (context == PGC_USERSET || context == PGC_BACKEND)
7090 			{
7091 				ereport(elevel,
7092 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7093 						 errmsg("permission denied to set parameter \"%s\"",
7094 								name)));
7095 				return 0;
7096 			}
7097 			break;
7098 		case PGC_USERSET:
7099 			/* always okay */
7100 			break;
7101 	}
7102 
7103 	/*
7104 	 * Disallow changing GUC_NOT_WHILE_SEC_REST values if we are inside a
7105 	 * security restriction context.  We can reject this regardless of the GUC
7106 	 * context or source, mainly because sources that it might be reasonable
7107 	 * to override for won't be seen while inside a function.
7108 	 *
7109 	 * Note: variables marked GUC_NOT_WHILE_SEC_REST should usually be marked
7110 	 * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this.
7111 	 * An exception might be made if the reset value is assumed to be "safe".
7112 	 *
7113 	 * Note: this flag is currently used for "session_authorization" and
7114 	 * "role".  We need to prohibit changing these inside a local userid
7115 	 * context because when we exit it, GUC won't be notified, leaving things
7116 	 * out of sync.  (This could be fixed by forcing a new GUC nesting level,
7117 	 * but that would change behavior in possibly-undesirable ways.)  Also, we
7118 	 * prohibit changing these in a security-restricted operation because
7119 	 * otherwise RESET could be used to regain the session user's privileges.
7120 	 */
7121 	if (record->flags & GUC_NOT_WHILE_SEC_REST)
7122 	{
7123 		if (InLocalUserIdChange())
7124 		{
7125 			/*
7126 			 * Phrasing of this error message is historical, but it's the most
7127 			 * common case.
7128 			 */
7129 			ereport(elevel,
7130 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7131 					 errmsg("cannot set parameter \"%s\" within security-definer function",
7132 							name)));
7133 			return 0;
7134 		}
7135 		if (InSecurityRestrictedOperation())
7136 		{
7137 			ereport(elevel,
7138 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7139 					 errmsg("cannot set parameter \"%s\" within security-restricted operation",
7140 							name)));
7141 			return 0;
7142 		}
7143 	}
7144 
7145 	/*
7146 	 * Should we set reset/stacked values?	(If so, the behavior is not
7147 	 * transactional.)	This is done either when we get a default value from
7148 	 * the database's/user's/client's default settings or when we reset a
7149 	 * value to its default.
7150 	 */
7151 	makeDefault = changeVal && (source <= PGC_S_OVERRIDE) &&
7152 		((value != NULL) || source == PGC_S_DEFAULT);
7153 
7154 	/*
7155 	 * Ignore attempted set if overridden by previously processed setting.
7156 	 * However, if changeVal is false then plow ahead anyway since we are
7157 	 * trying to find out if the value is potentially good, not actually use
7158 	 * it. Also keep going if makeDefault is true, since we may want to set
7159 	 * the reset/stacked values even if we can't set the variable itself.
7160 	 */
7161 	if (record->source > source)
7162 	{
7163 		if (changeVal && !makeDefault)
7164 		{
7165 			elog(DEBUG3, "\"%s\": setting ignored because previous source is higher priority",
7166 				 name);
7167 			return -1;
7168 		}
7169 		changeVal = false;
7170 	}
7171 
7172 	/*
7173 	 * Evaluate value and set variable.
7174 	 */
7175 	switch (record->vartype)
7176 	{
7177 		case PGC_BOOL:
7178 			{
7179 				struct config_bool *conf = (struct config_bool *) record;
7180 
7181 #define newval (newval_union.boolval)
7182 
7183 				if (value)
7184 				{
7185 					if (!parse_and_validate_value(record, name, value,
7186 												  source, elevel,
7187 												  &newval_union, &newextra))
7188 						return 0;
7189 				}
7190 				else if (source == PGC_S_DEFAULT)
7191 				{
7192 					newval = conf->boot_val;
7193 					if (!call_bool_check_hook(conf, &newval, &newextra,
7194 											  source, elevel))
7195 						return 0;
7196 				}
7197 				else
7198 				{
7199 					newval = conf->reset_val;
7200 					newextra = conf->reset_extra;
7201 					source = conf->gen.reset_source;
7202 					context = conf->gen.reset_scontext;
7203 				}
7204 
7205 				if (prohibitValueChange)
7206 				{
7207 					/* Release newextra, unless it's reset_extra */
7208 					if (newextra && !extra_field_used(&conf->gen, newextra))
7209 						free(newextra);
7210 
7211 					if (*conf->variable != newval)
7212 					{
7213 						record->status |= GUC_PENDING_RESTART;
7214 						ereport(elevel,
7215 								(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7216 								 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7217 										name)));
7218 						return 0;
7219 					}
7220 					record->status &= ~GUC_PENDING_RESTART;
7221 					return -1;
7222 				}
7223 
7224 				if (changeVal)
7225 				{
7226 					/* Save old value to support transaction abort */
7227 					if (!makeDefault)
7228 						push_old_value(&conf->gen, action);
7229 
7230 					if (conf->assign_hook)
7231 						conf->assign_hook(newval, newextra);
7232 					*conf->variable = newval;
7233 					set_extra_field(&conf->gen, &conf->gen.extra,
7234 									newextra);
7235 					conf->gen.source = source;
7236 					conf->gen.scontext = context;
7237 				}
7238 				if (makeDefault)
7239 				{
7240 					GucStack   *stack;
7241 
7242 					if (conf->gen.reset_source <= source)
7243 					{
7244 						conf->reset_val = newval;
7245 						set_extra_field(&conf->gen, &conf->reset_extra,
7246 										newextra);
7247 						conf->gen.reset_source = source;
7248 						conf->gen.reset_scontext = context;
7249 					}
7250 					for (stack = conf->gen.stack; stack; stack = stack->prev)
7251 					{
7252 						if (stack->source <= source)
7253 						{
7254 							stack->prior.val.boolval = newval;
7255 							set_extra_field(&conf->gen, &stack->prior.extra,
7256 											newextra);
7257 							stack->source = source;
7258 							stack->scontext = context;
7259 						}
7260 					}
7261 				}
7262 
7263 				/* Perhaps we didn't install newextra anywhere */
7264 				if (newextra && !extra_field_used(&conf->gen, newextra))
7265 					free(newextra);
7266 				break;
7267 
7268 #undef newval
7269 			}
7270 
7271 		case PGC_INT:
7272 			{
7273 				struct config_int *conf = (struct config_int *) record;
7274 
7275 #define newval (newval_union.intval)
7276 
7277 				if (value)
7278 				{
7279 					if (!parse_and_validate_value(record, name, value,
7280 												  source, elevel,
7281 												  &newval_union, &newextra))
7282 						return 0;
7283 				}
7284 				else if (source == PGC_S_DEFAULT)
7285 				{
7286 					newval = conf->boot_val;
7287 					if (!call_int_check_hook(conf, &newval, &newextra,
7288 											 source, elevel))
7289 						return 0;
7290 				}
7291 				else
7292 				{
7293 					newval = conf->reset_val;
7294 					newextra = conf->reset_extra;
7295 					source = conf->gen.reset_source;
7296 					context = conf->gen.reset_scontext;
7297 				}
7298 
7299 				if (prohibitValueChange)
7300 				{
7301 					/* Release newextra, unless it's reset_extra */
7302 					if (newextra && !extra_field_used(&conf->gen, newextra))
7303 						free(newextra);
7304 
7305 					if (*conf->variable != newval)
7306 					{
7307 						record->status |= GUC_PENDING_RESTART;
7308 						ereport(elevel,
7309 								(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7310 								 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7311 										name)));
7312 						return 0;
7313 					}
7314 					record->status &= ~GUC_PENDING_RESTART;
7315 					return -1;
7316 				}
7317 
7318 				if (changeVal)
7319 				{
7320 					/* Save old value to support transaction abort */
7321 					if (!makeDefault)
7322 						push_old_value(&conf->gen, action);
7323 
7324 					if (conf->assign_hook)
7325 						conf->assign_hook(newval, newextra);
7326 					*conf->variable = newval;
7327 					set_extra_field(&conf->gen, &conf->gen.extra,
7328 									newextra);
7329 					conf->gen.source = source;
7330 					conf->gen.scontext = context;
7331 				}
7332 				if (makeDefault)
7333 				{
7334 					GucStack   *stack;
7335 
7336 					if (conf->gen.reset_source <= source)
7337 					{
7338 						conf->reset_val = newval;
7339 						set_extra_field(&conf->gen, &conf->reset_extra,
7340 										newextra);
7341 						conf->gen.reset_source = source;
7342 						conf->gen.reset_scontext = context;
7343 					}
7344 					for (stack = conf->gen.stack; stack; stack = stack->prev)
7345 					{
7346 						if (stack->source <= source)
7347 						{
7348 							stack->prior.val.intval = newval;
7349 							set_extra_field(&conf->gen, &stack->prior.extra,
7350 											newextra);
7351 							stack->source = source;
7352 							stack->scontext = context;
7353 						}
7354 					}
7355 				}
7356 
7357 				/* Perhaps we didn't install newextra anywhere */
7358 				if (newextra && !extra_field_used(&conf->gen, newextra))
7359 					free(newextra);
7360 				break;
7361 
7362 #undef newval
7363 			}
7364 
7365 		case PGC_REAL:
7366 			{
7367 				struct config_real *conf = (struct config_real *) record;
7368 
7369 #define newval (newval_union.realval)
7370 
7371 				if (value)
7372 				{
7373 					if (!parse_and_validate_value(record, name, value,
7374 												  source, elevel,
7375 												  &newval_union, &newextra))
7376 						return 0;
7377 				}
7378 				else if (source == PGC_S_DEFAULT)
7379 				{
7380 					newval = conf->boot_val;
7381 					if (!call_real_check_hook(conf, &newval, &newextra,
7382 											  source, elevel))
7383 						return 0;
7384 				}
7385 				else
7386 				{
7387 					newval = conf->reset_val;
7388 					newextra = conf->reset_extra;
7389 					source = conf->gen.reset_source;
7390 					context = conf->gen.reset_scontext;
7391 				}
7392 
7393 				if (prohibitValueChange)
7394 				{
7395 					/* Release newextra, unless it's reset_extra */
7396 					if (newextra && !extra_field_used(&conf->gen, newextra))
7397 						free(newextra);
7398 
7399 					if (*conf->variable != newval)
7400 					{
7401 						record->status |= GUC_PENDING_RESTART;
7402 						ereport(elevel,
7403 								(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7404 								 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7405 										name)));
7406 						return 0;
7407 					}
7408 					record->status &= ~GUC_PENDING_RESTART;
7409 					return -1;
7410 				}
7411 
7412 				if (changeVal)
7413 				{
7414 					/* Save old value to support transaction abort */
7415 					if (!makeDefault)
7416 						push_old_value(&conf->gen, action);
7417 
7418 					if (conf->assign_hook)
7419 						conf->assign_hook(newval, newextra);
7420 					*conf->variable = newval;
7421 					set_extra_field(&conf->gen, &conf->gen.extra,
7422 									newextra);
7423 					conf->gen.source = source;
7424 					conf->gen.scontext = context;
7425 				}
7426 				if (makeDefault)
7427 				{
7428 					GucStack   *stack;
7429 
7430 					if (conf->gen.reset_source <= source)
7431 					{
7432 						conf->reset_val = newval;
7433 						set_extra_field(&conf->gen, &conf->reset_extra,
7434 										newextra);
7435 						conf->gen.reset_source = source;
7436 						conf->gen.reset_scontext = context;
7437 					}
7438 					for (stack = conf->gen.stack; stack; stack = stack->prev)
7439 					{
7440 						if (stack->source <= source)
7441 						{
7442 							stack->prior.val.realval = newval;
7443 							set_extra_field(&conf->gen, &stack->prior.extra,
7444 											newextra);
7445 							stack->source = source;
7446 							stack->scontext = context;
7447 						}
7448 					}
7449 				}
7450 
7451 				/* Perhaps we didn't install newextra anywhere */
7452 				if (newextra && !extra_field_used(&conf->gen, newextra))
7453 					free(newextra);
7454 				break;
7455 
7456 #undef newval
7457 			}
7458 
7459 		case PGC_STRING:
7460 			{
7461 				struct config_string *conf = (struct config_string *) record;
7462 
7463 #define newval (newval_union.stringval)
7464 
7465 				if (value)
7466 				{
7467 					if (!parse_and_validate_value(record, name, value,
7468 												  source, elevel,
7469 												  &newval_union, &newextra))
7470 						return 0;
7471 				}
7472 				else if (source == PGC_S_DEFAULT)
7473 				{
7474 					/* non-NULL boot_val must always get strdup'd */
7475 					if (conf->boot_val != NULL)
7476 					{
7477 						newval = guc_strdup(elevel, conf->boot_val);
7478 						if (newval == NULL)
7479 							return 0;
7480 					}
7481 					else
7482 						newval = NULL;
7483 
7484 					if (!call_string_check_hook(conf, &newval, &newextra,
7485 												source, elevel))
7486 					{
7487 						free(newval);
7488 						return 0;
7489 					}
7490 				}
7491 				else
7492 				{
7493 					/*
7494 					 * strdup not needed, since reset_val is already under
7495 					 * guc.c's control
7496 					 */
7497 					newval = conf->reset_val;
7498 					newextra = conf->reset_extra;
7499 					source = conf->gen.reset_source;
7500 					context = conf->gen.reset_scontext;
7501 				}
7502 
7503 				if (prohibitValueChange)
7504 				{
7505 					bool		newval_different;
7506 
7507 					/* newval shouldn't be NULL, so we're a bit sloppy here */
7508 					newval_different = (*conf->variable == NULL ||
7509 										newval == NULL ||
7510 										strcmp(*conf->variable, newval) != 0);
7511 
7512 					/* Release newval, unless it's reset_val */
7513 					if (newval && !string_field_used(conf, newval))
7514 						free(newval);
7515 					/* Release newextra, unless it's reset_extra */
7516 					if (newextra && !extra_field_used(&conf->gen, newextra))
7517 						free(newextra);
7518 
7519 					if (newval_different)
7520 					{
7521 						record->status |= GUC_PENDING_RESTART;
7522 						ereport(elevel,
7523 								(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7524 								 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7525 										name)));
7526 						return 0;
7527 					}
7528 					record->status &= ~GUC_PENDING_RESTART;
7529 					return -1;
7530 				}
7531 
7532 				if (changeVal)
7533 				{
7534 					/* Save old value to support transaction abort */
7535 					if (!makeDefault)
7536 						push_old_value(&conf->gen, action);
7537 
7538 					if (conf->assign_hook)
7539 						conf->assign_hook(newval, newextra);
7540 					set_string_field(conf, conf->variable, newval);
7541 					set_extra_field(&conf->gen, &conf->gen.extra,
7542 									newextra);
7543 					conf->gen.source = source;
7544 					conf->gen.scontext = context;
7545 				}
7546 
7547 				if (makeDefault)
7548 				{
7549 					GucStack   *stack;
7550 
7551 					if (conf->gen.reset_source <= source)
7552 					{
7553 						set_string_field(conf, &conf->reset_val, newval);
7554 						set_extra_field(&conf->gen, &conf->reset_extra,
7555 										newextra);
7556 						conf->gen.reset_source = source;
7557 						conf->gen.reset_scontext = context;
7558 					}
7559 					for (stack = conf->gen.stack; stack; stack = stack->prev)
7560 					{
7561 						if (stack->source <= source)
7562 						{
7563 							set_string_field(conf, &stack->prior.val.stringval,
7564 											 newval);
7565 							set_extra_field(&conf->gen, &stack->prior.extra,
7566 											newextra);
7567 							stack->source = source;
7568 							stack->scontext = context;
7569 						}
7570 					}
7571 				}
7572 
7573 				/* Perhaps we didn't install newval anywhere */
7574 				if (newval && !string_field_used(conf, newval))
7575 					free(newval);
7576 				/* Perhaps we didn't install newextra anywhere */
7577 				if (newextra && !extra_field_used(&conf->gen, newextra))
7578 					free(newextra);
7579 				break;
7580 
7581 #undef newval
7582 			}
7583 
7584 		case PGC_ENUM:
7585 			{
7586 				struct config_enum *conf = (struct config_enum *) record;
7587 
7588 #define newval (newval_union.enumval)
7589 
7590 				if (value)
7591 				{
7592 					if (!parse_and_validate_value(record, name, value,
7593 												  source, elevel,
7594 												  &newval_union, &newextra))
7595 						return 0;
7596 				}
7597 				else if (source == PGC_S_DEFAULT)
7598 				{
7599 					newval = conf->boot_val;
7600 					if (!call_enum_check_hook(conf, &newval, &newextra,
7601 											  source, elevel))
7602 						return 0;
7603 				}
7604 				else
7605 				{
7606 					newval = conf->reset_val;
7607 					newextra = conf->reset_extra;
7608 					source = conf->gen.reset_source;
7609 					context = conf->gen.reset_scontext;
7610 				}
7611 
7612 				if (prohibitValueChange)
7613 				{
7614 					/* Release newextra, unless it's reset_extra */
7615 					if (newextra && !extra_field_used(&conf->gen, newextra))
7616 						free(newextra);
7617 
7618 					if (*conf->variable != newval)
7619 					{
7620 						record->status |= GUC_PENDING_RESTART;
7621 						ereport(elevel,
7622 								(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
7623 								 errmsg("parameter \"%s\" cannot be changed without restarting the server",
7624 										name)));
7625 						return 0;
7626 					}
7627 					record->status &= ~GUC_PENDING_RESTART;
7628 					return -1;
7629 				}
7630 
7631 				if (changeVal)
7632 				{
7633 					/* Save old value to support transaction abort */
7634 					if (!makeDefault)
7635 						push_old_value(&conf->gen, action);
7636 
7637 					if (conf->assign_hook)
7638 						conf->assign_hook(newval, newextra);
7639 					*conf->variable = newval;
7640 					set_extra_field(&conf->gen, &conf->gen.extra,
7641 									newextra);
7642 					conf->gen.source = source;
7643 					conf->gen.scontext = context;
7644 				}
7645 				if (makeDefault)
7646 				{
7647 					GucStack   *stack;
7648 
7649 					if (conf->gen.reset_source <= source)
7650 					{
7651 						conf->reset_val = newval;
7652 						set_extra_field(&conf->gen, &conf->reset_extra,
7653 										newextra);
7654 						conf->gen.reset_source = source;
7655 						conf->gen.reset_scontext = context;
7656 					}
7657 					for (stack = conf->gen.stack; stack; stack = stack->prev)
7658 					{
7659 						if (stack->source <= source)
7660 						{
7661 							stack->prior.val.enumval = newval;
7662 							set_extra_field(&conf->gen, &stack->prior.extra,
7663 											newextra);
7664 							stack->source = source;
7665 							stack->scontext = context;
7666 						}
7667 					}
7668 				}
7669 
7670 				/* Perhaps we didn't install newextra anywhere */
7671 				if (newextra && !extra_field_used(&conf->gen, newextra))
7672 					free(newextra);
7673 				break;
7674 
7675 #undef newval
7676 			}
7677 	}
7678 
7679 	if (changeVal && (record->flags & GUC_REPORT))
7680 		ReportGUCOption(record);
7681 
7682 	return changeVal ? 1 : -1;
7683 }
7684 
7685 
7686 /*
7687  * Set the fields for source file and line number the setting came from.
7688  */
7689 static void
set_config_sourcefile(const char * name,char * sourcefile,int sourceline)7690 set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
7691 {
7692 	struct config_generic *record;
7693 	int			elevel;
7694 
7695 	/*
7696 	 * To avoid cluttering the log, only the postmaster bleats loudly about
7697 	 * problems with the config file.
7698 	 */
7699 	elevel = IsUnderPostmaster ? DEBUG3 : LOG;
7700 
7701 	record = find_option(name, true, elevel);
7702 	/* should not happen */
7703 	if (record == NULL)
7704 		elog(ERROR, "unrecognized configuration parameter \"%s\"", name);
7705 
7706 	sourcefile = guc_strdup(elevel, sourcefile);
7707 	if (record->sourcefile)
7708 		free(record->sourcefile);
7709 	record->sourcefile = sourcefile;
7710 	record->sourceline = sourceline;
7711 }
7712 
7713 /*
7714  * Set a config option to the given value.
7715  *
7716  * See also set_config_option; this is just the wrapper to be called from
7717  * outside GUC.  (This function should be used when possible, because its API
7718  * is more stable than set_config_option's.)
7719  *
7720  * Note: there is no support here for setting source file/line, as it
7721  * is currently not needed.
7722  */
7723 void
SetConfigOption(const char * name,const char * value,GucContext context,GucSource source)7724 SetConfigOption(const char *name, const char *value,
7725 				GucContext context, GucSource source)
7726 {
7727 	(void) set_config_option(name, value, context, source,
7728 							 GUC_ACTION_SET, true, 0, false);
7729 }
7730 
7731 
7732 
7733 /*
7734  * Fetch the current value of the option `name', as a string.
7735  *
7736  * If the option doesn't exist, return NULL if missing_ok is true (NOTE that
7737  * this cannot be distinguished from a string variable with a NULL value!),
7738  * otherwise throw an ereport and don't return.
7739  *
7740  * If restrict_privileged is true, we also enforce that only superusers and
7741  * members of the pg_read_all_settings role can see GUC_SUPERUSER_ONLY
7742  * variables.  This should only be passed as true in user-driven calls.
7743  *
7744  * The string is *not* allocated for modification and is really only
7745  * valid until the next call to configuration related functions.
7746  */
7747 const char *
GetConfigOption(const char * name,bool missing_ok,bool restrict_privileged)7748 GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
7749 {
7750 	struct config_generic *record;
7751 	static char buffer[256];
7752 
7753 	record = find_option(name, false, ERROR);
7754 	if (record == NULL)
7755 	{
7756 		if (missing_ok)
7757 			return NULL;
7758 		ereport(ERROR,
7759 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7760 				 errmsg("unrecognized configuration parameter \"%s\"",
7761 						name)));
7762 	}
7763 	if (restrict_privileged &&
7764 		(record->flags & GUC_SUPERUSER_ONLY) &&
7765 		!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
7766 		ereport(ERROR,
7767 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7768 				 errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
7769 						name)));
7770 
7771 	switch (record->vartype)
7772 	{
7773 		case PGC_BOOL:
7774 			return *((struct config_bool *) record)->variable ? "on" : "off";
7775 
7776 		case PGC_INT:
7777 			snprintf(buffer, sizeof(buffer), "%d",
7778 					 *((struct config_int *) record)->variable);
7779 			return buffer;
7780 
7781 		case PGC_REAL:
7782 			snprintf(buffer, sizeof(buffer), "%g",
7783 					 *((struct config_real *) record)->variable);
7784 			return buffer;
7785 
7786 		case PGC_STRING:
7787 			return *((struct config_string *) record)->variable;
7788 
7789 		case PGC_ENUM:
7790 			return config_enum_lookup_by_value((struct config_enum *) record,
7791 											   *((struct config_enum *) record)->variable);
7792 	}
7793 	return NULL;
7794 }
7795 
7796 /*
7797  * Get the RESET value associated with the given option.
7798  *
7799  * Note: this is not re-entrant, due to use of static result buffer;
7800  * not to mention that a string variable could have its reset_val changed.
7801  * Beware of assuming the result value is good for very long.
7802  */
7803 const char *
GetConfigOptionResetString(const char * name)7804 GetConfigOptionResetString(const char *name)
7805 {
7806 	struct config_generic *record;
7807 	static char buffer[256];
7808 
7809 	record = find_option(name, false, ERROR);
7810 	if (record == NULL)
7811 		ereport(ERROR,
7812 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7813 				 errmsg("unrecognized configuration parameter \"%s\"", name)));
7814 	if ((record->flags & GUC_SUPERUSER_ONLY) &&
7815 		!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
7816 		ereport(ERROR,
7817 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
7818 				 errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
7819 						name)));
7820 
7821 	switch (record->vartype)
7822 	{
7823 		case PGC_BOOL:
7824 			return ((struct config_bool *) record)->reset_val ? "on" : "off";
7825 
7826 		case PGC_INT:
7827 			snprintf(buffer, sizeof(buffer), "%d",
7828 					 ((struct config_int *) record)->reset_val);
7829 			return buffer;
7830 
7831 		case PGC_REAL:
7832 			snprintf(buffer, sizeof(buffer), "%g",
7833 					 ((struct config_real *) record)->reset_val);
7834 			return buffer;
7835 
7836 		case PGC_STRING:
7837 			return ((struct config_string *) record)->reset_val;
7838 
7839 		case PGC_ENUM:
7840 			return config_enum_lookup_by_value((struct config_enum *) record,
7841 											   ((struct config_enum *) record)->reset_val);
7842 	}
7843 	return NULL;
7844 }
7845 
7846 /*
7847  * Get the GUC flags associated with the given option.
7848  *
7849  * If the option doesn't exist, return 0 if missing_ok is true,
7850  * otherwise throw an ereport and don't return.
7851  */
7852 int
GetConfigOptionFlags(const char * name,bool missing_ok)7853 GetConfigOptionFlags(const char *name, bool missing_ok)
7854 {
7855 	struct config_generic *record;
7856 
7857 	record = find_option(name, false, WARNING);
7858 	if (record == NULL)
7859 	{
7860 		if (missing_ok)
7861 			return 0;
7862 		ereport(ERROR,
7863 				(errcode(ERRCODE_UNDEFINED_OBJECT),
7864 				 errmsg("unrecognized configuration parameter \"%s\"",
7865 						name)));
7866 	}
7867 	return record->flags;
7868 }
7869 
7870 
7871 /*
7872  * flatten_set_variable_args
7873  *		Given a parsenode List as emitted by the grammar for SET,
7874  *		convert to the flat string representation used by GUC.
7875  *
7876  * We need to be told the name of the variable the args are for, because
7877  * the flattening rules vary (ugh).
7878  *
7879  * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise
7880  * a palloc'd string.
7881  */
7882 static char *
flatten_set_variable_args(const char * name,List * args)7883 flatten_set_variable_args(const char *name, List *args)
7884 {
7885 	struct config_generic *record;
7886 	int			flags;
7887 	StringInfoData buf;
7888 	ListCell   *l;
7889 
7890 	/* Fast path if just DEFAULT */
7891 	if (args == NIL)
7892 		return NULL;
7893 
7894 	/*
7895 	 * Get flags for the variable; if it's not known, use default flags.
7896 	 * (Caller might throw error later, but not our business to do so here.)
7897 	 */
7898 	record = find_option(name, false, WARNING);
7899 	if (record)
7900 		flags = record->flags;
7901 	else
7902 		flags = 0;
7903 
7904 	/* Complain if list input and non-list variable */
7905 	if ((flags & GUC_LIST_INPUT) == 0 &&
7906 		list_length(args) != 1)
7907 		ereport(ERROR,
7908 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
7909 				 errmsg("SET %s takes only one argument", name)));
7910 
7911 	initStringInfo(&buf);
7912 
7913 	/*
7914 	 * Each list member may be a plain A_Const node, or an A_Const within a
7915 	 * TypeCast; the latter case is supported only for ConstInterval arguments
7916 	 * (for SET TIME ZONE).
7917 	 */
7918 	foreach(l, args)
7919 	{
7920 		Node	   *arg = (Node *) lfirst(l);
7921 		char	   *val;
7922 		TypeName   *typeName = NULL;
7923 		A_Const    *con;
7924 
7925 		if (l != list_head(args))
7926 			appendStringInfoString(&buf, ", ");
7927 
7928 		if (IsA(arg, TypeCast))
7929 		{
7930 			TypeCast   *tc = (TypeCast *) arg;
7931 
7932 			arg = tc->arg;
7933 			typeName = tc->typeName;
7934 		}
7935 
7936 		if (!IsA(arg, A_Const))
7937 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(arg));
7938 		con = (A_Const *) arg;
7939 
7940 		switch (nodeTag(&con->val))
7941 		{
7942 			case T_Integer:
7943 				appendStringInfo(&buf, "%d", intVal(&con->val));
7944 				break;
7945 			case T_Float:
7946 				/* represented as a string, so just copy it */
7947 				appendStringInfoString(&buf, strVal(&con->val));
7948 				break;
7949 			case T_String:
7950 				val = strVal(&con->val);
7951 				if (typeName != NULL)
7952 				{
7953 					/*
7954 					 * Must be a ConstInterval argument for TIME ZONE. Coerce
7955 					 * to interval and back to normalize the value and account
7956 					 * for any typmod.
7957 					 */
7958 					Oid			typoid;
7959 					int32		typmod;
7960 					Datum		interval;
7961 					char	   *intervalout;
7962 
7963 					typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod);
7964 					Assert(typoid == INTERVALOID);
7965 
7966 					interval =
7967 						DirectFunctionCall3(interval_in,
7968 											CStringGetDatum(val),
7969 											ObjectIdGetDatum(InvalidOid),
7970 											Int32GetDatum(typmod));
7971 
7972 					intervalout =
7973 						DatumGetCString(DirectFunctionCall1(interval_out,
7974 															interval));
7975 					appendStringInfo(&buf, "INTERVAL '%s'", intervalout);
7976 				}
7977 				else
7978 				{
7979 					/*
7980 					 * Plain string literal or identifier.  For quote mode,
7981 					 * quote it if it's not a vanilla identifier.
7982 					 */
7983 					if (flags & GUC_LIST_QUOTE)
7984 						appendStringInfoString(&buf, quote_identifier(val));
7985 					else
7986 						appendStringInfoString(&buf, val);
7987 				}
7988 				break;
7989 			default:
7990 				elog(ERROR, "unrecognized node type: %d",
7991 					 (int) nodeTag(&con->val));
7992 				break;
7993 		}
7994 	}
7995 
7996 	return buf.data;
7997 }
7998 
7999 /*
8000  * Write updated configuration parameter values into a temporary file.
8001  * This function traverses the list of parameters and quotes the string
8002  * values before writing them.
8003  */
8004 static void
write_auto_conf_file(int fd,const char * filename,ConfigVariable * head)8005 write_auto_conf_file(int fd, const char *filename, ConfigVariable *head)
8006 {
8007 	StringInfoData buf;
8008 	ConfigVariable *item;
8009 
8010 	initStringInfo(&buf);
8011 
8012 	/* Emit file header containing warning comment */
8013 	appendStringInfoString(&buf, "# Do not edit this file manually!\n");
8014 	appendStringInfoString(&buf, "# It will be overwritten by the ALTER SYSTEM command.\n");
8015 
8016 	errno = 0;
8017 	if (write(fd, buf.data, buf.len) != buf.len)
8018 	{
8019 		/* if write didn't set errno, assume problem is no disk space */
8020 		if (errno == 0)
8021 			errno = ENOSPC;
8022 		ereport(ERROR,
8023 				(errcode_for_file_access(),
8024 				 errmsg("could not write to file \"%s\": %m", filename)));
8025 	}
8026 
8027 	/* Emit each parameter, properly quoting the value */
8028 	for (item = head; item != NULL; item = item->next)
8029 	{
8030 		char	   *escaped;
8031 
8032 		resetStringInfo(&buf);
8033 
8034 		appendStringInfoString(&buf, item->name);
8035 		appendStringInfoString(&buf, " = '");
8036 
8037 		escaped = escape_single_quotes_ascii(item->value);
8038 		if (!escaped)
8039 			ereport(ERROR,
8040 					(errcode(ERRCODE_OUT_OF_MEMORY),
8041 					 errmsg("out of memory")));
8042 		appendStringInfoString(&buf, escaped);
8043 		free(escaped);
8044 
8045 		appendStringInfoString(&buf, "'\n");
8046 
8047 		errno = 0;
8048 		if (write(fd, buf.data, buf.len) != buf.len)
8049 		{
8050 			/* if write didn't set errno, assume problem is no disk space */
8051 			if (errno == 0)
8052 				errno = ENOSPC;
8053 			ereport(ERROR,
8054 					(errcode_for_file_access(),
8055 					 errmsg("could not write to file \"%s\": %m", filename)));
8056 		}
8057 	}
8058 
8059 	/* fsync before considering the write to be successful */
8060 	if (pg_fsync(fd) != 0)
8061 		ereport(ERROR,
8062 				(errcode_for_file_access(),
8063 				 errmsg("could not fsync file \"%s\": %m", filename)));
8064 
8065 	pfree(buf.data);
8066 }
8067 
8068 /*
8069  * Update the given list of configuration parameters, adding, replacing
8070  * or deleting the entry for item "name" (delete if "value" == NULL).
8071  */
8072 static void
replace_auto_config_value(ConfigVariable ** head_p,ConfigVariable ** tail_p,const char * name,const char * value)8073 replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p,
8074 						  const char *name, const char *value)
8075 {
8076 	ConfigVariable *item,
8077 			   *next,
8078 			   *prev = NULL;
8079 
8080 	/*
8081 	 * Remove any existing match(es) for "name".  Normally there'd be at most
8082 	 * one, but if external tools have modified the config file, there could
8083 	 * be more.
8084 	 */
8085 	for (item = *head_p; item != NULL; item = next)
8086 	{
8087 		next = item->next;
8088 		if (guc_name_compare(item->name, name) == 0)
8089 		{
8090 			/* found a match, delete it */
8091 			if (prev)
8092 				prev->next = next;
8093 			else
8094 				*head_p = next;
8095 			if (next == NULL)
8096 				*tail_p = prev;
8097 
8098 			pfree(item->name);
8099 			pfree(item->value);
8100 			pfree(item->filename);
8101 			pfree(item);
8102 		}
8103 		else
8104 			prev = item;
8105 	}
8106 
8107 	/* Done if we're trying to delete it */
8108 	if (value == NULL)
8109 		return;
8110 
8111 	/* OK, append a new entry */
8112 	item = palloc(sizeof *item);
8113 	item->name = pstrdup(name);
8114 	item->value = pstrdup(value);
8115 	item->errmsg = NULL;
8116 	item->filename = pstrdup("");	/* new item has no location */
8117 	item->sourceline = 0;
8118 	item->ignore = false;
8119 	item->applied = false;
8120 	item->next = NULL;
8121 
8122 	if (*head_p == NULL)
8123 		*head_p = item;
8124 	else
8125 		(*tail_p)->next = item;
8126 	*tail_p = item;
8127 }
8128 
8129 
8130 /*
8131  * Execute ALTER SYSTEM statement.
8132  *
8133  * Read the old PG_AUTOCONF_FILENAME file, merge in the new variable value,
8134  * and write out an updated file.  If the command is ALTER SYSTEM RESET ALL,
8135  * we can skip reading the old file and just write an empty file.
8136  *
8137  * An LWLock is used to serialize updates of the configuration file.
8138  *
8139  * In case of an error, we leave the original automatic
8140  * configuration file (PG_AUTOCONF_FILENAME) intact.
8141  */
8142 void
AlterSystemSetConfigFile(AlterSystemStmt * altersysstmt)8143 AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
8144 {
8145 	char	   *name;
8146 	char	   *value;
8147 	bool		resetall = false;
8148 	ConfigVariable *head = NULL;
8149 	ConfigVariable *tail = NULL;
8150 	volatile int Tmpfd;
8151 	char		AutoConfFileName[MAXPGPATH];
8152 	char		AutoConfTmpFileName[MAXPGPATH];
8153 
8154 	if (!superuser())
8155 		ereport(ERROR,
8156 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
8157 				 errmsg("must be superuser to execute ALTER SYSTEM command")));
8158 
8159 	/*
8160 	 * Extract statement arguments
8161 	 */
8162 	name = altersysstmt->setstmt->name;
8163 
8164 	switch (altersysstmt->setstmt->kind)
8165 	{
8166 		case VAR_SET_VALUE:
8167 			value = ExtractSetVariableArgs(altersysstmt->setstmt);
8168 			break;
8169 
8170 		case VAR_SET_DEFAULT:
8171 		case VAR_RESET:
8172 			value = NULL;
8173 			break;
8174 
8175 		case VAR_RESET_ALL:
8176 			value = NULL;
8177 			resetall = true;
8178 			break;
8179 
8180 		default:
8181 			elog(ERROR, "unrecognized alter system stmt type: %d",
8182 				 altersysstmt->setstmt->kind);
8183 			break;
8184 	}
8185 
8186 	/*
8187 	 * Unless it's RESET_ALL, validate the target variable and value
8188 	 */
8189 	if (!resetall)
8190 	{
8191 		struct config_generic *record;
8192 
8193 		record = find_option(name, false, ERROR);
8194 		if (record == NULL)
8195 			ereport(ERROR,
8196 					(errcode(ERRCODE_UNDEFINED_OBJECT),
8197 					 errmsg("unrecognized configuration parameter \"%s\"",
8198 							name)));
8199 
8200 		/*
8201 		 * Don't allow parameters that can't be set in configuration files to
8202 		 * be set in PG_AUTOCONF_FILENAME file.
8203 		 */
8204 		if ((record->context == PGC_INTERNAL) ||
8205 			(record->flags & GUC_DISALLOW_IN_FILE) ||
8206 			(record->flags & GUC_DISALLOW_IN_AUTO_FILE))
8207 			ereport(ERROR,
8208 					(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
8209 					 errmsg("parameter \"%s\" cannot be changed",
8210 							name)));
8211 
8212 		/*
8213 		 * If a value is specified, verify that it's sane.
8214 		 */
8215 		if (value)
8216 		{
8217 			union config_var_val newval;
8218 			void	   *newextra = NULL;
8219 
8220 			/* Check that it's acceptable for the indicated parameter */
8221 			if (!parse_and_validate_value(record, name, value,
8222 										  PGC_S_FILE, ERROR,
8223 										  &newval, &newextra))
8224 				ereport(ERROR,
8225 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8226 						 errmsg("invalid value for parameter \"%s\": \"%s\"",
8227 								name, value)));
8228 
8229 			if (record->vartype == PGC_STRING && newval.stringval != NULL)
8230 				free(newval.stringval);
8231 			if (newextra)
8232 				free(newextra);
8233 
8234 			/*
8235 			 * We must also reject values containing newlines, because the
8236 			 * grammar for config files doesn't support embedded newlines in
8237 			 * string literals.
8238 			 */
8239 			if (strchr(value, '\n'))
8240 				ereport(ERROR,
8241 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8242 						 errmsg("parameter value for ALTER SYSTEM must not contain a newline")));
8243 		}
8244 	}
8245 
8246 	/*
8247 	 * PG_AUTOCONF_FILENAME and its corresponding temporary file are always in
8248 	 * the data directory, so we can reference them by simple relative paths.
8249 	 */
8250 	snprintf(AutoConfFileName, sizeof(AutoConfFileName), "%s",
8251 			 PG_AUTOCONF_FILENAME);
8252 	snprintf(AutoConfTmpFileName, sizeof(AutoConfTmpFileName), "%s.%s",
8253 			 AutoConfFileName,
8254 			 "tmp");
8255 
8256 	/*
8257 	 * Only one backend is allowed to operate on PG_AUTOCONF_FILENAME at a
8258 	 * time.  Use AutoFileLock to ensure that.  We must hold the lock while
8259 	 * reading the old file contents.
8260 	 */
8261 	LWLockAcquire(AutoFileLock, LW_EXCLUSIVE);
8262 
8263 	/*
8264 	 * If we're going to reset everything, then no need to open or parse the
8265 	 * old file.  We'll just write out an empty list.
8266 	 */
8267 	if (!resetall)
8268 	{
8269 		struct stat st;
8270 
8271 		if (stat(AutoConfFileName, &st) == 0)
8272 		{
8273 			/* open old file PG_AUTOCONF_FILENAME */
8274 			FILE	   *infile;
8275 
8276 			infile = AllocateFile(AutoConfFileName, "r");
8277 			if (infile == NULL)
8278 				ereport(ERROR,
8279 						(errcode_for_file_access(),
8280 						 errmsg("could not open file \"%s\": %m",
8281 								AutoConfFileName)));
8282 
8283 			/* parse it */
8284 			if (!ParseConfigFp(infile, AutoConfFileName, 0, LOG, &head, &tail))
8285 				ereport(ERROR,
8286 						(errcode(ERRCODE_CONFIG_FILE_ERROR),
8287 						 errmsg("could not parse contents of file \"%s\"",
8288 								AutoConfFileName)));
8289 
8290 			FreeFile(infile);
8291 		}
8292 
8293 		/*
8294 		 * Now, replace any existing entry with the new value, or add it if
8295 		 * not present.
8296 		 */
8297 		replace_auto_config_value(&head, &tail, name, value);
8298 	}
8299 
8300 	/*
8301 	 * To ensure crash safety, first write the new file data to a temp file,
8302 	 * then atomically rename it into place.
8303 	 *
8304 	 * If there is a temp file left over due to a previous crash, it's okay to
8305 	 * truncate and reuse it.
8306 	 */
8307 	Tmpfd = BasicOpenFile(AutoConfTmpFileName,
8308 						  O_CREAT | O_RDWR | O_TRUNC);
8309 	if (Tmpfd < 0)
8310 		ereport(ERROR,
8311 				(errcode_for_file_access(),
8312 				 errmsg("could not open file \"%s\": %m",
8313 						AutoConfTmpFileName)));
8314 
8315 	/*
8316 	 * Use a TRY block to clean up the file if we fail.  Since we need a TRY
8317 	 * block anyway, OK to use BasicOpenFile rather than OpenTransientFile.
8318 	 */
8319 	PG_TRY();
8320 	{
8321 		/* Write and sync the new contents to the temporary file */
8322 		write_auto_conf_file(Tmpfd, AutoConfTmpFileName, head);
8323 
8324 		/* Close before renaming; may be required on some platforms */
8325 		close(Tmpfd);
8326 		Tmpfd = -1;
8327 
8328 		/*
8329 		 * As the rename is atomic operation, if any problem occurs after this
8330 		 * at worst it can lose the parameters set by last ALTER SYSTEM
8331 		 * command.
8332 		 */
8333 		durable_rename(AutoConfTmpFileName, AutoConfFileName, ERROR);
8334 	}
8335 	PG_CATCH();
8336 	{
8337 		/* Close file first, else unlink might fail on some platforms */
8338 		if (Tmpfd >= 0)
8339 			close(Tmpfd);
8340 
8341 		/* Unlink, but ignore any error */
8342 		(void) unlink(AutoConfTmpFileName);
8343 
8344 		PG_RE_THROW();
8345 	}
8346 	PG_END_TRY();
8347 
8348 	FreeConfigVariables(head);
8349 
8350 	LWLockRelease(AutoFileLock);
8351 }
8352 
8353 /*
8354  * SET command
8355  */
8356 void
ExecSetVariableStmt(VariableSetStmt * stmt,bool isTopLevel)8357 ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel)
8358 {
8359 	GucAction	action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET;
8360 
8361 	/*
8362 	 * Workers synchronize these parameters at the start of the parallel
8363 	 * operation; then, we block SET during the operation.
8364 	 */
8365 	if (IsInParallelMode())
8366 		ereport(ERROR,
8367 				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
8368 				 errmsg("cannot set parameters during a parallel operation")));
8369 
8370 	switch (stmt->kind)
8371 	{
8372 		case VAR_SET_VALUE:
8373 		case VAR_SET_CURRENT:
8374 			if (stmt->is_local)
8375 				WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
8376 			(void) set_config_option(stmt->name,
8377 									 ExtractSetVariableArgs(stmt),
8378 									 (superuser() ? PGC_SUSET : PGC_USERSET),
8379 									 PGC_S_SESSION,
8380 									 action, true, 0, false);
8381 			break;
8382 		case VAR_SET_MULTI:
8383 
8384 			/*
8385 			 * Special-case SQL syntaxes.  The TRANSACTION and SESSION
8386 			 * CHARACTERISTICS cases effectively set more than one variable
8387 			 * per statement.  TRANSACTION SNAPSHOT only takes one argument,
8388 			 * but we put it here anyway since it's a special case and not
8389 			 * related to any GUC variable.
8390 			 */
8391 			if (strcmp(stmt->name, "TRANSACTION") == 0)
8392 			{
8393 				ListCell   *head;
8394 
8395 				WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
8396 
8397 				foreach(head, stmt->args)
8398 				{
8399 					DefElem    *item = (DefElem *) lfirst(head);
8400 
8401 					if (strcmp(item->defname, "transaction_isolation") == 0)
8402 						SetPGVariable("transaction_isolation",
8403 									  list_make1(item->arg), stmt->is_local);
8404 					else if (strcmp(item->defname, "transaction_read_only") == 0)
8405 						SetPGVariable("transaction_read_only",
8406 									  list_make1(item->arg), stmt->is_local);
8407 					else if (strcmp(item->defname, "transaction_deferrable") == 0)
8408 						SetPGVariable("transaction_deferrable",
8409 									  list_make1(item->arg), stmt->is_local);
8410 					else
8411 						elog(ERROR, "unexpected SET TRANSACTION element: %s",
8412 							 item->defname);
8413 				}
8414 			}
8415 			else if (strcmp(stmt->name, "SESSION CHARACTERISTICS") == 0)
8416 			{
8417 				ListCell   *head;
8418 
8419 				foreach(head, stmt->args)
8420 				{
8421 					DefElem    *item = (DefElem *) lfirst(head);
8422 
8423 					if (strcmp(item->defname, "transaction_isolation") == 0)
8424 						SetPGVariable("default_transaction_isolation",
8425 									  list_make1(item->arg), stmt->is_local);
8426 					else if (strcmp(item->defname, "transaction_read_only") == 0)
8427 						SetPGVariable("default_transaction_read_only",
8428 									  list_make1(item->arg), stmt->is_local);
8429 					else if (strcmp(item->defname, "transaction_deferrable") == 0)
8430 						SetPGVariable("default_transaction_deferrable",
8431 									  list_make1(item->arg), stmt->is_local);
8432 					else
8433 						elog(ERROR, "unexpected SET SESSION element: %s",
8434 							 item->defname);
8435 				}
8436 			}
8437 			else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT") == 0)
8438 			{
8439 				A_Const    *con = linitial_node(A_Const, stmt->args);
8440 
8441 				if (stmt->is_local)
8442 					ereport(ERROR,
8443 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
8444 							 errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented")));
8445 
8446 				WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION");
8447 				Assert(nodeTag(&con->val) == T_String);
8448 				ImportSnapshot(strVal(&con->val));
8449 			}
8450 			else
8451 				elog(ERROR, "unexpected SET MULTI element: %s",
8452 					 stmt->name);
8453 			break;
8454 		case VAR_SET_DEFAULT:
8455 			if (stmt->is_local)
8456 				WarnNoTransactionBlock(isTopLevel, "SET LOCAL");
8457 			/* fall through */
8458 		case VAR_RESET:
8459 			if (strcmp(stmt->name, "transaction_isolation") == 0)
8460 				WarnNoTransactionBlock(isTopLevel, "RESET TRANSACTION");
8461 
8462 			(void) set_config_option(stmt->name,
8463 									 NULL,
8464 									 (superuser() ? PGC_SUSET : PGC_USERSET),
8465 									 PGC_S_SESSION,
8466 									 action, true, 0, false);
8467 			break;
8468 		case VAR_RESET_ALL:
8469 			ResetAllOptions();
8470 			break;
8471 	}
8472 }
8473 
8474 /*
8475  * Get the value to assign for a VariableSetStmt, or NULL if it's RESET.
8476  * The result is palloc'd.
8477  *
8478  * This is exported for use by actions such as ALTER ROLE SET.
8479  */
8480 char *
ExtractSetVariableArgs(VariableSetStmt * stmt)8481 ExtractSetVariableArgs(VariableSetStmt *stmt)
8482 {
8483 	switch (stmt->kind)
8484 	{
8485 		case VAR_SET_VALUE:
8486 			return flatten_set_variable_args(stmt->name, stmt->args);
8487 		case VAR_SET_CURRENT:
8488 			return GetConfigOptionByName(stmt->name, NULL, false);
8489 		default:
8490 			return NULL;
8491 	}
8492 }
8493 
8494 /*
8495  * SetPGVariable - SET command exported as an easily-C-callable function.
8496  *
8497  * This provides access to SET TO value, as well as SET TO DEFAULT (expressed
8498  * by passing args == NIL), but not SET FROM CURRENT functionality.
8499  */
8500 void
SetPGVariable(const char * name,List * args,bool is_local)8501 SetPGVariable(const char *name, List *args, bool is_local)
8502 {
8503 	char	   *argstring = flatten_set_variable_args(name, args);
8504 
8505 	/* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
8506 	(void) set_config_option(name,
8507 							 argstring,
8508 							 (superuser() ? PGC_SUSET : PGC_USERSET),
8509 							 PGC_S_SESSION,
8510 							 is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
8511 							 true, 0, false);
8512 }
8513 
8514 /*
8515  * SET command wrapped as a SQL callable function.
8516  */
8517 Datum
set_config_by_name(PG_FUNCTION_ARGS)8518 set_config_by_name(PG_FUNCTION_ARGS)
8519 {
8520 	char	   *name;
8521 	char	   *value;
8522 	char	   *new_value;
8523 	bool		is_local;
8524 
8525 	if (PG_ARGISNULL(0))
8526 		ereport(ERROR,
8527 				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
8528 				 errmsg("SET requires parameter name")));
8529 
8530 	/* Get the GUC variable name */
8531 	name = TextDatumGetCString(PG_GETARG_DATUM(0));
8532 
8533 	/* Get the desired value or set to NULL for a reset request */
8534 	if (PG_ARGISNULL(1))
8535 		value = NULL;
8536 	else
8537 		value = TextDatumGetCString(PG_GETARG_DATUM(1));
8538 
8539 	/*
8540 	 * Get the desired state of is_local. Default to false if provided value
8541 	 * is NULL
8542 	 */
8543 	if (PG_ARGISNULL(2))
8544 		is_local = false;
8545 	else
8546 		is_local = PG_GETARG_BOOL(2);
8547 
8548 	/* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */
8549 	(void) set_config_option(name,
8550 							 value,
8551 							 (superuser() ? PGC_SUSET : PGC_USERSET),
8552 							 PGC_S_SESSION,
8553 							 is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET,
8554 							 true, 0, false);
8555 
8556 	/* get the new current value */
8557 	new_value = GetConfigOptionByName(name, NULL, false);
8558 
8559 	/* Convert return string to text */
8560 	PG_RETURN_TEXT_P(cstring_to_text(new_value));
8561 }
8562 
8563 
8564 /*
8565  * Common code for DefineCustomXXXVariable subroutines: allocate the
8566  * new variable's config struct and fill in generic fields.
8567  */
8568 static struct config_generic *
init_custom_variable(const char * name,const char * short_desc,const char * long_desc,GucContext context,int flags,enum config_type type,size_t sz)8569 init_custom_variable(const char *name,
8570 					 const char *short_desc,
8571 					 const char *long_desc,
8572 					 GucContext context,
8573 					 int flags,
8574 					 enum config_type type,
8575 					 size_t sz)
8576 {
8577 	struct config_generic *gen;
8578 
8579 	/*
8580 	 * Only allow custom PGC_POSTMASTER variables to be created during shared
8581 	 * library preload; any later than that, we can't ensure that the value
8582 	 * doesn't change after startup.  This is a fatal elog if it happens; just
8583 	 * erroring out isn't safe because we don't know what the calling loadable
8584 	 * module might already have hooked into.
8585 	 */
8586 	if (context == PGC_POSTMASTER &&
8587 		!process_shared_preload_libraries_in_progress)
8588 		elog(FATAL, "cannot create PGC_POSTMASTER variables after startup");
8589 
8590 	/*
8591 	 * We can't support custom GUC_LIST_QUOTE variables, because the wrong
8592 	 * things would happen if such a variable were set or pg_dump'd when the
8593 	 * defining extension isn't loaded.  Again, treat this as fatal because
8594 	 * the loadable module may be partly initialized already.
8595 	 */
8596 	if (flags & GUC_LIST_QUOTE)
8597 		elog(FATAL, "extensions cannot define GUC_LIST_QUOTE variables");
8598 
8599 	/*
8600 	 * Before pljava commit 398f3b876ed402bdaec8bc804f29e2be95c75139
8601 	 * (2015-12-15), two of that module's PGC_USERSET variables facilitated
8602 	 * trivial escalation to superuser privileges.  Restrict the variables to
8603 	 * protect sites that have yet to upgrade pljava.
8604 	 */
8605 	if (context == PGC_USERSET &&
8606 		(strcmp(name, "pljava.classpath") == 0 ||
8607 		 strcmp(name, "pljava.vmoptions") == 0))
8608 		context = PGC_SUSET;
8609 
8610 	gen = (struct config_generic *) guc_malloc(ERROR, sz);
8611 	memset(gen, 0, sz);
8612 
8613 	gen->name = guc_strdup(ERROR, name);
8614 	gen->context = context;
8615 	gen->group = CUSTOM_OPTIONS;
8616 	gen->short_desc = short_desc;
8617 	gen->long_desc = long_desc;
8618 	gen->flags = flags;
8619 	gen->vartype = type;
8620 
8621 	return gen;
8622 }
8623 
8624 /*
8625  * Common code for DefineCustomXXXVariable subroutines: insert the new
8626  * variable into the GUC variable array, replacing any placeholder.
8627  */
8628 static void
define_custom_variable(struct config_generic * variable)8629 define_custom_variable(struct config_generic *variable)
8630 {
8631 	const char *name = variable->name;
8632 	const char **nameAddr = &name;
8633 	struct config_string *pHolder;
8634 	struct config_generic **res;
8635 
8636 	/*
8637 	 * See if there's a placeholder by the same name.
8638 	 */
8639 	res = (struct config_generic **) bsearch((void *) &nameAddr,
8640 											 (void *) guc_variables,
8641 											 num_guc_variables,
8642 											 sizeof(struct config_generic *),
8643 											 guc_var_compare);
8644 	if (res == NULL)
8645 	{
8646 		/*
8647 		 * No placeholder to replace, so we can just add it ... but first,
8648 		 * make sure it's initialized to its default value.
8649 		 */
8650 		InitializeOneGUCOption(variable);
8651 		add_guc_variable(variable, ERROR);
8652 		return;
8653 	}
8654 
8655 	/*
8656 	 * This better be a placeholder
8657 	 */
8658 	if (((*res)->flags & GUC_CUSTOM_PLACEHOLDER) == 0)
8659 		ereport(ERROR,
8660 				(errcode(ERRCODE_INTERNAL_ERROR),
8661 				 errmsg("attempt to redefine parameter \"%s\"", name)));
8662 
8663 	Assert((*res)->vartype == PGC_STRING);
8664 	pHolder = (struct config_string *) (*res);
8665 
8666 	/*
8667 	 * First, set the variable to its default value.  We must do this even
8668 	 * though we intend to immediately apply a new value, since it's possible
8669 	 * that the new value is invalid.
8670 	 */
8671 	InitializeOneGUCOption(variable);
8672 
8673 	/*
8674 	 * Replace the placeholder. We aren't changing the name, so no re-sorting
8675 	 * is necessary
8676 	 */
8677 	*res = variable;
8678 
8679 	/*
8680 	 * Assign the string value(s) stored in the placeholder to the real
8681 	 * variable.  Essentially, we need to duplicate all the active and stacked
8682 	 * values, but with appropriate validation and datatype adjustment.
8683 	 *
8684 	 * If an assignment fails, we report a WARNING and keep going.  We don't
8685 	 * want to throw ERROR for bad values, because it'd bollix the add-on
8686 	 * module that's presumably halfway through getting loaded.  In such cases
8687 	 * the default or previous state will become active instead.
8688 	 */
8689 
8690 	/* First, apply the reset value if any */
8691 	if (pHolder->reset_val)
8692 		(void) set_config_option(name, pHolder->reset_val,
8693 								 pHolder->gen.reset_scontext,
8694 								 pHolder->gen.reset_source,
8695 								 GUC_ACTION_SET, true, WARNING, false);
8696 	/* That should not have resulted in stacking anything */
8697 	Assert(variable->stack == NULL);
8698 
8699 	/* Now, apply current and stacked values, in the order they were stacked */
8700 	reapply_stacked_values(variable, pHolder, pHolder->gen.stack,
8701 						   *(pHolder->variable),
8702 						   pHolder->gen.scontext, pHolder->gen.source);
8703 
8704 	/* Also copy over any saved source-location information */
8705 	if (pHolder->gen.sourcefile)
8706 		set_config_sourcefile(name, pHolder->gen.sourcefile,
8707 							  pHolder->gen.sourceline);
8708 
8709 	/*
8710 	 * Free up as much as we conveniently can of the placeholder structure.
8711 	 * (This neglects any stack items, so it's possible for some memory to be
8712 	 * leaked.  Since this can only happen once per session per variable, it
8713 	 * doesn't seem worth spending much code on.)
8714 	 */
8715 	set_string_field(pHolder, pHolder->variable, NULL);
8716 	set_string_field(pHolder, &pHolder->reset_val, NULL);
8717 
8718 	free(pHolder);
8719 }
8720 
8721 /*
8722  * Recursive subroutine for define_custom_variable: reapply non-reset values
8723  *
8724  * We recurse so that the values are applied in the same order as originally.
8725  * At each recursion level, apply the upper-level value (passed in) in the
8726  * fashion implied by the stack entry.
8727  */
8728 static void
reapply_stacked_values(struct config_generic * variable,struct config_string * pHolder,GucStack * stack,const char * curvalue,GucContext curscontext,GucSource cursource)8729 reapply_stacked_values(struct config_generic *variable,
8730 					   struct config_string *pHolder,
8731 					   GucStack *stack,
8732 					   const char *curvalue,
8733 					   GucContext curscontext, GucSource cursource)
8734 {
8735 	const char *name = variable->name;
8736 	GucStack   *oldvarstack = variable->stack;
8737 
8738 	if (stack != NULL)
8739 	{
8740 		/* First, recurse, so that stack items are processed bottom to top */
8741 		reapply_stacked_values(variable, pHolder, stack->prev,
8742 							   stack->prior.val.stringval,
8743 							   stack->scontext, stack->source);
8744 
8745 		/* See how to apply the passed-in value */
8746 		switch (stack->state)
8747 		{
8748 			case GUC_SAVE:
8749 				(void) set_config_option(name, curvalue,
8750 										 curscontext, cursource,
8751 										 GUC_ACTION_SAVE, true,
8752 										 WARNING, false);
8753 				break;
8754 
8755 			case GUC_SET:
8756 				(void) set_config_option(name, curvalue,
8757 										 curscontext, cursource,
8758 										 GUC_ACTION_SET, true,
8759 										 WARNING, false);
8760 				break;
8761 
8762 			case GUC_LOCAL:
8763 				(void) set_config_option(name, curvalue,
8764 										 curscontext, cursource,
8765 										 GUC_ACTION_LOCAL, true,
8766 										 WARNING, false);
8767 				break;
8768 
8769 			case GUC_SET_LOCAL:
8770 				/* first, apply the masked value as SET */
8771 				(void) set_config_option(name, stack->masked.val.stringval,
8772 										 stack->masked_scontext, PGC_S_SESSION,
8773 										 GUC_ACTION_SET, true,
8774 										 WARNING, false);
8775 				/* then apply the current value as LOCAL */
8776 				(void) set_config_option(name, curvalue,
8777 										 curscontext, cursource,
8778 										 GUC_ACTION_LOCAL, true,
8779 										 WARNING, false);
8780 				break;
8781 		}
8782 
8783 		/* If we successfully made a stack entry, adjust its nest level */
8784 		if (variable->stack != oldvarstack)
8785 			variable->stack->nest_level = stack->nest_level;
8786 	}
8787 	else
8788 	{
8789 		/*
8790 		 * We are at the end of the stack.  If the active/previous value is
8791 		 * different from the reset value, it must represent a previously
8792 		 * committed session value.  Apply it, and then drop the stack entry
8793 		 * that set_config_option will have created under the impression that
8794 		 * this is to be just a transactional assignment.  (We leak the stack
8795 		 * entry.)
8796 		 */
8797 		if (curvalue != pHolder->reset_val ||
8798 			curscontext != pHolder->gen.reset_scontext ||
8799 			cursource != pHolder->gen.reset_source)
8800 		{
8801 			(void) set_config_option(name, curvalue,
8802 									 curscontext, cursource,
8803 									 GUC_ACTION_SET, true, WARNING, false);
8804 			variable->stack = NULL;
8805 		}
8806 	}
8807 }
8808 
8809 void
DefineCustomBoolVariable(const char * name,const char * short_desc,const char * long_desc,bool * valueAddr,bool bootValue,GucContext context,int flags,GucBoolCheckHook check_hook,GucBoolAssignHook assign_hook,GucShowHook show_hook)8810 DefineCustomBoolVariable(const char *name,
8811 						 const char *short_desc,
8812 						 const char *long_desc,
8813 						 bool *valueAddr,
8814 						 bool bootValue,
8815 						 GucContext context,
8816 						 int flags,
8817 						 GucBoolCheckHook check_hook,
8818 						 GucBoolAssignHook assign_hook,
8819 						 GucShowHook show_hook)
8820 {
8821 	struct config_bool *var;
8822 
8823 	var = (struct config_bool *)
8824 		init_custom_variable(name, short_desc, long_desc, context, flags,
8825 							 PGC_BOOL, sizeof(struct config_bool));
8826 	var->variable = valueAddr;
8827 	var->boot_val = bootValue;
8828 	var->reset_val = bootValue;
8829 	var->check_hook = check_hook;
8830 	var->assign_hook = assign_hook;
8831 	var->show_hook = show_hook;
8832 	define_custom_variable(&var->gen);
8833 }
8834 
8835 void
DefineCustomIntVariable(const char * name,const char * short_desc,const char * long_desc,int * valueAddr,int bootValue,int minValue,int maxValue,GucContext context,int flags,GucIntCheckHook check_hook,GucIntAssignHook assign_hook,GucShowHook show_hook)8836 DefineCustomIntVariable(const char *name,
8837 						const char *short_desc,
8838 						const char *long_desc,
8839 						int *valueAddr,
8840 						int bootValue,
8841 						int minValue,
8842 						int maxValue,
8843 						GucContext context,
8844 						int flags,
8845 						GucIntCheckHook check_hook,
8846 						GucIntAssignHook assign_hook,
8847 						GucShowHook show_hook)
8848 {
8849 	struct config_int *var;
8850 
8851 	var = (struct config_int *)
8852 		init_custom_variable(name, short_desc, long_desc, context, flags,
8853 							 PGC_INT, sizeof(struct config_int));
8854 	var->variable = valueAddr;
8855 	var->boot_val = bootValue;
8856 	var->reset_val = bootValue;
8857 	var->min = minValue;
8858 	var->max = maxValue;
8859 	var->check_hook = check_hook;
8860 	var->assign_hook = assign_hook;
8861 	var->show_hook = show_hook;
8862 	define_custom_variable(&var->gen);
8863 }
8864 
8865 void
DefineCustomRealVariable(const char * name,const char * short_desc,const char * long_desc,double * valueAddr,double bootValue,double minValue,double maxValue,GucContext context,int flags,GucRealCheckHook check_hook,GucRealAssignHook assign_hook,GucShowHook show_hook)8866 DefineCustomRealVariable(const char *name,
8867 						 const char *short_desc,
8868 						 const char *long_desc,
8869 						 double *valueAddr,
8870 						 double bootValue,
8871 						 double minValue,
8872 						 double maxValue,
8873 						 GucContext context,
8874 						 int flags,
8875 						 GucRealCheckHook check_hook,
8876 						 GucRealAssignHook assign_hook,
8877 						 GucShowHook show_hook)
8878 {
8879 	struct config_real *var;
8880 
8881 	var = (struct config_real *)
8882 		init_custom_variable(name, short_desc, long_desc, context, flags,
8883 							 PGC_REAL, sizeof(struct config_real));
8884 	var->variable = valueAddr;
8885 	var->boot_val = bootValue;
8886 	var->reset_val = bootValue;
8887 	var->min = minValue;
8888 	var->max = maxValue;
8889 	var->check_hook = check_hook;
8890 	var->assign_hook = assign_hook;
8891 	var->show_hook = show_hook;
8892 	define_custom_variable(&var->gen);
8893 }
8894 
8895 void
DefineCustomStringVariable(const char * name,const char * short_desc,const char * long_desc,char ** valueAddr,const char * bootValue,GucContext context,int flags,GucStringCheckHook check_hook,GucStringAssignHook assign_hook,GucShowHook show_hook)8896 DefineCustomStringVariable(const char *name,
8897 						   const char *short_desc,
8898 						   const char *long_desc,
8899 						   char **valueAddr,
8900 						   const char *bootValue,
8901 						   GucContext context,
8902 						   int flags,
8903 						   GucStringCheckHook check_hook,
8904 						   GucStringAssignHook assign_hook,
8905 						   GucShowHook show_hook)
8906 {
8907 	struct config_string *var;
8908 
8909 	var = (struct config_string *)
8910 		init_custom_variable(name, short_desc, long_desc, context, flags,
8911 							 PGC_STRING, sizeof(struct config_string));
8912 	var->variable = valueAddr;
8913 	var->boot_val = bootValue;
8914 	var->check_hook = check_hook;
8915 	var->assign_hook = assign_hook;
8916 	var->show_hook = show_hook;
8917 	define_custom_variable(&var->gen);
8918 }
8919 
8920 void
DefineCustomEnumVariable(const char * name,const char * short_desc,const char * long_desc,int * valueAddr,int bootValue,const struct config_enum_entry * options,GucContext context,int flags,GucEnumCheckHook check_hook,GucEnumAssignHook assign_hook,GucShowHook show_hook)8921 DefineCustomEnumVariable(const char *name,
8922 						 const char *short_desc,
8923 						 const char *long_desc,
8924 						 int *valueAddr,
8925 						 int bootValue,
8926 						 const struct config_enum_entry *options,
8927 						 GucContext context,
8928 						 int flags,
8929 						 GucEnumCheckHook check_hook,
8930 						 GucEnumAssignHook assign_hook,
8931 						 GucShowHook show_hook)
8932 {
8933 	struct config_enum *var;
8934 
8935 	var = (struct config_enum *)
8936 		init_custom_variable(name, short_desc, long_desc, context, flags,
8937 							 PGC_ENUM, sizeof(struct config_enum));
8938 	var->variable = valueAddr;
8939 	var->boot_val = bootValue;
8940 	var->reset_val = bootValue;
8941 	var->options = options;
8942 	var->check_hook = check_hook;
8943 	var->assign_hook = assign_hook;
8944 	var->show_hook = show_hook;
8945 	define_custom_variable(&var->gen);
8946 }
8947 
8948 void
EmitWarningsOnPlaceholders(const char * className)8949 EmitWarningsOnPlaceholders(const char *className)
8950 {
8951 	int			classLen = strlen(className);
8952 	int			i;
8953 
8954 	for (i = 0; i < num_guc_variables; i++)
8955 	{
8956 		struct config_generic *var = guc_variables[i];
8957 
8958 		if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 &&
8959 			strncmp(className, var->name, classLen) == 0 &&
8960 			var->name[classLen] == GUC_QUALIFIER_SEPARATOR)
8961 		{
8962 			ereport(WARNING,
8963 					(errcode(ERRCODE_UNDEFINED_OBJECT),
8964 					 errmsg("unrecognized configuration parameter \"%s\"",
8965 							var->name)));
8966 		}
8967 	}
8968 }
8969 
8970 
8971 /*
8972  * SHOW command
8973  */
8974 void
GetPGVariable(const char * name,DestReceiver * dest)8975 GetPGVariable(const char *name, DestReceiver *dest)
8976 {
8977 	if (guc_name_compare(name, "all") == 0)
8978 		ShowAllGUCConfig(dest);
8979 	else
8980 		ShowGUCConfigOption(name, dest);
8981 }
8982 
8983 TupleDesc
GetPGVariableResultDesc(const char * name)8984 GetPGVariableResultDesc(const char *name)
8985 {
8986 	TupleDesc	tupdesc;
8987 
8988 	if (guc_name_compare(name, "all") == 0)
8989 	{
8990 		/* need a tuple descriptor representing three TEXT columns */
8991 		tupdesc = CreateTemplateTupleDesc(3);
8992 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
8993 						   TEXTOID, -1, 0);
8994 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
8995 						   TEXTOID, -1, 0);
8996 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description",
8997 						   TEXTOID, -1, 0);
8998 	}
8999 	else
9000 	{
9001 		const char *varname;
9002 
9003 		/* Get the canonical spelling of name */
9004 		(void) GetConfigOptionByName(name, &varname, false);
9005 
9006 		/* need a tuple descriptor representing a single TEXT column */
9007 		tupdesc = CreateTemplateTupleDesc(1);
9008 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname,
9009 						   TEXTOID, -1, 0);
9010 	}
9011 	return tupdesc;
9012 }
9013 
9014 
9015 /*
9016  * SHOW command
9017  */
9018 static void
ShowGUCConfigOption(const char * name,DestReceiver * dest)9019 ShowGUCConfigOption(const char *name, DestReceiver *dest)
9020 {
9021 	TupOutputState *tstate;
9022 	TupleDesc	tupdesc;
9023 	const char *varname;
9024 	char	   *value;
9025 
9026 	/* Get the value and canonical spelling of name */
9027 	value = GetConfigOptionByName(name, &varname, false);
9028 
9029 	/* need a tuple descriptor representing a single TEXT column */
9030 	tupdesc = CreateTemplateTupleDesc(1);
9031 	TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname,
9032 							  TEXTOID, -1, 0);
9033 
9034 	/* prepare for projection of tuples */
9035 	tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
9036 
9037 	/* Send it */
9038 	do_text_output_oneline(tstate, value);
9039 
9040 	end_tup_output(tstate);
9041 }
9042 
9043 /*
9044  * SHOW ALL command
9045  */
9046 static void
ShowAllGUCConfig(DestReceiver * dest)9047 ShowAllGUCConfig(DestReceiver *dest)
9048 {
9049 	int			i;
9050 	TupOutputState *tstate;
9051 	TupleDesc	tupdesc;
9052 	Datum		values[3];
9053 	bool		isnull[3] = {false, false, false};
9054 
9055 	/* need a tuple descriptor representing three TEXT columns */
9056 	tupdesc = CreateTemplateTupleDesc(3);
9057 	TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "name",
9058 							  TEXTOID, -1, 0);
9059 	TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting",
9060 							  TEXTOID, -1, 0);
9061 	TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description",
9062 							  TEXTOID, -1, 0);
9063 
9064 	/* prepare for projection of tuples */
9065 	tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
9066 
9067 	for (i = 0; i < num_guc_variables; i++)
9068 	{
9069 		struct config_generic *conf = guc_variables[i];
9070 		char	   *setting;
9071 
9072 		if ((conf->flags & GUC_NO_SHOW_ALL) ||
9073 			((conf->flags & GUC_SUPERUSER_ONLY) &&
9074 			 !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
9075 			continue;
9076 
9077 		/* assign to the values array */
9078 		values[0] = PointerGetDatum(cstring_to_text(conf->name));
9079 
9080 		setting = _ShowOption(conf, true);
9081 		if (setting)
9082 		{
9083 			values[1] = PointerGetDatum(cstring_to_text(setting));
9084 			isnull[1] = false;
9085 		}
9086 		else
9087 		{
9088 			values[1] = PointerGetDatum(NULL);
9089 			isnull[1] = true;
9090 		}
9091 
9092 		values[2] = PointerGetDatum(cstring_to_text(conf->short_desc));
9093 
9094 		/* send it to dest */
9095 		do_tup_output(tstate, values, isnull);
9096 
9097 		/* clean up */
9098 		pfree(DatumGetPointer(values[0]));
9099 		if (setting)
9100 		{
9101 			pfree(setting);
9102 			pfree(DatumGetPointer(values[1]));
9103 		}
9104 		pfree(DatumGetPointer(values[2]));
9105 	}
9106 
9107 	end_tup_output(tstate);
9108 }
9109 
9110 /*
9111  * Return an array of modified GUC options to show in EXPLAIN.
9112  *
9113  * We only report options related to query planning (marked with GUC_EXPLAIN),
9114  * with values different from their built-in defaults.
9115  */
9116 struct config_generic **
get_explain_guc_options(int * num)9117 get_explain_guc_options(int *num)
9118 {
9119 	struct config_generic **result;
9120 
9121 	*num = 0;
9122 
9123 	/*
9124 	 * While only a fraction of all the GUC variables are marked GUC_EXPLAIN,
9125 	 * it doesn't seem worth dynamically resizing this array.
9126 	 */
9127 	result = palloc(sizeof(struct config_generic *) * num_guc_variables);
9128 
9129 	for (int i = 0; i < num_guc_variables; i++)
9130 	{
9131 		bool		modified;
9132 		struct config_generic *conf = guc_variables[i];
9133 
9134 		/* return only parameters marked for inclusion in explain */
9135 		if (!(conf->flags & GUC_EXPLAIN))
9136 			continue;
9137 
9138 		/* return only options visible to the current user */
9139 		if ((conf->flags & GUC_NO_SHOW_ALL) ||
9140 			((conf->flags & GUC_SUPERUSER_ONLY) &&
9141 			 !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
9142 			continue;
9143 
9144 		/* return only options that are different from their boot values */
9145 		modified = false;
9146 
9147 		switch (conf->vartype)
9148 		{
9149 			case PGC_BOOL:
9150 				{
9151 					struct config_bool *lconf = (struct config_bool *) conf;
9152 
9153 					modified = (lconf->boot_val != *(lconf->variable));
9154 				}
9155 				break;
9156 
9157 			case PGC_INT:
9158 				{
9159 					struct config_int *lconf = (struct config_int *) conf;
9160 
9161 					modified = (lconf->boot_val != *(lconf->variable));
9162 				}
9163 				break;
9164 
9165 			case PGC_REAL:
9166 				{
9167 					struct config_real *lconf = (struct config_real *) conf;
9168 
9169 					modified = (lconf->boot_val != *(lconf->variable));
9170 				}
9171 				break;
9172 
9173 			case PGC_STRING:
9174 				{
9175 					struct config_string *lconf = (struct config_string *) conf;
9176 
9177 					modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0);
9178 				}
9179 				break;
9180 
9181 			case PGC_ENUM:
9182 				{
9183 					struct config_enum *lconf = (struct config_enum *) conf;
9184 
9185 					modified = (lconf->boot_val != *(lconf->variable));
9186 				}
9187 				break;
9188 
9189 			default:
9190 				elog(ERROR, "unexpected GUC type: %d", conf->vartype);
9191 		}
9192 
9193 		if (!modified)
9194 			continue;
9195 
9196 		/* OK, report it */
9197 		result[*num] = conf;
9198 		*num = *num + 1;
9199 	}
9200 
9201 	return result;
9202 }
9203 
9204 /*
9205  * Return GUC variable value by name; optionally return canonical form of
9206  * name.  If the GUC is unset, then throw an error unless missing_ok is true,
9207  * in which case return NULL.  Return value is palloc'd (but *varname isn't).
9208  */
9209 char *
GetConfigOptionByName(const char * name,const char ** varname,bool missing_ok)9210 GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
9211 {
9212 	struct config_generic *record;
9213 
9214 	record = find_option(name, false, ERROR);
9215 	if (record == NULL)
9216 	{
9217 		if (missing_ok)
9218 		{
9219 			if (varname)
9220 				*varname = NULL;
9221 			return NULL;
9222 		}
9223 
9224 		ereport(ERROR,
9225 				(errcode(ERRCODE_UNDEFINED_OBJECT),
9226 				 errmsg("unrecognized configuration parameter \"%s\"", name)));
9227 	}
9228 
9229 	if ((record->flags & GUC_SUPERUSER_ONLY) &&
9230 		!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
9231 		ereport(ERROR,
9232 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
9233 				 errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
9234 						name)));
9235 
9236 	if (varname)
9237 		*varname = record->name;
9238 
9239 	return _ShowOption(record, true);
9240 }
9241 
9242 /*
9243  * Return GUC variable value by variable number; optionally return canonical
9244  * form of name.  Return value is palloc'd.
9245  */
9246 void
GetConfigOptionByNum(int varnum,const char ** values,bool * noshow)9247 GetConfigOptionByNum(int varnum, const char **values, bool *noshow)
9248 {
9249 	char		buffer[256];
9250 	struct config_generic *conf;
9251 
9252 	/* check requested variable number valid */
9253 	Assert((varnum >= 0) && (varnum < num_guc_variables));
9254 
9255 	conf = guc_variables[varnum];
9256 
9257 	if (noshow)
9258 	{
9259 		if ((conf->flags & GUC_NO_SHOW_ALL) ||
9260 			((conf->flags & GUC_SUPERUSER_ONLY) &&
9261 			 !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
9262 			*noshow = true;
9263 		else
9264 			*noshow = false;
9265 	}
9266 
9267 	/* first get the generic attributes */
9268 
9269 	/* name */
9270 	values[0] = conf->name;
9271 
9272 	/* setting: use _ShowOption in order to avoid duplicating the logic */
9273 	values[1] = _ShowOption(conf, false);
9274 
9275 	/* unit, if any (NULL is fine) */
9276 	values[2] = get_config_unit_name(conf->flags);
9277 
9278 	/* group */
9279 	values[3] = _(config_group_names[conf->group]);
9280 
9281 	/* short_desc */
9282 	values[4] = _(conf->short_desc);
9283 
9284 	/* extra_desc */
9285 	values[5] = _(conf->long_desc);
9286 
9287 	/* context */
9288 	values[6] = GucContext_Names[conf->context];
9289 
9290 	/* vartype */
9291 	values[7] = config_type_names[conf->vartype];
9292 
9293 	/* source */
9294 	values[8] = GucSource_Names[conf->source];
9295 
9296 	/* now get the type specific attributes */
9297 	switch (conf->vartype)
9298 	{
9299 		case PGC_BOOL:
9300 			{
9301 				struct config_bool *lconf = (struct config_bool *) conf;
9302 
9303 				/* min_val */
9304 				values[9] = NULL;
9305 
9306 				/* max_val */
9307 				values[10] = NULL;
9308 
9309 				/* enumvals */
9310 				values[11] = NULL;
9311 
9312 				/* boot_val */
9313 				values[12] = pstrdup(lconf->boot_val ? "on" : "off");
9314 
9315 				/* reset_val */
9316 				values[13] = pstrdup(lconf->reset_val ? "on" : "off");
9317 			}
9318 			break;
9319 
9320 		case PGC_INT:
9321 			{
9322 				struct config_int *lconf = (struct config_int *) conf;
9323 
9324 				/* min_val */
9325 				snprintf(buffer, sizeof(buffer), "%d", lconf->min);
9326 				values[9] = pstrdup(buffer);
9327 
9328 				/* max_val */
9329 				snprintf(buffer, sizeof(buffer), "%d", lconf->max);
9330 				values[10] = pstrdup(buffer);
9331 
9332 				/* enumvals */
9333 				values[11] = NULL;
9334 
9335 				/* boot_val */
9336 				snprintf(buffer, sizeof(buffer), "%d", lconf->boot_val);
9337 				values[12] = pstrdup(buffer);
9338 
9339 				/* reset_val */
9340 				snprintf(buffer, sizeof(buffer), "%d", lconf->reset_val);
9341 				values[13] = pstrdup(buffer);
9342 			}
9343 			break;
9344 
9345 		case PGC_REAL:
9346 			{
9347 				struct config_real *lconf = (struct config_real *) conf;
9348 
9349 				/* min_val */
9350 				snprintf(buffer, sizeof(buffer), "%g", lconf->min);
9351 				values[9] = pstrdup(buffer);
9352 
9353 				/* max_val */
9354 				snprintf(buffer, sizeof(buffer), "%g", lconf->max);
9355 				values[10] = pstrdup(buffer);
9356 
9357 				/* enumvals */
9358 				values[11] = NULL;
9359 
9360 				/* boot_val */
9361 				snprintf(buffer, sizeof(buffer), "%g", lconf->boot_val);
9362 				values[12] = pstrdup(buffer);
9363 
9364 				/* reset_val */
9365 				snprintf(buffer, sizeof(buffer), "%g", lconf->reset_val);
9366 				values[13] = pstrdup(buffer);
9367 			}
9368 			break;
9369 
9370 		case PGC_STRING:
9371 			{
9372 				struct config_string *lconf = (struct config_string *) conf;
9373 
9374 				/* min_val */
9375 				values[9] = NULL;
9376 
9377 				/* max_val */
9378 				values[10] = NULL;
9379 
9380 				/* enumvals */
9381 				values[11] = NULL;
9382 
9383 				/* boot_val */
9384 				if (lconf->boot_val == NULL)
9385 					values[12] = NULL;
9386 				else
9387 					values[12] = pstrdup(lconf->boot_val);
9388 
9389 				/* reset_val */
9390 				if (lconf->reset_val == NULL)
9391 					values[13] = NULL;
9392 				else
9393 					values[13] = pstrdup(lconf->reset_val);
9394 			}
9395 			break;
9396 
9397 		case PGC_ENUM:
9398 			{
9399 				struct config_enum *lconf = (struct config_enum *) conf;
9400 
9401 				/* min_val */
9402 				values[9] = NULL;
9403 
9404 				/* max_val */
9405 				values[10] = NULL;
9406 
9407 				/* enumvals */
9408 
9409 				/*
9410 				 * NOTE! enumvals with double quotes in them are not
9411 				 * supported!
9412 				 */
9413 				values[11] = config_enum_get_options((struct config_enum *) conf,
9414 													 "{\"", "\"}", "\",\"");
9415 
9416 				/* boot_val */
9417 				values[12] = pstrdup(config_enum_lookup_by_value(lconf,
9418 																 lconf->boot_val));
9419 
9420 				/* reset_val */
9421 				values[13] = pstrdup(config_enum_lookup_by_value(lconf,
9422 																 lconf->reset_val));
9423 			}
9424 			break;
9425 
9426 		default:
9427 			{
9428 				/*
9429 				 * should never get here, but in case we do, set 'em to NULL
9430 				 */
9431 
9432 				/* min_val */
9433 				values[9] = NULL;
9434 
9435 				/* max_val */
9436 				values[10] = NULL;
9437 
9438 				/* enumvals */
9439 				values[11] = NULL;
9440 
9441 				/* boot_val */
9442 				values[12] = NULL;
9443 
9444 				/* reset_val */
9445 				values[13] = NULL;
9446 			}
9447 			break;
9448 	}
9449 
9450 	/*
9451 	 * If the setting came from a config file, set the source location. For
9452 	 * security reasons, we don't show source file/line number for
9453 	 * insufficiently-privileged users.
9454 	 */
9455 	if (conf->source == PGC_S_FILE &&
9456 		is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
9457 	{
9458 		values[14] = conf->sourcefile;
9459 		snprintf(buffer, sizeof(buffer), "%d", conf->sourceline);
9460 		values[15] = pstrdup(buffer);
9461 	}
9462 	else
9463 	{
9464 		values[14] = NULL;
9465 		values[15] = NULL;
9466 	}
9467 
9468 	values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f";
9469 }
9470 
9471 /*
9472  * Return the total number of GUC variables
9473  */
9474 int
GetNumConfigOptions(void)9475 GetNumConfigOptions(void)
9476 {
9477 	return num_guc_variables;
9478 }
9479 
9480 /*
9481  * show_config_by_name - equiv to SHOW X command but implemented as
9482  * a function.
9483  */
9484 Datum
show_config_by_name(PG_FUNCTION_ARGS)9485 show_config_by_name(PG_FUNCTION_ARGS)
9486 {
9487 	char	   *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
9488 	char	   *varval;
9489 
9490 	/* Get the value */
9491 	varval = GetConfigOptionByName(varname, NULL, false);
9492 
9493 	/* Convert to text */
9494 	PG_RETURN_TEXT_P(cstring_to_text(varval));
9495 }
9496 
9497 /*
9498  * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as
9499  * a function.  If X does not exist, suppress the error and just return NULL
9500  * if missing_ok is true.
9501  */
9502 Datum
show_config_by_name_missing_ok(PG_FUNCTION_ARGS)9503 show_config_by_name_missing_ok(PG_FUNCTION_ARGS)
9504 {
9505 	char	   *varname = TextDatumGetCString(PG_GETARG_DATUM(0));
9506 	bool		missing_ok = PG_GETARG_BOOL(1);
9507 	char	   *varval;
9508 
9509 	/* Get the value */
9510 	varval = GetConfigOptionByName(varname, NULL, missing_ok);
9511 
9512 	/* return NULL if no such variable */
9513 	if (varval == NULL)
9514 		PG_RETURN_NULL();
9515 
9516 	/* Convert to text */
9517 	PG_RETURN_TEXT_P(cstring_to_text(varval));
9518 }
9519 
9520 /*
9521  * show_all_settings - equiv to SHOW ALL command but implemented as
9522  * a Table Function.
9523  */
9524 #define NUM_PG_SETTINGS_ATTS	17
9525 
9526 Datum
show_all_settings(PG_FUNCTION_ARGS)9527 show_all_settings(PG_FUNCTION_ARGS)
9528 {
9529 	FuncCallContext *funcctx;
9530 	TupleDesc	tupdesc;
9531 	int			call_cntr;
9532 	int			max_calls;
9533 	AttInMetadata *attinmeta;
9534 	MemoryContext oldcontext;
9535 
9536 	/* stuff done only on the first call of the function */
9537 	if (SRF_IS_FIRSTCALL())
9538 	{
9539 		/* create a function context for cross-call persistence */
9540 		funcctx = SRF_FIRSTCALL_INIT();
9541 
9542 		/*
9543 		 * switch to memory context appropriate for multiple function calls
9544 		 */
9545 		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
9546 
9547 		/*
9548 		 * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns
9549 		 * of the appropriate types
9550 		 */
9551 		tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS);
9552 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
9553 						   TEXTOID, -1, 0);
9554 		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
9555 						   TEXTOID, -1, 0);
9556 		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit",
9557 						   TEXTOID, -1, 0);
9558 		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category",
9559 						   TEXTOID, -1, 0);
9560 		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc",
9561 						   TEXTOID, -1, 0);
9562 		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc",
9563 						   TEXTOID, -1, 0);
9564 		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context",
9565 						   TEXTOID, -1, 0);
9566 		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype",
9567 						   TEXTOID, -1, 0);
9568 		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source",
9569 						   TEXTOID, -1, 0);
9570 		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val",
9571 						   TEXTOID, -1, 0);
9572 		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val",
9573 						   TEXTOID, -1, 0);
9574 		TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals",
9575 						   TEXTARRAYOID, -1, 0);
9576 		TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val",
9577 						   TEXTOID, -1, 0);
9578 		TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val",
9579 						   TEXTOID, -1, 0);
9580 		TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile",
9581 						   TEXTOID, -1, 0);
9582 		TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline",
9583 						   INT4OID, -1, 0);
9584 		TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart",
9585 						   BOOLOID, -1, 0);
9586 
9587 		/*
9588 		 * Generate attribute metadata needed later to produce tuples from raw
9589 		 * C strings
9590 		 */
9591 		attinmeta = TupleDescGetAttInMetadata(tupdesc);
9592 		funcctx->attinmeta = attinmeta;
9593 
9594 		/* total number of tuples to be returned */
9595 		funcctx->max_calls = GetNumConfigOptions();
9596 
9597 		MemoryContextSwitchTo(oldcontext);
9598 	}
9599 
9600 	/* stuff done on every call of the function */
9601 	funcctx = SRF_PERCALL_SETUP();
9602 
9603 	call_cntr = funcctx->call_cntr;
9604 	max_calls = funcctx->max_calls;
9605 	attinmeta = funcctx->attinmeta;
9606 
9607 	if (call_cntr < max_calls)	/* do when there is more left to send */
9608 	{
9609 		char	   *values[NUM_PG_SETTINGS_ATTS];
9610 		bool		noshow;
9611 		HeapTuple	tuple;
9612 		Datum		result;
9613 
9614 		/*
9615 		 * Get the next visible GUC variable name and value
9616 		 */
9617 		do
9618 		{
9619 			GetConfigOptionByNum(call_cntr, (const char **) values, &noshow);
9620 			if (noshow)
9621 			{
9622 				/* bump the counter and get the next config setting */
9623 				call_cntr = ++funcctx->call_cntr;
9624 
9625 				/* make sure we haven't gone too far now */
9626 				if (call_cntr >= max_calls)
9627 					SRF_RETURN_DONE(funcctx);
9628 			}
9629 		} while (noshow);
9630 
9631 		/* build a tuple */
9632 		tuple = BuildTupleFromCStrings(attinmeta, values);
9633 
9634 		/* make the tuple into a datum */
9635 		result = HeapTupleGetDatum(tuple);
9636 
9637 		SRF_RETURN_NEXT(funcctx, result);
9638 	}
9639 	else
9640 	{
9641 		/* do when there is no more left */
9642 		SRF_RETURN_DONE(funcctx);
9643 	}
9644 }
9645 
9646 /*
9647  * show_all_file_settings
9648  *
9649  * Returns a table of all parameter settings in all configuration files
9650  * which includes the config file pathname, the line number, a sequence number
9651  * indicating the order in which the settings were encountered, the parameter
9652  * name and value, a bool showing if the value could be applied, and possibly
9653  * an associated error message.  (For problems such as syntax errors, the
9654  * parameter name/value might be NULL.)
9655  *
9656  * Note: no filtering is done here, instead we depend on the GRANT system
9657  * to prevent unprivileged users from accessing this function or the view
9658  * built on top of it.
9659  */
9660 Datum
show_all_file_settings(PG_FUNCTION_ARGS)9661 show_all_file_settings(PG_FUNCTION_ARGS)
9662 {
9663 #define NUM_PG_FILE_SETTINGS_ATTS 7
9664 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
9665 	TupleDesc	tupdesc;
9666 	Tuplestorestate *tupstore;
9667 	ConfigVariable *conf;
9668 	int			seqno;
9669 	MemoryContext per_query_ctx;
9670 	MemoryContext oldcontext;
9671 
9672 	/* Check to see if caller supports us returning a tuplestore */
9673 	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
9674 		ereport(ERROR,
9675 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9676 				 errmsg("set-valued function called in context that cannot accept a set")));
9677 	if (!(rsinfo->allowedModes & SFRM_Materialize))
9678 		ereport(ERROR,
9679 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
9680 				 errmsg("materialize mode required, but it is not allowed in this context")));
9681 
9682 	/* Scan the config files using current context as workspace */
9683 	conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3);
9684 
9685 	/* Switch into long-lived context to construct returned data structures */
9686 	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
9687 	oldcontext = MemoryContextSwitchTo(per_query_ctx);
9688 
9689 	/* Build a tuple descriptor for our result type */
9690 	tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS);
9691 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile",
9692 					   TEXTOID, -1, 0);
9693 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline",
9694 					   INT4OID, -1, 0);
9695 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno",
9696 					   INT4OID, -1, 0);
9697 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name",
9698 					   TEXTOID, -1, 0);
9699 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting",
9700 					   TEXTOID, -1, 0);
9701 	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "applied",
9702 					   BOOLOID, -1, 0);
9703 	TupleDescInitEntry(tupdesc, (AttrNumber) 7, "error",
9704 					   TEXTOID, -1, 0);
9705 
9706 	/* Build a tuplestore to return our results in */
9707 	tupstore = tuplestore_begin_heap(true, false, work_mem);
9708 	rsinfo->returnMode = SFRM_Materialize;
9709 	rsinfo->setResult = tupstore;
9710 	rsinfo->setDesc = tupdesc;
9711 
9712 	/* The rest can be done in short-lived context */
9713 	MemoryContextSwitchTo(oldcontext);
9714 
9715 	/* Process the results and create a tuplestore */
9716 	for (seqno = 1; conf != NULL; conf = conf->next, seqno++)
9717 	{
9718 		Datum		values[NUM_PG_FILE_SETTINGS_ATTS];
9719 		bool		nulls[NUM_PG_FILE_SETTINGS_ATTS];
9720 
9721 		memset(values, 0, sizeof(values));
9722 		memset(nulls, 0, sizeof(nulls));
9723 
9724 		/* sourcefile */
9725 		if (conf->filename)
9726 			values[0] = PointerGetDatum(cstring_to_text(conf->filename));
9727 		else
9728 			nulls[0] = true;
9729 
9730 		/* sourceline (not meaningful if no sourcefile) */
9731 		if (conf->filename)
9732 			values[1] = Int32GetDatum(conf->sourceline);
9733 		else
9734 			nulls[1] = true;
9735 
9736 		/* seqno */
9737 		values[2] = Int32GetDatum(seqno);
9738 
9739 		/* name */
9740 		if (conf->name)
9741 			values[3] = PointerGetDatum(cstring_to_text(conf->name));
9742 		else
9743 			nulls[3] = true;
9744 
9745 		/* setting */
9746 		if (conf->value)
9747 			values[4] = PointerGetDatum(cstring_to_text(conf->value));
9748 		else
9749 			nulls[4] = true;
9750 
9751 		/* applied */
9752 		values[5] = BoolGetDatum(conf->applied);
9753 
9754 		/* error */
9755 		if (conf->errmsg)
9756 			values[6] = PointerGetDatum(cstring_to_text(conf->errmsg));
9757 		else
9758 			nulls[6] = true;
9759 
9760 		/* shove row into tuplestore */
9761 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
9762 	}
9763 
9764 	tuplestore_donestoring(tupstore);
9765 
9766 	return (Datum) 0;
9767 }
9768 
9769 static char *
_ShowOption(struct config_generic * record,bool use_units)9770 _ShowOption(struct config_generic *record, bool use_units)
9771 {
9772 	char		buffer[256];
9773 	const char *val;
9774 
9775 	switch (record->vartype)
9776 	{
9777 		case PGC_BOOL:
9778 			{
9779 				struct config_bool *conf = (struct config_bool *) record;
9780 
9781 				if (conf->show_hook)
9782 					val = conf->show_hook();
9783 				else
9784 					val = *conf->variable ? "on" : "off";
9785 			}
9786 			break;
9787 
9788 		case PGC_INT:
9789 			{
9790 				struct config_int *conf = (struct config_int *) record;
9791 
9792 				if (conf->show_hook)
9793 					val = conf->show_hook();
9794 				else
9795 				{
9796 					/*
9797 					 * Use int64 arithmetic to avoid overflows in units
9798 					 * conversion.
9799 					 */
9800 					int64		result = *conf->variable;
9801 					const char *unit;
9802 
9803 					if (use_units && result > 0 && (record->flags & GUC_UNIT))
9804 						convert_int_from_base_unit(result,
9805 												   record->flags & GUC_UNIT,
9806 												   &result, &unit);
9807 					else
9808 						unit = "";
9809 
9810 					snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s",
9811 							 result, unit);
9812 					val = buffer;
9813 				}
9814 			}
9815 			break;
9816 
9817 		case PGC_REAL:
9818 			{
9819 				struct config_real *conf = (struct config_real *) record;
9820 
9821 				if (conf->show_hook)
9822 					val = conf->show_hook();
9823 				else
9824 				{
9825 					double		result = *conf->variable;
9826 					const char *unit;
9827 
9828 					if (use_units && result > 0 && (record->flags & GUC_UNIT))
9829 						convert_real_from_base_unit(result,
9830 													record->flags & GUC_UNIT,
9831 													&result, &unit);
9832 					else
9833 						unit = "";
9834 
9835 					snprintf(buffer, sizeof(buffer), "%g%s",
9836 							 result, unit);
9837 					val = buffer;
9838 				}
9839 			}
9840 			break;
9841 
9842 		case PGC_STRING:
9843 			{
9844 				struct config_string *conf = (struct config_string *) record;
9845 
9846 				if (conf->show_hook)
9847 					val = conf->show_hook();
9848 				else if (*conf->variable && **conf->variable)
9849 					val = *conf->variable;
9850 				else
9851 					val = "";
9852 			}
9853 			break;
9854 
9855 		case PGC_ENUM:
9856 			{
9857 				struct config_enum *conf = (struct config_enum *) record;
9858 
9859 				if (conf->show_hook)
9860 					val = conf->show_hook();
9861 				else
9862 					val = config_enum_lookup_by_value(conf, *conf->variable);
9863 			}
9864 			break;
9865 
9866 		default:
9867 			/* just to keep compiler quiet */
9868 			val = "???";
9869 			break;
9870 	}
9871 
9872 	return pstrdup(val);
9873 }
9874 
9875 
9876 #ifdef EXEC_BACKEND
9877 
9878 /*
9879  *	These routines dump out all non-default GUC options into a binary
9880  *	file that is read by all exec'ed backends.  The format is:
9881  *
9882  *		variable name, string, null terminated
9883  *		variable value, string, null terminated
9884  *		variable sourcefile, string, null terminated (empty if none)
9885  *		variable sourceline, integer
9886  *		variable source, integer
9887  *		variable scontext, integer
9888  */
9889 static void
write_one_nondefault_variable(FILE * fp,struct config_generic * gconf)9890 write_one_nondefault_variable(FILE *fp, struct config_generic *gconf)
9891 {
9892 	if (gconf->source == PGC_S_DEFAULT)
9893 		return;
9894 
9895 	fprintf(fp, "%s", gconf->name);
9896 	fputc(0, fp);
9897 
9898 	switch (gconf->vartype)
9899 	{
9900 		case PGC_BOOL:
9901 			{
9902 				struct config_bool *conf = (struct config_bool *) gconf;
9903 
9904 				if (*conf->variable)
9905 					fprintf(fp, "true");
9906 				else
9907 					fprintf(fp, "false");
9908 			}
9909 			break;
9910 
9911 		case PGC_INT:
9912 			{
9913 				struct config_int *conf = (struct config_int *) gconf;
9914 
9915 				fprintf(fp, "%d", *conf->variable);
9916 			}
9917 			break;
9918 
9919 		case PGC_REAL:
9920 			{
9921 				struct config_real *conf = (struct config_real *) gconf;
9922 
9923 				fprintf(fp, "%.17g", *conf->variable);
9924 			}
9925 			break;
9926 
9927 		case PGC_STRING:
9928 			{
9929 				struct config_string *conf = (struct config_string *) gconf;
9930 
9931 				fprintf(fp, "%s", *conf->variable);
9932 			}
9933 			break;
9934 
9935 		case PGC_ENUM:
9936 			{
9937 				struct config_enum *conf = (struct config_enum *) gconf;
9938 
9939 				fprintf(fp, "%s",
9940 						config_enum_lookup_by_value(conf, *conf->variable));
9941 			}
9942 			break;
9943 	}
9944 
9945 	fputc(0, fp);
9946 
9947 	if (gconf->sourcefile)
9948 		fprintf(fp, "%s", gconf->sourcefile);
9949 	fputc(0, fp);
9950 
9951 	fwrite(&gconf->sourceline, 1, sizeof(gconf->sourceline), fp);
9952 	fwrite(&gconf->source, 1, sizeof(gconf->source), fp);
9953 	fwrite(&gconf->scontext, 1, sizeof(gconf->scontext), fp);
9954 }
9955 
9956 void
write_nondefault_variables(GucContext context)9957 write_nondefault_variables(GucContext context)
9958 {
9959 	int			elevel;
9960 	FILE	   *fp;
9961 	int			i;
9962 
9963 	Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
9964 
9965 	elevel = (context == PGC_SIGHUP) ? LOG : ERROR;
9966 
9967 	/*
9968 	 * Open file
9969 	 */
9970 	fp = AllocateFile(CONFIG_EXEC_PARAMS_NEW, "w");
9971 	if (!fp)
9972 	{
9973 		ereport(elevel,
9974 				(errcode_for_file_access(),
9975 				 errmsg("could not write to file \"%s\": %m",
9976 						CONFIG_EXEC_PARAMS_NEW)));
9977 		return;
9978 	}
9979 
9980 	for (i = 0; i < num_guc_variables; i++)
9981 	{
9982 		write_one_nondefault_variable(fp, guc_variables[i]);
9983 	}
9984 
9985 	if (FreeFile(fp))
9986 	{
9987 		ereport(elevel,
9988 				(errcode_for_file_access(),
9989 				 errmsg("could not write to file \"%s\": %m",
9990 						CONFIG_EXEC_PARAMS_NEW)));
9991 		return;
9992 	}
9993 
9994 	/*
9995 	 * Put new file in place.  This could delay on Win32, but we don't hold
9996 	 * any exclusive locks.
9997 	 */
9998 	rename(CONFIG_EXEC_PARAMS_NEW, CONFIG_EXEC_PARAMS);
9999 }
10000 
10001 
10002 /*
10003  *	Read string, including null byte from file
10004  *
10005  *	Return NULL on EOF and nothing read
10006  */
10007 static char *
read_string_with_null(FILE * fp)10008 read_string_with_null(FILE *fp)
10009 {
10010 	int			i = 0,
10011 				ch,
10012 				maxlen = 256;
10013 	char	   *str = NULL;
10014 
10015 	do
10016 	{
10017 		if ((ch = fgetc(fp)) == EOF)
10018 		{
10019 			if (i == 0)
10020 				return NULL;
10021 			else
10022 				elog(FATAL, "invalid format of exec config params file");
10023 		}
10024 		if (i == 0)
10025 			str = guc_malloc(FATAL, maxlen);
10026 		else if (i == maxlen)
10027 			str = guc_realloc(FATAL, str, maxlen *= 2);
10028 		str[i++] = ch;
10029 	} while (ch != 0);
10030 
10031 	return str;
10032 }
10033 
10034 
10035 /*
10036  *	This routine loads a previous postmaster dump of its non-default
10037  *	settings.
10038  */
10039 void
read_nondefault_variables(void)10040 read_nondefault_variables(void)
10041 {
10042 	FILE	   *fp;
10043 	char	   *varname,
10044 			   *varvalue,
10045 			   *varsourcefile;
10046 	int			varsourceline;
10047 	GucSource	varsource;
10048 	GucContext	varscontext;
10049 
10050 	/*
10051 	 * Assert that PGC_BACKEND/PGC_SU_BACKEND case in set_config_option() will
10052 	 * do the right thing.
10053 	 */
10054 	Assert(IsInitProcessingMode());
10055 
10056 	/*
10057 	 * Open file
10058 	 */
10059 	fp = AllocateFile(CONFIG_EXEC_PARAMS, "r");
10060 	if (!fp)
10061 	{
10062 		/* File not found is fine */
10063 		if (errno != ENOENT)
10064 			ereport(FATAL,
10065 					(errcode_for_file_access(),
10066 					 errmsg("could not read from file \"%s\": %m",
10067 							CONFIG_EXEC_PARAMS)));
10068 		return;
10069 	}
10070 
10071 	for (;;)
10072 	{
10073 		struct config_generic *record;
10074 
10075 		if ((varname = read_string_with_null(fp)) == NULL)
10076 			break;
10077 
10078 		if ((record = find_option(varname, true, FATAL)) == NULL)
10079 			elog(FATAL, "failed to locate variable \"%s\" in exec config params file", varname);
10080 
10081 		if ((varvalue = read_string_with_null(fp)) == NULL)
10082 			elog(FATAL, "invalid format of exec config params file");
10083 		if ((varsourcefile = read_string_with_null(fp)) == NULL)
10084 			elog(FATAL, "invalid format of exec config params file");
10085 		if (fread(&varsourceline, 1, sizeof(varsourceline), fp) != sizeof(varsourceline))
10086 			elog(FATAL, "invalid format of exec config params file");
10087 		if (fread(&varsource, 1, sizeof(varsource), fp) != sizeof(varsource))
10088 			elog(FATAL, "invalid format of exec config params file");
10089 		if (fread(&varscontext, 1, sizeof(varscontext), fp) != sizeof(varscontext))
10090 			elog(FATAL, "invalid format of exec config params file");
10091 
10092 		(void) set_config_option(varname, varvalue,
10093 								 varscontext, varsource,
10094 								 GUC_ACTION_SET, true, 0, true);
10095 		if (varsourcefile[0])
10096 			set_config_sourcefile(varname, varsourcefile, varsourceline);
10097 
10098 		free(varname);
10099 		free(varvalue);
10100 		free(varsourcefile);
10101 	}
10102 
10103 	FreeFile(fp);
10104 }
10105 #endif							/* EXEC_BACKEND */
10106 
10107 /*
10108  * can_skip_gucvar:
10109  * When serializing, determine whether to skip this GUC.  When restoring, the
10110  * negation of this test determines whether to restore the compiled-in default
10111  * value before processing serialized values.
10112  *
10113  * A PGC_S_DEFAULT setting on the serialize side will typically match new
10114  * postmaster children, but that can be false when got_SIGHUP == true and the
10115  * pending configuration change modifies this setting.  Nonetheless, we omit
10116  * PGC_S_DEFAULT settings from serialization and make up for that by restoring
10117  * defaults before applying serialized values.
10118  *
10119  * PGC_POSTMASTER variables always have the same value in every child of a
10120  * particular postmaster.  Most PGC_INTERNAL variables are compile-time
10121  * constants; a few, like server_encoding and lc_ctype, are handled specially
10122  * outside the serialize/restore procedure.  Therefore, SerializeGUCState()
10123  * never sends these, and RestoreGUCState() never changes them.
10124  *
10125  * Role is a special variable in the sense that its current value can be an
10126  * invalid value and there are multiple ways by which that can happen (like
10127  * after setting the role, someone drops it).  So we handle it outside of
10128  * serialize/restore machinery.
10129  */
10130 static bool
can_skip_gucvar(struct config_generic * gconf)10131 can_skip_gucvar(struct config_generic *gconf)
10132 {
10133 	return gconf->context == PGC_POSTMASTER ||
10134 		gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT ||
10135 		strcmp(gconf->name, "role") == 0;
10136 }
10137 
10138 /*
10139  * estimate_variable_size:
10140  *		Compute space needed for dumping the given GUC variable.
10141  *
10142  * It's OK to overestimate, but not to underestimate.
10143  */
10144 static Size
estimate_variable_size(struct config_generic * gconf)10145 estimate_variable_size(struct config_generic *gconf)
10146 {
10147 	Size		size;
10148 	Size		valsize = 0;
10149 
10150 	if (can_skip_gucvar(gconf))
10151 		return 0;
10152 
10153 	/* Name, plus trailing zero byte. */
10154 	size = strlen(gconf->name) + 1;
10155 
10156 	/* Get the maximum display length of the GUC value. */
10157 	switch (gconf->vartype)
10158 	{
10159 		case PGC_BOOL:
10160 			{
10161 				valsize = 5;	/* max(strlen('true'), strlen('false')) */
10162 			}
10163 			break;
10164 
10165 		case PGC_INT:
10166 			{
10167 				struct config_int *conf = (struct config_int *) gconf;
10168 
10169 				/*
10170 				 * Instead of getting the exact display length, use max
10171 				 * length.  Also reduce the max length for typical ranges of
10172 				 * small values.  Maximum value is 2147483647, i.e. 10 chars.
10173 				 * Include one byte for sign.
10174 				 */
10175 				if (Abs(*conf->variable) < 1000)
10176 					valsize = 3 + 1;
10177 				else
10178 					valsize = 10 + 1;
10179 			}
10180 			break;
10181 
10182 		case PGC_REAL:
10183 			{
10184 				/*
10185 				 * We are going to print it with %e with REALTYPE_PRECISION
10186 				 * fractional digits.  Account for sign, leading digit,
10187 				 * decimal point, and exponent with up to 3 digits.  E.g.
10188 				 * -3.99329042340000021e+110
10189 				 */
10190 				valsize = 1 + 1 + 1 + REALTYPE_PRECISION + 5;
10191 			}
10192 			break;
10193 
10194 		case PGC_STRING:
10195 			{
10196 				struct config_string *conf = (struct config_string *) gconf;
10197 
10198 				/*
10199 				 * If the value is NULL, we transmit it as an empty string.
10200 				 * Although this is not physically the same value, GUC
10201 				 * generally treats a NULL the same as empty string.
10202 				 */
10203 				if (*conf->variable)
10204 					valsize = strlen(*conf->variable);
10205 				else
10206 					valsize = 0;
10207 			}
10208 			break;
10209 
10210 		case PGC_ENUM:
10211 			{
10212 				struct config_enum *conf = (struct config_enum *) gconf;
10213 
10214 				valsize = strlen(config_enum_lookup_by_value(conf, *conf->variable));
10215 			}
10216 			break;
10217 	}
10218 
10219 	/* Allow space for terminating zero-byte for value */
10220 	size = add_size(size, valsize + 1);
10221 
10222 	if (gconf->sourcefile)
10223 		size = add_size(size, strlen(gconf->sourcefile));
10224 
10225 	/* Allow space for terminating zero-byte for sourcefile */
10226 	size = add_size(size, 1);
10227 
10228 	/* Include line whenever file is nonempty. */
10229 	if (gconf->sourcefile && gconf->sourcefile[0])
10230 		size = add_size(size, sizeof(gconf->sourceline));
10231 
10232 	size = add_size(size, sizeof(gconf->source));
10233 	size = add_size(size, sizeof(gconf->scontext));
10234 
10235 	return size;
10236 }
10237 
10238 /*
10239  * EstimateGUCStateSpace:
10240  * Returns the size needed to store the GUC state for the current process
10241  */
10242 Size
EstimateGUCStateSpace(void)10243 EstimateGUCStateSpace(void)
10244 {
10245 	Size		size;
10246 	int			i;
10247 
10248 	/* Add space reqd for saving the data size of the guc state */
10249 	size = sizeof(Size);
10250 
10251 	/* Add up the space needed for each GUC variable */
10252 	for (i = 0; i < num_guc_variables; i++)
10253 		size = add_size(size,
10254 						estimate_variable_size(guc_variables[i]));
10255 
10256 	return size;
10257 }
10258 
10259 /*
10260  * do_serialize:
10261  * Copies the formatted string into the destination.  Moves ahead the
10262  * destination pointer, and decrements the maxbytes by that many bytes. If
10263  * maxbytes is not sufficient to copy the string, error out.
10264  */
10265 static void
do_serialize(char ** destptr,Size * maxbytes,const char * fmt,...)10266 do_serialize(char **destptr, Size *maxbytes, const char *fmt,...)
10267 {
10268 	va_list		vargs;
10269 	int			n;
10270 
10271 	if (*maxbytes <= 0)
10272 		elog(ERROR, "not enough space to serialize GUC state");
10273 
10274 	va_start(vargs, fmt);
10275 	n = vsnprintf(*destptr, *maxbytes, fmt, vargs);
10276 	va_end(vargs);
10277 
10278 	if (n < 0)
10279 	{
10280 		/* Shouldn't happen. Better show errno description. */
10281 		elog(ERROR, "vsnprintf failed: %m with format string \"%s\"", fmt);
10282 	}
10283 	if (n >= *maxbytes)
10284 	{
10285 		/* This shouldn't happen either, really. */
10286 		elog(ERROR, "not enough space to serialize GUC state");
10287 	}
10288 
10289 	/* Shift the destptr ahead of the null terminator */
10290 	*destptr += n + 1;
10291 	*maxbytes -= n + 1;
10292 }
10293 
10294 /* Binary copy version of do_serialize() */
10295 static void
do_serialize_binary(char ** destptr,Size * maxbytes,void * val,Size valsize)10296 do_serialize_binary(char **destptr, Size *maxbytes, void *val, Size valsize)
10297 {
10298 	if (valsize > *maxbytes)
10299 		elog(ERROR, "not enough space to serialize GUC state");
10300 
10301 	memcpy(*destptr, val, valsize);
10302 	*destptr += valsize;
10303 	*maxbytes -= valsize;
10304 }
10305 
10306 /*
10307  * serialize_variable:
10308  * Dumps name, value and other information of a GUC variable into destptr.
10309  */
10310 static void
serialize_variable(char ** destptr,Size * maxbytes,struct config_generic * gconf)10311 serialize_variable(char **destptr, Size *maxbytes,
10312 				   struct config_generic *gconf)
10313 {
10314 	if (can_skip_gucvar(gconf))
10315 		return;
10316 
10317 	do_serialize(destptr, maxbytes, "%s", gconf->name);
10318 
10319 	switch (gconf->vartype)
10320 	{
10321 		case PGC_BOOL:
10322 			{
10323 				struct config_bool *conf = (struct config_bool *) gconf;
10324 
10325 				do_serialize(destptr, maxbytes,
10326 							 (*conf->variable ? "true" : "false"));
10327 			}
10328 			break;
10329 
10330 		case PGC_INT:
10331 			{
10332 				struct config_int *conf = (struct config_int *) gconf;
10333 
10334 				do_serialize(destptr, maxbytes, "%d", *conf->variable);
10335 			}
10336 			break;
10337 
10338 		case PGC_REAL:
10339 			{
10340 				struct config_real *conf = (struct config_real *) gconf;
10341 
10342 				do_serialize(destptr, maxbytes, "%.*e",
10343 							 REALTYPE_PRECISION, *conf->variable);
10344 			}
10345 			break;
10346 
10347 		case PGC_STRING:
10348 			{
10349 				struct config_string *conf = (struct config_string *) gconf;
10350 
10351 				/* NULL becomes empty string, see estimate_variable_size() */
10352 				do_serialize(destptr, maxbytes, "%s",
10353 							 *conf->variable ? *conf->variable : "");
10354 			}
10355 			break;
10356 
10357 		case PGC_ENUM:
10358 			{
10359 				struct config_enum *conf = (struct config_enum *) gconf;
10360 
10361 				do_serialize(destptr, maxbytes, "%s",
10362 							 config_enum_lookup_by_value(conf, *conf->variable));
10363 			}
10364 			break;
10365 	}
10366 
10367 	do_serialize(destptr, maxbytes, "%s",
10368 				 (gconf->sourcefile ? gconf->sourcefile : ""));
10369 
10370 	if (gconf->sourcefile && gconf->sourcefile[0])
10371 		do_serialize_binary(destptr, maxbytes, &gconf->sourceline,
10372 							sizeof(gconf->sourceline));
10373 
10374 	do_serialize_binary(destptr, maxbytes, &gconf->source,
10375 						sizeof(gconf->source));
10376 	do_serialize_binary(destptr, maxbytes, &gconf->scontext,
10377 						sizeof(gconf->scontext));
10378 }
10379 
10380 /*
10381  * SerializeGUCState:
10382  * Dumps the complete GUC state onto the memory location at start_address.
10383  */
10384 void
SerializeGUCState(Size maxsize,char * start_address)10385 SerializeGUCState(Size maxsize, char *start_address)
10386 {
10387 	char	   *curptr;
10388 	Size		actual_size;
10389 	Size		bytes_left;
10390 	int			i;
10391 
10392 	/* Reserve space for saving the actual size of the guc state */
10393 	Assert(maxsize > sizeof(actual_size));
10394 	curptr = start_address + sizeof(actual_size);
10395 	bytes_left = maxsize - sizeof(actual_size);
10396 
10397 	for (i = 0; i < num_guc_variables; i++)
10398 		serialize_variable(&curptr, &bytes_left, guc_variables[i]);
10399 
10400 	/* Store actual size without assuming alignment of start_address. */
10401 	actual_size = maxsize - bytes_left - sizeof(actual_size);
10402 	memcpy(start_address, &actual_size, sizeof(actual_size));
10403 }
10404 
10405 /*
10406  * read_gucstate:
10407  * Actually it does not read anything, just returns the srcptr. But it does
10408  * move the srcptr past the terminating zero byte, so that the caller is ready
10409  * to read the next string.
10410  */
10411 static char *
read_gucstate(char ** srcptr,char * srcend)10412 read_gucstate(char **srcptr, char *srcend)
10413 {
10414 	char	   *retptr = *srcptr;
10415 	char	   *ptr;
10416 
10417 	if (*srcptr >= srcend)
10418 		elog(ERROR, "incomplete GUC state");
10419 
10420 	/* The string variables are all null terminated */
10421 	for (ptr = *srcptr; ptr < srcend && *ptr != '\0'; ptr++)
10422 		;
10423 
10424 	if (ptr >= srcend)
10425 		elog(ERROR, "could not find null terminator in GUC state");
10426 
10427 	/* Set the new position to the byte following the terminating NUL */
10428 	*srcptr = ptr + 1;
10429 
10430 	return retptr;
10431 }
10432 
10433 /* Binary read version of read_gucstate(). Copies into dest */
10434 static void
read_gucstate_binary(char ** srcptr,char * srcend,void * dest,Size size)10435 read_gucstate_binary(char **srcptr, char *srcend, void *dest, Size size)
10436 {
10437 	if (*srcptr + size > srcend)
10438 		elog(ERROR, "incomplete GUC state");
10439 
10440 	memcpy(dest, *srcptr, size);
10441 	*srcptr += size;
10442 }
10443 
10444 /*
10445  * Callback used to add a context message when reporting errors that occur
10446  * while trying to restore GUCs in parallel workers.
10447  */
10448 static void
guc_restore_error_context_callback(void * arg)10449 guc_restore_error_context_callback(void *arg)
10450 {
10451 	char	  **error_context_name_and_value = (char **) arg;
10452 
10453 	if (error_context_name_and_value)
10454 		errcontext("while setting parameter \"%s\" to \"%s\"",
10455 				   error_context_name_and_value[0],
10456 				   error_context_name_and_value[1]);
10457 }
10458 
10459 /*
10460  * RestoreGUCState:
10461  * Reads the GUC state at the specified address and updates the GUCs with the
10462  * values read from the GUC state.
10463  */
10464 void
RestoreGUCState(void * gucstate)10465 RestoreGUCState(void *gucstate)
10466 {
10467 	char	   *varname,
10468 			   *varvalue,
10469 			   *varsourcefile;
10470 	int			varsourceline;
10471 	GucSource	varsource;
10472 	GucContext	varscontext;
10473 	char	   *srcptr = (char *) gucstate;
10474 	char	   *srcend;
10475 	Size		len;
10476 	int			i;
10477 	ErrorContextCallback error_context_callback;
10478 
10479 	/* See comment at can_skip_gucvar(). */
10480 	for (i = 0; i < num_guc_variables; i++)
10481 		if (!can_skip_gucvar(guc_variables[i]))
10482 			InitializeOneGUCOption(guc_variables[i]);
10483 
10484 	/* First item is the length of the subsequent data */
10485 	memcpy(&len, gucstate, sizeof(len));
10486 
10487 	srcptr += sizeof(len);
10488 	srcend = srcptr + len;
10489 
10490 	/* If the GUC value check fails, we want errors to show useful context. */
10491 	error_context_callback.callback = guc_restore_error_context_callback;
10492 	error_context_callback.previous = error_context_stack;
10493 	error_context_callback.arg = NULL;
10494 	error_context_stack = &error_context_callback;
10495 
10496 	while (srcptr < srcend)
10497 	{
10498 		int			result;
10499 		char	   *error_context_name_and_value[2];
10500 
10501 		varname = read_gucstate(&srcptr, srcend);
10502 		varvalue = read_gucstate(&srcptr, srcend);
10503 		varsourcefile = read_gucstate(&srcptr, srcend);
10504 		if (varsourcefile[0])
10505 			read_gucstate_binary(&srcptr, srcend,
10506 								 &varsourceline, sizeof(varsourceline));
10507 		else
10508 			varsourceline = 0;
10509 		read_gucstate_binary(&srcptr, srcend,
10510 							 &varsource, sizeof(varsource));
10511 		read_gucstate_binary(&srcptr, srcend,
10512 							 &varscontext, sizeof(varscontext));
10513 
10514 		error_context_name_and_value[0] = varname;
10515 		error_context_name_and_value[1] = varvalue;
10516 		error_context_callback.arg = &error_context_name_and_value[0];
10517 		result = set_config_option(varname, varvalue, varscontext, varsource,
10518 								   GUC_ACTION_SET, true, ERROR, true);
10519 		if (result <= 0)
10520 			ereport(ERROR,
10521 					(errcode(ERRCODE_INTERNAL_ERROR),
10522 					 errmsg("parameter \"%s\" could not be set", varname)));
10523 		if (varsourcefile[0])
10524 			set_config_sourcefile(varname, varsourcefile, varsourceline);
10525 		error_context_callback.arg = NULL;
10526 	}
10527 
10528 	error_context_stack = error_context_callback.previous;
10529 }
10530 
10531 /*
10532  * A little "long argument" simulation, although not quite GNU
10533  * compliant. Takes a string of the form "some-option=some value" and
10534  * returns name = "some_option" and value = "some value" in malloc'ed
10535  * storage. Note that '-' is converted to '_' in the option name. If
10536  * there is no '=' in the input string then value will be NULL.
10537  */
10538 void
ParseLongOption(const char * string,char ** name,char ** value)10539 ParseLongOption(const char *string, char **name, char **value)
10540 {
10541 	size_t		equal_pos;
10542 	char	   *cp;
10543 
10544 	AssertArg(string);
10545 	AssertArg(name);
10546 	AssertArg(value);
10547 
10548 	equal_pos = strcspn(string, "=");
10549 
10550 	if (string[equal_pos] == '=')
10551 	{
10552 		*name = guc_malloc(FATAL, equal_pos + 1);
10553 		strlcpy(*name, string, equal_pos + 1);
10554 
10555 		*value = guc_strdup(FATAL, &string[equal_pos + 1]);
10556 	}
10557 	else
10558 	{
10559 		/* no equal sign in string */
10560 		*name = guc_strdup(FATAL, string);
10561 		*value = NULL;
10562 	}
10563 
10564 	for (cp = *name; *cp; cp++)
10565 		if (*cp == '-')
10566 			*cp = '_';
10567 }
10568 
10569 
10570 /*
10571  * Handle options fetched from pg_db_role_setting.setconfig,
10572  * pg_proc.proconfig, etc.  Caller must specify proper context/source/action.
10573  *
10574  * The array parameter must be an array of TEXT (it must not be NULL).
10575  */
10576 void
ProcessGUCArray(ArrayType * array,GucContext context,GucSource source,GucAction action)10577 ProcessGUCArray(ArrayType *array,
10578 				GucContext context, GucSource source, GucAction action)
10579 {
10580 	int			i;
10581 
10582 	Assert(array != NULL);
10583 	Assert(ARR_ELEMTYPE(array) == TEXTOID);
10584 	Assert(ARR_NDIM(array) == 1);
10585 	Assert(ARR_LBOUND(array)[0] == 1);
10586 
10587 	for (i = 1; i <= ARR_DIMS(array)[0]; i++)
10588 	{
10589 		Datum		d;
10590 		bool		isnull;
10591 		char	   *s;
10592 		char	   *name;
10593 		char	   *value;
10594 		char	   *namecopy;
10595 		char	   *valuecopy;
10596 
10597 		d = array_ref(array, 1, &i,
10598 					  -1 /* varlenarray */ ,
10599 					  -1 /* TEXT's typlen */ ,
10600 					  false /* TEXT's typbyval */ ,
10601 					  TYPALIGN_INT /* TEXT's typalign */ ,
10602 					  &isnull);
10603 
10604 		if (isnull)
10605 			continue;
10606 
10607 		s = TextDatumGetCString(d);
10608 
10609 		ParseLongOption(s, &name, &value);
10610 		if (!value)
10611 		{
10612 			ereport(WARNING,
10613 					(errcode(ERRCODE_SYNTAX_ERROR),
10614 					 errmsg("could not parse setting for parameter \"%s\"",
10615 							name)));
10616 			free(name);
10617 			continue;
10618 		}
10619 
10620 		/* free malloc'd strings immediately to avoid leak upon error */
10621 		namecopy = pstrdup(name);
10622 		free(name);
10623 		valuecopy = pstrdup(value);
10624 		free(value);
10625 
10626 		(void) set_config_option(namecopy, valuecopy,
10627 								 context, source,
10628 								 action, true, 0, false);
10629 
10630 		pfree(namecopy);
10631 		pfree(valuecopy);
10632 		pfree(s);
10633 	}
10634 }
10635 
10636 
10637 /*
10638  * Add an entry to an option array.  The array parameter may be NULL
10639  * to indicate the current table entry is NULL.
10640  */
10641 ArrayType *
GUCArrayAdd(ArrayType * array,const char * name,const char * value)10642 GUCArrayAdd(ArrayType *array, const char *name, const char *value)
10643 {
10644 	struct config_generic *record;
10645 	Datum		datum;
10646 	char	   *newval;
10647 	ArrayType  *a;
10648 
10649 	Assert(name);
10650 	Assert(value);
10651 
10652 	/* test if the option is valid and we're allowed to set it */
10653 	(void) validate_option_array_item(name, value, false);
10654 
10655 	/* normalize name (converts obsolete GUC names to modern spellings) */
10656 	record = find_option(name, false, WARNING);
10657 	if (record)
10658 		name = record->name;
10659 
10660 	/* build new item for array */
10661 	newval = psprintf("%s=%s", name, value);
10662 	datum = CStringGetTextDatum(newval);
10663 
10664 	if (array)
10665 	{
10666 		int			index;
10667 		bool		isnull;
10668 		int			i;
10669 
10670 		Assert(ARR_ELEMTYPE(array) == TEXTOID);
10671 		Assert(ARR_NDIM(array) == 1);
10672 		Assert(ARR_LBOUND(array)[0] == 1);
10673 
10674 		index = ARR_DIMS(array)[0] + 1; /* add after end */
10675 
10676 		for (i = 1; i <= ARR_DIMS(array)[0]; i++)
10677 		{
10678 			Datum		d;
10679 			char	   *current;
10680 
10681 			d = array_ref(array, 1, &i,
10682 						  -1 /* varlenarray */ ,
10683 						  -1 /* TEXT's typlen */ ,
10684 						  false /* TEXT's typbyval */ ,
10685 						  TYPALIGN_INT /* TEXT's typalign */ ,
10686 						  &isnull);
10687 			if (isnull)
10688 				continue;
10689 			current = TextDatumGetCString(d);
10690 
10691 			/* check for match up through and including '=' */
10692 			if (strncmp(current, newval, strlen(name) + 1) == 0)
10693 			{
10694 				index = i;
10695 				break;
10696 			}
10697 		}
10698 
10699 		a = array_set(array, 1, &index,
10700 					  datum,
10701 					  false,
10702 					  -1 /* varlena array */ ,
10703 					  -1 /* TEXT's typlen */ ,
10704 					  false /* TEXT's typbyval */ ,
10705 					  TYPALIGN_INT /* TEXT's typalign */ );
10706 	}
10707 	else
10708 		a = construct_array(&datum, 1,
10709 							TEXTOID,
10710 							-1, false, TYPALIGN_INT);
10711 
10712 	return a;
10713 }
10714 
10715 
10716 /*
10717  * Delete an entry from an option array.  The array parameter may be NULL
10718  * to indicate the current table entry is NULL.  Also, if the return value
10719  * is NULL then a null should be stored.
10720  */
10721 ArrayType *
GUCArrayDelete(ArrayType * array,const char * name)10722 GUCArrayDelete(ArrayType *array, const char *name)
10723 {
10724 	struct config_generic *record;
10725 	ArrayType  *newarray;
10726 	int			i;
10727 	int			index;
10728 
10729 	Assert(name);
10730 
10731 	/* test if the option is valid and we're allowed to set it */
10732 	(void) validate_option_array_item(name, NULL, false);
10733 
10734 	/* normalize name (converts obsolete GUC names to modern spellings) */
10735 	record = find_option(name, false, WARNING);
10736 	if (record)
10737 		name = record->name;
10738 
10739 	/* if array is currently null, then surely nothing to delete */
10740 	if (!array)
10741 		return NULL;
10742 
10743 	newarray = NULL;
10744 	index = 1;
10745 
10746 	for (i = 1; i <= ARR_DIMS(array)[0]; i++)
10747 	{
10748 		Datum		d;
10749 		char	   *val;
10750 		bool		isnull;
10751 
10752 		d = array_ref(array, 1, &i,
10753 					  -1 /* varlenarray */ ,
10754 					  -1 /* TEXT's typlen */ ,
10755 					  false /* TEXT's typbyval */ ,
10756 					  TYPALIGN_INT /* TEXT's typalign */ ,
10757 					  &isnull);
10758 		if (isnull)
10759 			continue;
10760 		val = TextDatumGetCString(d);
10761 
10762 		/* ignore entry if it's what we want to delete */
10763 		if (strncmp(val, name, strlen(name)) == 0
10764 			&& val[strlen(name)] == '=')
10765 			continue;
10766 
10767 		/* else add it to the output array */
10768 		if (newarray)
10769 			newarray = array_set(newarray, 1, &index,
10770 								 d,
10771 								 false,
10772 								 -1 /* varlenarray */ ,
10773 								 -1 /* TEXT's typlen */ ,
10774 								 false /* TEXT's typbyval */ ,
10775 								 TYPALIGN_INT /* TEXT's typalign */ );
10776 		else
10777 			newarray = construct_array(&d, 1,
10778 									   TEXTOID,
10779 									   -1, false, TYPALIGN_INT);
10780 
10781 		index++;
10782 	}
10783 
10784 	return newarray;
10785 }
10786 
10787 
10788 /*
10789  * Given a GUC array, delete all settings from it that our permission
10790  * level allows: if superuser, delete them all; if regular user, only
10791  * those that are PGC_USERSET
10792  */
10793 ArrayType *
GUCArrayReset(ArrayType * array)10794 GUCArrayReset(ArrayType *array)
10795 {
10796 	ArrayType  *newarray;
10797 	int			i;
10798 	int			index;
10799 
10800 	/* if array is currently null, nothing to do */
10801 	if (!array)
10802 		return NULL;
10803 
10804 	/* if we're superuser, we can delete everything, so just do it */
10805 	if (superuser())
10806 		return NULL;
10807 
10808 	newarray = NULL;
10809 	index = 1;
10810 
10811 	for (i = 1; i <= ARR_DIMS(array)[0]; i++)
10812 	{
10813 		Datum		d;
10814 		char	   *val;
10815 		char	   *eqsgn;
10816 		bool		isnull;
10817 
10818 		d = array_ref(array, 1, &i,
10819 					  -1 /* varlenarray */ ,
10820 					  -1 /* TEXT's typlen */ ,
10821 					  false /* TEXT's typbyval */ ,
10822 					  TYPALIGN_INT /* TEXT's typalign */ ,
10823 					  &isnull);
10824 		if (isnull)
10825 			continue;
10826 		val = TextDatumGetCString(d);
10827 
10828 		eqsgn = strchr(val, '=');
10829 		*eqsgn = '\0';
10830 
10831 		/* skip if we have permission to delete it */
10832 		if (validate_option_array_item(val, NULL, true))
10833 			continue;
10834 
10835 		/* else add it to the output array */
10836 		if (newarray)
10837 			newarray = array_set(newarray, 1, &index,
10838 								 d,
10839 								 false,
10840 								 -1 /* varlenarray */ ,
10841 								 -1 /* TEXT's typlen */ ,
10842 								 false /* TEXT's typbyval */ ,
10843 								 TYPALIGN_INT /* TEXT's typalign */ );
10844 		else
10845 			newarray = construct_array(&d, 1,
10846 									   TEXTOID,
10847 									   -1, false, TYPALIGN_INT);
10848 
10849 		index++;
10850 		pfree(val);
10851 	}
10852 
10853 	return newarray;
10854 }
10855 
10856 /*
10857  * Validate a proposed option setting for GUCArrayAdd/Delete/Reset.
10858  *
10859  * name is the option name.  value is the proposed value for the Add case,
10860  * or NULL for the Delete/Reset cases.  If skipIfNoPermissions is true, it's
10861  * not an error to have no permissions to set the option.
10862  *
10863  * Returns true if OK, false if skipIfNoPermissions is true and user does not
10864  * have permission to change this option (all other error cases result in an
10865  * error being thrown).
10866  */
10867 static bool
validate_option_array_item(const char * name,const char * value,bool skipIfNoPermissions)10868 validate_option_array_item(const char *name, const char *value,
10869 						   bool skipIfNoPermissions)
10870 
10871 {
10872 	struct config_generic *gconf;
10873 
10874 	/*
10875 	 * There are three cases to consider:
10876 	 *
10877 	 * name is a known GUC variable.  Check the value normally, check
10878 	 * permissions normally (i.e., allow if variable is USERSET, or if it's
10879 	 * SUSET and user is superuser).
10880 	 *
10881 	 * name is not known, but exists or can be created as a placeholder (i.e.,
10882 	 * it has a prefixed name).  We allow this case if you're a superuser,
10883 	 * otherwise not.  Superusers are assumed to know what they're doing. We
10884 	 * can't allow it for other users, because when the placeholder is
10885 	 * resolved it might turn out to be a SUSET variable;
10886 	 * define_custom_variable assumes we checked that.
10887 	 *
10888 	 * name is not known and can't be created as a placeholder.  Throw error,
10889 	 * unless skipIfNoPermissions is true, in which case return false.
10890 	 */
10891 	gconf = find_option(name, true, WARNING);
10892 	if (!gconf)
10893 	{
10894 		/* not known, failed to make a placeholder */
10895 		if (skipIfNoPermissions)
10896 			return false;
10897 		ereport(ERROR,
10898 				(errcode(ERRCODE_UNDEFINED_OBJECT),
10899 				 errmsg("unrecognized configuration parameter \"%s\"",
10900 						name)));
10901 	}
10902 
10903 	if (gconf->flags & GUC_CUSTOM_PLACEHOLDER)
10904 	{
10905 		/*
10906 		 * We cannot do any meaningful check on the value, so only permissions
10907 		 * are useful to check.
10908 		 */
10909 		if (superuser())
10910 			return true;
10911 		if (skipIfNoPermissions)
10912 			return false;
10913 		ereport(ERROR,
10914 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
10915 				 errmsg("permission denied to set parameter \"%s\"", name)));
10916 	}
10917 
10918 	/* manual permissions check so we can avoid an error being thrown */
10919 	if (gconf->context == PGC_USERSET)
10920 		 /* ok */ ;
10921 	else if (gconf->context == PGC_SUSET && superuser())
10922 		 /* ok */ ;
10923 	else if (skipIfNoPermissions)
10924 		return false;
10925 	/* if a permissions error should be thrown, let set_config_option do it */
10926 
10927 	/* test for permissions and valid option value */
10928 	(void) set_config_option(name, value,
10929 							 superuser() ? PGC_SUSET : PGC_USERSET,
10930 							 PGC_S_TEST, GUC_ACTION_SET, false, 0, false);
10931 
10932 	return true;
10933 }
10934 
10935 
10936 /*
10937  * Called by check_hooks that want to override the normal
10938  * ERRCODE_INVALID_PARAMETER_VALUE SQLSTATE for check hook failures.
10939  *
10940  * Note that GUC_check_errmsg() etc are just macros that result in a direct
10941  * assignment to the associated variables.  That is ugly, but forced by the
10942  * limitations of C's macro mechanisms.
10943  */
10944 void
GUC_check_errcode(int sqlerrcode)10945 GUC_check_errcode(int sqlerrcode)
10946 {
10947 	GUC_check_errcode_value = sqlerrcode;
10948 }
10949 
10950 
10951 /*
10952  * Convenience functions to manage calling a variable's check_hook.
10953  * These mostly take care of the protocol for letting check hooks supply
10954  * portions of the error report on failure.
10955  */
10956 
10957 static bool
call_bool_check_hook(struct config_bool * conf,bool * newval,void ** extra,GucSource source,int elevel)10958 call_bool_check_hook(struct config_bool *conf, bool *newval, void **extra,
10959 					 GucSource source, int elevel)
10960 {
10961 	/* Quick success if no hook */
10962 	if (!conf->check_hook)
10963 		return true;
10964 
10965 	/* Reset variables that might be set by hook */
10966 	GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
10967 	GUC_check_errmsg_string = NULL;
10968 	GUC_check_errdetail_string = NULL;
10969 	GUC_check_errhint_string = NULL;
10970 
10971 	if (!conf->check_hook(newval, extra, source))
10972 	{
10973 		ereport(elevel,
10974 				(errcode(GUC_check_errcode_value),
10975 				 GUC_check_errmsg_string ?
10976 				 errmsg_internal("%s", GUC_check_errmsg_string) :
10977 				 errmsg("invalid value for parameter \"%s\": %d",
10978 						conf->gen.name, (int) *newval),
10979 				 GUC_check_errdetail_string ?
10980 				 errdetail_internal("%s", GUC_check_errdetail_string) : 0,
10981 				 GUC_check_errhint_string ?
10982 				 errhint("%s", GUC_check_errhint_string) : 0));
10983 		/* Flush any strings created in ErrorContext */
10984 		FlushErrorState();
10985 		return false;
10986 	}
10987 
10988 	return true;
10989 }
10990 
10991 static bool
call_int_check_hook(struct config_int * conf,int * newval,void ** extra,GucSource source,int elevel)10992 call_int_check_hook(struct config_int *conf, int *newval, void **extra,
10993 					GucSource source, int elevel)
10994 {
10995 	/* Quick success if no hook */
10996 	if (!conf->check_hook)
10997 		return true;
10998 
10999 	/* Reset variables that might be set by hook */
11000 	GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
11001 	GUC_check_errmsg_string = NULL;
11002 	GUC_check_errdetail_string = NULL;
11003 	GUC_check_errhint_string = NULL;
11004 
11005 	if (!conf->check_hook(newval, extra, source))
11006 	{
11007 		ereport(elevel,
11008 				(errcode(GUC_check_errcode_value),
11009 				 GUC_check_errmsg_string ?
11010 				 errmsg_internal("%s", GUC_check_errmsg_string) :
11011 				 errmsg("invalid value for parameter \"%s\": %d",
11012 						conf->gen.name, *newval),
11013 				 GUC_check_errdetail_string ?
11014 				 errdetail_internal("%s", GUC_check_errdetail_string) : 0,
11015 				 GUC_check_errhint_string ?
11016 				 errhint("%s", GUC_check_errhint_string) : 0));
11017 		/* Flush any strings created in ErrorContext */
11018 		FlushErrorState();
11019 		return false;
11020 	}
11021 
11022 	return true;
11023 }
11024 
11025 static bool
call_real_check_hook(struct config_real * conf,double * newval,void ** extra,GucSource source,int elevel)11026 call_real_check_hook(struct config_real *conf, double *newval, void **extra,
11027 					 GucSource source, int elevel)
11028 {
11029 	/* Quick success if no hook */
11030 	if (!conf->check_hook)
11031 		return true;
11032 
11033 	/* Reset variables that might be set by hook */
11034 	GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
11035 	GUC_check_errmsg_string = NULL;
11036 	GUC_check_errdetail_string = NULL;
11037 	GUC_check_errhint_string = NULL;
11038 
11039 	if (!conf->check_hook(newval, extra, source))
11040 	{
11041 		ereport(elevel,
11042 				(errcode(GUC_check_errcode_value),
11043 				 GUC_check_errmsg_string ?
11044 				 errmsg_internal("%s", GUC_check_errmsg_string) :
11045 				 errmsg("invalid value for parameter \"%s\": %g",
11046 						conf->gen.name, *newval),
11047 				 GUC_check_errdetail_string ?
11048 				 errdetail_internal("%s", GUC_check_errdetail_string) : 0,
11049 				 GUC_check_errhint_string ?
11050 				 errhint("%s", GUC_check_errhint_string) : 0));
11051 		/* Flush any strings created in ErrorContext */
11052 		FlushErrorState();
11053 		return false;
11054 	}
11055 
11056 	return true;
11057 }
11058 
11059 static bool
call_string_check_hook(struct config_string * conf,char ** newval,void ** extra,GucSource source,int elevel)11060 call_string_check_hook(struct config_string *conf, char **newval, void **extra,
11061 					   GucSource source, int elevel)
11062 {
11063 	volatile bool result = true;
11064 
11065 	/* Quick success if no hook */
11066 	if (!conf->check_hook)
11067 		return true;
11068 
11069 	/*
11070 	 * If elevel is ERROR, or if the check_hook itself throws an elog
11071 	 * (undesirable, but not always avoidable), make sure we don't leak the
11072 	 * already-malloc'd newval string.
11073 	 */
11074 	PG_TRY();
11075 	{
11076 		/* Reset variables that might be set by hook */
11077 		GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
11078 		GUC_check_errmsg_string = NULL;
11079 		GUC_check_errdetail_string = NULL;
11080 		GUC_check_errhint_string = NULL;
11081 
11082 		if (!conf->check_hook(newval, extra, source))
11083 		{
11084 			ereport(elevel,
11085 					(errcode(GUC_check_errcode_value),
11086 					 GUC_check_errmsg_string ?
11087 					 errmsg_internal("%s", GUC_check_errmsg_string) :
11088 					 errmsg("invalid value for parameter \"%s\": \"%s\"",
11089 							conf->gen.name, *newval ? *newval : ""),
11090 					 GUC_check_errdetail_string ?
11091 					 errdetail_internal("%s", GUC_check_errdetail_string) : 0,
11092 					 GUC_check_errhint_string ?
11093 					 errhint("%s", GUC_check_errhint_string) : 0));
11094 			/* Flush any strings created in ErrorContext */
11095 			FlushErrorState();
11096 			result = false;
11097 		}
11098 	}
11099 	PG_CATCH();
11100 	{
11101 		free(*newval);
11102 		PG_RE_THROW();
11103 	}
11104 	PG_END_TRY();
11105 
11106 	return result;
11107 }
11108 
11109 static bool
call_enum_check_hook(struct config_enum * conf,int * newval,void ** extra,GucSource source,int elevel)11110 call_enum_check_hook(struct config_enum *conf, int *newval, void **extra,
11111 					 GucSource source, int elevel)
11112 {
11113 	/* Quick success if no hook */
11114 	if (!conf->check_hook)
11115 		return true;
11116 
11117 	/* Reset variables that might be set by hook */
11118 	GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE;
11119 	GUC_check_errmsg_string = NULL;
11120 	GUC_check_errdetail_string = NULL;
11121 	GUC_check_errhint_string = NULL;
11122 
11123 	if (!conf->check_hook(newval, extra, source))
11124 	{
11125 		ereport(elevel,
11126 				(errcode(GUC_check_errcode_value),
11127 				 GUC_check_errmsg_string ?
11128 				 errmsg_internal("%s", GUC_check_errmsg_string) :
11129 				 errmsg("invalid value for parameter \"%s\": \"%s\"",
11130 						conf->gen.name,
11131 						config_enum_lookup_by_value(conf, *newval)),
11132 				 GUC_check_errdetail_string ?
11133 				 errdetail_internal("%s", GUC_check_errdetail_string) : 0,
11134 				 GUC_check_errhint_string ?
11135 				 errhint("%s", GUC_check_errhint_string) : 0));
11136 		/* Flush any strings created in ErrorContext */
11137 		FlushErrorState();
11138 		return false;
11139 	}
11140 
11141 	return true;
11142 }
11143 
11144 
11145 /*
11146  * check_hook, assign_hook and show_hook subroutines
11147  */
11148 
11149 static bool
check_wal_consistency_checking(char ** newval,void ** extra,GucSource source)11150 check_wal_consistency_checking(char **newval, void **extra, GucSource source)
11151 {
11152 	char	   *rawstring;
11153 	List	   *elemlist;
11154 	ListCell   *l;
11155 	bool		newwalconsistency[RM_MAX_ID + 1];
11156 
11157 	/* Initialize the array */
11158 	MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool));
11159 
11160 	/* Need a modifiable copy of string */
11161 	rawstring = pstrdup(*newval);
11162 
11163 	/* Parse string into list of identifiers */
11164 	if (!SplitIdentifierString(rawstring, ',', &elemlist))
11165 	{
11166 		/* syntax error in list */
11167 		GUC_check_errdetail("List syntax is invalid.");
11168 		pfree(rawstring);
11169 		list_free(elemlist);
11170 		return false;
11171 	}
11172 
11173 	foreach(l, elemlist)
11174 	{
11175 		char	   *tok = (char *) lfirst(l);
11176 		bool		found = false;
11177 		RmgrId		rmid;
11178 
11179 		/* Check for 'all'. */
11180 		if (pg_strcasecmp(tok, "all") == 0)
11181 		{
11182 			for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
11183 				if (RmgrTable[rmid].rm_mask != NULL)
11184 					newwalconsistency[rmid] = true;
11185 			found = true;
11186 		}
11187 		else
11188 		{
11189 			/*
11190 			 * Check if the token matches with any individual resource
11191 			 * manager.
11192 			 */
11193 			for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
11194 			{
11195 				if (pg_strcasecmp(tok, RmgrTable[rmid].rm_name) == 0 &&
11196 					RmgrTable[rmid].rm_mask != NULL)
11197 				{
11198 					newwalconsistency[rmid] = true;
11199 					found = true;
11200 				}
11201 			}
11202 		}
11203 
11204 		/* If a valid resource manager is found, check for the next one. */
11205 		if (!found)
11206 		{
11207 			GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
11208 			pfree(rawstring);
11209 			list_free(elemlist);
11210 			return false;
11211 		}
11212 	}
11213 
11214 	pfree(rawstring);
11215 	list_free(elemlist);
11216 
11217 	/* assign new value */
11218 	*extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool));
11219 	memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool));
11220 	return true;
11221 }
11222 
11223 static void
assign_wal_consistency_checking(const char * newval,void * extra)11224 assign_wal_consistency_checking(const char *newval, void *extra)
11225 {
11226 	wal_consistency_checking = (bool *) extra;
11227 }
11228 
11229 static bool
check_log_destination(char ** newval,void ** extra,GucSource source)11230 check_log_destination(char **newval, void **extra, GucSource source)
11231 {
11232 	char	   *rawstring;
11233 	List	   *elemlist;
11234 	ListCell   *l;
11235 	int			newlogdest = 0;
11236 	int		   *myextra;
11237 
11238 	/* Need a modifiable copy of string */
11239 	rawstring = pstrdup(*newval);
11240 
11241 	/* Parse string into list of identifiers */
11242 	if (!SplitIdentifierString(rawstring, ',', &elemlist))
11243 	{
11244 		/* syntax error in list */
11245 		GUC_check_errdetail("List syntax is invalid.");
11246 		pfree(rawstring);
11247 		list_free(elemlist);
11248 		return false;
11249 	}
11250 
11251 	foreach(l, elemlist)
11252 	{
11253 		char	   *tok = (char *) lfirst(l);
11254 
11255 		if (pg_strcasecmp(tok, "stderr") == 0)
11256 			newlogdest |= LOG_DESTINATION_STDERR;
11257 		else if (pg_strcasecmp(tok, "csvlog") == 0)
11258 			newlogdest |= LOG_DESTINATION_CSVLOG;
11259 #ifdef HAVE_SYSLOG
11260 		else if (pg_strcasecmp(tok, "syslog") == 0)
11261 			newlogdest |= LOG_DESTINATION_SYSLOG;
11262 #endif
11263 #ifdef WIN32
11264 		else if (pg_strcasecmp(tok, "eventlog") == 0)
11265 			newlogdest |= LOG_DESTINATION_EVENTLOG;
11266 #endif
11267 		else
11268 		{
11269 			GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
11270 			pfree(rawstring);
11271 			list_free(elemlist);
11272 			return false;
11273 		}
11274 	}
11275 
11276 	pfree(rawstring);
11277 	list_free(elemlist);
11278 
11279 	myextra = (int *) guc_malloc(ERROR, sizeof(int));
11280 	*myextra = newlogdest;
11281 	*extra = (void *) myextra;
11282 
11283 	return true;
11284 }
11285 
11286 static void
assign_log_destination(const char * newval,void * extra)11287 assign_log_destination(const char *newval, void *extra)
11288 {
11289 	Log_destination = *((int *) extra);
11290 }
11291 
11292 static void
assign_syslog_facility(int newval,void * extra)11293 assign_syslog_facility(int newval, void *extra)
11294 {
11295 #ifdef HAVE_SYSLOG
11296 	set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres",
11297 						  newval);
11298 #endif
11299 	/* Without syslog support, just ignore it */
11300 }
11301 
11302 static void
assign_syslog_ident(const char * newval,void * extra)11303 assign_syslog_ident(const char *newval, void *extra)
11304 {
11305 #ifdef HAVE_SYSLOG
11306 	set_syslog_parameters(newval, syslog_facility);
11307 #endif
11308 	/* Without syslog support, it will always be set to "none", so ignore */
11309 }
11310 
11311 
11312 static void
assign_session_replication_role(int newval,void * extra)11313 assign_session_replication_role(int newval, void *extra)
11314 {
11315 	/*
11316 	 * Must flush the plan cache when changing replication role; but don't
11317 	 * flush unnecessarily.
11318 	 */
11319 	if (SessionReplicationRole != newval)
11320 		ResetPlanCache();
11321 }
11322 
11323 static bool
check_temp_buffers(int * newval,void ** extra,GucSource source)11324 check_temp_buffers(int *newval, void **extra, GucSource source)
11325 {
11326 	/*
11327 	 * Once local buffers have been initialized, it's too late to change this.
11328 	 * However, if this is only a test call, allow it.
11329 	 */
11330 	if (source != PGC_S_TEST && NLocBuffer && NLocBuffer != *newval)
11331 	{
11332 		GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
11333 		return false;
11334 	}
11335 	return true;
11336 }
11337 
11338 static bool
check_bonjour(bool * newval,void ** extra,GucSource source)11339 check_bonjour(bool *newval, void **extra, GucSource source)
11340 {
11341 #ifndef USE_BONJOUR
11342 	if (*newval)
11343 	{
11344 		GUC_check_errmsg("Bonjour is not supported by this build");
11345 		return false;
11346 	}
11347 #endif
11348 	return true;
11349 }
11350 
11351 static bool
check_ssl(bool * newval,void ** extra,GucSource source)11352 check_ssl(bool *newval, void **extra, GucSource source)
11353 {
11354 #ifndef USE_SSL
11355 	if (*newval)
11356 	{
11357 		GUC_check_errmsg("SSL is not supported by this build");
11358 		return false;
11359 	}
11360 #endif
11361 	return true;
11362 }
11363 
11364 static bool
check_stage_log_stats(bool * newval,void ** extra,GucSource source)11365 check_stage_log_stats(bool *newval, void **extra, GucSource source)
11366 {
11367 	if (*newval && log_statement_stats)
11368 	{
11369 		GUC_check_errdetail("Cannot enable parameter when \"log_statement_stats\" is true.");
11370 		return false;
11371 	}
11372 	return true;
11373 }
11374 
11375 static bool
check_log_stats(bool * newval,void ** extra,GucSource source)11376 check_log_stats(bool *newval, void **extra, GucSource source)
11377 {
11378 	if (*newval &&
11379 		(log_parser_stats || log_planner_stats || log_executor_stats))
11380 	{
11381 		GUC_check_errdetail("Cannot enable \"log_statement_stats\" when "
11382 							"\"log_parser_stats\", \"log_planner_stats\", "
11383 							"or \"log_executor_stats\" is true.");
11384 		return false;
11385 	}
11386 	return true;
11387 }
11388 
11389 static bool
check_canonical_path(char ** newval,void ** extra,GucSource source)11390 check_canonical_path(char **newval, void **extra, GucSource source)
11391 {
11392 	/*
11393 	 * Since canonicalize_path never enlarges the string, we can just modify
11394 	 * newval in-place.  But watch out for NULL, which is the default value
11395 	 * for external_pid_file.
11396 	 */
11397 	if (*newval)
11398 		canonicalize_path(*newval);
11399 	return true;
11400 }
11401 
11402 static bool
check_timezone_abbreviations(char ** newval,void ** extra,GucSource source)11403 check_timezone_abbreviations(char **newval, void **extra, GucSource source)
11404 {
11405 	/*
11406 	 * The boot_val given above for timezone_abbreviations is NULL. When we
11407 	 * see this we just do nothing.  If this value isn't overridden from the
11408 	 * config file then pg_timezone_abbrev_initialize() will eventually
11409 	 * replace it with "Default".  This hack has two purposes: to avoid
11410 	 * wasting cycles loading values that might soon be overridden from the
11411 	 * config file, and to avoid trying to read the timezone abbrev files
11412 	 * during InitializeGUCOptions().  The latter doesn't work in an
11413 	 * EXEC_BACKEND subprocess because my_exec_path hasn't been set yet and so
11414 	 * we can't locate PGSHAREDIR.
11415 	 */
11416 	if (*newval == NULL)
11417 	{
11418 		Assert(source == PGC_S_DEFAULT);
11419 		return true;
11420 	}
11421 
11422 	/* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */
11423 	*extra = load_tzoffsets(*newval);
11424 
11425 	/* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
11426 	if (!*extra)
11427 		return false;
11428 
11429 	return true;
11430 }
11431 
11432 static void
assign_timezone_abbreviations(const char * newval,void * extra)11433 assign_timezone_abbreviations(const char *newval, void *extra)
11434 {
11435 	/* Do nothing for the boot_val default of NULL */
11436 	if (!extra)
11437 		return;
11438 
11439 	InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
11440 }
11441 
11442 /*
11443  * pg_timezone_abbrev_initialize --- set default value if not done already
11444  *
11445  * This is called after initial loading of postgresql.conf.  If no
11446  * timezone_abbreviations setting was found therein, select default.
11447  * If a non-default value is already installed, nothing will happen.
11448  *
11449  * This can also be called from ProcessConfigFile to establish the default
11450  * value after a postgresql.conf entry for it is removed.
11451  */
11452 static void
pg_timezone_abbrev_initialize(void)11453 pg_timezone_abbrev_initialize(void)
11454 {
11455 	SetConfigOption("timezone_abbreviations", "Default",
11456 					PGC_POSTMASTER, PGC_S_DYNAMIC_DEFAULT);
11457 }
11458 
11459 static const char *
show_archive_command(void)11460 show_archive_command(void)
11461 {
11462 	if (XLogArchivingActive())
11463 		return XLogArchiveCommand;
11464 	else
11465 		return "(disabled)";
11466 }
11467 
11468 static void
assign_tcp_keepalives_idle(int newval,void * extra)11469 assign_tcp_keepalives_idle(int newval, void *extra)
11470 {
11471 	/*
11472 	 * The kernel API provides no way to test a value without setting it; and
11473 	 * once we set it we might fail to unset it.  So there seems little point
11474 	 * in fully implementing the check-then-assign GUC API for these
11475 	 * variables.  Instead we just do the assignment on demand.  pqcomm.c
11476 	 * reports any problems via elog(LOG).
11477 	 *
11478 	 * This approach means that the GUC value might have little to do with the
11479 	 * actual kernel value, so we use a show_hook that retrieves the kernel
11480 	 * value rather than trusting GUC's copy.
11481 	 */
11482 	(void) pq_setkeepalivesidle(newval, MyProcPort);
11483 }
11484 
11485 static const char *
show_tcp_keepalives_idle(void)11486 show_tcp_keepalives_idle(void)
11487 {
11488 	/* See comments in assign_tcp_keepalives_idle */
11489 	static char nbuf[16];
11490 
11491 	snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesidle(MyProcPort));
11492 	return nbuf;
11493 }
11494 
11495 static void
assign_tcp_keepalives_interval(int newval,void * extra)11496 assign_tcp_keepalives_interval(int newval, void *extra)
11497 {
11498 	/* See comments in assign_tcp_keepalives_idle */
11499 	(void) pq_setkeepalivesinterval(newval, MyProcPort);
11500 }
11501 
11502 static const char *
show_tcp_keepalives_interval(void)11503 show_tcp_keepalives_interval(void)
11504 {
11505 	/* See comments in assign_tcp_keepalives_idle */
11506 	static char nbuf[16];
11507 
11508 	snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivesinterval(MyProcPort));
11509 	return nbuf;
11510 }
11511 
11512 static void
assign_tcp_keepalives_count(int newval,void * extra)11513 assign_tcp_keepalives_count(int newval, void *extra)
11514 {
11515 	/* See comments in assign_tcp_keepalives_idle */
11516 	(void) pq_setkeepalivescount(newval, MyProcPort);
11517 }
11518 
11519 static const char *
show_tcp_keepalives_count(void)11520 show_tcp_keepalives_count(void)
11521 {
11522 	/* See comments in assign_tcp_keepalives_idle */
11523 	static char nbuf[16];
11524 
11525 	snprintf(nbuf, sizeof(nbuf), "%d", pq_getkeepalivescount(MyProcPort));
11526 	return nbuf;
11527 }
11528 
11529 static void
assign_tcp_user_timeout(int newval,void * extra)11530 assign_tcp_user_timeout(int newval, void *extra)
11531 {
11532 	/* See comments in assign_tcp_keepalives_idle */
11533 	(void) pq_settcpusertimeout(newval, MyProcPort);
11534 }
11535 
11536 static const char *
show_tcp_user_timeout(void)11537 show_tcp_user_timeout(void)
11538 {
11539 	/* See comments in assign_tcp_keepalives_idle */
11540 	static char nbuf[16];
11541 
11542 	snprintf(nbuf, sizeof(nbuf), "%d", pq_gettcpusertimeout(MyProcPort));
11543 	return nbuf;
11544 }
11545 
11546 static bool
check_maxconnections(int * newval,void ** extra,GucSource source)11547 check_maxconnections(int *newval, void **extra, GucSource source)
11548 {
11549 	if (*newval + autovacuum_max_workers + 1 +
11550 		max_worker_processes + max_wal_senders > MAX_BACKENDS)
11551 		return false;
11552 	return true;
11553 }
11554 
11555 static bool
check_autovacuum_max_workers(int * newval,void ** extra,GucSource source)11556 check_autovacuum_max_workers(int *newval, void **extra, GucSource source)
11557 {
11558 	if (MaxConnections + *newval + 1 +
11559 		max_worker_processes + max_wal_senders > MAX_BACKENDS)
11560 		return false;
11561 	return true;
11562 }
11563 
11564 static bool
check_max_wal_senders(int * newval,void ** extra,GucSource source)11565 check_max_wal_senders(int *newval, void **extra, GucSource source)
11566 {
11567 	if (MaxConnections + autovacuum_max_workers + 1 +
11568 		max_worker_processes + *newval > MAX_BACKENDS)
11569 		return false;
11570 	return true;
11571 }
11572 
11573 static bool
check_autovacuum_work_mem(int * newval,void ** extra,GucSource source)11574 check_autovacuum_work_mem(int *newval, void **extra, GucSource source)
11575 {
11576 	/*
11577 	 * -1 indicates fallback.
11578 	 *
11579 	 * If we haven't yet changed the boot_val default of -1, just let it be.
11580 	 * Autovacuum will look to maintenance_work_mem instead.
11581 	 */
11582 	if (*newval == -1)
11583 		return true;
11584 
11585 	/*
11586 	 * We clamp manually-set values to at least 1MB.  Since
11587 	 * maintenance_work_mem is always set to at least this value, do the same
11588 	 * here.
11589 	 */
11590 	if (*newval < 1024)
11591 		*newval = 1024;
11592 
11593 	return true;
11594 }
11595 
11596 static bool
check_max_worker_processes(int * newval,void ** extra,GucSource source)11597 check_max_worker_processes(int *newval, void **extra, GucSource source)
11598 {
11599 	if (MaxConnections + autovacuum_max_workers + 1 +
11600 		*newval + max_wal_senders > MAX_BACKENDS)
11601 		return false;
11602 	return true;
11603 }
11604 
11605 static bool
check_effective_io_concurrency(int * newval,void ** extra,GucSource source)11606 check_effective_io_concurrency(int *newval, void **extra, GucSource source)
11607 {
11608 #ifndef USE_PREFETCH
11609 	if (*newval != 0)
11610 	{
11611 		GUC_check_errdetail("effective_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
11612 		return false;
11613 	}
11614 #endif							/* USE_PREFETCH */
11615 	return true;
11616 }
11617 
11618 static bool
check_maintenance_io_concurrency(int * newval,void ** extra,GucSource source)11619 check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
11620 {
11621 #ifndef USE_PREFETCH
11622 	if (*newval != 0)
11623 	{
11624 		GUC_check_errdetail("maintenance_io_concurrency must be set to 0 on platforms that lack posix_fadvise().");
11625 		return false;
11626 	}
11627 #endif							/* USE_PREFETCH */
11628 	return true;
11629 }
11630 
11631 static void
assign_pgstat_temp_directory(const char * newval,void * extra)11632 assign_pgstat_temp_directory(const char *newval, void *extra)
11633 {
11634 	/* check_canonical_path already canonicalized newval for us */
11635 	char	   *dname;
11636 	char	   *tname;
11637 	char	   *fname;
11638 
11639 	/* directory */
11640 	dname = guc_malloc(ERROR, strlen(newval) + 1);	/* runtime dir */
11641 	sprintf(dname, "%s", newval);
11642 
11643 	/* global stats */
11644 	tname = guc_malloc(ERROR, strlen(newval) + 12); /* /global.tmp */
11645 	sprintf(tname, "%s/global.tmp", newval);
11646 	fname = guc_malloc(ERROR, strlen(newval) + 13); /* /global.stat */
11647 	sprintf(fname, "%s/global.stat", newval);
11648 
11649 	if (pgstat_stat_directory)
11650 		free(pgstat_stat_directory);
11651 	pgstat_stat_directory = dname;
11652 	if (pgstat_stat_tmpname)
11653 		free(pgstat_stat_tmpname);
11654 	pgstat_stat_tmpname = tname;
11655 	if (pgstat_stat_filename)
11656 		free(pgstat_stat_filename);
11657 	pgstat_stat_filename = fname;
11658 }
11659 
11660 static bool
check_application_name(char ** newval,void ** extra,GucSource source)11661 check_application_name(char **newval, void **extra, GucSource source)
11662 {
11663 	/* Only allow clean ASCII chars in the application name */
11664 	pg_clean_ascii(*newval);
11665 
11666 	return true;
11667 }
11668 
11669 static void
assign_application_name(const char * newval,void * extra)11670 assign_application_name(const char *newval, void *extra)
11671 {
11672 	/* Update the pg_stat_activity view */
11673 	pgstat_report_appname(newval);
11674 }
11675 
11676 static bool
check_cluster_name(char ** newval,void ** extra,GucSource source)11677 check_cluster_name(char **newval, void **extra, GucSource source)
11678 {
11679 	/* Only allow clean ASCII chars in the cluster name */
11680 	pg_clean_ascii(*newval);
11681 
11682 	return true;
11683 }
11684 
11685 static const char *
show_unix_socket_permissions(void)11686 show_unix_socket_permissions(void)
11687 {
11688 	static char buf[12];
11689 
11690 	snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
11691 	return buf;
11692 }
11693 
11694 static const char *
show_log_file_mode(void)11695 show_log_file_mode(void)
11696 {
11697 	static char buf[12];
11698 
11699 	snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
11700 	return buf;
11701 }
11702 
11703 static const char *
show_data_directory_mode(void)11704 show_data_directory_mode(void)
11705 {
11706 	static char buf[12];
11707 
11708 	snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
11709 	return buf;
11710 }
11711 
11712 /*
11713  * We split the input string, where commas separate function names
11714  * and certain whitespace chars are ignored, into a \0-separated (and
11715  * \0\0-terminated) list of function names.  This formulation allows
11716  * easy scanning when an error is thrown while avoiding the use of
11717  * non-reentrant strtok(), as well as keeping the output data in a
11718  * single palloc() chunk.
11719  */
11720 static bool
check_backtrace_functions(char ** newval,void ** extra,GucSource source)11721 check_backtrace_functions(char **newval, void **extra, GucSource source)
11722 {
11723 	int			newvallen = strlen(*newval);
11724 	char	   *someval;
11725 	int			validlen;
11726 	int			i;
11727 	int			j;
11728 
11729 	/*
11730 	 * Allow characters that can be C identifiers and commas as separators, as
11731 	 * well as some whitespace for readability.
11732 	 */
11733 	validlen = strspn(*newval,
11734 					  "0123456789_"
11735 					  "abcdefghijklmnopqrstuvwxyz"
11736 					  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
11737 					  ", \n\t");
11738 	if (validlen != newvallen)
11739 	{
11740 		GUC_check_errdetail("invalid character");
11741 		return false;
11742 	}
11743 
11744 	if (*newval[0] == '\0')
11745 	{
11746 		*extra = NULL;
11747 		return true;
11748 	}
11749 
11750 	/*
11751 	 * Allocate space for the output and create the copy.  We could discount
11752 	 * whitespace chars to save some memory, but it doesn't seem worth the
11753 	 * trouble.
11754 	 */
11755 	someval = guc_malloc(ERROR, newvallen + 1 + 1);
11756 	for (i = 0, j = 0; i < newvallen; i++)
11757 	{
11758 		if ((*newval)[i] == ',')
11759 			someval[j++] = '\0';	/* next item */
11760 		else if ((*newval)[i] == ' ' ||
11761 				 (*newval)[i] == '\n' ||
11762 				 (*newval)[i] == '\t')
11763 			;					/* ignore these */
11764 		else
11765 			someval[j++] = (*newval)[i];	/* copy anything else */
11766 	}
11767 
11768 	/* two \0s end the setting */
11769 	someval[j] = '\0';
11770 	someval[j + 1] = '\0';
11771 
11772 	*extra = someval;
11773 	return true;
11774 }
11775 
11776 static void
assign_backtrace_functions(const char * newval,void * extra)11777 assign_backtrace_functions(const char *newval, void *extra)
11778 {
11779 	backtrace_symbol_list = (char *) extra;
11780 }
11781 
11782 static bool
check_recovery_target_timeline(char ** newval,void ** extra,GucSource source)11783 check_recovery_target_timeline(char **newval, void **extra, GucSource source)
11784 {
11785 	RecoveryTargetTimeLineGoal rttg;
11786 	RecoveryTargetTimeLineGoal *myextra;
11787 
11788 	if (strcmp(*newval, "current") == 0)
11789 		rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
11790 	else if (strcmp(*newval, "latest") == 0)
11791 		rttg = RECOVERY_TARGET_TIMELINE_LATEST;
11792 	else
11793 	{
11794 		rttg = RECOVERY_TARGET_TIMELINE_NUMERIC;
11795 
11796 		errno = 0;
11797 		strtoul(*newval, NULL, 0);
11798 		if (errno == EINVAL || errno == ERANGE)
11799 		{
11800 			GUC_check_errdetail("recovery_target_timeline is not a valid number.");
11801 			return false;
11802 		}
11803 	}
11804 
11805 	myextra = (RecoveryTargetTimeLineGoal *) guc_malloc(ERROR, sizeof(RecoveryTargetTimeLineGoal));
11806 	*myextra = rttg;
11807 	*extra = (void *) myextra;
11808 
11809 	return true;
11810 }
11811 
11812 static void
assign_recovery_target_timeline(const char * newval,void * extra)11813 assign_recovery_target_timeline(const char *newval, void *extra)
11814 {
11815 	recoveryTargetTimeLineGoal = *((RecoveryTargetTimeLineGoal *) extra);
11816 	if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
11817 		recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
11818 	else
11819 		recoveryTargetTLIRequested = 0;
11820 }
11821 
11822 /*
11823  * Recovery target settings: Only one of the several recovery_target* settings
11824  * may be set.  Setting a second one results in an error.  The global variable
11825  * recoveryTarget tracks which kind of recovery target was chosen.  Other
11826  * variables store the actual target value (for example a string or a xid).
11827  * The assign functions of the parameters check whether a competing parameter
11828  * was already set.  But we want to allow setting the same parameter multiple
11829  * times.  We also want to allow unsetting a parameter and setting a different
11830  * one, so we unset recoveryTarget when the parameter is set to an empty
11831  * string.
11832  */
11833 
11834 static void
pg_attribute_noreturn()11835 pg_attribute_noreturn()
11836 error_multiple_recovery_targets(void)
11837 {
11838 	ereport(ERROR,
11839 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11840 			 errmsg("multiple recovery targets specified"),
11841 			 errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set.")));
11842 }
11843 
11844 static bool
check_recovery_target(char ** newval,void ** extra,GucSource source)11845 check_recovery_target(char **newval, void **extra, GucSource source)
11846 {
11847 	if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
11848 	{
11849 		GUC_check_errdetail("The only allowed value is \"immediate\".");
11850 		return false;
11851 	}
11852 	return true;
11853 }
11854 
11855 static void
assign_recovery_target(const char * newval,void * extra)11856 assign_recovery_target(const char *newval, void *extra)
11857 {
11858 	if (recoveryTarget != RECOVERY_TARGET_UNSET &&
11859 		recoveryTarget != RECOVERY_TARGET_IMMEDIATE)
11860 		error_multiple_recovery_targets();
11861 
11862 	if (newval && strcmp(newval, "") != 0)
11863 		recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
11864 	else
11865 		recoveryTarget = RECOVERY_TARGET_UNSET;
11866 }
11867 
11868 static bool
check_recovery_target_xid(char ** newval,void ** extra,GucSource source)11869 check_recovery_target_xid(char **newval, void **extra, GucSource source)
11870 {
11871 	if (strcmp(*newval, "") != 0)
11872 	{
11873 		TransactionId xid;
11874 		TransactionId *myextra;
11875 
11876 		errno = 0;
11877 		xid = (TransactionId) pg_strtouint64(*newval, NULL, 0);
11878 		if (errno == EINVAL || errno == ERANGE)
11879 			return false;
11880 
11881 		myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
11882 		*myextra = xid;
11883 		*extra = (void *) myextra;
11884 	}
11885 	return true;
11886 }
11887 
11888 static void
assign_recovery_target_xid(const char * newval,void * extra)11889 assign_recovery_target_xid(const char *newval, void *extra)
11890 {
11891 	if (recoveryTarget != RECOVERY_TARGET_UNSET &&
11892 		recoveryTarget != RECOVERY_TARGET_XID)
11893 		error_multiple_recovery_targets();
11894 
11895 	if (newval && strcmp(newval, "") != 0)
11896 	{
11897 		recoveryTarget = RECOVERY_TARGET_XID;
11898 		recoveryTargetXid = *((TransactionId *) extra);
11899 	}
11900 	else
11901 		recoveryTarget = RECOVERY_TARGET_UNSET;
11902 }
11903 
11904 /*
11905  * The interpretation of the recovery_target_time string can depend on the
11906  * time zone setting, so we need to wait until after all GUC processing is
11907  * done before we can do the final parsing of the string.  This check function
11908  * only does a parsing pass to catch syntax errors, but we store the string
11909  * and parse it again when we need to use it.
11910  */
11911 static bool
check_recovery_target_time(char ** newval,void ** extra,GucSource source)11912 check_recovery_target_time(char **newval, void **extra, GucSource source)
11913 {
11914 	if (strcmp(*newval, "") != 0)
11915 	{
11916 		/* reject some special values */
11917 		if (strcmp(*newval, "now") == 0 ||
11918 			strcmp(*newval, "today") == 0 ||
11919 			strcmp(*newval, "tomorrow") == 0 ||
11920 			strcmp(*newval, "yesterday") == 0)
11921 		{
11922 			return false;
11923 		}
11924 
11925 		/*
11926 		 * parse timestamp value (see also timestamptz_in())
11927 		 */
11928 		{
11929 			char	   *str = *newval;
11930 			fsec_t		fsec;
11931 			struct pg_tm tt,
11932 					   *tm = &tt;
11933 			int			tz;
11934 			int			dtype;
11935 			int			nf;
11936 			int			dterr;
11937 			char	   *field[MAXDATEFIELDS];
11938 			int			ftype[MAXDATEFIELDS];
11939 			char		workbuf[MAXDATELEN + MAXDATEFIELDS];
11940 			TimestampTz timestamp;
11941 
11942 			dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
11943 								  field, ftype, MAXDATEFIELDS, &nf);
11944 			if (dterr == 0)
11945 				dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
11946 			if (dterr != 0)
11947 				return false;
11948 			if (dtype != DTK_DATE)
11949 				return false;
11950 
11951 			if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
11952 			{
11953 				GUC_check_errdetail("timestamp out of range: \"%s\"", str);
11954 				return false;
11955 			}
11956 		}
11957 	}
11958 	return true;
11959 }
11960 
11961 static void
assign_recovery_target_time(const char * newval,void * extra)11962 assign_recovery_target_time(const char *newval, void *extra)
11963 {
11964 	if (recoveryTarget != RECOVERY_TARGET_UNSET &&
11965 		recoveryTarget != RECOVERY_TARGET_TIME)
11966 		error_multiple_recovery_targets();
11967 
11968 	if (newval && strcmp(newval, "") != 0)
11969 		recoveryTarget = RECOVERY_TARGET_TIME;
11970 	else
11971 		recoveryTarget = RECOVERY_TARGET_UNSET;
11972 }
11973 
11974 static bool
check_recovery_target_name(char ** newval,void ** extra,GucSource source)11975 check_recovery_target_name(char **newval, void **extra, GucSource source)
11976 {
11977 	/* Use the value of newval directly */
11978 	if (strlen(*newval) >= MAXFNAMELEN)
11979 	{
11980 		GUC_check_errdetail("%s is too long (maximum %d characters).",
11981 							"recovery_target_name", MAXFNAMELEN - 1);
11982 		return false;
11983 	}
11984 	return true;
11985 }
11986 
11987 static void
assign_recovery_target_name(const char * newval,void * extra)11988 assign_recovery_target_name(const char *newval, void *extra)
11989 {
11990 	if (recoveryTarget != RECOVERY_TARGET_UNSET &&
11991 		recoveryTarget != RECOVERY_TARGET_NAME)
11992 		error_multiple_recovery_targets();
11993 
11994 	if (newval && strcmp(newval, "") != 0)
11995 	{
11996 		recoveryTarget = RECOVERY_TARGET_NAME;
11997 		recoveryTargetName = newval;
11998 	}
11999 	else
12000 		recoveryTarget = RECOVERY_TARGET_UNSET;
12001 }
12002 
12003 static bool
check_recovery_target_lsn(char ** newval,void ** extra,GucSource source)12004 check_recovery_target_lsn(char **newval, void **extra, GucSource source)
12005 {
12006 	if (strcmp(*newval, "") != 0)
12007 	{
12008 		XLogRecPtr	lsn;
12009 		XLogRecPtr *myextra;
12010 		bool		have_error = false;
12011 
12012 		lsn = pg_lsn_in_internal(*newval, &have_error);
12013 		if (have_error)
12014 			return false;
12015 
12016 		myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
12017 		*myextra = lsn;
12018 		*extra = (void *) myextra;
12019 	}
12020 	return true;
12021 }
12022 
12023 static void
assign_recovery_target_lsn(const char * newval,void * extra)12024 assign_recovery_target_lsn(const char *newval, void *extra)
12025 {
12026 	if (recoveryTarget != RECOVERY_TARGET_UNSET &&
12027 		recoveryTarget != RECOVERY_TARGET_LSN)
12028 		error_multiple_recovery_targets();
12029 
12030 	if (newval && strcmp(newval, "") != 0)
12031 	{
12032 		recoveryTarget = RECOVERY_TARGET_LSN;
12033 		recoveryTargetLSN = *((XLogRecPtr *) extra);
12034 	}
12035 	else
12036 		recoveryTarget = RECOVERY_TARGET_UNSET;
12037 }
12038 
12039 static bool
check_primary_slot_name(char ** newval,void ** extra,GucSource source)12040 check_primary_slot_name(char **newval, void **extra, GucSource source)
12041 {
12042 	if (*newval && strcmp(*newval, "") != 0 &&
12043 		!ReplicationSlotValidateName(*newval, WARNING))
12044 		return false;
12045 
12046 	return true;
12047 }
12048 
12049 static bool
check_default_with_oids(bool * newval,void ** extra,GucSource source)12050 check_default_with_oids(bool *newval, void **extra, GucSource source)
12051 {
12052 	if (*newval)
12053 	{
12054 		/* check the GUC's definition for an explanation */
12055 		GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
12056 		GUC_check_errmsg("tables declared WITH OIDS are not supported");
12057 
12058 		return false;
12059 	}
12060 
12061 	return true;
12062 }
12063 
12064 #include "guc-file.c"
12065