1 | /*-------------------------------------------------------------------- |
2 | * guc.c |
3 | * |
4 | * Support for grand unified configuration scheme, including SET |
5 | * command, configuration file, and command line options. |
6 | * See src/backend/utils/misc/README for more information. |
7 | * |
8 | * |
9 | * Copyright (c) 2000-2019, PostgreSQL Global Development Group |
10 | * Written by Peter Eisentraut <peter_e@gmx.net>. |
11 | * |
12 | * IDENTIFICATION |
13 | * src/backend/utils/misc/guc.c |
14 | * |
15 | *-------------------------------------------------------------------- |
16 | */ |
17 | #include "postgres.h" |
18 | |
19 | #include <ctype.h> |
20 | #include <float.h> |
21 | #include <math.h> |
22 | #include <limits.h> |
23 | #include <unistd.h> |
24 | #include <sys/stat.h> |
25 | #ifdef HAVE_SYSLOG |
26 | #include <syslog.h> |
27 | #endif |
28 | |
29 | #include "access/commit_ts.h" |
30 | #include "access/gin.h" |
31 | #include "access/rmgr.h" |
32 | #include "access/tableam.h" |
33 | #include "access/transam.h" |
34 | #include "access/twophase.h" |
35 | #include "access/xact.h" |
36 | #include "access/xlog_internal.h" |
37 | #include "catalog/namespace.h" |
38 | #include "catalog/pg_authid.h" |
39 | #include "commands/async.h" |
40 | #include "commands/prepare.h" |
41 | #include "commands/user.h" |
42 | #include "commands/vacuum.h" |
43 | #include "commands/variable.h" |
44 | #include "commands/trigger.h" |
45 | #include "common/string.h" |
46 | #include "funcapi.h" |
47 | #include "jit/jit.h" |
48 | #include "libpq/auth.h" |
49 | #include "libpq/libpq.h" |
50 | #include "libpq/pqformat.h" |
51 | #include "miscadmin.h" |
52 | #include "optimizer/cost.h" |
53 | #include "optimizer/geqo.h" |
54 | #include "optimizer/optimizer.h" |
55 | #include "optimizer/paths.h" |
56 | #include "optimizer/planmain.h" |
57 | #include "parser/parse_expr.h" |
58 | #include "parser/parse_type.h" |
59 | #include "parser/parser.h" |
60 | #include "parser/scansup.h" |
61 | #include "pgstat.h" |
62 | #include "postmaster/autovacuum.h" |
63 | #include "postmaster/bgworker_internals.h" |
64 | #include "postmaster/bgwriter.h" |
65 | #include "postmaster/postmaster.h" |
66 | #include "postmaster/syslogger.h" |
67 | #include "postmaster/walwriter.h" |
68 | #include "replication/logicallauncher.h" |
69 | #include "replication/slot.h" |
70 | #include "replication/syncrep.h" |
71 | #include "replication/walreceiver.h" |
72 | #include "replication/walsender.h" |
73 | #include "storage/bufmgr.h" |
74 | #include "storage/dsm_impl.h" |
75 | #include "storage/standby.h" |
76 | #include "storage/fd.h" |
77 | #include "storage/large_object.h" |
78 | #include "storage/pg_shmem.h" |
79 | #include "storage/proc.h" |
80 | #include "storage/predicate.h" |
81 | #include "tcop/tcopprot.h" |
82 | #include "tsearch/ts_cache.h" |
83 | #include "utils/builtins.h" |
84 | #include "utils/bytea.h" |
85 | #include "utils/guc_tables.h" |
86 | #include "utils/float.h" |
87 | #include "utils/memutils.h" |
88 | #include "utils/pg_locale.h" |
89 | #include "utils/pg_lsn.h" |
90 | #include "utils/plancache.h" |
91 | #include "utils/portal.h" |
92 | #include "utils/ps_status.h" |
93 | #include "utils/rls.h" |
94 | #include "utils/snapmgr.h" |
95 | #include "utils/tzparser.h" |
96 | #include "utils/varlena.h" |
97 | #include "utils/xml.h" |
98 | |
99 | #ifndef PG_KRB_SRVTAB |
100 | #define PG_KRB_SRVTAB "" |
101 | #endif |
102 | |
103 | #define CONFIG_FILENAME "postgresql.conf" |
104 | #define HBA_FILENAME "pg_hba.conf" |
105 | #define IDENT_FILENAME "pg_ident.conf" |
106 | |
107 | #ifdef EXEC_BACKEND |
108 | #define CONFIG_EXEC_PARAMS "global/config_exec_params" |
109 | #define CONFIG_EXEC_PARAMS_NEW "global/config_exec_params.new" |
110 | #endif |
111 | |
112 | /* |
113 | * Precision with which REAL type guc values are to be printed for GUC |
114 | * serialization. |
115 | */ |
116 | #define REALTYPE_PRECISION 17 |
117 | |
118 | /* XXX these should appear in other modules' header files */ |
119 | extern bool Log_disconnections; |
120 | extern int CommitDelay; |
121 | extern int CommitSiblings; |
122 | extern char *default_tablespace; |
123 | extern char *temp_tablespaces; |
124 | extern bool ignore_checksum_failure; |
125 | extern bool synchronize_seqscans; |
126 | |
127 | #ifdef TRACE_SYNCSCAN |
128 | extern bool trace_syncscan; |
129 | #endif |
130 | #ifdef DEBUG_BOUNDED_SORT |
131 | extern bool optimize_bounded_sort; |
132 | #endif |
133 | |
134 | static int GUC_check_errcode_value; |
135 | |
136 | /* global variables for check hook support */ |
137 | char *GUC_check_errmsg_string; |
138 | char *GUC_check_errdetail_string; |
139 | char *GUC_check_errhint_string; |
140 | |
141 | static void do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) pg_attribute_printf(3, 4); |
142 | |
143 | static void set_config_sourcefile(const char *name, char *sourcefile, |
144 | int sourceline); |
145 | static bool call_bool_check_hook(struct config_bool *conf, bool *newval, |
146 | void **, GucSource source, int elevel); |
147 | static bool call_int_check_hook(struct config_int *conf, int *newval, |
148 | void **, GucSource source, int elevel); |
149 | static bool call_real_check_hook(struct config_real *conf, double *newval, |
150 | void **, GucSource source, int elevel); |
151 | static bool call_string_check_hook(struct config_string *conf, char **newval, |
152 | void **, GucSource source, int elevel); |
153 | static bool call_enum_check_hook(struct config_enum *conf, int *newval, |
154 | void **, GucSource source, int elevel); |
155 | |
156 | static bool check_log_destination(char **newval, void **, GucSource source); |
157 | static void assign_log_destination(const char *newval, void *); |
158 | |
159 | static bool check_wal_consistency_checking(char **newval, void **, |
160 | GucSource source); |
161 | static void assign_wal_consistency_checking(const char *newval, void *); |
162 | |
163 | #ifdef HAVE_SYSLOG |
164 | static int syslog_facility = LOG_LOCAL0; |
165 | #else |
166 | static int syslog_facility = 0; |
167 | #endif |
168 | |
169 | static void assign_syslog_facility(int newval, void *); |
170 | static void assign_syslog_ident(const char *newval, void *); |
171 | static void assign_session_replication_role(int newval, void *); |
172 | static bool check_temp_buffers(int *newval, void **, GucSource source); |
173 | static bool check_bonjour(bool *newval, void **, GucSource source); |
174 | static bool check_ssl(bool *newval, void **, GucSource source); |
175 | static bool check_stage_log_stats(bool *newval, void **, GucSource source); |
176 | static bool check_log_stats(bool *newval, void **, GucSource source); |
177 | static bool check_canonical_path(char **newval, void **, GucSource source); |
178 | static bool check_timezone_abbreviations(char **newval, void **, GucSource source); |
179 | static void assign_timezone_abbreviations(const char *newval, void *); |
180 | static void pg_timezone_abbrev_initialize(void); |
181 | static const char *show_archive_command(void); |
182 | static void assign_tcp_keepalives_idle(int newval, void *); |
183 | static void assign_tcp_keepalives_interval(int newval, void *); |
184 | static void assign_tcp_keepalives_count(int newval, void *); |
185 | static void assign_tcp_user_timeout(int newval, void *); |
186 | static const char *show_tcp_keepalives_idle(void); |
187 | static const char *show_tcp_keepalives_interval(void); |
188 | static const char *show_tcp_keepalives_count(void); |
189 | static const char *show_tcp_user_timeout(void); |
190 | static bool check_maxconnections(int *newval, void **, GucSource source); |
191 | static bool check_max_worker_processes(int *newval, void **, GucSource source); |
192 | static bool check_autovacuum_max_workers(int *newval, void **, GucSource source); |
193 | static bool check_max_wal_senders(int *newval, void **, GucSource source); |
194 | static bool check_autovacuum_work_mem(int *newval, void **, GucSource source); |
195 | static bool check_effective_io_concurrency(int *newval, void **, GucSource source); |
196 | static void assign_effective_io_concurrency(int newval, void *); |
197 | static void assign_pgstat_temp_directory(const char *newval, void *); |
198 | static bool check_application_name(char **newval, void **, GucSource source); |
199 | static void assign_application_name(const char *newval, void *); |
200 | static bool check_cluster_name(char **newval, void **, GucSource source); |
201 | static const char *show_unix_socket_permissions(void); |
202 | static const char *show_log_file_mode(void); |
203 | static const char *show_data_directory_mode(void); |
204 | static bool check_recovery_target_timeline(char **newval, void **, GucSource source); |
205 | static void assign_recovery_target_timeline(const char *newval, void *); |
206 | static bool check_recovery_target(char **newval, void **, GucSource source); |
207 | static void assign_recovery_target(const char *newval, void *); |
208 | static bool check_recovery_target_xid(char **newval, void **, GucSource source); |
209 | static void assign_recovery_target_xid(const char *newval, void *); |
210 | static bool check_recovery_target_time(char **newval, void **, GucSource source); |
211 | static void assign_recovery_target_time(const char *newval, void *); |
212 | static bool check_recovery_target_name(char **newval, void **, GucSource source); |
213 | static void assign_recovery_target_name(const char *newval, void *); |
214 | static bool check_recovery_target_lsn(char **newval, void **, GucSource source); |
215 | static void assign_recovery_target_lsn(const char *newval, void *); |
216 | static bool check_primary_slot_name(char **newval, void **, GucSource source); |
217 | static bool check_default_with_oids(bool *newval, void **, GucSource source); |
218 | |
219 | /* Private functions in guc-file.l that need to be called from guc.c */ |
220 | static ConfigVariable *ProcessConfigFileInternal(GucContext context, |
221 | bool applySettings, int elevel); |
222 | |
223 | |
224 | /* |
225 | * Options for enum values defined in this module. |
226 | * |
227 | * NOTE! Option values may not contain double quotes! |
228 | */ |
229 | |
230 | static const struct config_enum_entry bytea_output_options[] = { |
231 | {"escape" , BYTEA_OUTPUT_ESCAPE, false}, |
232 | {"hex" , BYTEA_OUTPUT_HEX, false}, |
233 | {NULL, 0, false} |
234 | }; |
235 | |
236 | /* |
237 | * We have different sets for client and server message level options because |
238 | * they sort slightly different (see "log" level), and because "fatal"/"panic" |
239 | * aren't sensible for client_min_messages. |
240 | */ |
241 | static const struct config_enum_entry client_message_level_options[] = { |
242 | {"debug5" , DEBUG5, false}, |
243 | {"debug4" , DEBUG4, false}, |
244 | {"debug3" , DEBUG3, false}, |
245 | {"debug2" , DEBUG2, false}, |
246 | {"debug1" , DEBUG1, false}, |
247 | {"debug" , DEBUG2, true}, |
248 | {"log" , LOG, false}, |
249 | {"info" , INFO, true}, |
250 | {"notice" , NOTICE, false}, |
251 | {"warning" , WARNING, false}, |
252 | {"error" , ERROR, false}, |
253 | {NULL, 0, false} |
254 | }; |
255 | |
256 | static const struct config_enum_entry server_message_level_options[] = { |
257 | {"debug5" , DEBUG5, false}, |
258 | {"debug4" , DEBUG4, false}, |
259 | {"debug3" , DEBUG3, false}, |
260 | {"debug2" , DEBUG2, false}, |
261 | {"debug1" , DEBUG1, false}, |
262 | {"debug" , DEBUG2, true}, |
263 | {"info" , INFO, false}, |
264 | {"notice" , NOTICE, false}, |
265 | {"warning" , WARNING, false}, |
266 | {"error" , ERROR, false}, |
267 | {"log" , LOG, false}, |
268 | {"fatal" , FATAL, false}, |
269 | {"panic" , PANIC, false}, |
270 | {NULL, 0, false} |
271 | }; |
272 | |
273 | static const struct config_enum_entry intervalstyle_options[] = { |
274 | {"postgres" , INTSTYLE_POSTGRES, false}, |
275 | {"postgres_verbose" , INTSTYLE_POSTGRES_VERBOSE, false}, |
276 | {"sql_standard" , INTSTYLE_SQL_STANDARD, false}, |
277 | {"iso_8601" , INTSTYLE_ISO_8601, false}, |
278 | {NULL, 0, false} |
279 | }; |
280 | |
281 | static const struct config_enum_entry log_error_verbosity_options[] = { |
282 | {"terse" , PGERROR_TERSE, false}, |
283 | {"default" , PGERROR_DEFAULT, false}, |
284 | {"verbose" , PGERROR_VERBOSE, false}, |
285 | {NULL, 0, false} |
286 | }; |
287 | |
288 | static const struct config_enum_entry log_statement_options[] = { |
289 | {"none" , LOGSTMT_NONE, false}, |
290 | {"ddl" , LOGSTMT_DDL, false}, |
291 | {"mod" , LOGSTMT_MOD, false}, |
292 | {"all" , LOGSTMT_ALL, false}, |
293 | {NULL, 0, false} |
294 | }; |
295 | |
296 | static const struct config_enum_entry isolation_level_options[] = { |
297 | {"serializable" , XACT_SERIALIZABLE, false}, |
298 | {"repeatable read" , XACT_REPEATABLE_READ, false}, |
299 | {"read committed" , XACT_READ_COMMITTED, false}, |
300 | {"read uncommitted" , XACT_READ_UNCOMMITTED, false}, |
301 | {NULL, 0} |
302 | }; |
303 | |
304 | static const struct config_enum_entry session_replication_role_options[] = { |
305 | {"origin" , SESSION_REPLICATION_ROLE_ORIGIN, false}, |
306 | {"replica" , SESSION_REPLICATION_ROLE_REPLICA, false}, |
307 | {"local" , SESSION_REPLICATION_ROLE_LOCAL, false}, |
308 | {NULL, 0, false} |
309 | }; |
310 | |
311 | static const struct config_enum_entry syslog_facility_options[] = { |
312 | #ifdef HAVE_SYSLOG |
313 | {"local0" , LOG_LOCAL0, false}, |
314 | {"local1" , LOG_LOCAL1, false}, |
315 | {"local2" , LOG_LOCAL2, false}, |
316 | {"local3" , LOG_LOCAL3, false}, |
317 | {"local4" , LOG_LOCAL4, false}, |
318 | {"local5" , LOG_LOCAL5, false}, |
319 | {"local6" , LOG_LOCAL6, false}, |
320 | {"local7" , LOG_LOCAL7, false}, |
321 | #else |
322 | {"none" , 0, false}, |
323 | #endif |
324 | {NULL, 0} |
325 | }; |
326 | |
327 | static const struct config_enum_entry track_function_options[] = { |
328 | {"none" , TRACK_FUNC_OFF, false}, |
329 | {"pl" , TRACK_FUNC_PL, false}, |
330 | {"all" , TRACK_FUNC_ALL, false}, |
331 | {NULL, 0, false} |
332 | }; |
333 | |
334 | static const struct config_enum_entry xmlbinary_options[] = { |
335 | {"base64" , XMLBINARY_BASE64, false}, |
336 | {"hex" , XMLBINARY_HEX, false}, |
337 | {NULL, 0, false} |
338 | }; |
339 | |
340 | static const struct config_enum_entry xmloption_options[] = { |
341 | {"content" , XMLOPTION_CONTENT, false}, |
342 | {"document" , XMLOPTION_DOCUMENT, false}, |
343 | {NULL, 0, false} |
344 | }; |
345 | |
346 | /* |
347 | * Although only "on", "off", and "safe_encoding" are documented, we |
348 | * accept all the likely variants of "on" and "off". |
349 | */ |
350 | static const struct config_enum_entry backslash_quote_options[] = { |
351 | {"safe_encoding" , BACKSLASH_QUOTE_SAFE_ENCODING, false}, |
352 | {"on" , BACKSLASH_QUOTE_ON, false}, |
353 | {"off" , BACKSLASH_QUOTE_OFF, false}, |
354 | {"true" , BACKSLASH_QUOTE_ON, true}, |
355 | {"false" , BACKSLASH_QUOTE_OFF, true}, |
356 | {"yes" , BACKSLASH_QUOTE_ON, true}, |
357 | {"no" , BACKSLASH_QUOTE_OFF, true}, |
358 | {"1" , BACKSLASH_QUOTE_ON, true}, |
359 | {"0" , BACKSLASH_QUOTE_OFF, true}, |
360 | {NULL, 0, false} |
361 | }; |
362 | |
363 | /* |
364 | * Although only "on", "off", and "partition" are documented, we |
365 | * accept all the likely variants of "on" and "off". |
366 | */ |
367 | static const struct config_enum_entry constraint_exclusion_options[] = { |
368 | {"partition" , CONSTRAINT_EXCLUSION_PARTITION, false}, |
369 | {"on" , CONSTRAINT_EXCLUSION_ON, false}, |
370 | {"off" , CONSTRAINT_EXCLUSION_OFF, false}, |
371 | {"true" , CONSTRAINT_EXCLUSION_ON, true}, |
372 | {"false" , CONSTRAINT_EXCLUSION_OFF, true}, |
373 | {"yes" , CONSTRAINT_EXCLUSION_ON, true}, |
374 | {"no" , CONSTRAINT_EXCLUSION_OFF, true}, |
375 | {"1" , CONSTRAINT_EXCLUSION_ON, true}, |
376 | {"0" , CONSTRAINT_EXCLUSION_OFF, true}, |
377 | {NULL, 0, false} |
378 | }; |
379 | |
380 | /* |
381 | * Although only "on", "off", "remote_apply", "remote_write", and "local" are |
382 | * documented, we accept all the likely variants of "on" and "off". |
383 | */ |
384 | static const struct config_enum_entry synchronous_commit_options[] = { |
385 | {"local" , SYNCHRONOUS_COMMIT_LOCAL_FLUSH, false}, |
386 | {"remote_write" , SYNCHRONOUS_COMMIT_REMOTE_WRITE, false}, |
387 | {"remote_apply" , SYNCHRONOUS_COMMIT_REMOTE_APPLY, false}, |
388 | {"on" , SYNCHRONOUS_COMMIT_ON, false}, |
389 | {"off" , SYNCHRONOUS_COMMIT_OFF, false}, |
390 | {"true" , SYNCHRONOUS_COMMIT_ON, true}, |
391 | {"false" , SYNCHRONOUS_COMMIT_OFF, true}, |
392 | {"yes" , SYNCHRONOUS_COMMIT_ON, true}, |
393 | {"no" , SYNCHRONOUS_COMMIT_OFF, true}, |
394 | {"1" , SYNCHRONOUS_COMMIT_ON, true}, |
395 | {"0" , SYNCHRONOUS_COMMIT_OFF, true}, |
396 | {NULL, 0, false} |
397 | }; |
398 | |
399 | /* |
400 | * Although only "on", "off", "try" are documented, we accept all the likely |
401 | * variants of "on" and "off". |
402 | */ |
403 | static const struct config_enum_entry huge_pages_options[] = { |
404 | {"off" , HUGE_PAGES_OFF, false}, |
405 | {"on" , HUGE_PAGES_ON, false}, |
406 | {"try" , HUGE_PAGES_TRY, false}, |
407 | {"true" , HUGE_PAGES_ON, true}, |
408 | {"false" , HUGE_PAGES_OFF, true}, |
409 | {"yes" , HUGE_PAGES_ON, true}, |
410 | {"no" , HUGE_PAGES_OFF, true}, |
411 | {"1" , HUGE_PAGES_ON, true}, |
412 | {"0" , HUGE_PAGES_OFF, true}, |
413 | {NULL, 0, false} |
414 | }; |
415 | |
416 | static const struct config_enum_entry force_parallel_mode_options[] = { |
417 | {"off" , FORCE_PARALLEL_OFF, false}, |
418 | {"on" , FORCE_PARALLEL_ON, false}, |
419 | {"regress" , FORCE_PARALLEL_REGRESS, false}, |
420 | {"true" , FORCE_PARALLEL_ON, true}, |
421 | {"false" , FORCE_PARALLEL_OFF, true}, |
422 | {"yes" , FORCE_PARALLEL_ON, true}, |
423 | {"no" , FORCE_PARALLEL_OFF, true}, |
424 | {"1" , FORCE_PARALLEL_ON, true}, |
425 | {"0" , FORCE_PARALLEL_OFF, true}, |
426 | {NULL, 0, false} |
427 | }; |
428 | |
429 | static const struct config_enum_entry plan_cache_mode_options[] = { |
430 | {"auto" , PLAN_CACHE_MODE_AUTO, false}, |
431 | {"force_generic_plan" , PLAN_CACHE_MODE_FORCE_GENERIC_PLAN, false}, |
432 | {"force_custom_plan" , PLAN_CACHE_MODE_FORCE_CUSTOM_PLAN, false}, |
433 | {NULL, 0, false} |
434 | }; |
435 | |
436 | /* |
437 | * password_encryption used to be a boolean, so accept all the likely |
438 | * variants of "on", too. "off" used to store passwords in plaintext, |
439 | * but we don't support that anymore. |
440 | */ |
441 | static const struct config_enum_entry password_encryption_options[] = { |
442 | {"md5" , PASSWORD_TYPE_MD5, false}, |
443 | {"scram-sha-256" , PASSWORD_TYPE_SCRAM_SHA_256, false}, |
444 | {"on" , PASSWORD_TYPE_MD5, true}, |
445 | {"true" , PASSWORD_TYPE_MD5, true}, |
446 | {"yes" , PASSWORD_TYPE_MD5, true}, |
447 | {"1" , PASSWORD_TYPE_MD5, true}, |
448 | {NULL, 0, false} |
449 | }; |
450 | |
451 | const struct config_enum_entry ssl_protocol_versions_info[] = { |
452 | {"" , PG_TLS_ANY, false}, |
453 | {"TLSv1" , PG_TLS1_VERSION, false}, |
454 | {"TLSv1.1" , PG_TLS1_1_VERSION, false}, |
455 | {"TLSv1.2" , PG_TLS1_2_VERSION, false}, |
456 | {"TLSv1.3" , PG_TLS1_3_VERSION, false}, |
457 | {NULL, 0, false} |
458 | }; |
459 | |
460 | static struct config_enum_entry shared_memory_options[] = { |
461 | #ifndef WIN32 |
462 | {"sysv" , SHMEM_TYPE_SYSV, false}, |
463 | #endif |
464 | #ifndef EXEC_BACKEND |
465 | {"mmap" , SHMEM_TYPE_MMAP, false}, |
466 | #endif |
467 | #ifdef WIN32 |
468 | {"windows" , SHMEM_TYPE_WINDOWS, false}, |
469 | #endif |
470 | {NULL, 0, false} |
471 | }; |
472 | |
473 | /* |
474 | * Options for enum values stored in other modules |
475 | */ |
476 | extern const struct config_enum_entry wal_level_options[]; |
477 | extern const struct config_enum_entry archive_mode_options[]; |
478 | extern const struct config_enum_entry recovery_target_action_options[]; |
479 | extern const struct config_enum_entry sync_method_options[]; |
480 | extern const struct config_enum_entry dynamic_shared_memory_options[]; |
481 | |
482 | /* |
483 | * GUC option variables that are exported from this module |
484 | */ |
485 | bool log_duration = false; |
486 | bool Debug_print_plan = false; |
487 | bool Debug_print_parse = false; |
488 | bool Debug_print_rewritten = false; |
489 | bool Debug_pretty_print = true; |
490 | |
491 | bool log_parser_stats = false; |
492 | bool log_planner_stats = false; |
493 | bool log_executor_stats = false; |
494 | bool log_statement_stats = false; /* this is sort of all three above |
495 | * together */ |
496 | bool log_btree_build_stats = false; |
497 | char *event_source; |
498 | |
499 | bool row_security; |
500 | bool check_function_bodies = true; |
501 | |
502 | /* |
503 | * This GUC exists solely for backward compatibility, check its definition for |
504 | * details. |
505 | */ |
506 | bool default_with_oids = false; |
507 | bool session_auth_is_superuser; |
508 | |
509 | int log_min_error_statement = ERROR; |
510 | int log_min_messages = WARNING; |
511 | int client_min_messages = NOTICE; |
512 | int log_min_duration_statement = -1; |
513 | int log_temp_files = -1; |
514 | double log_xact_sample_rate = 0; |
515 | int trace_recovery_messages = LOG; |
516 | |
517 | int temp_file_limit = -1; |
518 | |
519 | int num_temp_buffers = 1024; |
520 | |
521 | char *cluster_name = "" ; |
522 | char *ConfigFileName; |
523 | char *HbaFileName; |
524 | char *IdentFileName; |
525 | char *external_pid_file; |
526 | |
527 | char *pgstat_temp_directory; |
528 | |
529 | char *application_name; |
530 | |
531 | int tcp_keepalives_idle; |
532 | int tcp_keepalives_interval; |
533 | int tcp_keepalives_count; |
534 | int tcp_user_timeout; |
535 | |
536 | /* |
537 | * SSL renegotiation was been removed in PostgreSQL 9.5, but we tolerate it |
538 | * being set to zero (meaning never renegotiate) for backward compatibility. |
539 | * This avoids breaking compatibility with clients that have never supported |
540 | * renegotiation and therefore always try to zero it. |
541 | */ |
542 | int ssl_renegotiation_limit; |
543 | |
544 | /* |
545 | * This really belongs in pg_shmem.c, but is defined here so that it doesn't |
546 | * need to be duplicated in all the different implementations of pg_shmem.c. |
547 | */ |
548 | int huge_pages; |
549 | |
550 | /* |
551 | * These variables are all dummies that don't do anything, except in some |
552 | * cases provide the value for SHOW to display. The real state is elsewhere |
553 | * and is kept in sync by assign_hooks. |
554 | */ |
555 | static char *syslog_ident_str; |
556 | static double phony_random_seed; |
557 | static char *client_encoding_string; |
558 | static char *datestyle_string; |
559 | static char *locale_collate; |
560 | static char *locale_ctype; |
561 | static char *server_encoding_string; |
562 | static char *server_version_string; |
563 | static int server_version_num; |
564 | static char *timezone_string; |
565 | static char *log_timezone_string; |
566 | static char *timezone_abbreviations_string; |
567 | static char *data_directory; |
568 | static char *session_authorization_string; |
569 | static int max_function_args; |
570 | static int max_index_keys; |
571 | static int max_identifier_length; |
572 | static int block_size; |
573 | static int segment_size; |
574 | static int wal_block_size; |
575 | static bool data_checksums; |
576 | static bool integer_datetimes; |
577 | static bool assert_enabled; |
578 | static char *recovery_target_timeline_string; |
579 | static char *recovery_target_string; |
580 | static char *recovery_target_xid_string; |
581 | static char *recovery_target_name_string; |
582 | static char *recovery_target_lsn_string; |
583 | |
584 | |
585 | /* should be static, but commands/variable.c needs to get at this */ |
586 | char *role_string; |
587 | |
588 | |
589 | /* |
590 | * Displayable names for context types (enum GucContext) |
591 | * |
592 | * Note: these strings are deliberately not localized. |
593 | */ |
594 | const char *const GucContext_Names[] = |
595 | { |
596 | /* PGC_INTERNAL */ "internal" , |
597 | /* PGC_POSTMASTER */ "postmaster" , |
598 | /* PGC_SIGHUP */ "sighup" , |
599 | /* PGC_SU_BACKEND */ "superuser-backend" , |
600 | /* PGC_BACKEND */ "backend" , |
601 | /* PGC_SUSET */ "superuser" , |
602 | /* PGC_USERSET */ "user" |
603 | }; |
604 | |
605 | /* |
606 | * Displayable names for source types (enum GucSource) |
607 | * |
608 | * Note: these strings are deliberately not localized. |
609 | */ |
610 | const char *const GucSource_Names[] = |
611 | { |
612 | /* PGC_S_DEFAULT */ "default" , |
613 | /* PGC_S_DYNAMIC_DEFAULT */ "default" , |
614 | /* PGC_S_ENV_VAR */ "environment variable" , |
615 | /* PGC_S_FILE */ "configuration file" , |
616 | /* PGC_S_ARGV */ "command line" , |
617 | /* PGC_S_GLOBAL */ "global" , |
618 | /* PGC_S_DATABASE */ "database" , |
619 | /* PGC_S_USER */ "user" , |
620 | /* PGC_S_DATABASE_USER */ "database user" , |
621 | /* PGC_S_CLIENT */ "client" , |
622 | /* PGC_S_OVERRIDE */ "override" , |
623 | /* PGC_S_INTERACTIVE */ "interactive" , |
624 | /* PGC_S_TEST */ "test" , |
625 | /* PGC_S_SESSION */ "session" |
626 | }; |
627 | |
628 | /* |
629 | * Displayable names for the groupings defined in enum config_group |
630 | */ |
631 | const char *const config_group_names[] = |
632 | { |
633 | /* UNGROUPED */ |
634 | gettext_noop("Ungrouped" ), |
635 | /* FILE_LOCATIONS */ |
636 | gettext_noop("File Locations" ), |
637 | /* CONN_AUTH */ |
638 | gettext_noop("Connections and Authentication" ), |
639 | /* CONN_AUTH_SETTINGS */ |
640 | gettext_noop("Connections and Authentication / Connection Settings" ), |
641 | /* CONN_AUTH_AUTH */ |
642 | gettext_noop("Connections and Authentication / Authentication" ), |
643 | /* CONN_AUTH_SSL */ |
644 | gettext_noop("Connections and Authentication / SSL" ), |
645 | /* RESOURCES */ |
646 | gettext_noop("Resource Usage" ), |
647 | /* RESOURCES_MEM */ |
648 | gettext_noop("Resource Usage / Memory" ), |
649 | /* RESOURCES_DISK */ |
650 | gettext_noop("Resource Usage / Disk" ), |
651 | /* RESOURCES_KERNEL */ |
652 | gettext_noop("Resource Usage / Kernel Resources" ), |
653 | /* RESOURCES_VACUUM_DELAY */ |
654 | gettext_noop("Resource Usage / Cost-Based Vacuum Delay" ), |
655 | /* RESOURCES_BGWRITER */ |
656 | gettext_noop("Resource Usage / Background Writer" ), |
657 | /* RESOURCES_ASYNCHRONOUS */ |
658 | gettext_noop("Resource Usage / Asynchronous Behavior" ), |
659 | /* WAL */ |
660 | gettext_noop("Write-Ahead Log" ), |
661 | /* WAL_SETTINGS */ |
662 | gettext_noop("Write-Ahead Log / Settings" ), |
663 | /* WAL_CHECKPOINTS */ |
664 | gettext_noop("Write-Ahead Log / Checkpoints" ), |
665 | /* WAL_ARCHIVING */ |
666 | gettext_noop("Write-Ahead Log / Archiving" ), |
667 | /* WAL_ARCHIVE_RECOVERY */ |
668 | gettext_noop("Write-Ahead Log / Archive Recovery" ), |
669 | /* WAL_RECOVERY_TARGET */ |
670 | gettext_noop("Write-Ahead Log / Recovery Target" ), |
671 | /* REPLICATION */ |
672 | gettext_noop("Replication" ), |
673 | /* REPLICATION_SENDING */ |
674 | gettext_noop("Replication / Sending Servers" ), |
675 | /* REPLICATION_MASTER */ |
676 | gettext_noop("Replication / Master Server" ), |
677 | /* REPLICATION_STANDBY */ |
678 | gettext_noop("Replication / Standby Servers" ), |
679 | /* REPLICATION_SUBSCRIBERS */ |
680 | gettext_noop("Replication / Subscribers" ), |
681 | /* QUERY_TUNING */ |
682 | gettext_noop("Query Tuning" ), |
683 | /* QUERY_TUNING_METHOD */ |
684 | gettext_noop("Query Tuning / Planner Method Configuration" ), |
685 | /* QUERY_TUNING_COST */ |
686 | gettext_noop("Query Tuning / Planner Cost Constants" ), |
687 | /* QUERY_TUNING_GEQO */ |
688 | gettext_noop("Query Tuning / Genetic Query Optimizer" ), |
689 | /* QUERY_TUNING_OTHER */ |
690 | gettext_noop("Query Tuning / Other Planner Options" ), |
691 | /* LOGGING */ |
692 | gettext_noop("Reporting and Logging" ), |
693 | /* LOGGING_WHERE */ |
694 | gettext_noop("Reporting and Logging / Where to Log" ), |
695 | /* LOGGING_WHEN */ |
696 | gettext_noop("Reporting and Logging / When to Log" ), |
697 | /* LOGGING_WHAT */ |
698 | gettext_noop("Reporting and Logging / What to Log" ), |
699 | /* PROCESS_TITLE */ |
700 | gettext_noop("Process Title" ), |
701 | /* STATS */ |
702 | gettext_noop("Statistics" ), |
703 | /* STATS_MONITORING */ |
704 | gettext_noop("Statistics / Monitoring" ), |
705 | /* STATS_COLLECTOR */ |
706 | gettext_noop("Statistics / Query and Index Statistics Collector" ), |
707 | /* AUTOVACUUM */ |
708 | gettext_noop("Autovacuum" ), |
709 | /* CLIENT_CONN */ |
710 | gettext_noop("Client Connection Defaults" ), |
711 | /* CLIENT_CONN_STATEMENT */ |
712 | gettext_noop("Client Connection Defaults / Statement Behavior" ), |
713 | /* CLIENT_CONN_LOCALE */ |
714 | gettext_noop("Client Connection Defaults / Locale and Formatting" ), |
715 | /* CLIENT_CONN_PRELOAD */ |
716 | gettext_noop("Client Connection Defaults / Shared Library Preloading" ), |
717 | /* CLIENT_CONN_OTHER */ |
718 | gettext_noop("Client Connection Defaults / Other Defaults" ), |
719 | /* LOCK_MANAGEMENT */ |
720 | gettext_noop("Lock Management" ), |
721 | /* COMPAT_OPTIONS */ |
722 | gettext_noop("Version and Platform Compatibility" ), |
723 | /* COMPAT_OPTIONS_PREVIOUS */ |
724 | gettext_noop("Version and Platform Compatibility / Previous PostgreSQL Versions" ), |
725 | /* COMPAT_OPTIONS_CLIENT */ |
726 | gettext_noop("Version and Platform Compatibility / Other Platforms and Clients" ), |
727 | /* ERROR_HANDLING */ |
728 | gettext_noop("Error Handling" ), |
729 | /* PRESET_OPTIONS */ |
730 | gettext_noop("Preset Options" ), |
731 | /* CUSTOM_OPTIONS */ |
732 | gettext_noop("Customized Options" ), |
733 | /* DEVELOPER_OPTIONS */ |
734 | gettext_noop("Developer Options" ), |
735 | /* help_config wants this array to be null-terminated */ |
736 | NULL |
737 | }; |
738 | |
739 | /* |
740 | * Displayable names for GUC variable types (enum config_type) |
741 | * |
742 | * Note: these strings are deliberately not localized. |
743 | */ |
744 | const char *const config_type_names[] = |
745 | { |
746 | /* PGC_BOOL */ "bool" , |
747 | /* PGC_INT */ "integer" , |
748 | /* PGC_REAL */ "real" , |
749 | /* PGC_STRING */ "string" , |
750 | /* PGC_ENUM */ "enum" |
751 | }; |
752 | |
753 | /* |
754 | * Unit conversion tables. |
755 | * |
756 | * There are two tables, one for memory units, and another for time units. |
757 | * For each supported conversion from one unit to another, we have an entry |
758 | * in the table. |
759 | * |
760 | * To keep things simple, and to avoid possible roundoff error, |
761 | * conversions are never chained. There needs to be a direct conversion |
762 | * between all units (of the same type). |
763 | * |
764 | * The conversions for each base unit must be kept in order from greatest to |
765 | * smallest human-friendly unit; convert_xxx_from_base_unit() rely on that. |
766 | * (The order of the base-unit groups does not matter.) |
767 | */ |
768 | #define MAX_UNIT_LEN 3 /* length of longest recognized unit string */ |
769 | |
770 | typedef struct |
771 | { |
772 | char unit[MAX_UNIT_LEN + 1]; /* unit, as a string, like "kB" or |
773 | * "min" */ |
774 | int base_unit; /* GUC_UNIT_XXX */ |
775 | double multiplier; /* Factor for converting unit -> base_unit */ |
776 | } unit_conversion; |
777 | |
778 | /* Ensure that the constants in the tables don't overflow or underflow */ |
779 | #if BLCKSZ < 1024 || BLCKSZ > (1024*1024) |
780 | #error BLCKSZ must be between 1KB and 1MB |
781 | #endif |
782 | #if XLOG_BLCKSZ < 1024 || XLOG_BLCKSZ > (1024*1024) |
783 | #error XLOG_BLCKSZ must be between 1KB and 1MB |
784 | #endif |
785 | |
786 | static const char *memory_units_hint = gettext_noop("Valid units for this parameter are \"B\", \"kB\", \"MB\", \"GB\", and \"TB\"." ); |
787 | |
788 | static const unit_conversion memory_unit_conversion_table[] = |
789 | { |
790 | {"TB" , GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0 * 1024.0}, |
791 | {"GB" , GUC_UNIT_BYTE, 1024.0 * 1024.0 * 1024.0}, |
792 | {"MB" , GUC_UNIT_BYTE, 1024.0 * 1024.0}, |
793 | {"kB" , GUC_UNIT_BYTE, 1024.0}, |
794 | {"B" , GUC_UNIT_BYTE, 1.0}, |
795 | |
796 | {"TB" , GUC_UNIT_KB, 1024.0 * 1024.0 * 1024.0}, |
797 | {"GB" , GUC_UNIT_KB, 1024.0 * 1024.0}, |
798 | {"MB" , GUC_UNIT_KB, 1024.0}, |
799 | {"kB" , GUC_UNIT_KB, 1.0}, |
800 | {"B" , GUC_UNIT_KB, 1.0 / 1024.0}, |
801 | |
802 | {"TB" , GUC_UNIT_MB, 1024.0 * 1024.0}, |
803 | {"GB" , GUC_UNIT_MB, 1024.0}, |
804 | {"MB" , GUC_UNIT_MB, 1.0}, |
805 | {"kB" , GUC_UNIT_MB, 1.0 / 1024.0}, |
806 | {"B" , GUC_UNIT_MB, 1.0 / (1024.0 * 1024.0)}, |
807 | |
808 | {"TB" , GUC_UNIT_BLOCKS, (1024.0 * 1024.0 * 1024.0) / (BLCKSZ / 1024)}, |
809 | {"GB" , GUC_UNIT_BLOCKS, (1024.0 * 1024.0) / (BLCKSZ / 1024)}, |
810 | {"MB" , GUC_UNIT_BLOCKS, 1024.0 / (BLCKSZ / 1024)}, |
811 | {"kB" , GUC_UNIT_BLOCKS, 1.0 / (BLCKSZ / 1024)}, |
812 | {"B" , GUC_UNIT_BLOCKS, 1.0 / BLCKSZ}, |
813 | |
814 | {"TB" , GUC_UNIT_XBLOCKS, (1024.0 * 1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)}, |
815 | {"GB" , GUC_UNIT_XBLOCKS, (1024.0 * 1024.0) / (XLOG_BLCKSZ / 1024)}, |
816 | {"MB" , GUC_UNIT_XBLOCKS, 1024.0 / (XLOG_BLCKSZ / 1024)}, |
817 | {"kB" , GUC_UNIT_XBLOCKS, 1.0 / (XLOG_BLCKSZ / 1024)}, |
818 | {"B" , GUC_UNIT_XBLOCKS, 1.0 / XLOG_BLCKSZ}, |
819 | |
820 | {"" } /* end of table marker */ |
821 | }; |
822 | |
823 | static const char *time_units_hint = gettext_noop("Valid units for this parameter are \"us\", \"ms\", \"s\", \"min\", \"h\", and \"d\"." ); |
824 | |
825 | static const unit_conversion time_unit_conversion_table[] = |
826 | { |
827 | {"d" , GUC_UNIT_MS, 1000 * 60 * 60 * 24}, |
828 | {"h" , GUC_UNIT_MS, 1000 * 60 * 60}, |
829 | {"min" , GUC_UNIT_MS, 1000 * 60}, |
830 | {"s" , GUC_UNIT_MS, 1000}, |
831 | {"ms" , GUC_UNIT_MS, 1}, |
832 | {"us" , GUC_UNIT_MS, 1.0 / 1000}, |
833 | |
834 | {"d" , GUC_UNIT_S, 60 * 60 * 24}, |
835 | {"h" , GUC_UNIT_S, 60 * 60}, |
836 | {"min" , GUC_UNIT_S, 60}, |
837 | {"s" , GUC_UNIT_S, 1}, |
838 | {"ms" , GUC_UNIT_S, 1.0 / 1000}, |
839 | {"us" , GUC_UNIT_S, 1.0 / (1000 * 1000)}, |
840 | |
841 | {"d" , GUC_UNIT_MIN, 60 * 24}, |
842 | {"h" , GUC_UNIT_MIN, 60}, |
843 | {"min" , GUC_UNIT_MIN, 1}, |
844 | {"s" , GUC_UNIT_MIN, 1.0 / 60}, |
845 | {"ms" , GUC_UNIT_MIN, 1.0 / (1000 * 60)}, |
846 | {"us" , GUC_UNIT_MIN, 1.0 / (1000 * 1000 * 60)}, |
847 | |
848 | {"" } /* end of table marker */ |
849 | }; |
850 | |
851 | /* |
852 | * Contents of GUC tables |
853 | * |
854 | * See src/backend/utils/misc/README for design notes. |
855 | * |
856 | * TO ADD AN OPTION: |
857 | * |
858 | * 1. Declare a global variable of type bool, int, double, or char* |
859 | * and make use of it. |
860 | * |
861 | * 2. Decide at what times it's safe to set the option. See guc.h for |
862 | * details. |
863 | * |
864 | * 3. Decide on a name, a default value, upper and lower bounds (if |
865 | * applicable), etc. |
866 | * |
867 | * 4. Add a record below. |
868 | * |
869 | * 5. Add it to src/backend/utils/misc/postgresql.conf.sample, if |
870 | * appropriate. |
871 | * |
872 | * 6. Don't forget to document the option (at least in config.sgml). |
873 | * |
874 | * 7. If it's a new GUC_LIST_QUOTE option, you must add it to |
875 | * variable_is_guc_list_quote() in src/bin/pg_dump/dumputils.c. |
876 | */ |
877 | |
878 | |
879 | /******** option records follow ********/ |
880 | |
881 | static struct config_bool ConfigureNamesBool[] = |
882 | { |
883 | { |
884 | {"enable_seqscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
885 | gettext_noop("Enables the planner's use of sequential-scan plans." ), |
886 | NULL, |
887 | GUC_EXPLAIN |
888 | }, |
889 | &enable_seqscan, |
890 | true, |
891 | NULL, NULL, NULL |
892 | }, |
893 | { |
894 | {"enable_indexscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
895 | gettext_noop("Enables the planner's use of index-scan plans." ), |
896 | NULL, |
897 | GUC_EXPLAIN |
898 | }, |
899 | &enable_indexscan, |
900 | true, |
901 | NULL, NULL, NULL |
902 | }, |
903 | { |
904 | {"enable_indexonlyscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
905 | gettext_noop("Enables the planner's use of index-only-scan plans." ), |
906 | NULL, |
907 | GUC_EXPLAIN |
908 | }, |
909 | &enable_indexonlyscan, |
910 | true, |
911 | NULL, NULL, NULL |
912 | }, |
913 | { |
914 | {"enable_bitmapscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
915 | gettext_noop("Enables the planner's use of bitmap-scan plans." ), |
916 | NULL, |
917 | GUC_EXPLAIN |
918 | }, |
919 | &enable_bitmapscan, |
920 | true, |
921 | NULL, NULL, NULL |
922 | }, |
923 | { |
924 | {"enable_tidscan" , PGC_USERSET, QUERY_TUNING_METHOD, |
925 | gettext_noop("Enables the planner's use of TID scan plans." ), |
926 | NULL, |
927 | GUC_EXPLAIN |
928 | }, |
929 | &enable_tidscan, |
930 | true, |
931 | NULL, NULL, NULL |
932 | }, |
933 | { |
934 | {"enable_sort" , PGC_USERSET, QUERY_TUNING_METHOD, |
935 | gettext_noop("Enables the planner's use of explicit sort steps." ), |
936 | NULL, |
937 | GUC_EXPLAIN |
938 | }, |
939 | &enable_sort, |
940 | true, |
941 | NULL, NULL, NULL |
942 | }, |
943 | { |
944 | {"enable_hashagg" , PGC_USERSET, QUERY_TUNING_METHOD, |
945 | gettext_noop("Enables the planner's use of hashed aggregation plans." ), |
946 | NULL, |
947 | GUC_EXPLAIN |
948 | }, |
949 | &enable_hashagg, |
950 | true, |
951 | NULL, NULL, NULL |
952 | }, |
953 | { |
954 | {"enable_material" , PGC_USERSET, QUERY_TUNING_METHOD, |
955 | gettext_noop("Enables the planner's use of materialization." ), |
956 | NULL, |
957 | GUC_EXPLAIN |
958 | }, |
959 | &enable_material, |
960 | true, |
961 | NULL, NULL, NULL |
962 | }, |
963 | { |
964 | {"enable_nestloop" , PGC_USERSET, QUERY_TUNING_METHOD, |
965 | gettext_noop("Enables the planner's use of nested-loop join plans." ), |
966 | NULL, |
967 | GUC_EXPLAIN |
968 | }, |
969 | &enable_nestloop, |
970 | true, |
971 | NULL, NULL, NULL |
972 | }, |
973 | { |
974 | {"enable_mergejoin" , PGC_USERSET, QUERY_TUNING_METHOD, |
975 | gettext_noop("Enables the planner's use of merge join plans." ), |
976 | NULL, |
977 | GUC_EXPLAIN |
978 | }, |
979 | &enable_mergejoin, |
980 | true, |
981 | NULL, NULL, NULL |
982 | }, |
983 | { |
984 | {"enable_hashjoin" , PGC_USERSET, QUERY_TUNING_METHOD, |
985 | gettext_noop("Enables the planner's use of hash join plans." ), |
986 | NULL, |
987 | GUC_EXPLAIN |
988 | }, |
989 | &enable_hashjoin, |
990 | true, |
991 | NULL, NULL, NULL |
992 | }, |
993 | { |
994 | {"enable_gathermerge" , PGC_USERSET, QUERY_TUNING_METHOD, |
995 | gettext_noop("Enables the planner's use of gather merge plans." ), |
996 | NULL, |
997 | GUC_EXPLAIN |
998 | }, |
999 | &enable_gathermerge, |
1000 | true, |
1001 | NULL, NULL, NULL |
1002 | }, |
1003 | { |
1004 | {"enable_partitionwise_join" , PGC_USERSET, QUERY_TUNING_METHOD, |
1005 | gettext_noop("Enables partitionwise join." ), |
1006 | NULL, |
1007 | GUC_EXPLAIN |
1008 | }, |
1009 | &enable_partitionwise_join, |
1010 | false, |
1011 | NULL, NULL, NULL |
1012 | }, |
1013 | { |
1014 | {"enable_partitionwise_aggregate" , PGC_USERSET, QUERY_TUNING_METHOD, |
1015 | gettext_noop("Enables partitionwise aggregation and grouping." ), |
1016 | NULL, |
1017 | GUC_EXPLAIN |
1018 | }, |
1019 | &enable_partitionwise_aggregate, |
1020 | false, |
1021 | NULL, NULL, NULL |
1022 | }, |
1023 | { |
1024 | {"enable_parallel_append" , PGC_USERSET, QUERY_TUNING_METHOD, |
1025 | gettext_noop("Enables the planner's use of parallel append plans." ), |
1026 | NULL, |
1027 | GUC_EXPLAIN |
1028 | }, |
1029 | &enable_parallel_append, |
1030 | true, |
1031 | NULL, NULL, NULL |
1032 | }, |
1033 | { |
1034 | {"enable_parallel_hash" , PGC_USERSET, QUERY_TUNING_METHOD, |
1035 | gettext_noop("Enables the planner's use of parallel hash plans." ), |
1036 | NULL, |
1037 | GUC_EXPLAIN |
1038 | }, |
1039 | &enable_parallel_hash, |
1040 | true, |
1041 | NULL, NULL, NULL |
1042 | }, |
1043 | { |
1044 | {"enable_partition_pruning" , PGC_USERSET, QUERY_TUNING_METHOD, |
1045 | gettext_noop("Enables plan-time and run-time partition pruning." ), |
1046 | gettext_noop("Allows the query planner and executor to compare partition " |
1047 | "bounds to conditions in the query to determine which " |
1048 | "partitions must be scanned." ), |
1049 | GUC_EXPLAIN |
1050 | }, |
1051 | &enable_partition_pruning, |
1052 | true, |
1053 | NULL, NULL, NULL |
1054 | }, |
1055 | { |
1056 | {"geqo" , PGC_USERSET, QUERY_TUNING_GEQO, |
1057 | gettext_noop("Enables genetic query optimization." ), |
1058 | gettext_noop("This algorithm attempts to do planning without " |
1059 | "exhaustive searching." ), |
1060 | GUC_EXPLAIN |
1061 | }, |
1062 | &enable_geqo, |
1063 | true, |
1064 | NULL, NULL, NULL |
1065 | }, |
1066 | { |
1067 | /* Not for general use --- used by SET SESSION AUTHORIZATION */ |
1068 | {"is_superuser" , PGC_INTERNAL, UNGROUPED, |
1069 | gettext_noop("Shows whether the current user is a superuser." ), |
1070 | NULL, |
1071 | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1072 | }, |
1073 | &session_auth_is_superuser, |
1074 | false, |
1075 | NULL, NULL, NULL |
1076 | }, |
1077 | { |
1078 | {"bonjour" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
1079 | gettext_noop("Enables advertising the server via Bonjour." ), |
1080 | NULL |
1081 | }, |
1082 | &enable_bonjour, |
1083 | false, |
1084 | check_bonjour, NULL, NULL |
1085 | }, |
1086 | { |
1087 | {"track_commit_timestamp" , PGC_POSTMASTER, REPLICATION, |
1088 | gettext_noop("Collects transaction commit time." ), |
1089 | NULL |
1090 | }, |
1091 | &track_commit_timestamp, |
1092 | false, |
1093 | NULL, NULL, NULL |
1094 | }, |
1095 | { |
1096 | {"ssl" , PGC_SIGHUP, CONN_AUTH_SSL, |
1097 | gettext_noop("Enables SSL connections." ), |
1098 | NULL |
1099 | }, |
1100 | &EnableSSL, |
1101 | false, |
1102 | check_ssl, NULL, NULL |
1103 | }, |
1104 | { |
1105 | {"ssl_passphrase_command_supports_reload" , PGC_SIGHUP, CONN_AUTH_SSL, |
1106 | gettext_noop("Also use ssl_passphrase_command during server reload." ), |
1107 | NULL |
1108 | }, |
1109 | &ssl_passphrase_command_supports_reload, |
1110 | false, |
1111 | NULL, NULL, NULL |
1112 | }, |
1113 | { |
1114 | {"ssl_prefer_server_ciphers" , PGC_SIGHUP, CONN_AUTH_SSL, |
1115 | gettext_noop("Give priority to server ciphersuite order." ), |
1116 | NULL |
1117 | }, |
1118 | &SSLPreferServerCiphers, |
1119 | true, |
1120 | NULL, NULL, NULL |
1121 | }, |
1122 | { |
1123 | {"fsync" , PGC_SIGHUP, WAL_SETTINGS, |
1124 | gettext_noop("Forces synchronization of updates to disk." ), |
1125 | gettext_noop("The server will use the fsync() system call in several places to make " |
1126 | "sure that updates are physically written to disk. This insures " |
1127 | "that a database cluster will recover to a consistent state after " |
1128 | "an operating system or hardware crash." ) |
1129 | }, |
1130 | &enableFsync, |
1131 | true, |
1132 | NULL, NULL, NULL |
1133 | }, |
1134 | { |
1135 | {"ignore_checksum_failure" , PGC_SUSET, DEVELOPER_OPTIONS, |
1136 | gettext_noop("Continues processing after a checksum failure." ), |
1137 | gettext_noop("Detection of a checksum failure normally causes PostgreSQL to " |
1138 | "report an error, aborting the current transaction. Setting " |
1139 | "ignore_checksum_failure to true causes the system to ignore the failure " |
1140 | "(but still report a warning), and continue processing. This " |
1141 | "behavior could cause crashes or other serious problems. Only " |
1142 | "has an effect if checksums are enabled." ), |
1143 | GUC_NOT_IN_SAMPLE |
1144 | }, |
1145 | &ignore_checksum_failure, |
1146 | false, |
1147 | NULL, NULL, NULL |
1148 | }, |
1149 | { |
1150 | {"zero_damaged_pages" , PGC_SUSET, DEVELOPER_OPTIONS, |
1151 | gettext_noop("Continues processing past damaged page headers." ), |
1152 | gettext_noop("Detection of a damaged page header normally causes PostgreSQL to " |
1153 | "report an error, aborting the current transaction. Setting " |
1154 | "zero_damaged_pages to true causes the system to instead report a " |
1155 | "warning, zero out the damaged page, and continue processing. This " |
1156 | "behavior will destroy data, namely all the rows on the damaged page." ), |
1157 | GUC_NOT_IN_SAMPLE |
1158 | }, |
1159 | &zero_damaged_pages, |
1160 | false, |
1161 | NULL, NULL, NULL |
1162 | }, |
1163 | { |
1164 | {"full_page_writes" , PGC_SIGHUP, WAL_SETTINGS, |
1165 | gettext_noop("Writes full pages to WAL when first modified after a checkpoint." ), |
1166 | gettext_noop("A page write in process during an operating system crash might be " |
1167 | "only partially written to disk. During recovery, the row changes " |
1168 | "stored in WAL are not enough to recover. This option writes " |
1169 | "pages when first modified after a checkpoint to WAL so full recovery " |
1170 | "is possible." ) |
1171 | }, |
1172 | &fullPageWrites, |
1173 | true, |
1174 | NULL, NULL, NULL |
1175 | }, |
1176 | |
1177 | { |
1178 | {"wal_log_hints" , PGC_POSTMASTER, WAL_SETTINGS, |
1179 | gettext_noop("Writes full pages to WAL when first modified after a checkpoint, even for a non-critical modifications." ), |
1180 | NULL |
1181 | }, |
1182 | &wal_log_hints, |
1183 | false, |
1184 | NULL, NULL, NULL |
1185 | }, |
1186 | |
1187 | { |
1188 | {"wal_compression" , PGC_SUSET, WAL_SETTINGS, |
1189 | gettext_noop("Compresses full-page writes written in WAL file." ), |
1190 | NULL |
1191 | }, |
1192 | &wal_compression, |
1193 | false, |
1194 | NULL, NULL, NULL |
1195 | }, |
1196 | |
1197 | { |
1198 | {"wal_init_zero" , PGC_SUSET, WAL_SETTINGS, |
1199 | gettext_noop("Writes zeroes to new WAL files before first use." ), |
1200 | NULL |
1201 | }, |
1202 | &wal_init_zero, |
1203 | true, |
1204 | NULL, NULL, NULL |
1205 | }, |
1206 | |
1207 | { |
1208 | {"wal_recycle" , PGC_SUSET, WAL_SETTINGS, |
1209 | gettext_noop("Recycles WAL files by renaming them." ), |
1210 | NULL |
1211 | }, |
1212 | &wal_recycle, |
1213 | true, |
1214 | NULL, NULL, NULL |
1215 | }, |
1216 | |
1217 | { |
1218 | {"log_checkpoints" , PGC_SIGHUP, LOGGING_WHAT, |
1219 | gettext_noop("Logs each checkpoint." ), |
1220 | NULL |
1221 | }, |
1222 | &log_checkpoints, |
1223 | false, |
1224 | NULL, NULL, NULL |
1225 | }, |
1226 | { |
1227 | {"log_connections" , PGC_SU_BACKEND, LOGGING_WHAT, |
1228 | gettext_noop("Logs each successful connection." ), |
1229 | NULL |
1230 | }, |
1231 | &Log_connections, |
1232 | false, |
1233 | NULL, NULL, NULL |
1234 | }, |
1235 | { |
1236 | {"log_disconnections" , PGC_SU_BACKEND, LOGGING_WHAT, |
1237 | gettext_noop("Logs end of a session, including duration." ), |
1238 | NULL |
1239 | }, |
1240 | &Log_disconnections, |
1241 | false, |
1242 | NULL, NULL, NULL |
1243 | }, |
1244 | { |
1245 | {"log_replication_commands" , PGC_SUSET, LOGGING_WHAT, |
1246 | gettext_noop("Logs each replication command." ), |
1247 | NULL |
1248 | }, |
1249 | &log_replication_commands, |
1250 | false, |
1251 | NULL, NULL, NULL |
1252 | }, |
1253 | { |
1254 | {"debug_assertions" , PGC_INTERNAL, PRESET_OPTIONS, |
1255 | gettext_noop("Shows whether the running server has assertion checks enabled." ), |
1256 | NULL, |
1257 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1258 | }, |
1259 | &assert_enabled, |
1260 | #ifdef USE_ASSERT_CHECKING |
1261 | true, |
1262 | #else |
1263 | false, |
1264 | #endif |
1265 | NULL, NULL, NULL |
1266 | }, |
1267 | |
1268 | { |
1269 | {"exit_on_error" , PGC_USERSET, ERROR_HANDLING_OPTIONS, |
1270 | gettext_noop("Terminate session on any error." ), |
1271 | NULL |
1272 | }, |
1273 | &ExitOnAnyError, |
1274 | false, |
1275 | NULL, NULL, NULL |
1276 | }, |
1277 | { |
1278 | {"restart_after_crash" , PGC_SIGHUP, ERROR_HANDLING_OPTIONS, |
1279 | gettext_noop("Reinitialize server after backend crash." ), |
1280 | NULL |
1281 | }, |
1282 | &restart_after_crash, |
1283 | true, |
1284 | NULL, NULL, NULL |
1285 | }, |
1286 | |
1287 | { |
1288 | {"log_duration" , PGC_SUSET, LOGGING_WHAT, |
1289 | gettext_noop("Logs the duration of each completed SQL statement." ), |
1290 | NULL |
1291 | }, |
1292 | &log_duration, |
1293 | false, |
1294 | NULL, NULL, NULL |
1295 | }, |
1296 | { |
1297 | {"debug_print_parse" , PGC_USERSET, LOGGING_WHAT, |
1298 | gettext_noop("Logs each query's parse tree." ), |
1299 | NULL |
1300 | }, |
1301 | &Debug_print_parse, |
1302 | false, |
1303 | NULL, NULL, NULL |
1304 | }, |
1305 | { |
1306 | {"debug_print_rewritten" , PGC_USERSET, LOGGING_WHAT, |
1307 | gettext_noop("Logs each query's rewritten parse tree." ), |
1308 | NULL |
1309 | }, |
1310 | &Debug_print_rewritten, |
1311 | false, |
1312 | NULL, NULL, NULL |
1313 | }, |
1314 | { |
1315 | {"debug_print_plan" , PGC_USERSET, LOGGING_WHAT, |
1316 | gettext_noop("Logs each query's execution plan." ), |
1317 | NULL |
1318 | }, |
1319 | &Debug_print_plan, |
1320 | false, |
1321 | NULL, NULL, NULL |
1322 | }, |
1323 | { |
1324 | {"debug_pretty_print" , PGC_USERSET, LOGGING_WHAT, |
1325 | gettext_noop("Indents parse and plan tree displays." ), |
1326 | NULL |
1327 | }, |
1328 | &Debug_pretty_print, |
1329 | true, |
1330 | NULL, NULL, NULL |
1331 | }, |
1332 | { |
1333 | {"log_parser_stats" , PGC_SUSET, STATS_MONITORING, |
1334 | gettext_noop("Writes parser performance statistics to the server log." ), |
1335 | NULL |
1336 | }, |
1337 | &log_parser_stats, |
1338 | false, |
1339 | check_stage_log_stats, NULL, NULL |
1340 | }, |
1341 | { |
1342 | {"log_planner_stats" , PGC_SUSET, STATS_MONITORING, |
1343 | gettext_noop("Writes planner performance statistics to the server log." ), |
1344 | NULL |
1345 | }, |
1346 | &log_planner_stats, |
1347 | false, |
1348 | check_stage_log_stats, NULL, NULL |
1349 | }, |
1350 | { |
1351 | {"log_executor_stats" , PGC_SUSET, STATS_MONITORING, |
1352 | gettext_noop("Writes executor performance statistics to the server log." ), |
1353 | NULL |
1354 | }, |
1355 | &log_executor_stats, |
1356 | false, |
1357 | check_stage_log_stats, NULL, NULL |
1358 | }, |
1359 | { |
1360 | {"log_statement_stats" , PGC_SUSET, STATS_MONITORING, |
1361 | gettext_noop("Writes cumulative performance statistics to the server log." ), |
1362 | NULL |
1363 | }, |
1364 | &log_statement_stats, |
1365 | false, |
1366 | check_log_stats, NULL, NULL |
1367 | }, |
1368 | #ifdef BTREE_BUILD_STATS |
1369 | { |
1370 | {"log_btree_build_stats" , PGC_SUSET, DEVELOPER_OPTIONS, |
1371 | gettext_noop("Logs system resource usage statistics (memory and CPU) on various B-tree operations." ), |
1372 | NULL, |
1373 | GUC_NOT_IN_SAMPLE |
1374 | }, |
1375 | &log_btree_build_stats, |
1376 | false, |
1377 | NULL, NULL, NULL |
1378 | }, |
1379 | #endif |
1380 | |
1381 | { |
1382 | {"track_activities" , PGC_SUSET, STATS_COLLECTOR, |
1383 | gettext_noop("Collects information about executing commands." ), |
1384 | gettext_noop("Enables the collection of information on the currently " |
1385 | "executing command of each session, along with " |
1386 | "the time at which that command began execution." ) |
1387 | }, |
1388 | &pgstat_track_activities, |
1389 | true, |
1390 | NULL, NULL, NULL |
1391 | }, |
1392 | { |
1393 | {"track_counts" , PGC_SUSET, STATS_COLLECTOR, |
1394 | gettext_noop("Collects statistics on database activity." ), |
1395 | NULL |
1396 | }, |
1397 | &pgstat_track_counts, |
1398 | true, |
1399 | NULL, NULL, NULL |
1400 | }, |
1401 | { |
1402 | {"track_io_timing" , PGC_SUSET, STATS_COLLECTOR, |
1403 | gettext_noop("Collects timing statistics for database I/O activity." ), |
1404 | NULL |
1405 | }, |
1406 | &track_io_timing, |
1407 | false, |
1408 | NULL, NULL, NULL |
1409 | }, |
1410 | |
1411 | { |
1412 | {"update_process_title" , PGC_SUSET, PROCESS_TITLE, |
1413 | gettext_noop("Updates the process title to show the active SQL command." ), |
1414 | gettext_noop("Enables updating of the process title every time a new SQL command is received by the server." ) |
1415 | }, |
1416 | &update_process_title, |
1417 | #ifdef WIN32 |
1418 | false, |
1419 | #else |
1420 | true, |
1421 | #endif |
1422 | NULL, NULL, NULL |
1423 | }, |
1424 | |
1425 | { |
1426 | {"autovacuum" , PGC_SIGHUP, AUTOVACUUM, |
1427 | gettext_noop("Starts the autovacuum subprocess." ), |
1428 | NULL |
1429 | }, |
1430 | &autovacuum_start_daemon, |
1431 | true, |
1432 | NULL, NULL, NULL |
1433 | }, |
1434 | |
1435 | { |
1436 | {"trace_notify" , PGC_USERSET, DEVELOPER_OPTIONS, |
1437 | gettext_noop("Generates debugging output for LISTEN and NOTIFY." ), |
1438 | NULL, |
1439 | GUC_NOT_IN_SAMPLE |
1440 | }, |
1441 | &Trace_notify, |
1442 | false, |
1443 | NULL, NULL, NULL |
1444 | }, |
1445 | |
1446 | #ifdef LOCK_DEBUG |
1447 | { |
1448 | {"trace_locks" , PGC_SUSET, DEVELOPER_OPTIONS, |
1449 | gettext_noop("Emits information about lock usage." ), |
1450 | NULL, |
1451 | GUC_NOT_IN_SAMPLE |
1452 | }, |
1453 | &Trace_locks, |
1454 | false, |
1455 | NULL, NULL, NULL |
1456 | }, |
1457 | { |
1458 | {"trace_userlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
1459 | gettext_noop("Emits information about user lock usage." ), |
1460 | NULL, |
1461 | GUC_NOT_IN_SAMPLE |
1462 | }, |
1463 | &Trace_userlocks, |
1464 | false, |
1465 | NULL, NULL, NULL |
1466 | }, |
1467 | { |
1468 | {"trace_lwlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
1469 | gettext_noop("Emits information about lightweight lock usage." ), |
1470 | NULL, |
1471 | GUC_NOT_IN_SAMPLE |
1472 | }, |
1473 | &Trace_lwlocks, |
1474 | false, |
1475 | NULL, NULL, NULL |
1476 | }, |
1477 | { |
1478 | {"debug_deadlocks" , PGC_SUSET, DEVELOPER_OPTIONS, |
1479 | gettext_noop("Dumps information about all current locks when a deadlock timeout occurs." ), |
1480 | NULL, |
1481 | GUC_NOT_IN_SAMPLE |
1482 | }, |
1483 | &Debug_deadlocks, |
1484 | false, |
1485 | NULL, NULL, NULL |
1486 | }, |
1487 | #endif |
1488 | |
1489 | { |
1490 | {"log_lock_waits" , PGC_SUSET, LOGGING_WHAT, |
1491 | gettext_noop("Logs long lock waits." ), |
1492 | NULL |
1493 | }, |
1494 | &log_lock_waits, |
1495 | false, |
1496 | NULL, NULL, NULL |
1497 | }, |
1498 | |
1499 | { |
1500 | {"log_hostname" , PGC_SIGHUP, LOGGING_WHAT, |
1501 | gettext_noop("Logs the host name in the connection logs." ), |
1502 | gettext_noop("By default, connection logs only show the IP address " |
1503 | "of the connecting host. If you want them to show the host name you " |
1504 | "can turn this on, but depending on your host name resolution " |
1505 | "setup it might impose a non-negligible performance penalty." ) |
1506 | }, |
1507 | &log_hostname, |
1508 | false, |
1509 | NULL, NULL, NULL |
1510 | }, |
1511 | { |
1512 | {"transform_null_equals" , PGC_USERSET, COMPAT_OPTIONS_CLIENT, |
1513 | gettext_noop("Treats \"expr=NULL\" as \"expr IS NULL\"." ), |
1514 | gettext_noop("When turned on, expressions of the form expr = NULL " |
1515 | "(or NULL = expr) are treated as expr IS NULL, that is, they " |
1516 | "return true if expr evaluates to the null value, and false " |
1517 | "otherwise. The correct behavior of expr = NULL is to always " |
1518 | "return null (unknown)." ) |
1519 | }, |
1520 | &Transform_null_equals, |
1521 | false, |
1522 | NULL, NULL, NULL |
1523 | }, |
1524 | { |
1525 | {"db_user_namespace" , PGC_SIGHUP, CONN_AUTH_AUTH, |
1526 | gettext_noop("Enables per-database user names." ), |
1527 | NULL |
1528 | }, |
1529 | &Db_user_namespace, |
1530 | false, |
1531 | NULL, NULL, NULL |
1532 | }, |
1533 | { |
1534 | {"default_transaction_read_only" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1535 | gettext_noop("Sets the default read-only status of new transactions." ), |
1536 | NULL |
1537 | }, |
1538 | &DefaultXactReadOnly, |
1539 | false, |
1540 | NULL, NULL, NULL |
1541 | }, |
1542 | { |
1543 | {"transaction_read_only" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1544 | gettext_noop("Sets the current transaction's read-only status." ), |
1545 | NULL, |
1546 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1547 | }, |
1548 | &XactReadOnly, |
1549 | false, |
1550 | check_transaction_read_only, NULL, NULL |
1551 | }, |
1552 | { |
1553 | {"default_transaction_deferrable" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1554 | gettext_noop("Sets the default deferrable status of new transactions." ), |
1555 | NULL |
1556 | }, |
1557 | &DefaultXactDeferrable, |
1558 | false, |
1559 | NULL, NULL, NULL |
1560 | }, |
1561 | { |
1562 | {"transaction_deferrable" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1563 | gettext_noop("Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures." ), |
1564 | NULL, |
1565 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1566 | }, |
1567 | &XactDeferrable, |
1568 | false, |
1569 | check_transaction_deferrable, NULL, NULL |
1570 | }, |
1571 | { |
1572 | {"row_security" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1573 | gettext_noop("Enable row security." ), |
1574 | gettext_noop("When enabled, row security will be applied to all users." ) |
1575 | }, |
1576 | &row_security, |
1577 | true, |
1578 | NULL, NULL, NULL |
1579 | }, |
1580 | { |
1581 | {"check_function_bodies" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
1582 | gettext_noop("Check function bodies during CREATE FUNCTION." ), |
1583 | NULL |
1584 | }, |
1585 | &check_function_bodies, |
1586 | true, |
1587 | NULL, NULL, NULL |
1588 | }, |
1589 | { |
1590 | {"array_nulls" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1591 | gettext_noop("Enable input of NULL elements in arrays." ), |
1592 | gettext_noop("When turned on, unquoted NULL in an array input " |
1593 | "value means a null value; " |
1594 | "otherwise it is taken literally." ) |
1595 | }, |
1596 | &Array_nulls, |
1597 | true, |
1598 | NULL, NULL, NULL |
1599 | }, |
1600 | |
1601 | /* |
1602 | * WITH OIDS support, and consequently default_with_oids, was removed in |
1603 | * PostgreSQL 12, but we tolerate the parameter being set to false to |
1604 | * avoid unnecessarily breaking older dump files. |
1605 | */ |
1606 | { |
1607 | {"default_with_oids" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1608 | gettext_noop("WITH OIDS is no longer supported; this can only be false." ), |
1609 | NULL, |
1610 | GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE |
1611 | }, |
1612 | &default_with_oids, |
1613 | false, |
1614 | check_default_with_oids, NULL, NULL |
1615 | }, |
1616 | { |
1617 | {"logging_collector" , PGC_POSTMASTER, LOGGING_WHERE, |
1618 | gettext_noop("Start a subprocess to capture stderr output and/or csvlogs into log files." ), |
1619 | NULL |
1620 | }, |
1621 | &Logging_collector, |
1622 | false, |
1623 | NULL, NULL, NULL |
1624 | }, |
1625 | { |
1626 | {"log_truncate_on_rotation" , PGC_SIGHUP, LOGGING_WHERE, |
1627 | gettext_noop("Truncate existing log files of same name during log rotation." ), |
1628 | NULL |
1629 | }, |
1630 | &Log_truncate_on_rotation, |
1631 | false, |
1632 | NULL, NULL, NULL |
1633 | }, |
1634 | |
1635 | #ifdef TRACE_SORT |
1636 | { |
1637 | {"trace_sort" , PGC_USERSET, DEVELOPER_OPTIONS, |
1638 | gettext_noop("Emit information about resource usage in sorting." ), |
1639 | NULL, |
1640 | GUC_NOT_IN_SAMPLE |
1641 | }, |
1642 | &trace_sort, |
1643 | false, |
1644 | NULL, NULL, NULL |
1645 | }, |
1646 | #endif |
1647 | |
1648 | #ifdef TRACE_SYNCSCAN |
1649 | /* this is undocumented because not exposed in a standard build */ |
1650 | { |
1651 | {"trace_syncscan" , PGC_USERSET, DEVELOPER_OPTIONS, |
1652 | gettext_noop("Generate debugging output for synchronized scanning." ), |
1653 | NULL, |
1654 | GUC_NOT_IN_SAMPLE |
1655 | }, |
1656 | &trace_syncscan, |
1657 | false, |
1658 | NULL, NULL, NULL |
1659 | }, |
1660 | #endif |
1661 | |
1662 | #ifdef DEBUG_BOUNDED_SORT |
1663 | /* this is undocumented because not exposed in a standard build */ |
1664 | { |
1665 | { |
1666 | "optimize_bounded_sort" , PGC_USERSET, QUERY_TUNING_METHOD, |
1667 | gettext_noop("Enable bounded sorting using heap sort." ), |
1668 | NULL, |
1669 | GUC_NOT_IN_SAMPLE | GUC_EXPLAIN |
1670 | }, |
1671 | &optimize_bounded_sort, |
1672 | true, |
1673 | NULL, NULL, NULL |
1674 | }, |
1675 | #endif |
1676 | |
1677 | #ifdef WAL_DEBUG |
1678 | { |
1679 | {"wal_debug" , PGC_SUSET, DEVELOPER_OPTIONS, |
1680 | gettext_noop("Emit WAL-related debugging output." ), |
1681 | NULL, |
1682 | GUC_NOT_IN_SAMPLE |
1683 | }, |
1684 | &XLOG_DEBUG, |
1685 | false, |
1686 | NULL, NULL, NULL |
1687 | }, |
1688 | #endif |
1689 | |
1690 | { |
1691 | {"integer_datetimes" , PGC_INTERNAL, PRESET_OPTIONS, |
1692 | gettext_noop("Datetimes are integer based." ), |
1693 | NULL, |
1694 | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1695 | }, |
1696 | &integer_datetimes, |
1697 | true, |
1698 | NULL, NULL, NULL |
1699 | }, |
1700 | |
1701 | { |
1702 | {"krb_caseins_users" , PGC_SIGHUP, CONN_AUTH_AUTH, |
1703 | gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive." ), |
1704 | NULL |
1705 | }, |
1706 | &pg_krb_caseins_users, |
1707 | false, |
1708 | NULL, NULL, NULL |
1709 | }, |
1710 | |
1711 | { |
1712 | {"escape_string_warning" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1713 | gettext_noop("Warn about backslash escapes in ordinary string literals." ), |
1714 | NULL |
1715 | }, |
1716 | &escape_string_warning, |
1717 | true, |
1718 | NULL, NULL, NULL |
1719 | }, |
1720 | |
1721 | { |
1722 | {"standard_conforming_strings" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1723 | gettext_noop("Causes '...' strings to treat backslashes literally." ), |
1724 | NULL, |
1725 | GUC_REPORT |
1726 | }, |
1727 | &standard_conforming_strings, |
1728 | true, |
1729 | NULL, NULL, NULL |
1730 | }, |
1731 | |
1732 | { |
1733 | {"synchronize_seqscans" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1734 | gettext_noop("Enable synchronized sequential scans." ), |
1735 | NULL |
1736 | }, |
1737 | &synchronize_seqscans, |
1738 | true, |
1739 | NULL, NULL, NULL |
1740 | }, |
1741 | |
1742 | { |
1743 | {"recovery_target_inclusive" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
1744 | gettext_noop("Sets whether to include or exclude transaction with recovery target." ), |
1745 | NULL |
1746 | }, |
1747 | &recoveryTargetInclusive, |
1748 | true, |
1749 | NULL, NULL, NULL |
1750 | }, |
1751 | |
1752 | { |
1753 | {"hot_standby" , PGC_POSTMASTER, REPLICATION_STANDBY, |
1754 | gettext_noop("Allows connections and queries during recovery." ), |
1755 | NULL |
1756 | }, |
1757 | &EnableHotStandby, |
1758 | true, |
1759 | NULL, NULL, NULL |
1760 | }, |
1761 | |
1762 | { |
1763 | {"hot_standby_feedback" , PGC_SIGHUP, REPLICATION_STANDBY, |
1764 | gettext_noop("Allows feedback from a hot standby to the primary that will avoid query conflicts." ), |
1765 | NULL |
1766 | }, |
1767 | &hot_standby_feedback, |
1768 | false, |
1769 | NULL, NULL, NULL |
1770 | }, |
1771 | |
1772 | { |
1773 | {"allow_system_table_mods" , PGC_POSTMASTER, DEVELOPER_OPTIONS, |
1774 | gettext_noop("Allows modifications of the structure of system tables." ), |
1775 | NULL, |
1776 | GUC_NOT_IN_SAMPLE |
1777 | }, |
1778 | &allowSystemTableMods, |
1779 | false, |
1780 | NULL, NULL, NULL |
1781 | }, |
1782 | |
1783 | { |
1784 | {"ignore_system_indexes" , PGC_BACKEND, DEVELOPER_OPTIONS, |
1785 | gettext_noop("Disables reading from system indexes." ), |
1786 | gettext_noop("It does not prevent updating the indexes, so it is safe " |
1787 | "to use. The worst consequence is slowness." ), |
1788 | GUC_NOT_IN_SAMPLE |
1789 | }, |
1790 | &IgnoreSystemIndexes, |
1791 | false, |
1792 | NULL, NULL, NULL |
1793 | }, |
1794 | |
1795 | { |
1796 | {"lo_compat_privileges" , PGC_SUSET, COMPAT_OPTIONS_PREVIOUS, |
1797 | gettext_noop("Enables backward compatibility mode for privilege checks on large objects." ), |
1798 | gettext_noop("Skips privilege checks when reading or modifying large objects, " |
1799 | "for compatibility with PostgreSQL releases prior to 9.0." ) |
1800 | }, |
1801 | &lo_compat_privileges, |
1802 | false, |
1803 | NULL, NULL, NULL |
1804 | }, |
1805 | |
1806 | { |
1807 | {"operator_precedence_warning" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1808 | gettext_noop("Emit a warning for constructs that changed meaning since PostgreSQL 9.4." ), |
1809 | NULL, |
1810 | }, |
1811 | &operator_precedence_warning, |
1812 | false, |
1813 | NULL, NULL, NULL |
1814 | }, |
1815 | |
1816 | { |
1817 | {"quote_all_identifiers" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
1818 | gettext_noop("When generating SQL fragments, quote all identifiers." ), |
1819 | NULL, |
1820 | }, |
1821 | "e_all_identifiers, |
1822 | false, |
1823 | NULL, NULL, NULL |
1824 | }, |
1825 | |
1826 | { |
1827 | {"data_checksums" , PGC_INTERNAL, PRESET_OPTIONS, |
1828 | gettext_noop("Shows whether data checksums are turned on for this cluster." ), |
1829 | NULL, |
1830 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
1831 | }, |
1832 | &data_checksums, |
1833 | false, |
1834 | NULL, NULL, NULL |
1835 | }, |
1836 | |
1837 | { |
1838 | {"syslog_sequence_numbers" , PGC_SIGHUP, LOGGING_WHERE, |
1839 | gettext_noop("Add sequence number to syslog messages to avoid duplicate suppression." ), |
1840 | NULL |
1841 | }, |
1842 | &syslog_sequence_numbers, |
1843 | true, |
1844 | NULL, NULL, NULL |
1845 | }, |
1846 | |
1847 | { |
1848 | {"syslog_split_messages" , PGC_SIGHUP, LOGGING_WHERE, |
1849 | gettext_noop("Split messages sent to syslog by lines and to fit into 1024 bytes." ), |
1850 | NULL |
1851 | }, |
1852 | &syslog_split_messages, |
1853 | true, |
1854 | NULL, NULL, NULL |
1855 | }, |
1856 | |
1857 | { |
1858 | {"parallel_leader_participation" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
1859 | gettext_noop("Controls whether Gather and Gather Merge also run subplans." ), |
1860 | gettext_noop("Should gather nodes also run subplans, or just gather tuples?" ), |
1861 | GUC_EXPLAIN |
1862 | }, |
1863 | ¶llel_leader_participation, |
1864 | true, |
1865 | NULL, NULL, NULL |
1866 | }, |
1867 | |
1868 | { |
1869 | {"jit" , PGC_USERSET, QUERY_TUNING_OTHER, |
1870 | gettext_noop("Allow JIT compilation." ), |
1871 | NULL, |
1872 | GUC_EXPLAIN |
1873 | }, |
1874 | &jit_enabled, |
1875 | true, |
1876 | NULL, NULL, NULL |
1877 | }, |
1878 | |
1879 | { |
1880 | {"jit_debugging_support" , PGC_SU_BACKEND, DEVELOPER_OPTIONS, |
1881 | gettext_noop("Register JIT compiled function with debugger." ), |
1882 | NULL, |
1883 | GUC_NOT_IN_SAMPLE |
1884 | }, |
1885 | &jit_debugging_support, |
1886 | false, |
1887 | |
1888 | /* |
1889 | * This is not guaranteed to be available, but given it's a developer |
1890 | * oriented option, it doesn't seem worth adding code checking |
1891 | * availability. |
1892 | */ |
1893 | NULL, NULL, NULL |
1894 | }, |
1895 | |
1896 | { |
1897 | {"jit_dump_bitcode" , PGC_SUSET, DEVELOPER_OPTIONS, |
1898 | gettext_noop("Write out LLVM bitcode to facilitate JIT debugging." ), |
1899 | NULL, |
1900 | GUC_NOT_IN_SAMPLE |
1901 | }, |
1902 | &jit_dump_bitcode, |
1903 | false, |
1904 | NULL, NULL, NULL |
1905 | }, |
1906 | |
1907 | { |
1908 | {"jit_expressions" , PGC_USERSET, DEVELOPER_OPTIONS, |
1909 | gettext_noop("Allow JIT compilation of expressions." ), |
1910 | NULL, |
1911 | GUC_NOT_IN_SAMPLE |
1912 | }, |
1913 | &jit_expressions, |
1914 | true, |
1915 | NULL, NULL, NULL |
1916 | }, |
1917 | |
1918 | { |
1919 | {"jit_profiling_support" , PGC_SU_BACKEND, DEVELOPER_OPTIONS, |
1920 | gettext_noop("Register JIT compiled function with perf profiler." ), |
1921 | NULL, |
1922 | GUC_NOT_IN_SAMPLE |
1923 | }, |
1924 | &jit_profiling_support, |
1925 | false, |
1926 | |
1927 | /* |
1928 | * This is not guaranteed to be available, but given it's a developer |
1929 | * oriented option, it doesn't seem worth adding code checking |
1930 | * availability. |
1931 | */ |
1932 | NULL, NULL, NULL |
1933 | }, |
1934 | |
1935 | { |
1936 | {"jit_tuple_deforming" , PGC_USERSET, DEVELOPER_OPTIONS, |
1937 | gettext_noop("Allow JIT compilation of tuple deforming." ), |
1938 | NULL, |
1939 | GUC_NOT_IN_SAMPLE |
1940 | }, |
1941 | &jit_tuple_deforming, |
1942 | true, |
1943 | NULL, NULL, NULL |
1944 | }, |
1945 | |
1946 | { |
1947 | {"data_sync_retry" , PGC_POSTMASTER, ERROR_HANDLING_OPTIONS, |
1948 | gettext_noop("Whether to continue running after a failure to sync data files." ), |
1949 | }, |
1950 | &data_sync_retry, |
1951 | false, |
1952 | NULL, NULL, NULL |
1953 | }, |
1954 | |
1955 | /* End-of-list marker */ |
1956 | { |
1957 | {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL |
1958 | } |
1959 | }; |
1960 | |
1961 | |
1962 | static struct config_int ConfigureNamesInt[] = |
1963 | { |
1964 | { |
1965 | {"archive_timeout" , PGC_SIGHUP, WAL_ARCHIVING, |
1966 | gettext_noop("Forces a switch to the next WAL file if a " |
1967 | "new file has not been started within N seconds." ), |
1968 | NULL, |
1969 | GUC_UNIT_S |
1970 | }, |
1971 | &XLogArchiveTimeout, |
1972 | 0, 0, INT_MAX / 2, |
1973 | NULL, NULL, NULL |
1974 | }, |
1975 | { |
1976 | {"post_auth_delay" , PGC_BACKEND, DEVELOPER_OPTIONS, |
1977 | gettext_noop("Waits N seconds on connection startup after authentication." ), |
1978 | gettext_noop("This allows attaching a debugger to the process." ), |
1979 | GUC_NOT_IN_SAMPLE | GUC_UNIT_S |
1980 | }, |
1981 | &PostAuthDelay, |
1982 | 0, 0, INT_MAX / 1000000, |
1983 | NULL, NULL, NULL |
1984 | }, |
1985 | { |
1986 | {"default_statistics_target" , PGC_USERSET, QUERY_TUNING_OTHER, |
1987 | gettext_noop("Sets the default statistics target." ), |
1988 | gettext_noop("This applies to table columns that have not had a " |
1989 | "column-specific target set via ALTER TABLE SET STATISTICS." ) |
1990 | }, |
1991 | &default_statistics_target, |
1992 | 100, 1, 10000, |
1993 | NULL, NULL, NULL |
1994 | }, |
1995 | { |
1996 | {"from_collapse_limit" , PGC_USERSET, QUERY_TUNING_OTHER, |
1997 | gettext_noop("Sets the FROM-list size beyond which subqueries " |
1998 | "are not collapsed." ), |
1999 | gettext_noop("The planner will merge subqueries into upper " |
2000 | "queries if the resulting FROM list would have no more than " |
2001 | "this many items." ), |
2002 | GUC_EXPLAIN |
2003 | }, |
2004 | &from_collapse_limit, |
2005 | 8, 1, INT_MAX, |
2006 | NULL, NULL, NULL |
2007 | }, |
2008 | { |
2009 | {"join_collapse_limit" , PGC_USERSET, QUERY_TUNING_OTHER, |
2010 | gettext_noop("Sets the FROM-list size beyond which JOIN " |
2011 | "constructs are not flattened." ), |
2012 | gettext_noop("The planner will flatten explicit JOIN " |
2013 | "constructs into lists of FROM items whenever a " |
2014 | "list of no more than this many items would result." ), |
2015 | GUC_EXPLAIN |
2016 | }, |
2017 | &join_collapse_limit, |
2018 | 8, 1, INT_MAX, |
2019 | NULL, NULL, NULL |
2020 | }, |
2021 | { |
2022 | {"geqo_threshold" , PGC_USERSET, QUERY_TUNING_GEQO, |
2023 | gettext_noop("Sets the threshold of FROM items beyond which GEQO is used." ), |
2024 | NULL, |
2025 | GUC_EXPLAIN |
2026 | }, |
2027 | &geqo_threshold, |
2028 | 12, 2, INT_MAX, |
2029 | NULL, NULL, NULL |
2030 | }, |
2031 | { |
2032 | {"geqo_effort" , PGC_USERSET, QUERY_TUNING_GEQO, |
2033 | gettext_noop("GEQO: effort is used to set the default for other GEQO parameters." ), |
2034 | NULL, |
2035 | GUC_EXPLAIN |
2036 | }, |
2037 | &Geqo_effort, |
2038 | DEFAULT_GEQO_EFFORT, MIN_GEQO_EFFORT, MAX_GEQO_EFFORT, |
2039 | NULL, NULL, NULL |
2040 | }, |
2041 | { |
2042 | {"geqo_pool_size" , PGC_USERSET, QUERY_TUNING_GEQO, |
2043 | gettext_noop("GEQO: number of individuals in the population." ), |
2044 | gettext_noop("Zero selects a suitable default value." ), |
2045 | GUC_EXPLAIN |
2046 | }, |
2047 | &Geqo_pool_size, |
2048 | 0, 0, INT_MAX, |
2049 | NULL, NULL, NULL |
2050 | }, |
2051 | { |
2052 | {"geqo_generations" , PGC_USERSET, QUERY_TUNING_GEQO, |
2053 | gettext_noop("GEQO: number of iterations of the algorithm." ), |
2054 | gettext_noop("Zero selects a suitable default value." ), |
2055 | GUC_EXPLAIN |
2056 | }, |
2057 | &Geqo_generations, |
2058 | 0, 0, INT_MAX, |
2059 | NULL, NULL, NULL |
2060 | }, |
2061 | |
2062 | { |
2063 | /* This is PGC_SUSET to prevent hiding from log_lock_waits. */ |
2064 | {"deadlock_timeout" , PGC_SUSET, LOCK_MANAGEMENT, |
2065 | gettext_noop("Sets the time to wait on a lock before checking for deadlock." ), |
2066 | NULL, |
2067 | GUC_UNIT_MS |
2068 | }, |
2069 | &DeadlockTimeout, |
2070 | 1000, 1, INT_MAX, |
2071 | NULL, NULL, NULL |
2072 | }, |
2073 | |
2074 | { |
2075 | {"max_standby_archive_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
2076 | gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing archived WAL data." ), |
2077 | NULL, |
2078 | GUC_UNIT_MS |
2079 | }, |
2080 | &max_standby_archive_delay, |
2081 | 30 * 1000, -1, INT_MAX, |
2082 | NULL, NULL, NULL |
2083 | }, |
2084 | |
2085 | { |
2086 | {"max_standby_streaming_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
2087 | gettext_noop("Sets the maximum delay before canceling queries when a hot standby server is processing streamed WAL data." ), |
2088 | NULL, |
2089 | GUC_UNIT_MS |
2090 | }, |
2091 | &max_standby_streaming_delay, |
2092 | 30 * 1000, -1, INT_MAX, |
2093 | NULL, NULL, NULL |
2094 | }, |
2095 | |
2096 | { |
2097 | {"recovery_min_apply_delay" , PGC_SIGHUP, REPLICATION_STANDBY, |
2098 | gettext_noop("Sets the minimum delay for applying changes during recovery." ), |
2099 | NULL, |
2100 | GUC_UNIT_MS |
2101 | }, |
2102 | &recovery_min_apply_delay, |
2103 | 0, 0, INT_MAX, |
2104 | NULL, NULL, NULL |
2105 | }, |
2106 | |
2107 | { |
2108 | {"wal_receiver_status_interval" , PGC_SIGHUP, REPLICATION_STANDBY, |
2109 | gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server." ), |
2110 | NULL, |
2111 | GUC_UNIT_S |
2112 | }, |
2113 | &wal_receiver_status_interval, |
2114 | 10, 0, INT_MAX / 1000, |
2115 | NULL, NULL, NULL |
2116 | }, |
2117 | |
2118 | { |
2119 | {"wal_receiver_timeout" , PGC_SIGHUP, REPLICATION_STANDBY, |
2120 | gettext_noop("Sets the maximum wait time to receive data from the sending server." ), |
2121 | NULL, |
2122 | GUC_UNIT_MS |
2123 | }, |
2124 | &wal_receiver_timeout, |
2125 | 60 * 1000, 0, INT_MAX, |
2126 | NULL, NULL, NULL |
2127 | }, |
2128 | |
2129 | { |
2130 | {"max_connections" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
2131 | gettext_noop("Sets the maximum number of concurrent connections." ), |
2132 | NULL |
2133 | }, |
2134 | &MaxConnections, |
2135 | 100, 1, MAX_BACKENDS, |
2136 | check_maxconnections, NULL, NULL |
2137 | }, |
2138 | |
2139 | { |
2140 | /* see max_connections */ |
2141 | {"superuser_reserved_connections" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
2142 | gettext_noop("Sets the number of connection slots reserved for superusers." ), |
2143 | NULL |
2144 | }, |
2145 | &ReservedBackends, |
2146 | 3, 0, MAX_BACKENDS, |
2147 | NULL, NULL, NULL |
2148 | }, |
2149 | |
2150 | /* |
2151 | * We sometimes multiply the number of shared buffers by two without |
2152 | * checking for overflow, so we mustn't allow more than INT_MAX / 2. |
2153 | */ |
2154 | { |
2155 | {"shared_buffers" , PGC_POSTMASTER, RESOURCES_MEM, |
2156 | gettext_noop("Sets the number of shared memory buffers used by the server." ), |
2157 | NULL, |
2158 | GUC_UNIT_BLOCKS |
2159 | }, |
2160 | &NBuffers, |
2161 | 1024, 16, INT_MAX / 2, |
2162 | NULL, NULL, NULL |
2163 | }, |
2164 | |
2165 | { |
2166 | {"temp_buffers" , PGC_USERSET, RESOURCES_MEM, |
2167 | gettext_noop("Sets the maximum number of temporary buffers used by each session." ), |
2168 | NULL, |
2169 | GUC_UNIT_BLOCKS | GUC_EXPLAIN |
2170 | }, |
2171 | &num_temp_buffers, |
2172 | 1024, 100, INT_MAX / 2, |
2173 | check_temp_buffers, NULL, NULL |
2174 | }, |
2175 | |
2176 | { |
2177 | {"port" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
2178 | gettext_noop("Sets the TCP port the server listens on." ), |
2179 | NULL |
2180 | }, |
2181 | &PostPortNumber, |
2182 | DEF_PGPORT, 1, 65535, |
2183 | NULL, NULL, NULL |
2184 | }, |
2185 | |
2186 | { |
2187 | {"unix_socket_permissions" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
2188 | gettext_noop("Sets the access permissions of the Unix-domain socket." ), |
2189 | gettext_noop("Unix-domain sockets use the usual Unix file system " |
2190 | "permission set. The parameter value is expected " |
2191 | "to be a numeric mode specification in the form " |
2192 | "accepted by the chmod and umask system calls. " |
2193 | "(To use the customary octal format the number must " |
2194 | "start with a 0 (zero).)" ) |
2195 | }, |
2196 | &Unix_socket_permissions, |
2197 | 0777, 0000, 0777, |
2198 | NULL, NULL, show_unix_socket_permissions |
2199 | }, |
2200 | |
2201 | { |
2202 | {"log_file_mode" , PGC_SIGHUP, LOGGING_WHERE, |
2203 | gettext_noop("Sets the file permissions for log files." ), |
2204 | gettext_noop("The parameter value is expected " |
2205 | "to be a numeric mode specification in the form " |
2206 | "accepted by the chmod and umask system calls. " |
2207 | "(To use the customary octal format the number must " |
2208 | "start with a 0 (zero).)" ) |
2209 | }, |
2210 | &Log_file_mode, |
2211 | 0600, 0000, 0777, |
2212 | NULL, NULL, show_log_file_mode |
2213 | }, |
2214 | |
2215 | |
2216 | { |
2217 | {"data_directory_mode" , PGC_INTERNAL, PRESET_OPTIONS, |
2218 | gettext_noop("Mode of the data directory." ), |
2219 | gettext_noop("The parameter value is a numeric mode specification " |
2220 | "in the form accepted by the chmod and umask system " |
2221 | "calls. (To use the customary octal format the number " |
2222 | "must start with a 0 (zero).)" ), |
2223 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2224 | }, |
2225 | &data_directory_mode, |
2226 | 0700, 0000, 0777, |
2227 | NULL, NULL, show_data_directory_mode |
2228 | }, |
2229 | |
2230 | { |
2231 | {"work_mem" , PGC_USERSET, RESOURCES_MEM, |
2232 | gettext_noop("Sets the maximum memory to be used for query workspaces." ), |
2233 | gettext_noop("This much memory can be used by each internal " |
2234 | "sort operation and hash table before switching to " |
2235 | "temporary disk files." ), |
2236 | GUC_UNIT_KB | GUC_EXPLAIN |
2237 | }, |
2238 | &work_mem, |
2239 | 4096, 64, MAX_KILOBYTES, |
2240 | NULL, NULL, NULL |
2241 | }, |
2242 | |
2243 | { |
2244 | {"maintenance_work_mem" , PGC_USERSET, RESOURCES_MEM, |
2245 | gettext_noop("Sets the maximum memory to be used for maintenance operations." ), |
2246 | gettext_noop("This includes operations such as VACUUM and CREATE INDEX." ), |
2247 | GUC_UNIT_KB |
2248 | }, |
2249 | &maintenance_work_mem, |
2250 | 65536, 1024, MAX_KILOBYTES, |
2251 | NULL, NULL, NULL |
2252 | }, |
2253 | |
2254 | /* |
2255 | * We use the hopefully-safely-small value of 100kB as the compiled-in |
2256 | * default for max_stack_depth. InitializeGUCOptions will increase it if |
2257 | * possible, depending on the actual platform-specific stack limit. |
2258 | */ |
2259 | { |
2260 | {"max_stack_depth" , PGC_SUSET, RESOURCES_MEM, |
2261 | gettext_noop("Sets the maximum stack depth, in kilobytes." ), |
2262 | NULL, |
2263 | GUC_UNIT_KB |
2264 | }, |
2265 | &max_stack_depth, |
2266 | 100, 100, MAX_KILOBYTES, |
2267 | check_max_stack_depth, assign_max_stack_depth, NULL |
2268 | }, |
2269 | |
2270 | { |
2271 | {"temp_file_limit" , PGC_SUSET, RESOURCES_DISK, |
2272 | gettext_noop("Limits the total size of all temporary files used by each process." ), |
2273 | gettext_noop("-1 means no limit." ), |
2274 | GUC_UNIT_KB |
2275 | }, |
2276 | &temp_file_limit, |
2277 | -1, -1, INT_MAX, |
2278 | NULL, NULL, NULL |
2279 | }, |
2280 | |
2281 | { |
2282 | {"vacuum_cost_page_hit" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
2283 | gettext_noop("Vacuum cost for a page found in the buffer cache." ), |
2284 | NULL |
2285 | }, |
2286 | &VacuumCostPageHit, |
2287 | 1, 0, 10000, |
2288 | NULL, NULL, NULL |
2289 | }, |
2290 | |
2291 | { |
2292 | {"vacuum_cost_page_miss" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
2293 | gettext_noop("Vacuum cost for a page not found in the buffer cache." ), |
2294 | NULL |
2295 | }, |
2296 | &VacuumCostPageMiss, |
2297 | 10, 0, 10000, |
2298 | NULL, NULL, NULL |
2299 | }, |
2300 | |
2301 | { |
2302 | {"vacuum_cost_page_dirty" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
2303 | gettext_noop("Vacuum cost for a page dirtied by vacuum." ), |
2304 | NULL |
2305 | }, |
2306 | &VacuumCostPageDirty, |
2307 | 20, 0, 10000, |
2308 | NULL, NULL, NULL |
2309 | }, |
2310 | |
2311 | { |
2312 | {"vacuum_cost_limit" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
2313 | gettext_noop("Vacuum cost amount available before napping." ), |
2314 | NULL |
2315 | }, |
2316 | &VacuumCostLimit, |
2317 | 200, 1, 10000, |
2318 | NULL, NULL, NULL |
2319 | }, |
2320 | |
2321 | { |
2322 | {"autovacuum_vacuum_cost_limit" , PGC_SIGHUP, AUTOVACUUM, |
2323 | gettext_noop("Vacuum cost amount available before napping, for autovacuum." ), |
2324 | NULL |
2325 | }, |
2326 | &autovacuum_vac_cost_limit, |
2327 | -1, -1, 10000, |
2328 | NULL, NULL, NULL |
2329 | }, |
2330 | |
2331 | { |
2332 | {"max_files_per_process" , PGC_POSTMASTER, RESOURCES_KERNEL, |
2333 | gettext_noop("Sets the maximum number of simultaneously open files for each server process." ), |
2334 | NULL |
2335 | }, |
2336 | &max_files_per_process, |
2337 | 1000, 25, INT_MAX, |
2338 | NULL, NULL, NULL |
2339 | }, |
2340 | |
2341 | /* |
2342 | * See also CheckRequiredParameterValues() if this parameter changes |
2343 | */ |
2344 | { |
2345 | {"max_prepared_transactions" , PGC_POSTMASTER, RESOURCES_MEM, |
2346 | gettext_noop("Sets the maximum number of simultaneously prepared transactions." ), |
2347 | NULL |
2348 | }, |
2349 | &max_prepared_xacts, |
2350 | 0, 0, MAX_BACKENDS, |
2351 | NULL, NULL, NULL |
2352 | }, |
2353 | |
2354 | #ifdef LOCK_DEBUG |
2355 | { |
2356 | {"trace_lock_oidmin" , PGC_SUSET, DEVELOPER_OPTIONS, |
2357 | gettext_noop("Sets the minimum OID of tables for tracking locks." ), |
2358 | gettext_noop("Is used to avoid output on system tables." ), |
2359 | GUC_NOT_IN_SAMPLE |
2360 | }, |
2361 | &Trace_lock_oidmin, |
2362 | FirstNormalObjectId, 0, INT_MAX, |
2363 | NULL, NULL, NULL |
2364 | }, |
2365 | { |
2366 | {"trace_lock_table" , PGC_SUSET, DEVELOPER_OPTIONS, |
2367 | gettext_noop("Sets the OID of the table with unconditionally lock tracing." ), |
2368 | NULL, |
2369 | GUC_NOT_IN_SAMPLE |
2370 | }, |
2371 | &Trace_lock_table, |
2372 | 0, 0, INT_MAX, |
2373 | NULL, NULL, NULL |
2374 | }, |
2375 | #endif |
2376 | |
2377 | { |
2378 | {"statement_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2379 | gettext_noop("Sets the maximum allowed duration of any statement." ), |
2380 | gettext_noop("A value of 0 turns off the timeout." ), |
2381 | GUC_UNIT_MS |
2382 | }, |
2383 | &StatementTimeout, |
2384 | 0, 0, INT_MAX, |
2385 | NULL, NULL, NULL |
2386 | }, |
2387 | |
2388 | { |
2389 | {"lock_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2390 | gettext_noop("Sets the maximum allowed duration of any wait for a lock." ), |
2391 | gettext_noop("A value of 0 turns off the timeout." ), |
2392 | GUC_UNIT_MS |
2393 | }, |
2394 | &LockTimeout, |
2395 | 0, 0, INT_MAX, |
2396 | NULL, NULL, NULL |
2397 | }, |
2398 | |
2399 | { |
2400 | {"idle_in_transaction_session_timeout" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2401 | gettext_noop("Sets the maximum allowed duration of any idling transaction." ), |
2402 | gettext_noop("A value of 0 turns off the timeout." ), |
2403 | GUC_UNIT_MS |
2404 | }, |
2405 | &IdleInTransactionSessionTimeout, |
2406 | 0, 0, INT_MAX, |
2407 | NULL, NULL, NULL |
2408 | }, |
2409 | |
2410 | { |
2411 | {"vacuum_freeze_min_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2412 | gettext_noop("Minimum age at which VACUUM should freeze a table row." ), |
2413 | NULL |
2414 | }, |
2415 | &vacuum_freeze_min_age, |
2416 | 50000000, 0, 1000000000, |
2417 | NULL, NULL, NULL |
2418 | }, |
2419 | |
2420 | { |
2421 | {"vacuum_freeze_table_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2422 | gettext_noop("Age at which VACUUM should scan whole table to freeze tuples." ), |
2423 | NULL |
2424 | }, |
2425 | &vacuum_freeze_table_age, |
2426 | 150000000, 0, 2000000000, |
2427 | NULL, NULL, NULL |
2428 | }, |
2429 | |
2430 | { |
2431 | {"vacuum_multixact_freeze_min_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2432 | gettext_noop("Minimum age at which VACUUM should freeze a MultiXactId in a table row." ), |
2433 | NULL |
2434 | }, |
2435 | &vacuum_multixact_freeze_min_age, |
2436 | 5000000, 0, 1000000000, |
2437 | NULL, NULL, NULL |
2438 | }, |
2439 | |
2440 | { |
2441 | {"vacuum_multixact_freeze_table_age" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
2442 | gettext_noop("Multixact age at which VACUUM should scan whole table to freeze tuples." ), |
2443 | NULL |
2444 | }, |
2445 | &vacuum_multixact_freeze_table_age, |
2446 | 150000000, 0, 2000000000, |
2447 | NULL, NULL, NULL |
2448 | }, |
2449 | |
2450 | { |
2451 | {"vacuum_defer_cleanup_age" , PGC_SIGHUP, REPLICATION_MASTER, |
2452 | gettext_noop("Number of transactions by which VACUUM and HOT cleanup should be deferred, if any." ), |
2453 | NULL |
2454 | }, |
2455 | &vacuum_defer_cleanup_age, |
2456 | 0, 0, 1000000, |
2457 | NULL, NULL, NULL |
2458 | }, |
2459 | |
2460 | /* |
2461 | * See also CheckRequiredParameterValues() if this parameter changes |
2462 | */ |
2463 | { |
2464 | {"max_locks_per_transaction" , PGC_POSTMASTER, LOCK_MANAGEMENT, |
2465 | gettext_noop("Sets the maximum number of locks per transaction." ), |
2466 | gettext_noop("The shared lock table is sized on the assumption that " |
2467 | "at most max_locks_per_transaction * max_connections distinct " |
2468 | "objects will need to be locked at any one time." ) |
2469 | }, |
2470 | &max_locks_per_xact, |
2471 | 64, 10, INT_MAX, |
2472 | NULL, NULL, NULL |
2473 | }, |
2474 | |
2475 | { |
2476 | {"max_pred_locks_per_transaction" , PGC_POSTMASTER, LOCK_MANAGEMENT, |
2477 | gettext_noop("Sets the maximum number of predicate locks per transaction." ), |
2478 | gettext_noop("The shared predicate lock table is sized on the assumption that " |
2479 | "at most max_pred_locks_per_transaction * max_connections distinct " |
2480 | "objects will need to be locked at any one time." ) |
2481 | }, |
2482 | &max_predicate_locks_per_xact, |
2483 | 64, 10, INT_MAX, |
2484 | NULL, NULL, NULL |
2485 | }, |
2486 | |
2487 | { |
2488 | {"max_pred_locks_per_relation" , PGC_SIGHUP, LOCK_MANAGEMENT, |
2489 | gettext_noop("Sets the maximum number of predicate-locked pages and tuples per relation." ), |
2490 | gettext_noop("If more than this total of pages and tuples in the same relation are locked " |
2491 | "by a connection, those locks are replaced by a relation-level lock." ) |
2492 | }, |
2493 | &max_predicate_locks_per_relation, |
2494 | -2, INT_MIN, INT_MAX, |
2495 | NULL, NULL, NULL |
2496 | }, |
2497 | |
2498 | { |
2499 | {"max_pred_locks_per_page" , PGC_SIGHUP, LOCK_MANAGEMENT, |
2500 | gettext_noop("Sets the maximum number of predicate-locked tuples per page." ), |
2501 | gettext_noop("If more than this number of tuples on the same page are locked " |
2502 | "by a connection, those locks are replaced by a page-level lock." ) |
2503 | }, |
2504 | &max_predicate_locks_per_page, |
2505 | 2, 0, INT_MAX, |
2506 | NULL, NULL, NULL |
2507 | }, |
2508 | |
2509 | { |
2510 | {"authentication_timeout" , PGC_SIGHUP, CONN_AUTH_AUTH, |
2511 | gettext_noop("Sets the maximum allowed time to complete client authentication." ), |
2512 | NULL, |
2513 | GUC_UNIT_S |
2514 | }, |
2515 | &AuthenticationTimeout, |
2516 | 60, 1, 600, |
2517 | NULL, NULL, NULL |
2518 | }, |
2519 | |
2520 | { |
2521 | /* Not for general use */ |
2522 | {"pre_auth_delay" , PGC_SIGHUP, DEVELOPER_OPTIONS, |
2523 | gettext_noop("Waits N seconds on connection startup before authentication." ), |
2524 | gettext_noop("This allows attaching a debugger to the process." ), |
2525 | GUC_NOT_IN_SAMPLE | GUC_UNIT_S |
2526 | }, |
2527 | &PreAuthDelay, |
2528 | 0, 0, 60, |
2529 | NULL, NULL, NULL |
2530 | }, |
2531 | |
2532 | { |
2533 | {"wal_keep_segments" , PGC_SIGHUP, REPLICATION_SENDING, |
2534 | gettext_noop("Sets the number of WAL files held for standby servers." ), |
2535 | NULL |
2536 | }, |
2537 | &wal_keep_segments, |
2538 | 0, 0, INT_MAX, |
2539 | NULL, NULL, NULL |
2540 | }, |
2541 | |
2542 | { |
2543 | {"min_wal_size" , PGC_SIGHUP, WAL_CHECKPOINTS, |
2544 | gettext_noop("Sets the minimum size to shrink the WAL to." ), |
2545 | NULL, |
2546 | GUC_UNIT_MB |
2547 | }, |
2548 | &min_wal_size_mb, |
2549 | DEFAULT_MIN_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)), |
2550 | 2, MAX_KILOBYTES, |
2551 | NULL, NULL, NULL |
2552 | }, |
2553 | |
2554 | { |
2555 | {"max_wal_size" , PGC_SIGHUP, WAL_CHECKPOINTS, |
2556 | gettext_noop("Sets the WAL size that triggers a checkpoint." ), |
2557 | NULL, |
2558 | GUC_UNIT_MB |
2559 | }, |
2560 | &max_wal_size_mb, |
2561 | DEFAULT_MAX_WAL_SEGS * (DEFAULT_XLOG_SEG_SIZE / (1024 * 1024)), |
2562 | 2, MAX_KILOBYTES, |
2563 | NULL, assign_max_wal_size, NULL |
2564 | }, |
2565 | |
2566 | { |
2567 | {"checkpoint_timeout" , PGC_SIGHUP, WAL_CHECKPOINTS, |
2568 | gettext_noop("Sets the maximum time between automatic WAL checkpoints." ), |
2569 | NULL, |
2570 | GUC_UNIT_S |
2571 | }, |
2572 | &CheckPointTimeout, |
2573 | 300, 30, 86400, |
2574 | NULL, NULL, NULL |
2575 | }, |
2576 | |
2577 | { |
2578 | {"checkpoint_warning" , PGC_SIGHUP, WAL_CHECKPOINTS, |
2579 | gettext_noop("Enables warnings if checkpoint segments are filled more " |
2580 | "frequently than this." ), |
2581 | gettext_noop("Write a message to the server log if checkpoints " |
2582 | "caused by the filling of checkpoint segment files happens more " |
2583 | "frequently than this number of seconds. Zero turns off the warning." ), |
2584 | GUC_UNIT_S |
2585 | }, |
2586 | &CheckPointWarning, |
2587 | 30, 0, INT_MAX, |
2588 | NULL, NULL, NULL |
2589 | }, |
2590 | |
2591 | { |
2592 | {"checkpoint_flush_after" , PGC_SIGHUP, WAL_CHECKPOINTS, |
2593 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
2594 | NULL, |
2595 | GUC_UNIT_BLOCKS |
2596 | }, |
2597 | &checkpoint_flush_after, |
2598 | DEFAULT_CHECKPOINT_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
2599 | NULL, NULL, NULL |
2600 | }, |
2601 | |
2602 | { |
2603 | {"wal_buffers" , PGC_POSTMASTER, WAL_SETTINGS, |
2604 | gettext_noop("Sets the number of disk-page buffers in shared memory for WAL." ), |
2605 | NULL, |
2606 | GUC_UNIT_XBLOCKS |
2607 | }, |
2608 | &XLOGbuffers, |
2609 | -1, -1, (INT_MAX / XLOG_BLCKSZ), |
2610 | check_wal_buffers, NULL, NULL |
2611 | }, |
2612 | |
2613 | { |
2614 | {"wal_writer_delay" , PGC_SIGHUP, WAL_SETTINGS, |
2615 | gettext_noop("Time between WAL flushes performed in the WAL writer." ), |
2616 | NULL, |
2617 | GUC_UNIT_MS |
2618 | }, |
2619 | &WalWriterDelay, |
2620 | 200, 1, 10000, |
2621 | NULL, NULL, NULL |
2622 | }, |
2623 | |
2624 | { |
2625 | {"wal_writer_flush_after" , PGC_SIGHUP, WAL_SETTINGS, |
2626 | gettext_noop("Amount of WAL written out by WAL writer that triggers a flush." ), |
2627 | NULL, |
2628 | GUC_UNIT_XBLOCKS |
2629 | }, |
2630 | &WalWriterFlushAfter, |
2631 | (1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX, |
2632 | NULL, NULL, NULL |
2633 | }, |
2634 | |
2635 | { |
2636 | {"max_wal_senders" , PGC_POSTMASTER, REPLICATION_SENDING, |
2637 | gettext_noop("Sets the maximum number of simultaneously running WAL sender processes." ), |
2638 | NULL |
2639 | }, |
2640 | &max_wal_senders, |
2641 | 10, 0, MAX_BACKENDS, |
2642 | check_max_wal_senders, NULL, NULL |
2643 | }, |
2644 | |
2645 | { |
2646 | /* see max_wal_senders */ |
2647 | {"max_replication_slots" , PGC_POSTMASTER, REPLICATION_SENDING, |
2648 | gettext_noop("Sets the maximum number of simultaneously defined replication slots." ), |
2649 | NULL |
2650 | }, |
2651 | &max_replication_slots, |
2652 | 10, 0, MAX_BACKENDS /* XXX? */ , |
2653 | NULL, NULL, NULL |
2654 | }, |
2655 | |
2656 | { |
2657 | {"wal_sender_timeout" , PGC_USERSET, REPLICATION_SENDING, |
2658 | gettext_noop("Sets the maximum time to wait for WAL replication." ), |
2659 | NULL, |
2660 | GUC_UNIT_MS |
2661 | }, |
2662 | &wal_sender_timeout, |
2663 | 60 * 1000, 0, INT_MAX, |
2664 | NULL, NULL, NULL |
2665 | }, |
2666 | |
2667 | { |
2668 | {"commit_delay" , PGC_SUSET, WAL_SETTINGS, |
2669 | gettext_noop("Sets the delay in microseconds between transaction commit and " |
2670 | "flushing WAL to disk." ), |
2671 | NULL |
2672 | /* we have no microseconds designation, so can't supply units here */ |
2673 | }, |
2674 | &CommitDelay, |
2675 | 0, 0, 100000, |
2676 | NULL, NULL, NULL |
2677 | }, |
2678 | |
2679 | { |
2680 | {"commit_siblings" , PGC_USERSET, WAL_SETTINGS, |
2681 | gettext_noop("Sets the minimum concurrent open transactions before performing " |
2682 | "commit_delay." ), |
2683 | NULL |
2684 | }, |
2685 | &CommitSiblings, |
2686 | 5, 0, 1000, |
2687 | NULL, NULL, NULL |
2688 | }, |
2689 | |
2690 | { |
2691 | {"extra_float_digits" , PGC_USERSET, CLIENT_CONN_LOCALE, |
2692 | gettext_noop("Sets the number of digits displayed for floating-point values." ), |
2693 | gettext_noop("This affects real, double precision, and geometric data types. " |
2694 | "A zero or negative parameter value is added to the standard " |
2695 | "number of digits (FLT_DIG or DBL_DIG as appropriate). " |
2696 | "Any value greater than zero selects precise output mode." ) |
2697 | }, |
2698 | &extra_float_digits, |
2699 | 1, -15, 3, |
2700 | NULL, NULL, NULL |
2701 | }, |
2702 | |
2703 | { |
2704 | {"log_min_duration_statement" , PGC_SUSET, LOGGING_WHEN, |
2705 | gettext_noop("Sets the minimum execution time above which " |
2706 | "statements will be logged." ), |
2707 | gettext_noop("Zero prints all queries. -1 turns this feature off." ), |
2708 | GUC_UNIT_MS |
2709 | }, |
2710 | &log_min_duration_statement, |
2711 | -1, -1, INT_MAX, |
2712 | NULL, NULL, NULL |
2713 | }, |
2714 | |
2715 | { |
2716 | {"log_autovacuum_min_duration" , PGC_SIGHUP, LOGGING_WHAT, |
2717 | gettext_noop("Sets the minimum execution time above which " |
2718 | "autovacuum actions will be logged." ), |
2719 | gettext_noop("Zero prints all actions. -1 turns autovacuum logging off." ), |
2720 | GUC_UNIT_MS |
2721 | }, |
2722 | &Log_autovacuum_min_duration, |
2723 | -1, -1, INT_MAX, |
2724 | NULL, NULL, NULL |
2725 | }, |
2726 | |
2727 | { |
2728 | {"bgwriter_delay" , PGC_SIGHUP, RESOURCES_BGWRITER, |
2729 | gettext_noop("Background writer sleep time between rounds." ), |
2730 | NULL, |
2731 | GUC_UNIT_MS |
2732 | }, |
2733 | &BgWriterDelay, |
2734 | 200, 10, 10000, |
2735 | NULL, NULL, NULL |
2736 | }, |
2737 | |
2738 | { |
2739 | {"bgwriter_lru_maxpages" , PGC_SIGHUP, RESOURCES_BGWRITER, |
2740 | gettext_noop("Background writer maximum number of LRU pages to flush per round." ), |
2741 | NULL |
2742 | }, |
2743 | &bgwriter_lru_maxpages, |
2744 | 100, 0, INT_MAX / 2, /* Same upper limit as shared_buffers */ |
2745 | NULL, NULL, NULL |
2746 | }, |
2747 | |
2748 | { |
2749 | {"bgwriter_flush_after" , PGC_SIGHUP, RESOURCES_BGWRITER, |
2750 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
2751 | NULL, |
2752 | GUC_UNIT_BLOCKS |
2753 | }, |
2754 | &bgwriter_flush_after, |
2755 | DEFAULT_BGWRITER_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
2756 | NULL, NULL, NULL |
2757 | }, |
2758 | |
2759 | { |
2760 | {"effective_io_concurrency" , |
2761 | PGC_USERSET, |
2762 | RESOURCES_ASYNCHRONOUS, |
2763 | gettext_noop("Number of simultaneous requests that can be handled efficiently by the disk subsystem." ), |
2764 | gettext_noop("For RAID arrays, this should be approximately the number of drive spindles in the array." ), |
2765 | GUC_EXPLAIN |
2766 | }, |
2767 | &effective_io_concurrency, |
2768 | #ifdef USE_PREFETCH |
2769 | 1, |
2770 | #else |
2771 | 0, |
2772 | #endif |
2773 | 0, MAX_IO_CONCURRENCY, |
2774 | check_effective_io_concurrency, assign_effective_io_concurrency, NULL |
2775 | }, |
2776 | |
2777 | { |
2778 | {"backend_flush_after" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
2779 | gettext_noop("Number of pages after which previously performed writes are flushed to disk." ), |
2780 | NULL, |
2781 | GUC_UNIT_BLOCKS |
2782 | }, |
2783 | &backend_flush_after, |
2784 | DEFAULT_BACKEND_FLUSH_AFTER, 0, WRITEBACK_MAX_PENDING_FLUSHES, |
2785 | NULL, NULL, NULL |
2786 | }, |
2787 | |
2788 | { |
2789 | {"max_worker_processes" , |
2790 | PGC_POSTMASTER, |
2791 | RESOURCES_ASYNCHRONOUS, |
2792 | gettext_noop("Maximum number of concurrent worker processes." ), |
2793 | NULL, |
2794 | }, |
2795 | &max_worker_processes, |
2796 | 8, 0, MAX_BACKENDS, |
2797 | check_max_worker_processes, NULL, NULL |
2798 | }, |
2799 | |
2800 | { |
2801 | {"max_logical_replication_workers" , |
2802 | PGC_POSTMASTER, |
2803 | REPLICATION_SUBSCRIBERS, |
2804 | gettext_noop("Maximum number of logical replication worker processes." ), |
2805 | NULL, |
2806 | }, |
2807 | &max_logical_replication_workers, |
2808 | 4, 0, MAX_BACKENDS, |
2809 | NULL, NULL, NULL |
2810 | }, |
2811 | |
2812 | { |
2813 | {"max_sync_workers_per_subscription" , |
2814 | PGC_SIGHUP, |
2815 | REPLICATION_SUBSCRIBERS, |
2816 | gettext_noop("Maximum number of table synchronization workers per subscription." ), |
2817 | NULL, |
2818 | }, |
2819 | &max_sync_workers_per_subscription, |
2820 | 2, 0, MAX_BACKENDS, |
2821 | NULL, NULL, NULL |
2822 | }, |
2823 | |
2824 | { |
2825 | {"log_rotation_age" , PGC_SIGHUP, LOGGING_WHERE, |
2826 | gettext_noop("Automatic log file rotation will occur after N minutes." ), |
2827 | NULL, |
2828 | GUC_UNIT_MIN |
2829 | }, |
2830 | &Log_RotationAge, |
2831 | HOURS_PER_DAY * MINS_PER_HOUR, 0, INT_MAX / SECS_PER_MINUTE, |
2832 | NULL, NULL, NULL |
2833 | }, |
2834 | |
2835 | { |
2836 | {"log_rotation_size" , PGC_SIGHUP, LOGGING_WHERE, |
2837 | gettext_noop("Automatic log file rotation will occur after N kilobytes." ), |
2838 | NULL, |
2839 | GUC_UNIT_KB |
2840 | }, |
2841 | &Log_RotationSize, |
2842 | 10 * 1024, 0, INT_MAX / 1024, |
2843 | NULL, NULL, NULL |
2844 | }, |
2845 | |
2846 | { |
2847 | {"max_function_args" , PGC_INTERNAL, PRESET_OPTIONS, |
2848 | gettext_noop("Shows the maximum number of function arguments." ), |
2849 | NULL, |
2850 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2851 | }, |
2852 | &max_function_args, |
2853 | FUNC_MAX_ARGS, FUNC_MAX_ARGS, FUNC_MAX_ARGS, |
2854 | NULL, NULL, NULL |
2855 | }, |
2856 | |
2857 | { |
2858 | {"max_index_keys" , PGC_INTERNAL, PRESET_OPTIONS, |
2859 | gettext_noop("Shows the maximum number of index keys." ), |
2860 | NULL, |
2861 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2862 | }, |
2863 | &max_index_keys, |
2864 | INDEX_MAX_KEYS, INDEX_MAX_KEYS, INDEX_MAX_KEYS, |
2865 | NULL, NULL, NULL |
2866 | }, |
2867 | |
2868 | { |
2869 | {"max_identifier_length" , PGC_INTERNAL, PRESET_OPTIONS, |
2870 | gettext_noop("Shows the maximum identifier length." ), |
2871 | NULL, |
2872 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2873 | }, |
2874 | &max_identifier_length, |
2875 | NAMEDATALEN - 1, NAMEDATALEN - 1, NAMEDATALEN - 1, |
2876 | NULL, NULL, NULL |
2877 | }, |
2878 | |
2879 | { |
2880 | {"block_size" , PGC_INTERNAL, PRESET_OPTIONS, |
2881 | gettext_noop("Shows the size of a disk block." ), |
2882 | NULL, |
2883 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2884 | }, |
2885 | &block_size, |
2886 | BLCKSZ, BLCKSZ, BLCKSZ, |
2887 | NULL, NULL, NULL |
2888 | }, |
2889 | |
2890 | { |
2891 | {"segment_size" , PGC_INTERNAL, PRESET_OPTIONS, |
2892 | gettext_noop("Shows the number of pages per disk file." ), |
2893 | NULL, |
2894 | GUC_UNIT_BLOCKS | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2895 | }, |
2896 | &segment_size, |
2897 | RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE, |
2898 | NULL, NULL, NULL |
2899 | }, |
2900 | |
2901 | { |
2902 | {"wal_block_size" , PGC_INTERNAL, PRESET_OPTIONS, |
2903 | gettext_noop("Shows the block size in the write ahead log." ), |
2904 | NULL, |
2905 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2906 | }, |
2907 | &wal_block_size, |
2908 | XLOG_BLCKSZ, XLOG_BLCKSZ, XLOG_BLCKSZ, |
2909 | NULL, NULL, NULL |
2910 | }, |
2911 | |
2912 | { |
2913 | {"wal_retrieve_retry_interval" , PGC_SIGHUP, REPLICATION_STANDBY, |
2914 | gettext_noop("Sets the time to wait before retrying to retrieve WAL " |
2915 | "after a failed attempt." ), |
2916 | NULL, |
2917 | GUC_UNIT_MS |
2918 | }, |
2919 | &wal_retrieve_retry_interval, |
2920 | 5000, 1, INT_MAX, |
2921 | NULL, NULL, NULL |
2922 | }, |
2923 | |
2924 | { |
2925 | {"wal_segment_size" , PGC_INTERNAL, PRESET_OPTIONS, |
2926 | gettext_noop("Shows the size of write ahead log segments." ), |
2927 | NULL, |
2928 | GUC_UNIT_BYTE | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
2929 | }, |
2930 | &wal_segment_size, |
2931 | DEFAULT_XLOG_SEG_SIZE, |
2932 | WalSegMinSize, |
2933 | WalSegMaxSize, |
2934 | NULL, NULL, NULL |
2935 | }, |
2936 | |
2937 | { |
2938 | {"autovacuum_naptime" , PGC_SIGHUP, AUTOVACUUM, |
2939 | gettext_noop("Time to sleep between autovacuum runs." ), |
2940 | NULL, |
2941 | GUC_UNIT_S |
2942 | }, |
2943 | &autovacuum_naptime, |
2944 | 60, 1, INT_MAX / 1000, |
2945 | NULL, NULL, NULL |
2946 | }, |
2947 | { |
2948 | {"autovacuum_vacuum_threshold" , PGC_SIGHUP, AUTOVACUUM, |
2949 | gettext_noop("Minimum number of tuple updates or deletes prior to vacuum." ), |
2950 | NULL |
2951 | }, |
2952 | &autovacuum_vac_thresh, |
2953 | 50, 0, INT_MAX, |
2954 | NULL, NULL, NULL |
2955 | }, |
2956 | { |
2957 | {"autovacuum_analyze_threshold" , PGC_SIGHUP, AUTOVACUUM, |
2958 | gettext_noop("Minimum number of tuple inserts, updates, or deletes prior to analyze." ), |
2959 | NULL |
2960 | }, |
2961 | &autovacuum_anl_thresh, |
2962 | 50, 0, INT_MAX, |
2963 | NULL, NULL, NULL |
2964 | }, |
2965 | { |
2966 | /* see varsup.c for why this is PGC_POSTMASTER not PGC_SIGHUP */ |
2967 | {"autovacuum_freeze_max_age" , PGC_POSTMASTER, AUTOVACUUM, |
2968 | gettext_noop("Age at which to autovacuum a table to prevent transaction ID wraparound." ), |
2969 | NULL |
2970 | }, |
2971 | &autovacuum_freeze_max_age, |
2972 | /* see pg_resetwal if you change the upper-limit value */ |
2973 | 200000000, 100000, 2000000000, |
2974 | NULL, NULL, NULL |
2975 | }, |
2976 | { |
2977 | /* see multixact.c for why this is PGC_POSTMASTER not PGC_SIGHUP */ |
2978 | {"autovacuum_multixact_freeze_max_age" , PGC_POSTMASTER, AUTOVACUUM, |
2979 | gettext_noop("Multixact age at which to autovacuum a table to prevent multixact wraparound." ), |
2980 | NULL |
2981 | }, |
2982 | &autovacuum_multixact_freeze_max_age, |
2983 | 400000000, 10000, 2000000000, |
2984 | NULL, NULL, NULL |
2985 | }, |
2986 | { |
2987 | /* see max_connections */ |
2988 | {"autovacuum_max_workers" , PGC_POSTMASTER, AUTOVACUUM, |
2989 | gettext_noop("Sets the maximum number of simultaneously running autovacuum worker processes." ), |
2990 | NULL |
2991 | }, |
2992 | &autovacuum_max_workers, |
2993 | 3, 1, MAX_BACKENDS, |
2994 | check_autovacuum_max_workers, NULL, NULL |
2995 | }, |
2996 | |
2997 | { |
2998 | {"max_parallel_maintenance_workers" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
2999 | gettext_noop("Sets the maximum number of parallel processes per maintenance operation." ), |
3000 | NULL |
3001 | }, |
3002 | &max_parallel_maintenance_workers, |
3003 | 2, 0, 1024, |
3004 | NULL, NULL, NULL |
3005 | }, |
3006 | |
3007 | { |
3008 | {"max_parallel_workers_per_gather" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
3009 | gettext_noop("Sets the maximum number of parallel processes per executor node." ), |
3010 | NULL, |
3011 | GUC_EXPLAIN |
3012 | }, |
3013 | &max_parallel_workers_per_gather, |
3014 | 2, 0, MAX_PARALLEL_WORKER_LIMIT, |
3015 | NULL, NULL, NULL |
3016 | }, |
3017 | |
3018 | { |
3019 | {"max_parallel_workers" , PGC_USERSET, RESOURCES_ASYNCHRONOUS, |
3020 | gettext_noop("Sets the maximum number of parallel workers that can be active at one time." ), |
3021 | NULL, |
3022 | GUC_EXPLAIN |
3023 | }, |
3024 | &max_parallel_workers, |
3025 | 8, 0, MAX_PARALLEL_WORKER_LIMIT, |
3026 | NULL, NULL, NULL |
3027 | }, |
3028 | |
3029 | { |
3030 | {"autovacuum_work_mem" , PGC_SIGHUP, RESOURCES_MEM, |
3031 | gettext_noop("Sets the maximum memory to be used by each autovacuum worker process." ), |
3032 | NULL, |
3033 | GUC_UNIT_KB |
3034 | }, |
3035 | &autovacuum_work_mem, |
3036 | -1, -1, MAX_KILOBYTES, |
3037 | check_autovacuum_work_mem, NULL, NULL |
3038 | }, |
3039 | |
3040 | { |
3041 | {"old_snapshot_threshold" , PGC_POSTMASTER, RESOURCES_ASYNCHRONOUS, |
3042 | gettext_noop("Time before a snapshot is too old to read pages changed after the snapshot was taken." ), |
3043 | gettext_noop("A value of -1 disables this feature." ), |
3044 | GUC_UNIT_MIN |
3045 | }, |
3046 | &old_snapshot_threshold, |
3047 | -1, -1, MINS_PER_HOUR * HOURS_PER_DAY * 60, |
3048 | NULL, NULL, NULL |
3049 | }, |
3050 | |
3051 | { |
3052 | {"tcp_keepalives_idle" , PGC_USERSET, CLIENT_CONN_OTHER, |
3053 | gettext_noop("Time between issuing TCP keepalives." ), |
3054 | gettext_noop("A value of 0 uses the system default." ), |
3055 | GUC_UNIT_S |
3056 | }, |
3057 | &tcp_keepalives_idle, |
3058 | 0, 0, INT_MAX, |
3059 | NULL, assign_tcp_keepalives_idle, show_tcp_keepalives_idle |
3060 | }, |
3061 | |
3062 | { |
3063 | {"tcp_keepalives_interval" , PGC_USERSET, CLIENT_CONN_OTHER, |
3064 | gettext_noop("Time between TCP keepalive retransmits." ), |
3065 | gettext_noop("A value of 0 uses the system default." ), |
3066 | GUC_UNIT_S |
3067 | }, |
3068 | &tcp_keepalives_interval, |
3069 | 0, 0, INT_MAX, |
3070 | NULL, assign_tcp_keepalives_interval, show_tcp_keepalives_interval |
3071 | }, |
3072 | |
3073 | { |
3074 | {"ssl_renegotiation_limit" , PGC_USERSET, CONN_AUTH_SSL, |
3075 | gettext_noop("SSL renegotiation is no longer supported; this can only be 0." ), |
3076 | NULL, |
3077 | GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE, |
3078 | }, |
3079 | &ssl_renegotiation_limit, |
3080 | 0, 0, 0, |
3081 | NULL, NULL, NULL |
3082 | }, |
3083 | |
3084 | { |
3085 | {"tcp_keepalives_count" , PGC_USERSET, CLIENT_CONN_OTHER, |
3086 | gettext_noop("Maximum number of TCP keepalive retransmits." ), |
3087 | gettext_noop("This controls the number of consecutive keepalive retransmits that can be " |
3088 | "lost before a connection is considered dead. A value of 0 uses the " |
3089 | "system default." ), |
3090 | }, |
3091 | &tcp_keepalives_count, |
3092 | 0, 0, INT_MAX, |
3093 | NULL, assign_tcp_keepalives_count, show_tcp_keepalives_count |
3094 | }, |
3095 | |
3096 | { |
3097 | {"gin_fuzzy_search_limit" , PGC_USERSET, CLIENT_CONN_OTHER, |
3098 | gettext_noop("Sets the maximum allowed result for exact search by GIN." ), |
3099 | NULL, |
3100 | 0 |
3101 | }, |
3102 | &GinFuzzySearchLimit, |
3103 | 0, 0, INT_MAX, |
3104 | NULL, NULL, NULL |
3105 | }, |
3106 | |
3107 | { |
3108 | {"effective_cache_size" , PGC_USERSET, QUERY_TUNING_COST, |
3109 | gettext_noop("Sets the planner's assumption about the total size of the data caches." ), |
3110 | gettext_noop("That is, the total size of the caches (kernel cache and shared buffers) used for PostgreSQL data files. " |
3111 | "This is measured in disk pages, which are normally 8 kB each." ), |
3112 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
3113 | }, |
3114 | &effective_cache_size, |
3115 | DEFAULT_EFFECTIVE_CACHE_SIZE, 1, INT_MAX, |
3116 | NULL, NULL, NULL |
3117 | }, |
3118 | |
3119 | { |
3120 | {"min_parallel_table_scan_size" , PGC_USERSET, QUERY_TUNING_COST, |
3121 | gettext_noop("Sets the minimum amount of table data for a parallel scan." ), |
3122 | gettext_noop("If the planner estimates that it will read a number of table pages too small to reach this limit, a parallel scan will not be considered." ), |
3123 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
3124 | }, |
3125 | &min_parallel_table_scan_size, |
3126 | (8 * 1024 * 1024) / BLCKSZ, 0, INT_MAX / 3, |
3127 | NULL, NULL, NULL |
3128 | }, |
3129 | |
3130 | { |
3131 | {"min_parallel_index_scan_size" , PGC_USERSET, QUERY_TUNING_COST, |
3132 | gettext_noop("Sets the minimum amount of index data for a parallel scan." ), |
3133 | gettext_noop("If the planner estimates that it will read a number of index pages too small to reach this limit, a parallel scan will not be considered." ), |
3134 | GUC_UNIT_BLOCKS | GUC_EXPLAIN, |
3135 | }, |
3136 | &min_parallel_index_scan_size, |
3137 | (512 * 1024) / BLCKSZ, 0, INT_MAX / 3, |
3138 | NULL, NULL, NULL |
3139 | }, |
3140 | |
3141 | { |
3142 | /* Can't be set in postgresql.conf */ |
3143 | {"server_version_num" , PGC_INTERNAL, PRESET_OPTIONS, |
3144 | gettext_noop("Shows the server version as an integer." ), |
3145 | NULL, |
3146 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3147 | }, |
3148 | &server_version_num, |
3149 | PG_VERSION_NUM, PG_VERSION_NUM, PG_VERSION_NUM, |
3150 | NULL, NULL, NULL |
3151 | }, |
3152 | |
3153 | { |
3154 | {"log_temp_files" , PGC_SUSET, LOGGING_WHAT, |
3155 | gettext_noop("Log the use of temporary files larger than this number of kilobytes." ), |
3156 | gettext_noop("Zero logs all files. The default is -1 (turning this feature off)." ), |
3157 | GUC_UNIT_KB |
3158 | }, |
3159 | &log_temp_files, |
3160 | -1, -1, INT_MAX, |
3161 | NULL, NULL, NULL |
3162 | }, |
3163 | |
3164 | { |
3165 | {"track_activity_query_size" , PGC_POSTMASTER, RESOURCES_MEM, |
3166 | gettext_noop("Sets the size reserved for pg_stat_activity.query, in bytes." ), |
3167 | NULL, |
3168 | GUC_UNIT_BYTE |
3169 | }, |
3170 | &pgstat_track_activity_query_size, |
3171 | 1024, 100, 102400, |
3172 | NULL, NULL, NULL |
3173 | }, |
3174 | |
3175 | { |
3176 | {"gin_pending_list_limit" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3177 | gettext_noop("Sets the maximum size of the pending list for GIN index." ), |
3178 | NULL, |
3179 | GUC_UNIT_KB |
3180 | }, |
3181 | &gin_pending_list_limit, |
3182 | 4096, 64, MAX_KILOBYTES, |
3183 | NULL, NULL, NULL |
3184 | }, |
3185 | |
3186 | { |
3187 | {"tcp_user_timeout" , PGC_USERSET, CLIENT_CONN_OTHER, |
3188 | gettext_noop("TCP user timeout." ), |
3189 | gettext_noop("A value of 0 uses the system default." ), |
3190 | GUC_UNIT_MS |
3191 | }, |
3192 | &tcp_user_timeout, |
3193 | 0, 0, INT_MAX, |
3194 | NULL, assign_tcp_user_timeout, show_tcp_user_timeout |
3195 | }, |
3196 | |
3197 | /* End-of-list marker */ |
3198 | { |
3199 | {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL |
3200 | } |
3201 | }; |
3202 | |
3203 | |
3204 | static struct config_real ConfigureNamesReal[] = |
3205 | { |
3206 | { |
3207 | {"seq_page_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3208 | gettext_noop("Sets the planner's estimate of the cost of a " |
3209 | "sequentially fetched disk page." ), |
3210 | NULL, |
3211 | GUC_EXPLAIN |
3212 | }, |
3213 | &seq_page_cost, |
3214 | DEFAULT_SEQ_PAGE_COST, 0, DBL_MAX, |
3215 | NULL, NULL, NULL |
3216 | }, |
3217 | { |
3218 | {"random_page_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3219 | gettext_noop("Sets the planner's estimate of the cost of a " |
3220 | "nonsequentially fetched disk page." ), |
3221 | NULL, |
3222 | GUC_EXPLAIN |
3223 | }, |
3224 | &random_page_cost, |
3225 | DEFAULT_RANDOM_PAGE_COST, 0, DBL_MAX, |
3226 | NULL, NULL, NULL |
3227 | }, |
3228 | { |
3229 | {"cpu_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3230 | gettext_noop("Sets the planner's estimate of the cost of " |
3231 | "processing each tuple (row)." ), |
3232 | NULL, |
3233 | GUC_EXPLAIN |
3234 | }, |
3235 | &cpu_tuple_cost, |
3236 | DEFAULT_CPU_TUPLE_COST, 0, DBL_MAX, |
3237 | NULL, NULL, NULL |
3238 | }, |
3239 | { |
3240 | {"cpu_index_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3241 | gettext_noop("Sets the planner's estimate of the cost of " |
3242 | "processing each index entry during an index scan." ), |
3243 | NULL, |
3244 | GUC_EXPLAIN |
3245 | }, |
3246 | &cpu_index_tuple_cost, |
3247 | DEFAULT_CPU_INDEX_TUPLE_COST, 0, DBL_MAX, |
3248 | NULL, NULL, NULL |
3249 | }, |
3250 | { |
3251 | {"cpu_operator_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3252 | gettext_noop("Sets the planner's estimate of the cost of " |
3253 | "processing each operator or function call." ), |
3254 | NULL, |
3255 | GUC_EXPLAIN |
3256 | }, |
3257 | &cpu_operator_cost, |
3258 | DEFAULT_CPU_OPERATOR_COST, 0, DBL_MAX, |
3259 | NULL, NULL, NULL |
3260 | }, |
3261 | { |
3262 | {"parallel_tuple_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3263 | gettext_noop("Sets the planner's estimate of the cost of " |
3264 | "passing each tuple (row) from worker to master backend." ), |
3265 | NULL, |
3266 | GUC_EXPLAIN |
3267 | }, |
3268 | ¶llel_tuple_cost, |
3269 | DEFAULT_PARALLEL_TUPLE_COST, 0, DBL_MAX, |
3270 | NULL, NULL, NULL |
3271 | }, |
3272 | { |
3273 | {"parallel_setup_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3274 | gettext_noop("Sets the planner's estimate of the cost of " |
3275 | "starting up worker processes for parallel query." ), |
3276 | NULL, |
3277 | GUC_EXPLAIN |
3278 | }, |
3279 | ¶llel_setup_cost, |
3280 | DEFAULT_PARALLEL_SETUP_COST, 0, DBL_MAX, |
3281 | NULL, NULL, NULL |
3282 | }, |
3283 | |
3284 | { |
3285 | {"jit_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3286 | gettext_noop("Perform JIT compilation if query is more expensive." ), |
3287 | gettext_noop("-1 disables JIT compilation." ), |
3288 | GUC_EXPLAIN |
3289 | }, |
3290 | &jit_above_cost, |
3291 | 100000, -1, DBL_MAX, |
3292 | NULL, NULL, NULL |
3293 | }, |
3294 | |
3295 | { |
3296 | {"jit_optimize_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3297 | gettext_noop("Optimize JITed functions if query is more expensive." ), |
3298 | gettext_noop("-1 disables optimization." ), |
3299 | GUC_EXPLAIN |
3300 | }, |
3301 | &jit_optimize_above_cost, |
3302 | 500000, -1, DBL_MAX, |
3303 | NULL, NULL, NULL |
3304 | }, |
3305 | |
3306 | { |
3307 | {"jit_inline_above_cost" , PGC_USERSET, QUERY_TUNING_COST, |
3308 | gettext_noop("Perform JIT inlining if query is more expensive." ), |
3309 | gettext_noop("-1 disables inlining." ), |
3310 | GUC_EXPLAIN |
3311 | }, |
3312 | &jit_inline_above_cost, |
3313 | 500000, -1, DBL_MAX, |
3314 | NULL, NULL, NULL |
3315 | }, |
3316 | |
3317 | { |
3318 | {"cursor_tuple_fraction" , PGC_USERSET, QUERY_TUNING_OTHER, |
3319 | gettext_noop("Sets the planner's estimate of the fraction of " |
3320 | "a cursor's rows that will be retrieved." ), |
3321 | NULL, |
3322 | GUC_EXPLAIN |
3323 | }, |
3324 | &cursor_tuple_fraction, |
3325 | DEFAULT_CURSOR_TUPLE_FRACTION, 0.0, 1.0, |
3326 | NULL, NULL, NULL |
3327 | }, |
3328 | |
3329 | { |
3330 | {"geqo_selection_bias" , PGC_USERSET, QUERY_TUNING_GEQO, |
3331 | gettext_noop("GEQO: selective pressure within the population." ), |
3332 | NULL, |
3333 | GUC_EXPLAIN |
3334 | }, |
3335 | &Geqo_selection_bias, |
3336 | DEFAULT_GEQO_SELECTION_BIAS, |
3337 | MIN_GEQO_SELECTION_BIAS, MAX_GEQO_SELECTION_BIAS, |
3338 | NULL, NULL, NULL |
3339 | }, |
3340 | { |
3341 | {"geqo_seed" , PGC_USERSET, QUERY_TUNING_GEQO, |
3342 | gettext_noop("GEQO: seed for random path selection." ), |
3343 | NULL, |
3344 | GUC_EXPLAIN |
3345 | }, |
3346 | &Geqo_seed, |
3347 | 0.0, 0.0, 1.0, |
3348 | NULL, NULL, NULL |
3349 | }, |
3350 | |
3351 | { |
3352 | {"bgwriter_lru_multiplier" , PGC_SIGHUP, RESOURCES_BGWRITER, |
3353 | gettext_noop("Multiple of the average buffer usage to free per round." ), |
3354 | NULL |
3355 | }, |
3356 | &bgwriter_lru_multiplier, |
3357 | 2.0, 0.0, 10.0, |
3358 | NULL, NULL, NULL |
3359 | }, |
3360 | |
3361 | { |
3362 | {"seed" , PGC_USERSET, UNGROUPED, |
3363 | gettext_noop("Sets the seed for random-number generation." ), |
3364 | NULL, |
3365 | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3366 | }, |
3367 | &phony_random_seed, |
3368 | 0.0, -1.0, 1.0, |
3369 | check_random_seed, assign_random_seed, show_random_seed |
3370 | }, |
3371 | |
3372 | { |
3373 | {"vacuum_cost_delay" , PGC_USERSET, RESOURCES_VACUUM_DELAY, |
3374 | gettext_noop("Vacuum cost delay in milliseconds." ), |
3375 | NULL, |
3376 | GUC_UNIT_MS |
3377 | }, |
3378 | &VacuumCostDelay, |
3379 | 0, 0, 100, |
3380 | NULL, NULL, NULL |
3381 | }, |
3382 | |
3383 | { |
3384 | {"autovacuum_vacuum_cost_delay" , PGC_SIGHUP, AUTOVACUUM, |
3385 | gettext_noop("Vacuum cost delay in milliseconds, for autovacuum." ), |
3386 | NULL, |
3387 | GUC_UNIT_MS |
3388 | }, |
3389 | &autovacuum_vac_cost_delay, |
3390 | 2, -1, 100, |
3391 | NULL, NULL, NULL |
3392 | }, |
3393 | |
3394 | { |
3395 | {"autovacuum_vacuum_scale_factor" , PGC_SIGHUP, AUTOVACUUM, |
3396 | gettext_noop("Number of tuple updates or deletes prior to vacuum as a fraction of reltuples." ), |
3397 | NULL |
3398 | }, |
3399 | &autovacuum_vac_scale, |
3400 | 0.2, 0.0, 100.0, |
3401 | NULL, NULL, NULL |
3402 | }, |
3403 | { |
3404 | {"autovacuum_analyze_scale_factor" , PGC_SIGHUP, AUTOVACUUM, |
3405 | gettext_noop("Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples." ), |
3406 | NULL |
3407 | }, |
3408 | &autovacuum_anl_scale, |
3409 | 0.1, 0.0, 100.0, |
3410 | NULL, NULL, NULL |
3411 | }, |
3412 | |
3413 | { |
3414 | {"checkpoint_completion_target" , PGC_SIGHUP, WAL_CHECKPOINTS, |
3415 | gettext_noop("Time spent flushing dirty buffers during checkpoint, as fraction of checkpoint interval." ), |
3416 | NULL |
3417 | }, |
3418 | &CheckPointCompletionTarget, |
3419 | 0.5, 0.0, 1.0, |
3420 | NULL, NULL, NULL |
3421 | }, |
3422 | |
3423 | { |
3424 | {"vacuum_cleanup_index_scale_factor" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3425 | gettext_noop("Number of tuple inserts prior to index cleanup as a fraction of reltuples." ), |
3426 | NULL |
3427 | }, |
3428 | &vacuum_cleanup_index_scale_factor, |
3429 | 0.1, 0.0, 1e10, |
3430 | NULL, NULL, NULL |
3431 | }, |
3432 | |
3433 | { |
3434 | {"log_transaction_sample_rate" , PGC_SUSET, LOGGING_WHEN, |
3435 | gettext_noop("Set the fraction of transactions to log for new transactions." ), |
3436 | gettext_noop("Logs all statements from a fraction of transactions. " |
3437 | "Use a value between 0.0 (never log) and 1.0 (log all " |
3438 | "statements for all transactions)." ) |
3439 | }, |
3440 | &log_xact_sample_rate, |
3441 | 0.0, 0.0, 1.0, |
3442 | NULL, NULL, NULL |
3443 | }, |
3444 | |
3445 | /* End-of-list marker */ |
3446 | { |
3447 | {NULL, 0, 0, NULL, NULL}, NULL, 0.0, 0.0, 0.0, NULL, NULL, NULL |
3448 | } |
3449 | }; |
3450 | |
3451 | |
3452 | static struct config_string ConfigureNamesString[] = |
3453 | { |
3454 | { |
3455 | {"archive_command" , PGC_SIGHUP, WAL_ARCHIVING, |
3456 | gettext_noop("Sets the shell command that will be called to archive a WAL file." ), |
3457 | NULL |
3458 | }, |
3459 | &XLogArchiveCommand, |
3460 | "" , |
3461 | NULL, NULL, show_archive_command |
3462 | }, |
3463 | |
3464 | { |
3465 | {"restore_command" , PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, |
3466 | gettext_noop("Sets the shell command that will retrieve an archived WAL file." ), |
3467 | NULL |
3468 | }, |
3469 | &recoveryRestoreCommand, |
3470 | "" , |
3471 | NULL, NULL, NULL |
3472 | }, |
3473 | |
3474 | { |
3475 | {"archive_cleanup_command" , PGC_SIGHUP, WAL_ARCHIVE_RECOVERY, |
3476 | gettext_noop("Sets the shell command that will be executed at every restart point." ), |
3477 | NULL |
3478 | }, |
3479 | &archiveCleanupCommand, |
3480 | "" , |
3481 | NULL, NULL, NULL |
3482 | }, |
3483 | |
3484 | { |
3485 | {"recovery_end_command" , PGC_SIGHUP, WAL_ARCHIVE_RECOVERY, |
3486 | gettext_noop("Sets the shell command that will be executed once at the end of recovery." ), |
3487 | NULL |
3488 | }, |
3489 | &recoveryEndCommand, |
3490 | "" , |
3491 | NULL, NULL, NULL |
3492 | }, |
3493 | |
3494 | { |
3495 | {"recovery_target_timeline" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3496 | gettext_noop("Specifies the timeline to recover into." ), |
3497 | NULL |
3498 | }, |
3499 | &recovery_target_timeline_string, |
3500 | "latest" , |
3501 | check_recovery_target_timeline, assign_recovery_target_timeline, NULL |
3502 | }, |
3503 | |
3504 | { |
3505 | {"recovery_target" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3506 | gettext_noop("Set to \"immediate\" to end recovery as soon as a consistent state is reached." ), |
3507 | NULL |
3508 | }, |
3509 | &recovery_target_string, |
3510 | "" , |
3511 | check_recovery_target, assign_recovery_target, NULL |
3512 | }, |
3513 | { |
3514 | {"recovery_target_xid" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3515 | gettext_noop("Sets the transaction ID up to which recovery will proceed." ), |
3516 | NULL |
3517 | }, |
3518 | &recovery_target_xid_string, |
3519 | "" , |
3520 | check_recovery_target_xid, assign_recovery_target_xid, NULL |
3521 | }, |
3522 | { |
3523 | {"recovery_target_time" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3524 | gettext_noop("Sets the time stamp up to which recovery will proceed." ), |
3525 | NULL |
3526 | }, |
3527 | &recovery_target_time_string, |
3528 | "" , |
3529 | check_recovery_target_time, assign_recovery_target_time, NULL |
3530 | }, |
3531 | { |
3532 | {"recovery_target_name" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3533 | gettext_noop("Sets the named restore point up to which recovery will proceed." ), |
3534 | NULL |
3535 | }, |
3536 | &recovery_target_name_string, |
3537 | "" , |
3538 | check_recovery_target_name, assign_recovery_target_name, NULL |
3539 | }, |
3540 | { |
3541 | {"recovery_target_lsn" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
3542 | gettext_noop("Sets the LSN of the write-ahead log location up to which recovery will proceed." ), |
3543 | NULL |
3544 | }, |
3545 | &recovery_target_lsn_string, |
3546 | "" , |
3547 | check_recovery_target_lsn, assign_recovery_target_lsn, NULL |
3548 | }, |
3549 | |
3550 | { |
3551 | {"promote_trigger_file" , PGC_SIGHUP, REPLICATION_STANDBY, |
3552 | gettext_noop("Specifies a file name whose presence ends recovery in the standby." ), |
3553 | NULL |
3554 | }, |
3555 | &PromoteTriggerFile, |
3556 | "" , |
3557 | NULL, NULL, NULL |
3558 | }, |
3559 | |
3560 | { |
3561 | {"primary_conninfo" , PGC_POSTMASTER, REPLICATION_STANDBY, |
3562 | gettext_noop("Sets the connection string to be used to connect to the sending server." ), |
3563 | NULL, |
3564 | GUC_SUPERUSER_ONLY |
3565 | }, |
3566 | &PrimaryConnInfo, |
3567 | "" , |
3568 | NULL, NULL, NULL |
3569 | }, |
3570 | |
3571 | { |
3572 | {"primary_slot_name" , PGC_POSTMASTER, REPLICATION_STANDBY, |
3573 | gettext_noop("Sets the name of the replication slot to use on the sending server." ), |
3574 | NULL |
3575 | }, |
3576 | &PrimarySlotName, |
3577 | "" , |
3578 | check_primary_slot_name, NULL, NULL |
3579 | }, |
3580 | |
3581 | { |
3582 | {"client_encoding" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3583 | gettext_noop("Sets the client's character set encoding." ), |
3584 | NULL, |
3585 | GUC_IS_NAME | GUC_REPORT |
3586 | }, |
3587 | &client_encoding_string, |
3588 | "SQL_ASCII" , |
3589 | check_client_encoding, assign_client_encoding, NULL |
3590 | }, |
3591 | |
3592 | { |
3593 | {"log_line_prefix" , PGC_SIGHUP, LOGGING_WHAT, |
3594 | gettext_noop("Controls information prefixed to each log line." ), |
3595 | gettext_noop("If blank, no prefix is used." ) |
3596 | }, |
3597 | &Log_line_prefix, |
3598 | "%m [%p] " , |
3599 | NULL, NULL, NULL |
3600 | }, |
3601 | |
3602 | { |
3603 | {"log_timezone" , PGC_SIGHUP, LOGGING_WHAT, |
3604 | gettext_noop("Sets the time zone to use in log messages." ), |
3605 | NULL |
3606 | }, |
3607 | &log_timezone_string, |
3608 | "GMT" , |
3609 | check_log_timezone, assign_log_timezone, show_log_timezone |
3610 | }, |
3611 | |
3612 | { |
3613 | {"DateStyle" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3614 | gettext_noop("Sets the display format for date and time values." ), |
3615 | gettext_noop("Also controls interpretation of ambiguous " |
3616 | "date inputs." ), |
3617 | GUC_LIST_INPUT | GUC_REPORT |
3618 | }, |
3619 | &datestyle_string, |
3620 | "ISO, MDY" , |
3621 | check_datestyle, assign_datestyle, NULL |
3622 | }, |
3623 | |
3624 | { |
3625 | {"default_table_access_method" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3626 | gettext_noop("Sets the default table access method for new tables." ), |
3627 | NULL, |
3628 | GUC_IS_NAME |
3629 | }, |
3630 | &default_table_access_method, |
3631 | DEFAULT_TABLE_ACCESS_METHOD, |
3632 | check_default_table_access_method, NULL, NULL |
3633 | }, |
3634 | |
3635 | { |
3636 | {"default_tablespace" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3637 | gettext_noop("Sets the default tablespace to create tables and indexes in." ), |
3638 | gettext_noop("An empty string selects the database's default tablespace." ), |
3639 | GUC_IS_NAME |
3640 | }, |
3641 | &default_tablespace, |
3642 | "" , |
3643 | check_default_tablespace, NULL, NULL |
3644 | }, |
3645 | |
3646 | { |
3647 | {"temp_tablespaces" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3648 | gettext_noop("Sets the tablespace(s) to use for temporary tables and sort files." ), |
3649 | NULL, |
3650 | GUC_LIST_INPUT | GUC_LIST_QUOTE |
3651 | }, |
3652 | &temp_tablespaces, |
3653 | "" , |
3654 | check_temp_tablespaces, assign_temp_tablespaces, NULL |
3655 | }, |
3656 | |
3657 | { |
3658 | {"dynamic_library_path" , PGC_SUSET, CLIENT_CONN_OTHER, |
3659 | gettext_noop("Sets the path for dynamically loadable modules." ), |
3660 | gettext_noop("If a dynamically loadable module needs to be opened and " |
3661 | "the specified name does not have a directory component (i.e., the " |
3662 | "name does not contain a slash), the system will search this path for " |
3663 | "the specified file." ), |
3664 | GUC_SUPERUSER_ONLY |
3665 | }, |
3666 | &Dynamic_library_path, |
3667 | "$libdir" , |
3668 | NULL, NULL, NULL |
3669 | }, |
3670 | |
3671 | { |
3672 | {"krb_server_keyfile" , PGC_SIGHUP, CONN_AUTH_AUTH, |
3673 | gettext_noop("Sets the location of the Kerberos server key file." ), |
3674 | NULL, |
3675 | GUC_SUPERUSER_ONLY |
3676 | }, |
3677 | &pg_krb_server_keyfile, |
3678 | PG_KRB_SRVTAB, |
3679 | NULL, NULL, NULL |
3680 | }, |
3681 | |
3682 | { |
3683 | {"bonjour_name" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
3684 | gettext_noop("Sets the Bonjour service name." ), |
3685 | NULL |
3686 | }, |
3687 | &bonjour_name, |
3688 | "" , |
3689 | NULL, NULL, NULL |
3690 | }, |
3691 | |
3692 | /* See main.c about why defaults for LC_foo are not all alike */ |
3693 | |
3694 | { |
3695 | {"lc_collate" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
3696 | gettext_noop("Shows the collation order locale." ), |
3697 | NULL, |
3698 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3699 | }, |
3700 | &locale_collate, |
3701 | "C" , |
3702 | NULL, NULL, NULL |
3703 | }, |
3704 | |
3705 | { |
3706 | {"lc_ctype" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
3707 | gettext_noop("Shows the character classification and case conversion locale." ), |
3708 | NULL, |
3709 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3710 | }, |
3711 | &locale_ctype, |
3712 | "C" , |
3713 | NULL, NULL, NULL |
3714 | }, |
3715 | |
3716 | { |
3717 | {"lc_messages" , PGC_SUSET, CLIENT_CONN_LOCALE, |
3718 | gettext_noop("Sets the language in which messages are displayed." ), |
3719 | NULL |
3720 | }, |
3721 | &locale_messages, |
3722 | "" , |
3723 | check_locale_messages, assign_locale_messages, NULL |
3724 | }, |
3725 | |
3726 | { |
3727 | {"lc_monetary" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3728 | gettext_noop("Sets the locale for formatting monetary amounts." ), |
3729 | NULL |
3730 | }, |
3731 | &locale_monetary, |
3732 | "C" , |
3733 | check_locale_monetary, assign_locale_monetary, NULL |
3734 | }, |
3735 | |
3736 | { |
3737 | {"lc_numeric" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3738 | gettext_noop("Sets the locale for formatting numbers." ), |
3739 | NULL |
3740 | }, |
3741 | &locale_numeric, |
3742 | "C" , |
3743 | check_locale_numeric, assign_locale_numeric, NULL |
3744 | }, |
3745 | |
3746 | { |
3747 | {"lc_time" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3748 | gettext_noop("Sets the locale for formatting date and time values." ), |
3749 | NULL |
3750 | }, |
3751 | &locale_time, |
3752 | "C" , |
3753 | check_locale_time, assign_locale_time, NULL |
3754 | }, |
3755 | |
3756 | { |
3757 | {"session_preload_libraries" , PGC_SUSET, CLIENT_CONN_PRELOAD, |
3758 | gettext_noop("Lists shared libraries to preload into each backend." ), |
3759 | NULL, |
3760 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY |
3761 | }, |
3762 | &session_preload_libraries_string, |
3763 | "" , |
3764 | NULL, NULL, NULL |
3765 | }, |
3766 | |
3767 | { |
3768 | {"shared_preload_libraries" , PGC_POSTMASTER, CLIENT_CONN_PRELOAD, |
3769 | gettext_noop("Lists shared libraries to preload into server." ), |
3770 | NULL, |
3771 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY |
3772 | }, |
3773 | &shared_preload_libraries_string, |
3774 | "" , |
3775 | NULL, NULL, NULL |
3776 | }, |
3777 | |
3778 | { |
3779 | {"local_preload_libraries" , PGC_USERSET, CLIENT_CONN_PRELOAD, |
3780 | gettext_noop("Lists unprivileged shared libraries to preload into each backend." ), |
3781 | NULL, |
3782 | GUC_LIST_INPUT | GUC_LIST_QUOTE |
3783 | }, |
3784 | &local_preload_libraries_string, |
3785 | "" , |
3786 | NULL, NULL, NULL |
3787 | }, |
3788 | |
3789 | { |
3790 | {"search_path" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
3791 | gettext_noop("Sets the schema search order for names that are not schema-qualified." ), |
3792 | NULL, |
3793 | GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_EXPLAIN |
3794 | }, |
3795 | &namespace_search_path, |
3796 | "\"$user\", public" , |
3797 | check_search_path, assign_search_path, NULL |
3798 | }, |
3799 | |
3800 | { |
3801 | /* Can't be set in postgresql.conf */ |
3802 | {"server_encoding" , PGC_INTERNAL, CLIENT_CONN_LOCALE, |
3803 | gettext_noop("Sets the server (database) character set encoding." ), |
3804 | NULL, |
3805 | GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3806 | }, |
3807 | &server_encoding_string, |
3808 | "SQL_ASCII" , |
3809 | NULL, NULL, NULL |
3810 | }, |
3811 | |
3812 | { |
3813 | /* Can't be set in postgresql.conf */ |
3814 | {"server_version" , PGC_INTERNAL, PRESET_OPTIONS, |
3815 | gettext_noop("Shows the server version." ), |
3816 | NULL, |
3817 | GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
3818 | }, |
3819 | &server_version_string, |
3820 | PG_VERSION, |
3821 | NULL, NULL, NULL |
3822 | }, |
3823 | |
3824 | { |
3825 | /* Not for general use --- used by SET ROLE */ |
3826 | {"role" , PGC_USERSET, UNGROUPED, |
3827 | gettext_noop("Sets the current role." ), |
3828 | NULL, |
3829 | GUC_IS_NAME | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST |
3830 | }, |
3831 | &role_string, |
3832 | "none" , |
3833 | check_role, assign_role, show_role |
3834 | }, |
3835 | |
3836 | { |
3837 | /* Not for general use --- used by SET SESSION AUTHORIZATION */ |
3838 | {"session_authorization" , PGC_USERSET, UNGROUPED, |
3839 | gettext_noop("Sets the session user name." ), |
3840 | NULL, |
3841 | GUC_IS_NAME | GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_NOT_WHILE_SEC_REST |
3842 | }, |
3843 | &session_authorization_string, |
3844 | NULL, |
3845 | check_session_authorization, assign_session_authorization, NULL |
3846 | }, |
3847 | |
3848 | { |
3849 | {"log_destination" , PGC_SIGHUP, LOGGING_WHERE, |
3850 | gettext_noop("Sets the destination for server log output." ), |
3851 | gettext_noop("Valid values are combinations of \"stderr\", " |
3852 | "\"syslog\", \"csvlog\", and \"eventlog\", " |
3853 | "depending on the platform." ), |
3854 | GUC_LIST_INPUT |
3855 | }, |
3856 | &Log_destination_string, |
3857 | "stderr" , |
3858 | check_log_destination, assign_log_destination, NULL |
3859 | }, |
3860 | { |
3861 | {"log_directory" , PGC_SIGHUP, LOGGING_WHERE, |
3862 | gettext_noop("Sets the destination directory for log files." ), |
3863 | gettext_noop("Can be specified as relative to the data directory " |
3864 | "or as absolute path." ), |
3865 | GUC_SUPERUSER_ONLY |
3866 | }, |
3867 | &Log_directory, |
3868 | "log" , |
3869 | check_canonical_path, NULL, NULL |
3870 | }, |
3871 | { |
3872 | {"log_filename" , PGC_SIGHUP, LOGGING_WHERE, |
3873 | gettext_noop("Sets the file name pattern for log files." ), |
3874 | NULL, |
3875 | GUC_SUPERUSER_ONLY |
3876 | }, |
3877 | &Log_filename, |
3878 | "postgresql-%Y-%m-%d_%H%M%S.log" , |
3879 | NULL, NULL, NULL |
3880 | }, |
3881 | |
3882 | { |
3883 | {"syslog_ident" , PGC_SIGHUP, LOGGING_WHERE, |
3884 | gettext_noop("Sets the program name used to identify PostgreSQL " |
3885 | "messages in syslog." ), |
3886 | NULL |
3887 | }, |
3888 | &syslog_ident_str, |
3889 | "postgres" , |
3890 | NULL, assign_syslog_ident, NULL |
3891 | }, |
3892 | |
3893 | { |
3894 | {"event_source" , PGC_POSTMASTER, LOGGING_WHERE, |
3895 | gettext_noop("Sets the application name used to identify " |
3896 | "PostgreSQL messages in the event log." ), |
3897 | NULL |
3898 | }, |
3899 | &event_source, |
3900 | DEFAULT_EVENT_SOURCE, |
3901 | NULL, NULL, NULL |
3902 | }, |
3903 | |
3904 | { |
3905 | {"TimeZone" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3906 | gettext_noop("Sets the time zone for displaying and interpreting time stamps." ), |
3907 | NULL, |
3908 | GUC_REPORT |
3909 | }, |
3910 | &timezone_string, |
3911 | "GMT" , |
3912 | check_timezone, assign_timezone, show_timezone |
3913 | }, |
3914 | { |
3915 | {"timezone_abbreviations" , PGC_USERSET, CLIENT_CONN_LOCALE, |
3916 | gettext_noop("Selects a file of time zone abbreviations." ), |
3917 | NULL |
3918 | }, |
3919 | &timezone_abbreviations_string, |
3920 | NULL, |
3921 | check_timezone_abbreviations, assign_timezone_abbreviations, NULL |
3922 | }, |
3923 | |
3924 | { |
3925 | {"unix_socket_group" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
3926 | gettext_noop("Sets the owning group of the Unix-domain socket." ), |
3927 | gettext_noop("The owning user of the socket is always the user " |
3928 | "that starts the server." ) |
3929 | }, |
3930 | &Unix_socket_group, |
3931 | "" , |
3932 | NULL, NULL, NULL |
3933 | }, |
3934 | |
3935 | { |
3936 | {"unix_socket_directories" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
3937 | gettext_noop("Sets the directories where Unix-domain sockets will be created." ), |
3938 | NULL, |
3939 | GUC_SUPERUSER_ONLY |
3940 | }, |
3941 | &Unix_socket_directories, |
3942 | #ifdef HAVE_UNIX_SOCKETS |
3943 | DEFAULT_PGSOCKET_DIR, |
3944 | #else |
3945 | "" , |
3946 | #endif |
3947 | NULL, NULL, NULL |
3948 | }, |
3949 | |
3950 | { |
3951 | {"listen_addresses" , PGC_POSTMASTER, CONN_AUTH_SETTINGS, |
3952 | gettext_noop("Sets the host name or IP address(es) to listen to." ), |
3953 | NULL, |
3954 | GUC_LIST_INPUT |
3955 | }, |
3956 | &ListenAddresses, |
3957 | "localhost" , |
3958 | NULL, NULL, NULL |
3959 | }, |
3960 | |
3961 | { |
3962 | /* |
3963 | * Can't be set by ALTER SYSTEM as it can lead to recursive definition |
3964 | * of data_directory. |
3965 | */ |
3966 | {"data_directory" , PGC_POSTMASTER, FILE_LOCATIONS, |
3967 | gettext_noop("Sets the server's data directory." ), |
3968 | NULL, |
3969 | GUC_SUPERUSER_ONLY | GUC_DISALLOW_IN_AUTO_FILE |
3970 | }, |
3971 | &data_directory, |
3972 | NULL, |
3973 | NULL, NULL, NULL |
3974 | }, |
3975 | |
3976 | { |
3977 | {"config_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
3978 | gettext_noop("Sets the server's main configuration file." ), |
3979 | NULL, |
3980 | GUC_DISALLOW_IN_FILE | GUC_SUPERUSER_ONLY |
3981 | }, |
3982 | &ConfigFileName, |
3983 | NULL, |
3984 | NULL, NULL, NULL |
3985 | }, |
3986 | |
3987 | { |
3988 | {"hba_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
3989 | gettext_noop("Sets the server's \"hba\" configuration file." ), |
3990 | NULL, |
3991 | GUC_SUPERUSER_ONLY |
3992 | }, |
3993 | &HbaFileName, |
3994 | NULL, |
3995 | NULL, NULL, NULL |
3996 | }, |
3997 | |
3998 | { |
3999 | {"ident_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
4000 | gettext_noop("Sets the server's \"ident\" configuration file." ), |
4001 | NULL, |
4002 | GUC_SUPERUSER_ONLY |
4003 | }, |
4004 | &IdentFileName, |
4005 | NULL, |
4006 | NULL, NULL, NULL |
4007 | }, |
4008 | |
4009 | { |
4010 | {"external_pid_file" , PGC_POSTMASTER, FILE_LOCATIONS, |
4011 | gettext_noop("Writes the postmaster PID to the specified file." ), |
4012 | NULL, |
4013 | GUC_SUPERUSER_ONLY |
4014 | }, |
4015 | &external_pid_file, |
4016 | NULL, |
4017 | check_canonical_path, NULL, NULL |
4018 | }, |
4019 | |
4020 | { |
4021 | {"ssl_library" , PGC_INTERNAL, PRESET_OPTIONS, |
4022 | gettext_noop("Name of the SSL library." ), |
4023 | NULL, |
4024 | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
4025 | }, |
4026 | &ssl_library, |
4027 | #ifdef USE_SSL |
4028 | "OpenSSL" , |
4029 | #else |
4030 | "" , |
4031 | #endif |
4032 | NULL, NULL, NULL |
4033 | }, |
4034 | |
4035 | { |
4036 | {"ssl_cert_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
4037 | gettext_noop("Location of the SSL server certificate file." ), |
4038 | NULL |
4039 | }, |
4040 | &ssl_cert_file, |
4041 | "server.crt" , |
4042 | NULL, NULL, NULL |
4043 | }, |
4044 | |
4045 | { |
4046 | {"ssl_key_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
4047 | gettext_noop("Location of the SSL server private key file." ), |
4048 | NULL |
4049 | }, |
4050 | &ssl_key_file, |
4051 | "server.key" , |
4052 | NULL, NULL, NULL |
4053 | }, |
4054 | |
4055 | { |
4056 | {"ssl_ca_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
4057 | gettext_noop("Location of the SSL certificate authority file." ), |
4058 | NULL |
4059 | }, |
4060 | &ssl_ca_file, |
4061 | "" , |
4062 | NULL, NULL, NULL |
4063 | }, |
4064 | |
4065 | { |
4066 | {"ssl_crl_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
4067 | gettext_noop("Location of the SSL certificate revocation list file." ), |
4068 | NULL |
4069 | }, |
4070 | &ssl_crl_file, |
4071 | "" , |
4072 | NULL, NULL, NULL |
4073 | }, |
4074 | |
4075 | { |
4076 | {"stats_temp_directory" , PGC_SIGHUP, STATS_COLLECTOR, |
4077 | gettext_noop("Writes temporary statistics files to the specified directory." ), |
4078 | NULL, |
4079 | GUC_SUPERUSER_ONLY |
4080 | }, |
4081 | &pgstat_temp_directory, |
4082 | PG_STAT_TMP_DIR, |
4083 | check_canonical_path, assign_pgstat_temp_directory, NULL |
4084 | }, |
4085 | |
4086 | { |
4087 | {"synchronous_standby_names" , PGC_SIGHUP, REPLICATION_MASTER, |
4088 | gettext_noop("Number of synchronous standbys and list of names of potential synchronous ones." ), |
4089 | NULL, |
4090 | GUC_LIST_INPUT |
4091 | }, |
4092 | &SyncRepStandbyNames, |
4093 | "" , |
4094 | check_synchronous_standby_names, assign_synchronous_standby_names, NULL |
4095 | }, |
4096 | |
4097 | { |
4098 | {"default_text_search_config" , PGC_USERSET, CLIENT_CONN_LOCALE, |
4099 | gettext_noop("Sets default text search configuration." ), |
4100 | NULL |
4101 | }, |
4102 | &TSCurrentConfig, |
4103 | "pg_catalog.simple" , |
4104 | check_TSCurrentConfig, assign_TSCurrentConfig, NULL |
4105 | }, |
4106 | |
4107 | { |
4108 | {"ssl_ciphers" , PGC_SIGHUP, CONN_AUTH_SSL, |
4109 | gettext_noop("Sets the list of allowed SSL ciphers." ), |
4110 | NULL, |
4111 | GUC_SUPERUSER_ONLY |
4112 | }, |
4113 | &SSLCipherSuites, |
4114 | #ifdef USE_SSL |
4115 | "HIGH:MEDIUM:+3DES:!aNULL" , |
4116 | #else |
4117 | "none" , |
4118 | #endif |
4119 | NULL, NULL, NULL |
4120 | }, |
4121 | |
4122 | { |
4123 | {"ssl_ecdh_curve" , PGC_SIGHUP, CONN_AUTH_SSL, |
4124 | gettext_noop("Sets the curve to use for ECDH." ), |
4125 | NULL, |
4126 | GUC_SUPERUSER_ONLY |
4127 | }, |
4128 | &SSLECDHCurve, |
4129 | #ifdef USE_SSL |
4130 | "prime256v1" , |
4131 | #else |
4132 | "none" , |
4133 | #endif |
4134 | NULL, NULL, NULL |
4135 | }, |
4136 | |
4137 | { |
4138 | {"ssl_dh_params_file" , PGC_SIGHUP, CONN_AUTH_SSL, |
4139 | gettext_noop("Location of the SSL DH parameters file." ), |
4140 | NULL, |
4141 | GUC_SUPERUSER_ONLY |
4142 | }, |
4143 | &ssl_dh_params_file, |
4144 | "" , |
4145 | NULL, NULL, NULL |
4146 | }, |
4147 | |
4148 | { |
4149 | {"ssl_passphrase_command" , PGC_SIGHUP, CONN_AUTH_SSL, |
4150 | gettext_noop("Command to obtain passphrases for SSL." ), |
4151 | NULL |
4152 | }, |
4153 | &ssl_passphrase_command, |
4154 | "" , |
4155 | NULL, NULL, NULL |
4156 | }, |
4157 | |
4158 | { |
4159 | {"application_name" , PGC_USERSET, LOGGING_WHAT, |
4160 | gettext_noop("Sets the application name to be reported in statistics and logs." ), |
4161 | NULL, |
4162 | GUC_IS_NAME | GUC_REPORT | GUC_NOT_IN_SAMPLE |
4163 | }, |
4164 | &application_name, |
4165 | "" , |
4166 | check_application_name, assign_application_name, NULL |
4167 | }, |
4168 | |
4169 | { |
4170 | {"cluster_name" , PGC_POSTMASTER, PROCESS_TITLE, |
4171 | gettext_noop("Sets the name of the cluster, which is included in the process title." ), |
4172 | NULL, |
4173 | GUC_IS_NAME |
4174 | }, |
4175 | &cluster_name, |
4176 | "" , |
4177 | check_cluster_name, NULL, NULL |
4178 | }, |
4179 | |
4180 | { |
4181 | {"wal_consistency_checking" , PGC_SUSET, DEVELOPER_OPTIONS, |
4182 | gettext_noop("Sets the WAL resource managers for which WAL consistency checks are done." ), |
4183 | gettext_noop("Full-page images will be logged for all data blocks and cross-checked against the results of WAL replay." ), |
4184 | GUC_LIST_INPUT | GUC_NOT_IN_SAMPLE |
4185 | }, |
4186 | &wal_consistency_checking_string, |
4187 | "" , |
4188 | check_wal_consistency_checking, assign_wal_consistency_checking, NULL |
4189 | }, |
4190 | |
4191 | { |
4192 | {"jit_provider" , PGC_POSTMASTER, CLIENT_CONN_PRELOAD, |
4193 | gettext_noop("JIT provider to use." ), |
4194 | NULL, |
4195 | GUC_SUPERUSER_ONLY |
4196 | }, |
4197 | &jit_provider, |
4198 | "llvmjit" , |
4199 | NULL, NULL, NULL |
4200 | }, |
4201 | |
4202 | /* End-of-list marker */ |
4203 | { |
4204 | {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL, NULL |
4205 | } |
4206 | }; |
4207 | |
4208 | |
4209 | static struct config_enum ConfigureNamesEnum[] = |
4210 | { |
4211 | { |
4212 | {"backslash_quote" , PGC_USERSET, COMPAT_OPTIONS_PREVIOUS, |
4213 | gettext_noop("Sets whether \"\\'\" is allowed in string literals." ), |
4214 | NULL |
4215 | }, |
4216 | &backslash_quote, |
4217 | BACKSLASH_QUOTE_SAFE_ENCODING, backslash_quote_options, |
4218 | NULL, NULL, NULL |
4219 | }, |
4220 | |
4221 | { |
4222 | {"bytea_output" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4223 | gettext_noop("Sets the output format for bytea." ), |
4224 | NULL |
4225 | }, |
4226 | &bytea_output, |
4227 | BYTEA_OUTPUT_HEX, bytea_output_options, |
4228 | NULL, NULL, NULL |
4229 | }, |
4230 | |
4231 | { |
4232 | {"client_min_messages" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4233 | gettext_noop("Sets the message levels that are sent to the client." ), |
4234 | gettext_noop("Each level includes all the levels that follow it. The later" |
4235 | " the level, the fewer messages are sent." ) |
4236 | }, |
4237 | &client_min_messages, |
4238 | NOTICE, client_message_level_options, |
4239 | NULL, NULL, NULL |
4240 | }, |
4241 | |
4242 | { |
4243 | {"constraint_exclusion" , PGC_USERSET, QUERY_TUNING_OTHER, |
4244 | gettext_noop("Enables the planner to use constraints to optimize queries." ), |
4245 | gettext_noop("Table scans will be skipped if their constraints" |
4246 | " guarantee that no rows match the query." ), |
4247 | GUC_EXPLAIN |
4248 | }, |
4249 | &constraint_exclusion, |
4250 | CONSTRAINT_EXCLUSION_PARTITION, constraint_exclusion_options, |
4251 | NULL, NULL, NULL |
4252 | }, |
4253 | |
4254 | { |
4255 | {"default_transaction_isolation" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4256 | gettext_noop("Sets the transaction isolation level of each new transaction." ), |
4257 | NULL |
4258 | }, |
4259 | &DefaultXactIsoLevel, |
4260 | XACT_READ_COMMITTED, isolation_level_options, |
4261 | NULL, NULL, NULL |
4262 | }, |
4263 | |
4264 | { |
4265 | {"transaction_isolation" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4266 | gettext_noop("Sets the current transaction's isolation level." ), |
4267 | NULL, |
4268 | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE |
4269 | }, |
4270 | &XactIsoLevel, |
4271 | XACT_READ_COMMITTED, isolation_level_options, |
4272 | check_XactIsoLevel, NULL, NULL |
4273 | }, |
4274 | |
4275 | { |
4276 | {"IntervalStyle" , PGC_USERSET, CLIENT_CONN_LOCALE, |
4277 | gettext_noop("Sets the display format for interval values." ), |
4278 | NULL, |
4279 | GUC_REPORT |
4280 | }, |
4281 | &IntervalStyle, |
4282 | INTSTYLE_POSTGRES, intervalstyle_options, |
4283 | NULL, NULL, NULL |
4284 | }, |
4285 | |
4286 | { |
4287 | {"log_error_verbosity" , PGC_SUSET, LOGGING_WHAT, |
4288 | gettext_noop("Sets the verbosity of logged messages." ), |
4289 | NULL |
4290 | }, |
4291 | &Log_error_verbosity, |
4292 | PGERROR_DEFAULT, log_error_verbosity_options, |
4293 | NULL, NULL, NULL |
4294 | }, |
4295 | |
4296 | { |
4297 | {"log_min_messages" , PGC_SUSET, LOGGING_WHEN, |
4298 | gettext_noop("Sets the message levels that are logged." ), |
4299 | gettext_noop("Each level includes all the levels that follow it. The later" |
4300 | " the level, the fewer messages are sent." ) |
4301 | }, |
4302 | &log_min_messages, |
4303 | WARNING, server_message_level_options, |
4304 | NULL, NULL, NULL |
4305 | }, |
4306 | |
4307 | { |
4308 | {"log_min_error_statement" , PGC_SUSET, LOGGING_WHEN, |
4309 | gettext_noop("Causes all statements generating error at or above this level to be logged." ), |
4310 | gettext_noop("Each level includes all the levels that follow it. The later" |
4311 | " the level, the fewer messages are sent." ) |
4312 | }, |
4313 | &log_min_error_statement, |
4314 | ERROR, server_message_level_options, |
4315 | NULL, NULL, NULL |
4316 | }, |
4317 | |
4318 | { |
4319 | {"log_statement" , PGC_SUSET, LOGGING_WHAT, |
4320 | gettext_noop("Sets the type of statements logged." ), |
4321 | NULL |
4322 | }, |
4323 | &log_statement, |
4324 | LOGSTMT_NONE, log_statement_options, |
4325 | NULL, NULL, NULL |
4326 | }, |
4327 | |
4328 | { |
4329 | {"syslog_facility" , PGC_SIGHUP, LOGGING_WHERE, |
4330 | gettext_noop("Sets the syslog \"facility\" to be used when syslog enabled." ), |
4331 | NULL |
4332 | }, |
4333 | &syslog_facility, |
4334 | #ifdef HAVE_SYSLOG |
4335 | LOG_LOCAL0, |
4336 | #else |
4337 | 0, |
4338 | #endif |
4339 | syslog_facility_options, |
4340 | NULL, assign_syslog_facility, NULL |
4341 | }, |
4342 | |
4343 | { |
4344 | {"session_replication_role" , PGC_SUSET, CLIENT_CONN_STATEMENT, |
4345 | gettext_noop("Sets the session's behavior for triggers and rewrite rules." ), |
4346 | NULL |
4347 | }, |
4348 | &SessionReplicationRole, |
4349 | SESSION_REPLICATION_ROLE_ORIGIN, session_replication_role_options, |
4350 | NULL, assign_session_replication_role, NULL |
4351 | }, |
4352 | |
4353 | { |
4354 | {"synchronous_commit" , PGC_USERSET, WAL_SETTINGS, |
4355 | gettext_noop("Sets the current transaction's synchronization level." ), |
4356 | NULL |
4357 | }, |
4358 | &synchronous_commit, |
4359 | SYNCHRONOUS_COMMIT_ON, synchronous_commit_options, |
4360 | NULL, assign_synchronous_commit, NULL |
4361 | }, |
4362 | |
4363 | { |
4364 | {"archive_mode" , PGC_POSTMASTER, WAL_ARCHIVING, |
4365 | gettext_noop("Allows archiving of WAL files using archive_command." ), |
4366 | NULL |
4367 | }, |
4368 | &XLogArchiveMode, |
4369 | ARCHIVE_MODE_OFF, archive_mode_options, |
4370 | NULL, NULL, NULL |
4371 | }, |
4372 | |
4373 | { |
4374 | {"recovery_target_action" , PGC_POSTMASTER, WAL_RECOVERY_TARGET, |
4375 | gettext_noop("Sets the action to perform upon reaching the recovery target." ), |
4376 | NULL |
4377 | }, |
4378 | &recoveryTargetAction, |
4379 | RECOVERY_TARGET_ACTION_PAUSE, recovery_target_action_options, |
4380 | NULL, NULL, NULL |
4381 | }, |
4382 | |
4383 | { |
4384 | {"trace_recovery_messages" , PGC_SIGHUP, DEVELOPER_OPTIONS, |
4385 | gettext_noop("Enables logging of recovery-related debugging information." ), |
4386 | gettext_noop("Each level includes all the levels that follow it. The later" |
4387 | " the level, the fewer messages are sent." ) |
4388 | }, |
4389 | &trace_recovery_messages, |
4390 | |
4391 | /* |
4392 | * client_message_level_options allows too many values, really, but |
4393 | * it's not worth having a separate options array for this. |
4394 | */ |
4395 | LOG, client_message_level_options, |
4396 | NULL, NULL, NULL |
4397 | }, |
4398 | |
4399 | { |
4400 | {"track_functions" , PGC_SUSET, STATS_COLLECTOR, |
4401 | gettext_noop("Collects function-level statistics on database activity." ), |
4402 | NULL |
4403 | }, |
4404 | &pgstat_track_functions, |
4405 | TRACK_FUNC_OFF, track_function_options, |
4406 | NULL, NULL, NULL |
4407 | }, |
4408 | |
4409 | { |
4410 | {"wal_level" , PGC_POSTMASTER, WAL_SETTINGS, |
4411 | gettext_noop("Set the level of information written to the WAL." ), |
4412 | NULL |
4413 | }, |
4414 | &wal_level, |
4415 | WAL_LEVEL_REPLICA, wal_level_options, |
4416 | NULL, NULL, NULL |
4417 | }, |
4418 | |
4419 | { |
4420 | {"dynamic_shared_memory_type" , PGC_POSTMASTER, RESOURCES_MEM, |
4421 | gettext_noop("Selects the dynamic shared memory implementation used." ), |
4422 | NULL |
4423 | }, |
4424 | &dynamic_shared_memory_type, |
4425 | DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE, dynamic_shared_memory_options, |
4426 | NULL, NULL, NULL |
4427 | }, |
4428 | |
4429 | { |
4430 | {"shared_memory_type" , PGC_POSTMASTER, RESOURCES_MEM, |
4431 | gettext_noop("Selects the shared memory implementation used for the main shared memory region." ), |
4432 | NULL |
4433 | }, |
4434 | &shared_memory_type, |
4435 | DEFAULT_SHARED_MEMORY_TYPE, shared_memory_options, |
4436 | NULL, NULL, NULL |
4437 | }, |
4438 | |
4439 | { |
4440 | {"wal_sync_method" , PGC_SIGHUP, WAL_SETTINGS, |
4441 | gettext_noop("Selects the method used for forcing WAL updates to disk." ), |
4442 | NULL |
4443 | }, |
4444 | &sync_method, |
4445 | DEFAULT_SYNC_METHOD, sync_method_options, |
4446 | NULL, assign_xlog_sync_method, NULL |
4447 | }, |
4448 | |
4449 | { |
4450 | {"xmlbinary" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4451 | gettext_noop("Sets how binary values are to be encoded in XML." ), |
4452 | NULL |
4453 | }, |
4454 | &xmlbinary, |
4455 | XMLBINARY_BASE64, xmlbinary_options, |
4456 | NULL, NULL, NULL |
4457 | }, |
4458 | |
4459 | { |
4460 | {"xmloption" , PGC_USERSET, CLIENT_CONN_STATEMENT, |
4461 | gettext_noop("Sets whether XML data in implicit parsing and serialization " |
4462 | "operations is to be considered as documents or content fragments." ), |
4463 | NULL |
4464 | }, |
4465 | &xmloption, |
4466 | XMLOPTION_CONTENT, xmloption_options, |
4467 | NULL, NULL, NULL |
4468 | }, |
4469 | |
4470 | { |
4471 | {"huge_pages" , PGC_POSTMASTER, RESOURCES_MEM, |
4472 | gettext_noop("Use of huge pages on Linux or Windows." ), |
4473 | NULL |
4474 | }, |
4475 | &huge_pages, |
4476 | HUGE_PAGES_TRY, huge_pages_options, |
4477 | NULL, NULL, NULL |
4478 | }, |
4479 | |
4480 | { |
4481 | {"force_parallel_mode" , PGC_USERSET, QUERY_TUNING_OTHER, |
4482 | gettext_noop("Forces use of parallel query facilities." ), |
4483 | gettext_noop("If possible, run query using a parallel worker and with parallel restrictions." ), |
4484 | GUC_EXPLAIN |
4485 | }, |
4486 | &force_parallel_mode, |
4487 | FORCE_PARALLEL_OFF, force_parallel_mode_options, |
4488 | NULL, NULL, NULL |
4489 | }, |
4490 | |
4491 | { |
4492 | {"password_encryption" , PGC_USERSET, CONN_AUTH_AUTH, |
4493 | gettext_noop("Encrypt passwords." ), |
4494 | gettext_noop("When a password is specified in CREATE USER or " |
4495 | "ALTER USER without writing either ENCRYPTED or UNENCRYPTED, " |
4496 | "this parameter determines whether the password is to be encrypted." ) |
4497 | }, |
4498 | &Password_encryption, |
4499 | PASSWORD_TYPE_MD5, password_encryption_options, |
4500 | NULL, NULL, NULL |
4501 | }, |
4502 | |
4503 | { |
4504 | {"plan_cache_mode" , PGC_USERSET, QUERY_TUNING_OTHER, |
4505 | gettext_noop("Controls the planner's selection of custom or generic plan." ), |
4506 | gettext_noop("Prepared statements can have custom and generic plans, and the planner " |
4507 | "will attempt to choose which is better. This can be set to override " |
4508 | "the default behavior." ), |
4509 | GUC_EXPLAIN |
4510 | }, |
4511 | &plan_cache_mode, |
4512 | PLAN_CACHE_MODE_AUTO, plan_cache_mode_options, |
4513 | NULL, NULL, NULL |
4514 | }, |
4515 | |
4516 | { |
4517 | {"ssl_min_protocol_version" , PGC_SIGHUP, CONN_AUTH_SSL, |
4518 | gettext_noop("Sets the minimum SSL/TLS protocol version to use." ), |
4519 | NULL, |
4520 | GUC_SUPERUSER_ONLY |
4521 | }, |
4522 | &ssl_min_protocol_version, |
4523 | PG_TLS1_VERSION, |
4524 | ssl_protocol_versions_info + 1, /* don't allow PG_TLS_ANY */ |
4525 | NULL, NULL, NULL |
4526 | }, |
4527 | |
4528 | { |
4529 | {"ssl_max_protocol_version" , PGC_SIGHUP, CONN_AUTH_SSL, |
4530 | gettext_noop("Sets the maximum SSL/TLS protocol version to use." ), |
4531 | NULL, |
4532 | GUC_SUPERUSER_ONLY |
4533 | }, |
4534 | &ssl_max_protocol_version, |
4535 | PG_TLS_ANY, |
4536 | ssl_protocol_versions_info, |
4537 | NULL, NULL, NULL |
4538 | }, |
4539 | |
4540 | /* End-of-list marker */ |
4541 | { |
4542 | {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL |
4543 | } |
4544 | }; |
4545 | |
4546 | /******** end of options list ********/ |
4547 | |
4548 | |
4549 | /* |
4550 | * To allow continued support of obsolete names for GUC variables, we apply |
4551 | * the following mappings to any unrecognized name. Note that an old name |
4552 | * should be mapped to a new one only if the new variable has very similar |
4553 | * semantics to the old. |
4554 | */ |
4555 | static const char *const map_old_guc_names[] = { |
4556 | "sort_mem" , "work_mem" , |
4557 | "vacuum_mem" , "maintenance_work_mem" , |
4558 | NULL |
4559 | }; |
4560 | |
4561 | |
4562 | /* |
4563 | * Actual lookup of variables is done through this single, sorted array. |
4564 | */ |
4565 | static struct config_generic **guc_variables; |
4566 | |
4567 | /* Current number of variables contained in the vector */ |
4568 | static int num_guc_variables; |
4569 | |
4570 | /* Current number of variables marked with GUC_EXPLAIN */ |
4571 | static int num_guc_explain_variables; |
4572 | |
4573 | /* Vector capacity */ |
4574 | static int size_guc_variables; |
4575 | |
4576 | |
4577 | static bool guc_dirty; /* true if need to do commit/abort work */ |
4578 | |
4579 | static bool reporting_enabled; /* true to enable GUC_REPORT */ |
4580 | |
4581 | static int GUCNestLevel = 0; /* 1 when in main transaction */ |
4582 | |
4583 | |
4584 | static int guc_var_compare(const void *a, const void *b); |
4585 | static int guc_name_compare(const char *namea, const char *nameb); |
4586 | static void InitializeGUCOptionsFromEnvironment(void); |
4587 | static void InitializeOneGUCOption(struct config_generic *gconf); |
4588 | static void push_old_value(struct config_generic *gconf, GucAction action); |
4589 | static void ReportGUCOption(struct config_generic *record); |
4590 | static void reapply_stacked_values(struct config_generic *variable, |
4591 | struct config_string *pHolder, |
4592 | GucStack *stack, |
4593 | const char *curvalue, |
4594 | GucContext curscontext, GucSource cursource); |
4595 | static void ShowGUCConfigOption(const char *name, DestReceiver *dest); |
4596 | static void ShowAllGUCConfig(DestReceiver *dest); |
4597 | static char *_ShowOption(struct config_generic *record, bool use_units); |
4598 | static bool validate_option_array_item(const char *name, const char *value, |
4599 | bool skipIfNoPermissions); |
4600 | static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head_p); |
4601 | static void replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, |
4602 | const char *name, const char *value); |
4603 | |
4604 | |
4605 | /* |
4606 | * Some infrastructure for checking malloc/strdup/realloc calls |
4607 | */ |
4608 | static void * |
4609 | guc_malloc(int elevel, size_t size) |
4610 | { |
4611 | void *data; |
4612 | |
4613 | /* Avoid unportable behavior of malloc(0) */ |
4614 | if (size == 0) |
4615 | size = 1; |
4616 | data = malloc(size); |
4617 | if (data == NULL) |
4618 | ereport(elevel, |
4619 | (errcode(ERRCODE_OUT_OF_MEMORY), |
4620 | errmsg("out of memory" ))); |
4621 | return data; |
4622 | } |
4623 | |
4624 | static void * |
4625 | guc_realloc(int elevel, void *old, size_t size) |
4626 | { |
4627 | void *data; |
4628 | |
4629 | /* Avoid unportable behavior of realloc(NULL, 0) */ |
4630 | if (old == NULL && size == 0) |
4631 | size = 1; |
4632 | data = realloc(old, size); |
4633 | if (data == NULL) |
4634 | ereport(elevel, |
4635 | (errcode(ERRCODE_OUT_OF_MEMORY), |
4636 | errmsg("out of memory" ))); |
4637 | return data; |
4638 | } |
4639 | |
4640 | static char * |
4641 | guc_strdup(int elevel, const char *src) |
4642 | { |
4643 | char *data; |
4644 | |
4645 | data = strdup(src); |
4646 | if (data == NULL) |
4647 | ereport(elevel, |
4648 | (errcode(ERRCODE_OUT_OF_MEMORY), |
4649 | errmsg("out of memory" ))); |
4650 | return data; |
4651 | } |
4652 | |
4653 | |
4654 | /* |
4655 | * Detect whether strval is referenced anywhere in a GUC string item |
4656 | */ |
4657 | static bool |
4658 | string_field_used(struct config_string *conf, char *strval) |
4659 | { |
4660 | GucStack *stack; |
4661 | |
4662 | if (strval == *(conf->variable) || |
4663 | strval == conf->reset_val || |
4664 | strval == conf->boot_val) |
4665 | return true; |
4666 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
4667 | { |
4668 | if (strval == stack->prior.val.stringval || |
4669 | strval == stack->masked.val.stringval) |
4670 | return true; |
4671 | } |
4672 | return false; |
4673 | } |
4674 | |
4675 | /* |
4676 | * Support for assigning to a field of a string GUC item. Free the prior |
4677 | * value if it's not referenced anywhere else in the item (including stacked |
4678 | * states). |
4679 | */ |
4680 | static void |
4681 | set_string_field(struct config_string *conf, char **field, char *newval) |
4682 | { |
4683 | char *oldval = *field; |
4684 | |
4685 | /* Do the assignment */ |
4686 | *field = newval; |
4687 | |
4688 | /* Free old value if it's not NULL and isn't referenced anymore */ |
4689 | if (oldval && !string_field_used(conf, oldval)) |
4690 | free(oldval); |
4691 | } |
4692 | |
4693 | /* |
4694 | * Detect whether an "extra" struct is referenced anywhere in a GUC item |
4695 | */ |
4696 | static bool |
4697 | (struct config_generic *gconf, void *) |
4698 | { |
4699 | GucStack *stack; |
4700 | |
4701 | if (extra == gconf->extra) |
4702 | return true; |
4703 | switch (gconf->vartype) |
4704 | { |
4705 | case PGC_BOOL: |
4706 | if (extra == ((struct config_bool *) gconf)->reset_extra) |
4707 | return true; |
4708 | break; |
4709 | case PGC_INT: |
4710 | if (extra == ((struct config_int *) gconf)->reset_extra) |
4711 | return true; |
4712 | break; |
4713 | case PGC_REAL: |
4714 | if (extra == ((struct config_real *) gconf)->reset_extra) |
4715 | return true; |
4716 | break; |
4717 | case PGC_STRING: |
4718 | if (extra == ((struct config_string *) gconf)->reset_extra) |
4719 | return true; |
4720 | break; |
4721 | case PGC_ENUM: |
4722 | if (extra == ((struct config_enum *) gconf)->reset_extra) |
4723 | return true; |
4724 | break; |
4725 | } |
4726 | for (stack = gconf->stack; stack; stack = stack->prev) |
4727 | { |
4728 | if (extra == stack->prior.extra || |
4729 | extra == stack->masked.extra) |
4730 | return true; |
4731 | } |
4732 | |
4733 | return false; |
4734 | } |
4735 | |
4736 | /* |
4737 | * Support for assigning to an "extra" field of a GUC item. Free the prior |
4738 | * value if it's not referenced anywhere else in the item (including stacked |
4739 | * states). |
4740 | */ |
4741 | static void |
4742 | (struct config_generic *gconf, void **field, void *newval) |
4743 | { |
4744 | void *oldval = *field; |
4745 | |
4746 | /* Do the assignment */ |
4747 | *field = newval; |
4748 | |
4749 | /* Free old value if it's not NULL and isn't referenced anymore */ |
4750 | if (oldval && !extra_field_used(gconf, oldval)) |
4751 | free(oldval); |
4752 | } |
4753 | |
4754 | /* |
4755 | * Support for copying a variable's active value into a stack entry. |
4756 | * The "extra" field associated with the active value is copied, too. |
4757 | * |
4758 | * NB: be sure stringval and extra fields of a new stack entry are |
4759 | * initialized to NULL before this is used, else we'll try to free() them. |
4760 | */ |
4761 | static void |
4762 | set_stack_value(struct config_generic *gconf, config_var_value *val) |
4763 | { |
4764 | switch (gconf->vartype) |
4765 | { |
4766 | case PGC_BOOL: |
4767 | val->val.boolval = |
4768 | *((struct config_bool *) gconf)->variable; |
4769 | break; |
4770 | case PGC_INT: |
4771 | val->val.intval = |
4772 | *((struct config_int *) gconf)->variable; |
4773 | break; |
4774 | case PGC_REAL: |
4775 | val->val.realval = |
4776 | *((struct config_real *) gconf)->variable; |
4777 | break; |
4778 | case PGC_STRING: |
4779 | set_string_field((struct config_string *) gconf, |
4780 | &(val->val.stringval), |
4781 | *((struct config_string *) gconf)->variable); |
4782 | break; |
4783 | case PGC_ENUM: |
4784 | val->val.enumval = |
4785 | *((struct config_enum *) gconf)->variable; |
4786 | break; |
4787 | } |
4788 | set_extra_field(gconf, &(val->extra), gconf->extra); |
4789 | } |
4790 | |
4791 | /* |
4792 | * Support for discarding a no-longer-needed value in a stack entry. |
4793 | * The "extra" field associated with the stack entry is cleared, too. |
4794 | */ |
4795 | static void |
4796 | discard_stack_value(struct config_generic *gconf, config_var_value *val) |
4797 | { |
4798 | switch (gconf->vartype) |
4799 | { |
4800 | case PGC_BOOL: |
4801 | case PGC_INT: |
4802 | case PGC_REAL: |
4803 | case PGC_ENUM: |
4804 | /* no need to do anything */ |
4805 | break; |
4806 | case PGC_STRING: |
4807 | set_string_field((struct config_string *) gconf, |
4808 | &(val->val.stringval), |
4809 | NULL); |
4810 | break; |
4811 | } |
4812 | set_extra_field(gconf, &(val->extra), NULL); |
4813 | } |
4814 | |
4815 | |
4816 | /* |
4817 | * Fetch the sorted array pointer (exported for help_config.c's use ONLY) |
4818 | */ |
4819 | struct config_generic ** |
4820 | get_guc_variables(void) |
4821 | { |
4822 | return guc_variables; |
4823 | } |
4824 | |
4825 | |
4826 | /* |
4827 | * Build the sorted array. This is split out so that it could be |
4828 | * re-executed after startup (e.g., we could allow loadable modules to |
4829 | * add vars, and then we'd need to re-sort). |
4830 | */ |
4831 | void |
4832 | build_guc_variables(void) |
4833 | { |
4834 | int size_vars; |
4835 | int num_vars = 0; |
4836 | int num_explain_vars = 0; |
4837 | struct config_generic **guc_vars; |
4838 | int i; |
4839 | |
4840 | for (i = 0; ConfigureNamesBool[i].gen.name; i++) |
4841 | { |
4842 | struct config_bool *conf = &ConfigureNamesBool[i]; |
4843 | |
4844 | /* Rather than requiring vartype to be filled in by hand, do this: */ |
4845 | conf->gen.vartype = PGC_BOOL; |
4846 | num_vars++; |
4847 | |
4848 | if (conf->gen.flags & GUC_EXPLAIN) |
4849 | num_explain_vars++; |
4850 | } |
4851 | |
4852 | for (i = 0; ConfigureNamesInt[i].gen.name; i++) |
4853 | { |
4854 | struct config_int *conf = &ConfigureNamesInt[i]; |
4855 | |
4856 | conf->gen.vartype = PGC_INT; |
4857 | num_vars++; |
4858 | |
4859 | if (conf->gen.flags & GUC_EXPLAIN) |
4860 | num_explain_vars++; |
4861 | } |
4862 | |
4863 | for (i = 0; ConfigureNamesReal[i].gen.name; i++) |
4864 | { |
4865 | struct config_real *conf = &ConfigureNamesReal[i]; |
4866 | |
4867 | conf->gen.vartype = PGC_REAL; |
4868 | num_vars++; |
4869 | |
4870 | if (conf->gen.flags & GUC_EXPLAIN) |
4871 | num_explain_vars++; |
4872 | } |
4873 | |
4874 | for (i = 0; ConfigureNamesString[i].gen.name; i++) |
4875 | { |
4876 | struct config_string *conf = &ConfigureNamesString[i]; |
4877 | |
4878 | conf->gen.vartype = PGC_STRING; |
4879 | num_vars++; |
4880 | |
4881 | if (conf->gen.flags & GUC_EXPLAIN) |
4882 | num_explain_vars++; |
4883 | } |
4884 | |
4885 | for (i = 0; ConfigureNamesEnum[i].gen.name; i++) |
4886 | { |
4887 | struct config_enum *conf = &ConfigureNamesEnum[i]; |
4888 | |
4889 | conf->gen.vartype = PGC_ENUM; |
4890 | num_vars++; |
4891 | |
4892 | if (conf->gen.flags & GUC_EXPLAIN) |
4893 | num_explain_vars++; |
4894 | } |
4895 | |
4896 | /* |
4897 | * Create table with 20% slack |
4898 | */ |
4899 | size_vars = num_vars + num_vars / 4; |
4900 | |
4901 | guc_vars = (struct config_generic **) |
4902 | guc_malloc(FATAL, size_vars * sizeof(struct config_generic *)); |
4903 | |
4904 | num_vars = 0; |
4905 | |
4906 | for (i = 0; ConfigureNamesBool[i].gen.name; i++) |
4907 | guc_vars[num_vars++] = &ConfigureNamesBool[i].gen; |
4908 | |
4909 | for (i = 0; ConfigureNamesInt[i].gen.name; i++) |
4910 | guc_vars[num_vars++] = &ConfigureNamesInt[i].gen; |
4911 | |
4912 | for (i = 0; ConfigureNamesReal[i].gen.name; i++) |
4913 | guc_vars[num_vars++] = &ConfigureNamesReal[i].gen; |
4914 | |
4915 | for (i = 0; ConfigureNamesString[i].gen.name; i++) |
4916 | guc_vars[num_vars++] = &ConfigureNamesString[i].gen; |
4917 | |
4918 | for (i = 0; ConfigureNamesEnum[i].gen.name; i++) |
4919 | guc_vars[num_vars++] = &ConfigureNamesEnum[i].gen; |
4920 | |
4921 | if (guc_variables) |
4922 | free(guc_variables); |
4923 | guc_variables = guc_vars; |
4924 | num_guc_variables = num_vars; |
4925 | num_guc_explain_variables = num_explain_vars; |
4926 | size_guc_variables = size_vars; |
4927 | qsort((void *) guc_variables, num_guc_variables, |
4928 | sizeof(struct config_generic *), guc_var_compare); |
4929 | } |
4930 | |
4931 | /* |
4932 | * Add a new GUC variable to the list of known variables. The |
4933 | * list is expanded if needed. |
4934 | */ |
4935 | static bool |
4936 | add_guc_variable(struct config_generic *var, int elevel) |
4937 | { |
4938 | if (num_guc_variables + 1 >= size_guc_variables) |
4939 | { |
4940 | /* |
4941 | * Increase the vector by 25% |
4942 | */ |
4943 | int size_vars = size_guc_variables + size_guc_variables / 4; |
4944 | struct config_generic **guc_vars; |
4945 | |
4946 | if (size_vars == 0) |
4947 | { |
4948 | size_vars = 100; |
4949 | guc_vars = (struct config_generic **) |
4950 | guc_malloc(elevel, size_vars * sizeof(struct config_generic *)); |
4951 | } |
4952 | else |
4953 | { |
4954 | guc_vars = (struct config_generic **) |
4955 | guc_realloc(elevel, guc_variables, size_vars * sizeof(struct config_generic *)); |
4956 | } |
4957 | |
4958 | if (guc_vars == NULL) |
4959 | return false; /* out of memory */ |
4960 | |
4961 | guc_variables = guc_vars; |
4962 | size_guc_variables = size_vars; |
4963 | } |
4964 | guc_variables[num_guc_variables++] = var; |
4965 | qsort((void *) guc_variables, num_guc_variables, |
4966 | sizeof(struct config_generic *), guc_var_compare); |
4967 | return true; |
4968 | } |
4969 | |
4970 | /* |
4971 | * Create and add a placeholder variable for a custom variable name. |
4972 | */ |
4973 | static struct config_generic * |
4974 | add_placeholder_variable(const char *name, int elevel) |
4975 | { |
4976 | size_t sz = sizeof(struct config_string) + sizeof(char *); |
4977 | struct config_string *var; |
4978 | struct config_generic *gen; |
4979 | |
4980 | var = (struct config_string *) guc_malloc(elevel, sz); |
4981 | if (var == NULL) |
4982 | return NULL; |
4983 | memset(var, 0, sz); |
4984 | gen = &var->gen; |
4985 | |
4986 | gen->name = guc_strdup(elevel, name); |
4987 | if (gen->name == NULL) |
4988 | { |
4989 | free(var); |
4990 | return NULL; |
4991 | } |
4992 | |
4993 | gen->context = PGC_USERSET; |
4994 | gen->group = CUSTOM_OPTIONS; |
4995 | gen->short_desc = "GUC placeholder variable" ; |
4996 | gen->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER; |
4997 | gen->vartype = PGC_STRING; |
4998 | |
4999 | /* |
5000 | * The char* is allocated at the end of the struct since we have no |
5001 | * 'static' place to point to. Note that the current value, as well as |
5002 | * the boot and reset values, start out NULL. |
5003 | */ |
5004 | var->variable = (char **) (var + 1); |
5005 | |
5006 | if (!add_guc_variable((struct config_generic *) var, elevel)) |
5007 | { |
5008 | free(unconstify(char *, gen->name)); |
5009 | free(var); |
5010 | return NULL; |
5011 | } |
5012 | |
5013 | return gen; |
5014 | } |
5015 | |
5016 | /* |
5017 | * Look up option NAME. If it exists, return a pointer to its record, |
5018 | * else return NULL. If create_placeholders is true, we'll create a |
5019 | * placeholder record for a valid-looking custom variable name. |
5020 | */ |
5021 | static struct config_generic * |
5022 | find_option(const char *name, bool create_placeholders, int elevel) |
5023 | { |
5024 | const char **key = &name; |
5025 | struct config_generic **res; |
5026 | int i; |
5027 | |
5028 | Assert(name); |
5029 | |
5030 | /* |
5031 | * By equating const char ** with struct config_generic *, we are assuming |
5032 | * the name field is first in config_generic. |
5033 | */ |
5034 | res = (struct config_generic **) bsearch((void *) &key, |
5035 | (void *) guc_variables, |
5036 | num_guc_variables, |
5037 | sizeof(struct config_generic *), |
5038 | guc_var_compare); |
5039 | if (res) |
5040 | return *res; |
5041 | |
5042 | /* |
5043 | * See if the name is an obsolete name for a variable. We assume that the |
5044 | * set of supported old names is short enough that a brute-force search is |
5045 | * the best way. |
5046 | */ |
5047 | for (i = 0; map_old_guc_names[i] != NULL; i += 2) |
5048 | { |
5049 | if (guc_name_compare(name, map_old_guc_names[i]) == 0) |
5050 | return find_option(map_old_guc_names[i + 1], false, elevel); |
5051 | } |
5052 | |
5053 | if (create_placeholders) |
5054 | { |
5055 | /* |
5056 | * Check if the name is qualified, and if so, add a placeholder. |
5057 | */ |
5058 | if (strchr(name, GUC_QUALIFIER_SEPARATOR) != NULL) |
5059 | return add_placeholder_variable(name, elevel); |
5060 | } |
5061 | |
5062 | /* Unknown name */ |
5063 | return NULL; |
5064 | } |
5065 | |
5066 | |
5067 | /* |
5068 | * comparator for qsorting and bsearching guc_variables array |
5069 | */ |
5070 | static int |
5071 | guc_var_compare(const void *a, const void *b) |
5072 | { |
5073 | const struct config_generic *confa = *(struct config_generic *const *) a; |
5074 | const struct config_generic *confb = *(struct config_generic *const *) b; |
5075 | |
5076 | return guc_name_compare(confa->name, confb->name); |
5077 | } |
5078 | |
5079 | /* |
5080 | * the bare comparison function for GUC names |
5081 | */ |
5082 | static int |
5083 | guc_name_compare(const char *namea, const char *nameb) |
5084 | { |
5085 | /* |
5086 | * The temptation to use strcasecmp() here must be resisted, because the |
5087 | * array ordering has to remain stable across setlocale() calls. So, build |
5088 | * our own with a simple ASCII-only downcasing. |
5089 | */ |
5090 | while (*namea && *nameb) |
5091 | { |
5092 | char cha = *namea++; |
5093 | char chb = *nameb++; |
5094 | |
5095 | if (cha >= 'A' && cha <= 'Z') |
5096 | cha += 'a' - 'A'; |
5097 | if (chb >= 'A' && chb <= 'Z') |
5098 | chb += 'a' - 'A'; |
5099 | if (cha != chb) |
5100 | return cha - chb; |
5101 | } |
5102 | if (*namea) |
5103 | return 1; /* a is longer */ |
5104 | if (*nameb) |
5105 | return -1; /* b is longer */ |
5106 | return 0; |
5107 | } |
5108 | |
5109 | |
5110 | /* |
5111 | * Initialize GUC options during program startup. |
5112 | * |
5113 | * Note that we cannot read the config file yet, since we have not yet |
5114 | * processed command-line switches. |
5115 | */ |
5116 | void |
5117 | InitializeGUCOptions(void) |
5118 | { |
5119 | int i; |
5120 | |
5121 | /* |
5122 | * Before log_line_prefix could possibly receive a nonempty setting, make |
5123 | * sure that timezone processing is minimally alive (see elog.c). |
5124 | */ |
5125 | pg_timezone_initialize(); |
5126 | |
5127 | /* |
5128 | * Build sorted array of all GUC variables. |
5129 | */ |
5130 | build_guc_variables(); |
5131 | |
5132 | /* |
5133 | * Load all variables with their compiled-in defaults, and initialize |
5134 | * status fields as needed. |
5135 | */ |
5136 | for (i = 0; i < num_guc_variables; i++) |
5137 | { |
5138 | InitializeOneGUCOption(guc_variables[i]); |
5139 | } |
5140 | |
5141 | guc_dirty = false; |
5142 | |
5143 | reporting_enabled = false; |
5144 | |
5145 | /* |
5146 | * Prevent any attempt to override the transaction modes from |
5147 | * non-interactive sources. |
5148 | */ |
5149 | SetConfigOption("transaction_isolation" , "read committed" , |
5150 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
5151 | SetConfigOption("transaction_read_only" , "no" , |
5152 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
5153 | SetConfigOption("transaction_deferrable" , "no" , |
5154 | PGC_POSTMASTER, PGC_S_OVERRIDE); |
5155 | |
5156 | /* |
5157 | * For historical reasons, some GUC parameters can receive defaults from |
5158 | * environment variables. Process those settings. |
5159 | */ |
5160 | InitializeGUCOptionsFromEnvironment(); |
5161 | } |
5162 | |
5163 | /* |
5164 | * Assign any GUC values that can come from the server's environment. |
5165 | * |
5166 | * This is called from InitializeGUCOptions, and also from ProcessConfigFile |
5167 | * to deal with the possibility that a setting has been removed from |
5168 | * postgresql.conf and should now get a value from the environment. |
5169 | * (The latter is a kludge that should probably go away someday; if so, |
5170 | * fold this back into InitializeGUCOptions.) |
5171 | */ |
5172 | static void |
5173 | InitializeGUCOptionsFromEnvironment(void) |
5174 | { |
5175 | char *env; |
5176 | long stack_rlimit; |
5177 | |
5178 | env = getenv("PGPORT" ); |
5179 | if (env != NULL) |
5180 | SetConfigOption("port" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
5181 | |
5182 | env = getenv("PGDATESTYLE" ); |
5183 | if (env != NULL) |
5184 | SetConfigOption("datestyle" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
5185 | |
5186 | env = getenv("PGCLIENTENCODING" ); |
5187 | if (env != NULL) |
5188 | SetConfigOption("client_encoding" , env, PGC_POSTMASTER, PGC_S_ENV_VAR); |
5189 | |
5190 | /* |
5191 | * rlimit isn't exactly an "environment variable", but it behaves about |
5192 | * the same. If we can identify the platform stack depth rlimit, increase |
5193 | * default stack depth setting up to whatever is safe (but at most 2MB). |
5194 | */ |
5195 | stack_rlimit = get_stack_depth_rlimit(); |
5196 | if (stack_rlimit > 0) |
5197 | { |
5198 | long new_limit = (stack_rlimit - STACK_DEPTH_SLOP) / 1024L; |
5199 | |
5200 | if (new_limit > 100) |
5201 | { |
5202 | char limbuf[16]; |
5203 | |
5204 | new_limit = Min(new_limit, 2048); |
5205 | sprintf(limbuf, "%ld" , new_limit); |
5206 | SetConfigOption("max_stack_depth" , limbuf, |
5207 | PGC_POSTMASTER, PGC_S_ENV_VAR); |
5208 | } |
5209 | } |
5210 | } |
5211 | |
5212 | /* |
5213 | * Initialize one GUC option variable to its compiled-in default. |
5214 | * |
5215 | * Note: the reason for calling check_hooks is not that we think the boot_val |
5216 | * might fail, but that the hooks might wish to compute an "extra" struct. |
5217 | */ |
5218 | static void |
5219 | InitializeOneGUCOption(struct config_generic *gconf) |
5220 | { |
5221 | gconf->status = 0; |
5222 | gconf->source = PGC_S_DEFAULT; |
5223 | gconf->reset_source = PGC_S_DEFAULT; |
5224 | gconf->scontext = PGC_INTERNAL; |
5225 | gconf->reset_scontext = PGC_INTERNAL; |
5226 | gconf->stack = NULL; |
5227 | gconf->extra = NULL; |
5228 | gconf->sourcefile = NULL; |
5229 | gconf->sourceline = 0; |
5230 | |
5231 | switch (gconf->vartype) |
5232 | { |
5233 | case PGC_BOOL: |
5234 | { |
5235 | struct config_bool *conf = (struct config_bool *) gconf; |
5236 | bool newval = conf->boot_val; |
5237 | void * = NULL; |
5238 | |
5239 | if (!call_bool_check_hook(conf, &newval, &extra, |
5240 | PGC_S_DEFAULT, LOG)) |
5241 | elog(FATAL, "failed to initialize %s to %d" , |
5242 | conf->gen.name, (int) newval); |
5243 | if (conf->assign_hook) |
5244 | conf->assign_hook(newval, extra); |
5245 | *conf->variable = conf->reset_val = newval; |
5246 | conf->gen.extra = conf->reset_extra = extra; |
5247 | break; |
5248 | } |
5249 | case PGC_INT: |
5250 | { |
5251 | struct config_int *conf = (struct config_int *) gconf; |
5252 | int newval = conf->boot_val; |
5253 | void * = NULL; |
5254 | |
5255 | Assert(newval >= conf->min); |
5256 | Assert(newval <= conf->max); |
5257 | if (!call_int_check_hook(conf, &newval, &extra, |
5258 | PGC_S_DEFAULT, LOG)) |
5259 | elog(FATAL, "failed to initialize %s to %d" , |
5260 | conf->gen.name, newval); |
5261 | if (conf->assign_hook) |
5262 | conf->assign_hook(newval, extra); |
5263 | *conf->variable = conf->reset_val = newval; |
5264 | conf->gen.extra = conf->reset_extra = extra; |
5265 | break; |
5266 | } |
5267 | case PGC_REAL: |
5268 | { |
5269 | struct config_real *conf = (struct config_real *) gconf; |
5270 | double newval = conf->boot_val; |
5271 | void * = NULL; |
5272 | |
5273 | Assert(newval >= conf->min); |
5274 | Assert(newval <= conf->max); |
5275 | if (!call_real_check_hook(conf, &newval, &extra, |
5276 | PGC_S_DEFAULT, LOG)) |
5277 | elog(FATAL, "failed to initialize %s to %g" , |
5278 | conf->gen.name, newval); |
5279 | if (conf->assign_hook) |
5280 | conf->assign_hook(newval, extra); |
5281 | *conf->variable = conf->reset_val = newval; |
5282 | conf->gen.extra = conf->reset_extra = extra; |
5283 | break; |
5284 | } |
5285 | case PGC_STRING: |
5286 | { |
5287 | struct config_string *conf = (struct config_string *) gconf; |
5288 | char *newval; |
5289 | void * = NULL; |
5290 | |
5291 | /* non-NULL boot_val must always get strdup'd */ |
5292 | if (conf->boot_val != NULL) |
5293 | newval = guc_strdup(FATAL, conf->boot_val); |
5294 | else |
5295 | newval = NULL; |
5296 | |
5297 | if (!call_string_check_hook(conf, &newval, &extra, |
5298 | PGC_S_DEFAULT, LOG)) |
5299 | elog(FATAL, "failed to initialize %s to \"%s\"" , |
5300 | conf->gen.name, newval ? newval : "" ); |
5301 | if (conf->assign_hook) |
5302 | conf->assign_hook(newval, extra); |
5303 | *conf->variable = conf->reset_val = newval; |
5304 | conf->gen.extra = conf->reset_extra = extra; |
5305 | break; |
5306 | } |
5307 | case PGC_ENUM: |
5308 | { |
5309 | struct config_enum *conf = (struct config_enum *) gconf; |
5310 | int newval = conf->boot_val; |
5311 | void * = NULL; |
5312 | |
5313 | if (!call_enum_check_hook(conf, &newval, &extra, |
5314 | PGC_S_DEFAULT, LOG)) |
5315 | elog(FATAL, "failed to initialize %s to %d" , |
5316 | conf->gen.name, newval); |
5317 | if (conf->assign_hook) |
5318 | conf->assign_hook(newval, extra); |
5319 | *conf->variable = conf->reset_val = newval; |
5320 | conf->gen.extra = conf->reset_extra = extra; |
5321 | break; |
5322 | } |
5323 | } |
5324 | } |
5325 | |
5326 | |
5327 | /* |
5328 | * Select the configuration files and data directory to be used, and |
5329 | * do the initial read of postgresql.conf. |
5330 | * |
5331 | * This is called after processing command-line switches. |
5332 | * userDoption is the -D switch value if any (NULL if unspecified). |
5333 | * progname is just for use in error messages. |
5334 | * |
5335 | * Returns true on success; on failure, prints a suitable error message |
5336 | * to stderr and returns false. |
5337 | */ |
5338 | bool |
5339 | SelectConfigFiles(const char *userDoption, const char *progname) |
5340 | { |
5341 | char *configdir; |
5342 | char *fname; |
5343 | struct stat stat_buf; |
5344 | |
5345 | /* configdir is -D option, or $PGDATA if no -D */ |
5346 | if (userDoption) |
5347 | configdir = make_absolute_path(userDoption); |
5348 | else |
5349 | configdir = make_absolute_path(getenv("PGDATA" )); |
5350 | |
5351 | if (configdir && stat(configdir, &stat_buf) != 0) |
5352 | { |
5353 | write_stderr("%s: could not access directory \"%s\": %s\n" , |
5354 | progname, |
5355 | configdir, |
5356 | strerror(errno)); |
5357 | if (errno == ENOENT) |
5358 | write_stderr("Run initdb or pg_basebackup to initialize a PostgreSQL data directory.\n" ); |
5359 | return false; |
5360 | } |
5361 | |
5362 | /* |
5363 | * Find the configuration file: if config_file was specified on the |
5364 | * command line, use it, else use configdir/postgresql.conf. In any case |
5365 | * ensure the result is an absolute path, so that it will be interpreted |
5366 | * the same way by future backends. |
5367 | */ |
5368 | if (ConfigFileName) |
5369 | fname = make_absolute_path(ConfigFileName); |
5370 | else if (configdir) |
5371 | { |
5372 | fname = guc_malloc(FATAL, |
5373 | strlen(configdir) + strlen(CONFIG_FILENAME) + 2); |
5374 | sprintf(fname, "%s/%s" , configdir, CONFIG_FILENAME); |
5375 | } |
5376 | else |
5377 | { |
5378 | write_stderr("%s does not know where to find the server configuration file.\n" |
5379 | "You must specify the --config-file or -D invocation " |
5380 | "option or set the PGDATA environment variable.\n" , |
5381 | progname); |
5382 | return false; |
5383 | } |
5384 | |
5385 | /* |
5386 | * Set the ConfigFileName GUC variable to its final value, ensuring that |
5387 | * it can't be overridden later. |
5388 | */ |
5389 | SetConfigOption("config_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
5390 | free(fname); |
5391 | |
5392 | /* |
5393 | * Now read the config file for the first time. |
5394 | */ |
5395 | if (stat(ConfigFileName, &stat_buf) != 0) |
5396 | { |
5397 | write_stderr("%s: could not access the server configuration file \"%s\": %s\n" , |
5398 | progname, ConfigFileName, strerror(errno)); |
5399 | free(configdir); |
5400 | return false; |
5401 | } |
5402 | |
5403 | /* |
5404 | * Read the configuration file for the first time. This time only the |
5405 | * data_directory parameter is picked up to determine the data directory, |
5406 | * so that we can read the PG_AUTOCONF_FILENAME file next time. |
5407 | */ |
5408 | ProcessConfigFile(PGC_POSTMASTER); |
5409 | |
5410 | /* |
5411 | * If the data_directory GUC variable has been set, use that as DataDir; |
5412 | * otherwise use configdir if set; else punt. |
5413 | * |
5414 | * Note: SetDataDir will copy and absolute-ize its argument, so we don't |
5415 | * have to. |
5416 | */ |
5417 | if (data_directory) |
5418 | SetDataDir(data_directory); |
5419 | else if (configdir) |
5420 | SetDataDir(configdir); |
5421 | else |
5422 | { |
5423 | write_stderr("%s does not know where to find the database system data.\n" |
5424 | "This can be specified as \"data_directory\" in \"%s\", " |
5425 | "or by the -D invocation option, or by the " |
5426 | "PGDATA environment variable.\n" , |
5427 | progname, ConfigFileName); |
5428 | return false; |
5429 | } |
5430 | |
5431 | /* |
5432 | * Reflect the final DataDir value back into the data_directory GUC var. |
5433 | * (If you are wondering why we don't just make them a single variable, |
5434 | * it's because the EXEC_BACKEND case needs DataDir to be transmitted to |
5435 | * child backends specially. XXX is that still true? Given that we now |
5436 | * chdir to DataDir, EXEC_BACKEND can read the config file without knowing |
5437 | * DataDir in advance.) |
5438 | */ |
5439 | SetConfigOption("data_directory" , DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE); |
5440 | |
5441 | /* |
5442 | * Now read the config file a second time, allowing any settings in the |
5443 | * PG_AUTOCONF_FILENAME file to take effect. (This is pretty ugly, but |
5444 | * since we have to determine the DataDir before we can find the autoconf |
5445 | * file, the alternatives seem worse.) |
5446 | */ |
5447 | ProcessConfigFile(PGC_POSTMASTER); |
5448 | |
5449 | /* |
5450 | * If timezone_abbreviations wasn't set in the configuration file, install |
5451 | * the default value. We do it this way because we can't safely install a |
5452 | * "real" value until my_exec_path is set, which may not have happened |
5453 | * when InitializeGUCOptions runs, so the bootstrap default value cannot |
5454 | * be the real desired default. |
5455 | */ |
5456 | pg_timezone_abbrev_initialize(); |
5457 | |
5458 | /* |
5459 | * Figure out where pg_hba.conf is, and make sure the path is absolute. |
5460 | */ |
5461 | if (HbaFileName) |
5462 | fname = make_absolute_path(HbaFileName); |
5463 | else if (configdir) |
5464 | { |
5465 | fname = guc_malloc(FATAL, |
5466 | strlen(configdir) + strlen(HBA_FILENAME) + 2); |
5467 | sprintf(fname, "%s/%s" , configdir, HBA_FILENAME); |
5468 | } |
5469 | else |
5470 | { |
5471 | write_stderr("%s does not know where to find the \"hba\" configuration file.\n" |
5472 | "This can be specified as \"hba_file\" in \"%s\", " |
5473 | "or by the -D invocation option, or by the " |
5474 | "PGDATA environment variable.\n" , |
5475 | progname, ConfigFileName); |
5476 | return false; |
5477 | } |
5478 | SetConfigOption("hba_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
5479 | free(fname); |
5480 | |
5481 | /* |
5482 | * Likewise for pg_ident.conf. |
5483 | */ |
5484 | if (IdentFileName) |
5485 | fname = make_absolute_path(IdentFileName); |
5486 | else if (configdir) |
5487 | { |
5488 | fname = guc_malloc(FATAL, |
5489 | strlen(configdir) + strlen(IDENT_FILENAME) + 2); |
5490 | sprintf(fname, "%s/%s" , configdir, IDENT_FILENAME); |
5491 | } |
5492 | else |
5493 | { |
5494 | write_stderr("%s does not know where to find the \"ident\" configuration file.\n" |
5495 | "This can be specified as \"ident_file\" in \"%s\", " |
5496 | "or by the -D invocation option, or by the " |
5497 | "PGDATA environment variable.\n" , |
5498 | progname, ConfigFileName); |
5499 | return false; |
5500 | } |
5501 | SetConfigOption("ident_file" , fname, PGC_POSTMASTER, PGC_S_OVERRIDE); |
5502 | free(fname); |
5503 | |
5504 | free(configdir); |
5505 | |
5506 | return true; |
5507 | } |
5508 | |
5509 | |
5510 | /* |
5511 | * Reset all options to their saved default values (implements RESET ALL) |
5512 | */ |
5513 | void |
5514 | ResetAllOptions(void) |
5515 | { |
5516 | int i; |
5517 | |
5518 | for (i = 0; i < num_guc_variables; i++) |
5519 | { |
5520 | struct config_generic *gconf = guc_variables[i]; |
5521 | |
5522 | /* Don't reset non-SET-able values */ |
5523 | if (gconf->context != PGC_SUSET && |
5524 | gconf->context != PGC_USERSET) |
5525 | continue; |
5526 | /* Don't reset if special exclusion from RESET ALL */ |
5527 | if (gconf->flags & GUC_NO_RESET_ALL) |
5528 | continue; |
5529 | /* No need to reset if wasn't SET */ |
5530 | if (gconf->source <= PGC_S_OVERRIDE) |
5531 | continue; |
5532 | |
5533 | /* Save old value to support transaction abort */ |
5534 | push_old_value(gconf, GUC_ACTION_SET); |
5535 | |
5536 | switch (gconf->vartype) |
5537 | { |
5538 | case PGC_BOOL: |
5539 | { |
5540 | struct config_bool *conf = (struct config_bool *) gconf; |
5541 | |
5542 | if (conf->assign_hook) |
5543 | conf->assign_hook(conf->reset_val, |
5544 | conf->reset_extra); |
5545 | *conf->variable = conf->reset_val; |
5546 | set_extra_field(&conf->gen, &conf->gen.extra, |
5547 | conf->reset_extra); |
5548 | break; |
5549 | } |
5550 | case PGC_INT: |
5551 | { |
5552 | struct config_int *conf = (struct config_int *) gconf; |
5553 | |
5554 | if (conf->assign_hook) |
5555 | conf->assign_hook(conf->reset_val, |
5556 | conf->reset_extra); |
5557 | *conf->variable = conf->reset_val; |
5558 | set_extra_field(&conf->gen, &conf->gen.extra, |
5559 | conf->reset_extra); |
5560 | break; |
5561 | } |
5562 | case PGC_REAL: |
5563 | { |
5564 | struct config_real *conf = (struct config_real *) gconf; |
5565 | |
5566 | if (conf->assign_hook) |
5567 | conf->assign_hook(conf->reset_val, |
5568 | conf->reset_extra); |
5569 | *conf->variable = conf->reset_val; |
5570 | set_extra_field(&conf->gen, &conf->gen.extra, |
5571 | conf->reset_extra); |
5572 | break; |
5573 | } |
5574 | case PGC_STRING: |
5575 | { |
5576 | struct config_string *conf = (struct config_string *) gconf; |
5577 | |
5578 | if (conf->assign_hook) |
5579 | conf->assign_hook(conf->reset_val, |
5580 | conf->reset_extra); |
5581 | set_string_field(conf, conf->variable, conf->reset_val); |
5582 | set_extra_field(&conf->gen, &conf->gen.extra, |
5583 | conf->reset_extra); |
5584 | break; |
5585 | } |
5586 | case PGC_ENUM: |
5587 | { |
5588 | struct config_enum *conf = (struct config_enum *) gconf; |
5589 | |
5590 | if (conf->assign_hook) |
5591 | conf->assign_hook(conf->reset_val, |
5592 | conf->reset_extra); |
5593 | *conf->variable = conf->reset_val; |
5594 | set_extra_field(&conf->gen, &conf->gen.extra, |
5595 | conf->reset_extra); |
5596 | break; |
5597 | } |
5598 | } |
5599 | |
5600 | gconf->source = gconf->reset_source; |
5601 | gconf->scontext = gconf->reset_scontext; |
5602 | |
5603 | if (gconf->flags & GUC_REPORT) |
5604 | ReportGUCOption(gconf); |
5605 | } |
5606 | } |
5607 | |
5608 | |
5609 | /* |
5610 | * push_old_value |
5611 | * Push previous state during transactional assignment to a GUC variable. |
5612 | */ |
5613 | static void |
5614 | push_old_value(struct config_generic *gconf, GucAction action) |
5615 | { |
5616 | GucStack *stack; |
5617 | |
5618 | /* If we're not inside a nest level, do nothing */ |
5619 | if (GUCNestLevel == 0) |
5620 | return; |
5621 | |
5622 | /* Do we already have a stack entry of the current nest level? */ |
5623 | stack = gconf->stack; |
5624 | if (stack && stack->nest_level >= GUCNestLevel) |
5625 | { |
5626 | /* Yes, so adjust its state if necessary */ |
5627 | Assert(stack->nest_level == GUCNestLevel); |
5628 | switch (action) |
5629 | { |
5630 | case GUC_ACTION_SET: |
5631 | /* SET overrides any prior action at same nest level */ |
5632 | if (stack->state == GUC_SET_LOCAL) |
5633 | { |
5634 | /* must discard old masked value */ |
5635 | discard_stack_value(gconf, &stack->masked); |
5636 | } |
5637 | stack->state = GUC_SET; |
5638 | break; |
5639 | case GUC_ACTION_LOCAL: |
5640 | if (stack->state == GUC_SET) |
5641 | { |
5642 | /* SET followed by SET LOCAL, remember SET's value */ |
5643 | stack->masked_scontext = gconf->scontext; |
5644 | set_stack_value(gconf, &stack->masked); |
5645 | stack->state = GUC_SET_LOCAL; |
5646 | } |
5647 | /* in all other cases, no change to stack entry */ |
5648 | break; |
5649 | case GUC_ACTION_SAVE: |
5650 | /* Could only have a prior SAVE of same variable */ |
5651 | Assert(stack->state == GUC_SAVE); |
5652 | break; |
5653 | } |
5654 | Assert(guc_dirty); /* must be set already */ |
5655 | return; |
5656 | } |
5657 | |
5658 | /* |
5659 | * Push a new stack entry |
5660 | * |
5661 | * We keep all the stack entries in TopTransactionContext for simplicity. |
5662 | */ |
5663 | stack = (GucStack *) MemoryContextAllocZero(TopTransactionContext, |
5664 | sizeof(GucStack)); |
5665 | |
5666 | stack->prev = gconf->stack; |
5667 | stack->nest_level = GUCNestLevel; |
5668 | switch (action) |
5669 | { |
5670 | case GUC_ACTION_SET: |
5671 | stack->state = GUC_SET; |
5672 | break; |
5673 | case GUC_ACTION_LOCAL: |
5674 | stack->state = GUC_LOCAL; |
5675 | break; |
5676 | case GUC_ACTION_SAVE: |
5677 | stack->state = GUC_SAVE; |
5678 | break; |
5679 | } |
5680 | stack->source = gconf->source; |
5681 | stack->scontext = gconf->scontext; |
5682 | set_stack_value(gconf, &stack->prior); |
5683 | |
5684 | gconf->stack = stack; |
5685 | |
5686 | /* Ensure we remember to pop at end of xact */ |
5687 | guc_dirty = true; |
5688 | } |
5689 | |
5690 | |
5691 | /* |
5692 | * Do GUC processing at main transaction start. |
5693 | */ |
5694 | void |
5695 | AtStart_GUC(void) |
5696 | { |
5697 | /* |
5698 | * The nest level should be 0 between transactions; if it isn't, somebody |
5699 | * didn't call AtEOXact_GUC, or called it with the wrong nestLevel. We |
5700 | * throw a warning but make no other effort to clean up. |
5701 | */ |
5702 | if (GUCNestLevel != 0) |
5703 | elog(WARNING, "GUC nest level = %d at transaction start" , |
5704 | GUCNestLevel); |
5705 | GUCNestLevel = 1; |
5706 | } |
5707 | |
5708 | /* |
5709 | * Enter a new nesting level for GUC values. This is called at subtransaction |
5710 | * start, and when entering a function that has proconfig settings, and in |
5711 | * some other places where we want to set GUC variables transiently. |
5712 | * NOTE we must not risk error here, else subtransaction start will be unhappy. |
5713 | */ |
5714 | int |
5715 | NewGUCNestLevel(void) |
5716 | { |
5717 | return ++GUCNestLevel; |
5718 | } |
5719 | |
5720 | /* |
5721 | * Do GUC processing at transaction or subtransaction commit or abort, or |
5722 | * when exiting a function that has proconfig settings, or when undoing a |
5723 | * transient assignment to some GUC variables. (The name is thus a bit of |
5724 | * a misnomer; perhaps it should be ExitGUCNestLevel or some such.) |
5725 | * During abort, we discard all GUC settings that were applied at nesting |
5726 | * levels >= nestLevel. nestLevel == 1 corresponds to the main transaction. |
5727 | */ |
5728 | void |
5729 | AtEOXact_GUC(bool isCommit, int nestLevel) |
5730 | { |
5731 | bool still_dirty; |
5732 | int i; |
5733 | |
5734 | /* |
5735 | * Note: it's possible to get here with GUCNestLevel == nestLevel-1 during |
5736 | * abort, if there is a failure during transaction start before |
5737 | * AtStart_GUC is called. |
5738 | */ |
5739 | Assert(nestLevel > 0 && |
5740 | (nestLevel <= GUCNestLevel || |
5741 | (nestLevel == GUCNestLevel + 1 && !isCommit))); |
5742 | |
5743 | /* Quick exit if nothing's changed in this transaction */ |
5744 | if (!guc_dirty) |
5745 | { |
5746 | GUCNestLevel = nestLevel - 1; |
5747 | return; |
5748 | } |
5749 | |
5750 | still_dirty = false; |
5751 | for (i = 0; i < num_guc_variables; i++) |
5752 | { |
5753 | struct config_generic *gconf = guc_variables[i]; |
5754 | GucStack *stack; |
5755 | |
5756 | /* |
5757 | * Process and pop each stack entry within the nest level. To simplify |
5758 | * fmgr_security_definer() and other places that use GUC_ACTION_SAVE, |
5759 | * we allow failure exit from code that uses a local nest level to be |
5760 | * recovered at the surrounding transaction or subtransaction abort; |
5761 | * so there could be more than one stack entry to pop. |
5762 | */ |
5763 | while ((stack = gconf->stack) != NULL && |
5764 | stack->nest_level >= nestLevel) |
5765 | { |
5766 | GucStack *prev = stack->prev; |
5767 | bool restorePrior = false; |
5768 | bool restoreMasked = false; |
5769 | bool changed; |
5770 | |
5771 | /* |
5772 | * In this next bit, if we don't set either restorePrior or |
5773 | * restoreMasked, we must "discard" any unwanted fields of the |
5774 | * stack entries to avoid leaking memory. If we do set one of |
5775 | * those flags, unused fields will be cleaned up after restoring. |
5776 | */ |
5777 | if (!isCommit) /* if abort, always restore prior value */ |
5778 | restorePrior = true; |
5779 | else if (stack->state == GUC_SAVE) |
5780 | restorePrior = true; |
5781 | else if (stack->nest_level == 1) |
5782 | { |
5783 | /* transaction commit */ |
5784 | if (stack->state == GUC_SET_LOCAL) |
5785 | restoreMasked = true; |
5786 | else if (stack->state == GUC_SET) |
5787 | { |
5788 | /* we keep the current active value */ |
5789 | discard_stack_value(gconf, &stack->prior); |
5790 | } |
5791 | else /* must be GUC_LOCAL */ |
5792 | restorePrior = true; |
5793 | } |
5794 | else if (prev == NULL || |
5795 | prev->nest_level < stack->nest_level - 1) |
5796 | { |
5797 | /* decrement entry's level and do not pop it */ |
5798 | stack->nest_level--; |
5799 | continue; |
5800 | } |
5801 | else |
5802 | { |
5803 | /* |
5804 | * We have to merge this stack entry into prev. See README for |
5805 | * discussion of this bit. |
5806 | */ |
5807 | switch (stack->state) |
5808 | { |
5809 | case GUC_SAVE: |
5810 | Assert(false); /* can't get here */ |
5811 | break; |
5812 | |
5813 | case GUC_SET: |
5814 | /* next level always becomes SET */ |
5815 | discard_stack_value(gconf, &stack->prior); |
5816 | if (prev->state == GUC_SET_LOCAL) |
5817 | discard_stack_value(gconf, &prev->masked); |
5818 | prev->state = GUC_SET; |
5819 | break; |
5820 | |
5821 | case GUC_LOCAL: |
5822 | if (prev->state == GUC_SET) |
5823 | { |
5824 | /* LOCAL migrates down */ |
5825 | prev->masked_scontext = stack->scontext; |
5826 | prev->masked = stack->prior; |
5827 | prev->state = GUC_SET_LOCAL; |
5828 | } |
5829 | else |
5830 | { |
5831 | /* else just forget this stack level */ |
5832 | discard_stack_value(gconf, &stack->prior); |
5833 | } |
5834 | break; |
5835 | |
5836 | case GUC_SET_LOCAL: |
5837 | /* prior state at this level no longer wanted */ |
5838 | discard_stack_value(gconf, &stack->prior); |
5839 | /* copy down the masked state */ |
5840 | prev->masked_scontext = stack->masked_scontext; |
5841 | if (prev->state == GUC_SET_LOCAL) |
5842 | discard_stack_value(gconf, &prev->masked); |
5843 | prev->masked = stack->masked; |
5844 | prev->state = GUC_SET_LOCAL; |
5845 | break; |
5846 | } |
5847 | } |
5848 | |
5849 | changed = false; |
5850 | |
5851 | if (restorePrior || restoreMasked) |
5852 | { |
5853 | /* Perform appropriate restoration of the stacked value */ |
5854 | config_var_value newvalue; |
5855 | GucSource newsource; |
5856 | GucContext newscontext; |
5857 | |
5858 | if (restoreMasked) |
5859 | { |
5860 | newvalue = stack->masked; |
5861 | newsource = PGC_S_SESSION; |
5862 | newscontext = stack->masked_scontext; |
5863 | } |
5864 | else |
5865 | { |
5866 | newvalue = stack->prior; |
5867 | newsource = stack->source; |
5868 | newscontext = stack->scontext; |
5869 | } |
5870 | |
5871 | switch (gconf->vartype) |
5872 | { |
5873 | case PGC_BOOL: |
5874 | { |
5875 | struct config_bool *conf = (struct config_bool *) gconf; |
5876 | bool newval = newvalue.val.boolval; |
5877 | void * = newvalue.extra; |
5878 | |
5879 | if (*conf->variable != newval || |
5880 | conf->gen.extra != newextra) |
5881 | { |
5882 | if (conf->assign_hook) |
5883 | conf->assign_hook(newval, newextra); |
5884 | *conf->variable = newval; |
5885 | set_extra_field(&conf->gen, &conf->gen.extra, |
5886 | newextra); |
5887 | changed = true; |
5888 | } |
5889 | break; |
5890 | } |
5891 | case PGC_INT: |
5892 | { |
5893 | struct config_int *conf = (struct config_int *) gconf; |
5894 | int newval = newvalue.val.intval; |
5895 | void * = newvalue.extra; |
5896 | |
5897 | if (*conf->variable != newval || |
5898 | conf->gen.extra != newextra) |
5899 | { |
5900 | if (conf->assign_hook) |
5901 | conf->assign_hook(newval, newextra); |
5902 | *conf->variable = newval; |
5903 | set_extra_field(&conf->gen, &conf->gen.extra, |
5904 | newextra); |
5905 | changed = true; |
5906 | } |
5907 | break; |
5908 | } |
5909 | case PGC_REAL: |
5910 | { |
5911 | struct config_real *conf = (struct config_real *) gconf; |
5912 | double newval = newvalue.val.realval; |
5913 | void * = newvalue.extra; |
5914 | |
5915 | if (*conf->variable != newval || |
5916 | conf->gen.extra != newextra) |
5917 | { |
5918 | if (conf->assign_hook) |
5919 | conf->assign_hook(newval, newextra); |
5920 | *conf->variable = newval; |
5921 | set_extra_field(&conf->gen, &conf->gen.extra, |
5922 | newextra); |
5923 | changed = true; |
5924 | } |
5925 | break; |
5926 | } |
5927 | case PGC_STRING: |
5928 | { |
5929 | struct config_string *conf = (struct config_string *) gconf; |
5930 | char *newval = newvalue.val.stringval; |
5931 | void * = newvalue.extra; |
5932 | |
5933 | if (*conf->variable != newval || |
5934 | conf->gen.extra != newextra) |
5935 | { |
5936 | if (conf->assign_hook) |
5937 | conf->assign_hook(newval, newextra); |
5938 | set_string_field(conf, conf->variable, newval); |
5939 | set_extra_field(&conf->gen, &conf->gen.extra, |
5940 | newextra); |
5941 | changed = true; |
5942 | } |
5943 | |
5944 | /* |
5945 | * Release stacked values if not used anymore. We |
5946 | * could use discard_stack_value() here, but since |
5947 | * we have type-specific code anyway, might as |
5948 | * well inline it. |
5949 | */ |
5950 | set_string_field(conf, &stack->prior.val.stringval, NULL); |
5951 | set_string_field(conf, &stack->masked.val.stringval, NULL); |
5952 | break; |
5953 | } |
5954 | case PGC_ENUM: |
5955 | { |
5956 | struct config_enum *conf = (struct config_enum *) gconf; |
5957 | int newval = newvalue.val.enumval; |
5958 | void * = newvalue.extra; |
5959 | |
5960 | if (*conf->variable != newval || |
5961 | conf->gen.extra != newextra) |
5962 | { |
5963 | if (conf->assign_hook) |
5964 | conf->assign_hook(newval, newextra); |
5965 | *conf->variable = newval; |
5966 | set_extra_field(&conf->gen, &conf->gen.extra, |
5967 | newextra); |
5968 | changed = true; |
5969 | } |
5970 | break; |
5971 | } |
5972 | } |
5973 | |
5974 | /* |
5975 | * Release stacked extra values if not used anymore. |
5976 | */ |
5977 | set_extra_field(gconf, &(stack->prior.extra), NULL); |
5978 | set_extra_field(gconf, &(stack->masked.extra), NULL); |
5979 | |
5980 | /* And restore source information */ |
5981 | gconf->source = newsource; |
5982 | gconf->scontext = newscontext; |
5983 | } |
5984 | |
5985 | /* Finish popping the state stack */ |
5986 | gconf->stack = prev; |
5987 | pfree(stack); |
5988 | |
5989 | /* Report new value if we changed it */ |
5990 | if (changed && (gconf->flags & GUC_REPORT)) |
5991 | ReportGUCOption(gconf); |
5992 | } /* end of stack-popping loop */ |
5993 | |
5994 | if (stack != NULL) |
5995 | still_dirty = true; |
5996 | } |
5997 | |
5998 | /* If there are no remaining stack entries, we can reset guc_dirty */ |
5999 | guc_dirty = still_dirty; |
6000 | |
6001 | /* Update nesting level */ |
6002 | GUCNestLevel = nestLevel - 1; |
6003 | } |
6004 | |
6005 | |
6006 | /* |
6007 | * Start up automatic reporting of changes to variables marked GUC_REPORT. |
6008 | * This is executed at completion of backend startup. |
6009 | */ |
6010 | void |
6011 | BeginReportingGUCOptions(void) |
6012 | { |
6013 | int i; |
6014 | |
6015 | /* |
6016 | * Don't do anything unless talking to an interactive frontend of protocol |
6017 | * 3.0 or later. |
6018 | */ |
6019 | if (whereToSendOutput != DestRemote || |
6020 | PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) |
6021 | return; |
6022 | |
6023 | reporting_enabled = true; |
6024 | |
6025 | /* Transmit initial values of interesting variables */ |
6026 | for (i = 0; i < num_guc_variables; i++) |
6027 | { |
6028 | struct config_generic *conf = guc_variables[i]; |
6029 | |
6030 | if (conf->flags & GUC_REPORT) |
6031 | ReportGUCOption(conf); |
6032 | } |
6033 | } |
6034 | |
6035 | /* |
6036 | * ReportGUCOption: if appropriate, transmit option value to frontend |
6037 | */ |
6038 | static void |
6039 | ReportGUCOption(struct config_generic *record) |
6040 | { |
6041 | if (reporting_enabled && (record->flags & GUC_REPORT)) |
6042 | { |
6043 | char *val = _ShowOption(record, false); |
6044 | StringInfoData msgbuf; |
6045 | |
6046 | pq_beginmessage(&msgbuf, 'S'); |
6047 | pq_sendstring(&msgbuf, record->name); |
6048 | pq_sendstring(&msgbuf, val); |
6049 | pq_endmessage(&msgbuf); |
6050 | |
6051 | pfree(val); |
6052 | } |
6053 | } |
6054 | |
6055 | /* |
6056 | * Convert a value from one of the human-friendly units ("kB", "min" etc.) |
6057 | * to the given base unit. 'value' and 'unit' are the input value and unit |
6058 | * to convert from (there can be trailing spaces in the unit string). |
6059 | * The converted value is stored in *base_value. |
6060 | * It's caller's responsibility to round off the converted value as necessary |
6061 | * and check for out-of-range. |
6062 | * |
6063 | * Returns true on success, false if the input unit is not recognized. |
6064 | */ |
6065 | static bool |
6066 | convert_to_base_unit(double value, const char *unit, |
6067 | int base_unit, double *base_value) |
6068 | { |
6069 | char unitstr[MAX_UNIT_LEN + 1]; |
6070 | int unitlen; |
6071 | const unit_conversion *table; |
6072 | int i; |
6073 | |
6074 | /* extract unit string to compare to table entries */ |
6075 | unitlen = 0; |
6076 | while (*unit != '\0' && !isspace((unsigned char) *unit) && |
6077 | unitlen < MAX_UNIT_LEN) |
6078 | unitstr[unitlen++] = *(unit++); |
6079 | unitstr[unitlen] = '\0'; |
6080 | /* allow whitespace after unit */ |
6081 | while (isspace((unsigned char) *unit)) |
6082 | unit++; |
6083 | if (*unit != '\0') |
6084 | return false; /* unit too long, or garbage after it */ |
6085 | |
6086 | /* now search the appropriate table */ |
6087 | if (base_unit & GUC_UNIT_MEMORY) |
6088 | table = memory_unit_conversion_table; |
6089 | else |
6090 | table = time_unit_conversion_table; |
6091 | |
6092 | for (i = 0; *table[i].unit; i++) |
6093 | { |
6094 | if (base_unit == table[i].base_unit && |
6095 | strcmp(unitstr, table[i].unit) == 0) |
6096 | { |
6097 | double cvalue = value * table[i].multiplier; |
6098 | |
6099 | /* |
6100 | * If the user gave a fractional value such as "30.1GB", round it |
6101 | * off to the nearest multiple of the next smaller unit, if there |
6102 | * is one. |
6103 | */ |
6104 | if (*table[i + 1].unit && |
6105 | base_unit == table[i + 1].base_unit) |
6106 | cvalue = rint(cvalue / table[i + 1].multiplier) * |
6107 | table[i + 1].multiplier; |
6108 | |
6109 | *base_value = cvalue; |
6110 | return true; |
6111 | } |
6112 | } |
6113 | return false; |
6114 | } |
6115 | |
6116 | /* |
6117 | * Convert an integer value in some base unit to a human-friendly unit. |
6118 | * |
6119 | * The output unit is chosen so that it's the greatest unit that can represent |
6120 | * the value without loss. For example, if the base unit is GUC_UNIT_KB, 1024 |
6121 | * is converted to 1 MB, but 1025 is represented as 1025 kB. |
6122 | */ |
6123 | static void |
6124 | convert_int_from_base_unit(int64 base_value, int base_unit, |
6125 | int64 *value, const char **unit) |
6126 | { |
6127 | const unit_conversion *table; |
6128 | int i; |
6129 | |
6130 | *unit = NULL; |
6131 | |
6132 | if (base_unit & GUC_UNIT_MEMORY) |
6133 | table = memory_unit_conversion_table; |
6134 | else |
6135 | table = time_unit_conversion_table; |
6136 | |
6137 | for (i = 0; *table[i].unit; i++) |
6138 | { |
6139 | if (base_unit == table[i].base_unit) |
6140 | { |
6141 | /* |
6142 | * Accept the first conversion that divides the value evenly. We |
6143 | * assume that the conversions for each base unit are ordered from |
6144 | * greatest unit to the smallest! |
6145 | */ |
6146 | if (table[i].multiplier <= 1.0 || |
6147 | base_value % (int64) table[i].multiplier == 0) |
6148 | { |
6149 | *value = (int64) rint(base_value / table[i].multiplier); |
6150 | *unit = table[i].unit; |
6151 | break; |
6152 | } |
6153 | } |
6154 | } |
6155 | |
6156 | Assert(*unit != NULL); |
6157 | } |
6158 | |
6159 | /* |
6160 | * Convert a floating-point value in some base unit to a human-friendly unit. |
6161 | * |
6162 | * Same as above, except we have to do the math a bit differently, and |
6163 | * there's a possibility that we don't find any exact divisor. |
6164 | */ |
6165 | static void |
6166 | convert_real_from_base_unit(double base_value, int base_unit, |
6167 | double *value, const char **unit) |
6168 | { |
6169 | const unit_conversion *table; |
6170 | int i; |
6171 | |
6172 | *unit = NULL; |
6173 | |
6174 | if (base_unit & GUC_UNIT_MEMORY) |
6175 | table = memory_unit_conversion_table; |
6176 | else |
6177 | table = time_unit_conversion_table; |
6178 | |
6179 | for (i = 0; *table[i].unit; i++) |
6180 | { |
6181 | if (base_unit == table[i].base_unit) |
6182 | { |
6183 | /* |
6184 | * Accept the first conversion that divides the value evenly; or |
6185 | * if there is none, use the smallest (last) target unit. |
6186 | * |
6187 | * What we actually care about here is whether snprintf with "%g" |
6188 | * will print the value as an integer, so the obvious test of |
6189 | * "*value == rint(*value)" is too strict; roundoff error might |
6190 | * make us choose an unreasonably small unit. As a compromise, |
6191 | * accept a divisor that is within 1e-8 of producing an integer. |
6192 | */ |
6193 | *value = base_value / table[i].multiplier; |
6194 | *unit = table[i].unit; |
6195 | if (*value > 0 && |
6196 | fabs((rint(*value) / *value) - 1.0) <= 1e-8) |
6197 | break; |
6198 | } |
6199 | } |
6200 | |
6201 | Assert(*unit != NULL); |
6202 | } |
6203 | |
6204 | /* |
6205 | * Return the name of a GUC's base unit (e.g. "ms") given its flags. |
6206 | * Return NULL if the GUC is unitless. |
6207 | */ |
6208 | static const char * |
6209 | get_config_unit_name(int flags) |
6210 | { |
6211 | switch (flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)) |
6212 | { |
6213 | case 0: |
6214 | return NULL; /* GUC has no units */ |
6215 | case GUC_UNIT_BYTE: |
6216 | return "B" ; |
6217 | case GUC_UNIT_KB: |
6218 | return "kB" ; |
6219 | case GUC_UNIT_MB: |
6220 | return "MB" ; |
6221 | case GUC_UNIT_BLOCKS: |
6222 | { |
6223 | static char bbuf[8]; |
6224 | |
6225 | /* initialize if first time through */ |
6226 | if (bbuf[0] == '\0') |
6227 | snprintf(bbuf, sizeof(bbuf), "%dkB" , BLCKSZ / 1024); |
6228 | return bbuf; |
6229 | } |
6230 | case GUC_UNIT_XBLOCKS: |
6231 | { |
6232 | static char xbuf[8]; |
6233 | |
6234 | /* initialize if first time through */ |
6235 | if (xbuf[0] == '\0') |
6236 | snprintf(xbuf, sizeof(xbuf), "%dkB" , XLOG_BLCKSZ / 1024); |
6237 | return xbuf; |
6238 | } |
6239 | case GUC_UNIT_MS: |
6240 | return "ms" ; |
6241 | case GUC_UNIT_S: |
6242 | return "s" ; |
6243 | case GUC_UNIT_MIN: |
6244 | return "min" ; |
6245 | default: |
6246 | elog(ERROR, "unrecognized GUC units value: %d" , |
6247 | flags & (GUC_UNIT_MEMORY | GUC_UNIT_TIME)); |
6248 | return NULL; |
6249 | } |
6250 | } |
6251 | |
6252 | |
6253 | /* |
6254 | * Try to parse value as an integer. The accepted formats are the |
6255 | * usual decimal, octal, or hexadecimal formats, as well as floating-point |
6256 | * formats (which will be rounded to integer after any units conversion). |
6257 | * Optionally, the value can be followed by a unit name if "flags" indicates |
6258 | * a unit is allowed. |
6259 | * |
6260 | * If the string parses okay, return true, else false. |
6261 | * If okay and result is not NULL, return the value in *result. |
6262 | * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable |
6263 | * HINT message, or NULL if no hint provided. |
6264 | */ |
6265 | bool |
6266 | parse_int(const char *value, int *result, int flags, const char **hintmsg) |
6267 | { |
6268 | /* |
6269 | * We assume here that double is wide enough to represent any integer |
6270 | * value with adequate precision. |
6271 | */ |
6272 | double val; |
6273 | char *endptr; |
6274 | |
6275 | /* To suppress compiler warnings, always set output params */ |
6276 | if (result) |
6277 | *result = 0; |
6278 | if (hintmsg) |
6279 | *hintmsg = NULL; |
6280 | |
6281 | /* |
6282 | * Try to parse as an integer (allowing octal or hex input). If the |
6283 | * conversion stops at a decimal point or 'e', or overflows, re-parse as |
6284 | * float. This should work fine as long as we have no unit names starting |
6285 | * with 'e'. If we ever do, the test could be extended to check for a |
6286 | * sign or digit after 'e', but for now that's unnecessary. |
6287 | */ |
6288 | errno = 0; |
6289 | val = strtol(value, &endptr, 0); |
6290 | if (*endptr == '.' || *endptr == 'e' || *endptr == 'E' || |
6291 | errno == ERANGE) |
6292 | { |
6293 | errno = 0; |
6294 | val = strtod(value, &endptr); |
6295 | } |
6296 | |
6297 | if (endptr == value || errno == ERANGE) |
6298 | return false; /* no HINT for these cases */ |
6299 | |
6300 | /* reject NaN (infinities will fail range check below) */ |
6301 | if (isnan(val)) |
6302 | return false; /* treat same as syntax error; no HINT */ |
6303 | |
6304 | /* allow whitespace between number and unit */ |
6305 | while (isspace((unsigned char) *endptr)) |
6306 | endptr++; |
6307 | |
6308 | /* Handle possible unit */ |
6309 | if (*endptr != '\0') |
6310 | { |
6311 | if ((flags & GUC_UNIT) == 0) |
6312 | return false; /* this setting does not accept a unit */ |
6313 | |
6314 | if (!convert_to_base_unit(val, |
6315 | endptr, (flags & GUC_UNIT), |
6316 | &val)) |
6317 | { |
6318 | /* invalid unit, or garbage after the unit; set hint and fail. */ |
6319 | if (hintmsg) |
6320 | { |
6321 | if (flags & GUC_UNIT_MEMORY) |
6322 | *hintmsg = memory_units_hint; |
6323 | else |
6324 | *hintmsg = time_units_hint; |
6325 | } |
6326 | return false; |
6327 | } |
6328 | } |
6329 | |
6330 | /* Round to int, then check for overflow */ |
6331 | val = rint(val); |
6332 | |
6333 | if (val > INT_MAX || val < INT_MIN) |
6334 | { |
6335 | if (hintmsg) |
6336 | *hintmsg = gettext_noop("Value exceeds integer range." ); |
6337 | return false; |
6338 | } |
6339 | |
6340 | if (result) |
6341 | *result = (int) val; |
6342 | return true; |
6343 | } |
6344 | |
6345 | /* |
6346 | * Try to parse value as a floating point number in the usual format. |
6347 | * Optionally, the value can be followed by a unit name if "flags" indicates |
6348 | * a unit is allowed. |
6349 | * |
6350 | * If the string parses okay, return true, else false. |
6351 | * If okay and result is not NULL, return the value in *result. |
6352 | * If not okay and hintmsg is not NULL, *hintmsg is set to a suitable |
6353 | * HINT message, or NULL if no hint provided. |
6354 | */ |
6355 | bool |
6356 | parse_real(const char *value, double *result, int flags, const char **hintmsg) |
6357 | { |
6358 | double val; |
6359 | char *endptr; |
6360 | |
6361 | /* To suppress compiler warnings, always set output params */ |
6362 | if (result) |
6363 | *result = 0; |
6364 | if (hintmsg) |
6365 | *hintmsg = NULL; |
6366 | |
6367 | errno = 0; |
6368 | val = strtod(value, &endptr); |
6369 | |
6370 | if (endptr == value || errno == ERANGE) |
6371 | return false; /* no HINT for these cases */ |
6372 | |
6373 | /* reject NaN (infinities will fail range checks later) */ |
6374 | if (isnan(val)) |
6375 | return false; /* treat same as syntax error; no HINT */ |
6376 | |
6377 | /* allow whitespace between number and unit */ |
6378 | while (isspace((unsigned char) *endptr)) |
6379 | endptr++; |
6380 | |
6381 | /* Handle possible unit */ |
6382 | if (*endptr != '\0') |
6383 | { |
6384 | if ((flags & GUC_UNIT) == 0) |
6385 | return false; /* this setting does not accept a unit */ |
6386 | |
6387 | if (!convert_to_base_unit(val, |
6388 | endptr, (flags & GUC_UNIT), |
6389 | &val)) |
6390 | { |
6391 | /* invalid unit, or garbage after the unit; set hint and fail. */ |
6392 | if (hintmsg) |
6393 | { |
6394 | if (flags & GUC_UNIT_MEMORY) |
6395 | *hintmsg = memory_units_hint; |
6396 | else |
6397 | *hintmsg = time_units_hint; |
6398 | } |
6399 | return false; |
6400 | } |
6401 | } |
6402 | |
6403 | if (result) |
6404 | *result = val; |
6405 | return true; |
6406 | } |
6407 | |
6408 | |
6409 | /* |
6410 | * Lookup the name for an enum option with the selected value. |
6411 | * Should only ever be called with known-valid values, so throws |
6412 | * an elog(ERROR) if the enum option is not found. |
6413 | * |
6414 | * The returned string is a pointer to static data and not |
6415 | * allocated for modification. |
6416 | */ |
6417 | const char * |
6418 | config_enum_lookup_by_value(struct config_enum *record, int val) |
6419 | { |
6420 | const struct config_enum_entry *entry; |
6421 | |
6422 | for (entry = record->options; entry && entry->name; entry++) |
6423 | { |
6424 | if (entry->val == val) |
6425 | return entry->name; |
6426 | } |
6427 | |
6428 | elog(ERROR, "could not find enum option %d for %s" , |
6429 | val, record->gen.name); |
6430 | return NULL; /* silence compiler */ |
6431 | } |
6432 | |
6433 | |
6434 | /* |
6435 | * Lookup the value for an enum option with the selected name |
6436 | * (case-insensitive). |
6437 | * If the enum option is found, sets the retval value and returns |
6438 | * true. If it's not found, return false and retval is set to 0. |
6439 | */ |
6440 | bool |
6441 | config_enum_lookup_by_name(struct config_enum *record, const char *value, |
6442 | int *retval) |
6443 | { |
6444 | const struct config_enum_entry *entry; |
6445 | |
6446 | for (entry = record->options; entry && entry->name; entry++) |
6447 | { |
6448 | if (pg_strcasecmp(value, entry->name) == 0) |
6449 | { |
6450 | *retval = entry->val; |
6451 | return true; |
6452 | } |
6453 | } |
6454 | |
6455 | *retval = 0; |
6456 | return false; |
6457 | } |
6458 | |
6459 | |
6460 | /* |
6461 | * Return a list of all available options for an enum, excluding |
6462 | * hidden ones, separated by the given separator. |
6463 | * If prefix is non-NULL, it is added before the first enum value. |
6464 | * If suffix is non-NULL, it is added to the end of the string. |
6465 | */ |
6466 | static char * |
6467 | config_enum_get_options(struct config_enum *record, const char *prefix, |
6468 | const char *suffix, const char *separator) |
6469 | { |
6470 | const struct config_enum_entry *entry; |
6471 | StringInfoData retstr; |
6472 | int seplen; |
6473 | |
6474 | initStringInfo(&retstr); |
6475 | appendStringInfoString(&retstr, prefix); |
6476 | |
6477 | seplen = strlen(separator); |
6478 | for (entry = record->options; entry && entry->name; entry++) |
6479 | { |
6480 | if (!entry->hidden) |
6481 | { |
6482 | appendStringInfoString(&retstr, entry->name); |
6483 | appendBinaryStringInfo(&retstr, separator, seplen); |
6484 | } |
6485 | } |
6486 | |
6487 | /* |
6488 | * All the entries may have been hidden, leaving the string empty if no |
6489 | * prefix was given. This indicates a broken GUC setup, since there is no |
6490 | * use for an enum without any values, so we just check to make sure we |
6491 | * don't write to invalid memory instead of actually trying to do |
6492 | * something smart with it. |
6493 | */ |
6494 | if (retstr.len >= seplen) |
6495 | { |
6496 | /* Replace final separator */ |
6497 | retstr.data[retstr.len - seplen] = '\0'; |
6498 | retstr.len -= seplen; |
6499 | } |
6500 | |
6501 | appendStringInfoString(&retstr, suffix); |
6502 | |
6503 | return retstr.data; |
6504 | } |
6505 | |
6506 | /* |
6507 | * Parse and validate a proposed value for the specified configuration |
6508 | * parameter. |
6509 | * |
6510 | * This does built-in checks (such as range limits for an integer parameter) |
6511 | * and also calls any check hook the parameter may have. |
6512 | * |
6513 | * record: GUC variable's info record |
6514 | * name: variable name (should match the record of course) |
6515 | * value: proposed value, as a string |
6516 | * source: identifies source of value (check hooks may need this) |
6517 | * elevel: level to log any error reports at |
6518 | * newval: on success, converted parameter value is returned here |
6519 | * newextra: on success, receives any "extra" data returned by check hook |
6520 | * (caller must initialize *newextra to NULL) |
6521 | * |
6522 | * Returns true if OK, false if not (or throws error, if elevel >= ERROR) |
6523 | */ |
6524 | static bool |
6525 | parse_and_validate_value(struct config_generic *record, |
6526 | const char *name, const char *value, |
6527 | GucSource source, int elevel, |
6528 | union config_var_val *newval, void **) |
6529 | { |
6530 | switch (record->vartype) |
6531 | { |
6532 | case PGC_BOOL: |
6533 | { |
6534 | struct config_bool *conf = (struct config_bool *) record; |
6535 | |
6536 | if (!parse_bool(value, &newval->boolval)) |
6537 | { |
6538 | ereport(elevel, |
6539 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6540 | errmsg("parameter \"%s\" requires a Boolean value" , |
6541 | name))); |
6542 | return false; |
6543 | } |
6544 | |
6545 | if (!call_bool_check_hook(conf, &newval->boolval, newextra, |
6546 | source, elevel)) |
6547 | return false; |
6548 | } |
6549 | break; |
6550 | case PGC_INT: |
6551 | { |
6552 | struct config_int *conf = (struct config_int *) record; |
6553 | const char *hintmsg; |
6554 | |
6555 | if (!parse_int(value, &newval->intval, |
6556 | conf->gen.flags, &hintmsg)) |
6557 | { |
6558 | ereport(elevel, |
6559 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6560 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
6561 | name, value), |
6562 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
6563 | return false; |
6564 | } |
6565 | |
6566 | if (newval->intval < conf->min || newval->intval > conf->max) |
6567 | { |
6568 | const char *unit = get_config_unit_name(conf->gen.flags); |
6569 | |
6570 | ereport(elevel, |
6571 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6572 | errmsg("%d%s%s is outside the valid range for parameter \"%s\" (%d .. %d)" , |
6573 | newval->intval, |
6574 | unit ? " " : "" , |
6575 | unit ? unit : "" , |
6576 | name, |
6577 | conf->min, conf->max))); |
6578 | return false; |
6579 | } |
6580 | |
6581 | if (!call_int_check_hook(conf, &newval->intval, newextra, |
6582 | source, elevel)) |
6583 | return false; |
6584 | } |
6585 | break; |
6586 | case PGC_REAL: |
6587 | { |
6588 | struct config_real *conf = (struct config_real *) record; |
6589 | const char *hintmsg; |
6590 | |
6591 | if (!parse_real(value, &newval->realval, |
6592 | conf->gen.flags, &hintmsg)) |
6593 | { |
6594 | ereport(elevel, |
6595 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6596 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
6597 | name, value), |
6598 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
6599 | return false; |
6600 | } |
6601 | |
6602 | if (newval->realval < conf->min || newval->realval > conf->max) |
6603 | { |
6604 | const char *unit = get_config_unit_name(conf->gen.flags); |
6605 | |
6606 | ereport(elevel, |
6607 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6608 | errmsg("%g%s%s is outside the valid range for parameter \"%s\" (%g .. %g)" , |
6609 | newval->realval, |
6610 | unit ? " " : "" , |
6611 | unit ? unit : "" , |
6612 | name, |
6613 | conf->min, conf->max))); |
6614 | return false; |
6615 | } |
6616 | |
6617 | if (!call_real_check_hook(conf, &newval->realval, newextra, |
6618 | source, elevel)) |
6619 | return false; |
6620 | } |
6621 | break; |
6622 | case PGC_STRING: |
6623 | { |
6624 | struct config_string *conf = (struct config_string *) record; |
6625 | |
6626 | /* |
6627 | * The value passed by the caller could be transient, so we |
6628 | * always strdup it. |
6629 | */ |
6630 | newval->stringval = guc_strdup(elevel, value); |
6631 | if (newval->stringval == NULL) |
6632 | return false; |
6633 | |
6634 | /* |
6635 | * The only built-in "parsing" check we have is to apply |
6636 | * truncation if GUC_IS_NAME. |
6637 | */ |
6638 | if (conf->gen.flags & GUC_IS_NAME) |
6639 | truncate_identifier(newval->stringval, |
6640 | strlen(newval->stringval), |
6641 | true); |
6642 | |
6643 | if (!call_string_check_hook(conf, &newval->stringval, newextra, |
6644 | source, elevel)) |
6645 | { |
6646 | free(newval->stringval); |
6647 | newval->stringval = NULL; |
6648 | return false; |
6649 | } |
6650 | } |
6651 | break; |
6652 | case PGC_ENUM: |
6653 | { |
6654 | struct config_enum *conf = (struct config_enum *) record; |
6655 | |
6656 | if (!config_enum_lookup_by_name(conf, value, &newval->enumval)) |
6657 | { |
6658 | char *hintmsg; |
6659 | |
6660 | hintmsg = config_enum_get_options(conf, |
6661 | "Available values: " , |
6662 | "." , ", " ); |
6663 | |
6664 | ereport(elevel, |
6665 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
6666 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
6667 | name, value), |
6668 | hintmsg ? errhint("%s" , _(hintmsg)) : 0)); |
6669 | |
6670 | if (hintmsg) |
6671 | pfree(hintmsg); |
6672 | return false; |
6673 | } |
6674 | |
6675 | if (!call_enum_check_hook(conf, &newval->enumval, newextra, |
6676 | source, elevel)) |
6677 | return false; |
6678 | } |
6679 | break; |
6680 | } |
6681 | |
6682 | return true; |
6683 | } |
6684 | |
6685 | |
6686 | /* |
6687 | * Sets option `name' to given value. |
6688 | * |
6689 | * The value should be a string, which will be parsed and converted to |
6690 | * the appropriate data type. The context and source parameters indicate |
6691 | * in which context this function is being called, so that it can apply the |
6692 | * access restrictions properly. |
6693 | * |
6694 | * If value is NULL, set the option to its default value (normally the |
6695 | * reset_val, but if source == PGC_S_DEFAULT we instead use the boot_val). |
6696 | * |
6697 | * action indicates whether to set the value globally in the session, locally |
6698 | * to the current top transaction, or just for the duration of a function call. |
6699 | * |
6700 | * If changeVal is false then don't really set the option but do all |
6701 | * the checks to see if it would work. |
6702 | * |
6703 | * elevel should normally be passed as zero, allowing this function to make |
6704 | * its standard choice of ereport level. However some callers need to be |
6705 | * able to override that choice; they should pass the ereport level to use. |
6706 | * |
6707 | * Return value: |
6708 | * +1: the value is valid and was successfully applied. |
6709 | * 0: the name or value is invalid (but see below). |
6710 | * -1: the value was not applied because of context, priority, or changeVal. |
6711 | * |
6712 | * If there is an error (non-existing option, invalid value) then an |
6713 | * ereport(ERROR) is thrown *unless* this is called for a source for which |
6714 | * we don't want an ERROR (currently, those are defaults, the config file, |
6715 | * and per-database or per-user settings, as well as callers who specify |
6716 | * a less-than-ERROR elevel). In those cases we write a suitable error |
6717 | * message via ereport() and return 0. |
6718 | * |
6719 | * See also SetConfigOption for an external interface. |
6720 | */ |
6721 | int |
6722 | set_config_option(const char *name, const char *value, |
6723 | GucContext context, GucSource source, |
6724 | GucAction action, bool changeVal, int elevel, |
6725 | bool is_reload) |
6726 | { |
6727 | struct config_generic *record; |
6728 | union config_var_val newval_union; |
6729 | void * = NULL; |
6730 | bool prohibitValueChange = false; |
6731 | bool makeDefault; |
6732 | |
6733 | if (elevel == 0) |
6734 | { |
6735 | if (source == PGC_S_DEFAULT || source == PGC_S_FILE) |
6736 | { |
6737 | /* |
6738 | * To avoid cluttering the log, only the postmaster bleats loudly |
6739 | * about problems with the config file. |
6740 | */ |
6741 | elevel = IsUnderPostmaster ? DEBUG3 : LOG; |
6742 | } |
6743 | else if (source == PGC_S_GLOBAL || |
6744 | source == PGC_S_DATABASE || |
6745 | source == PGC_S_USER || |
6746 | source == PGC_S_DATABASE_USER) |
6747 | elevel = WARNING; |
6748 | else |
6749 | elevel = ERROR; |
6750 | } |
6751 | |
6752 | /* |
6753 | * GUC_ACTION_SAVE changes are acceptable during a parallel operation, |
6754 | * because the current worker will also pop the change. We're probably |
6755 | * dealing with a function having a proconfig entry. Only the function's |
6756 | * body should observe the change, and peer workers do not share in the |
6757 | * execution of a function call started by this worker. |
6758 | * |
6759 | * Other changes might need to affect other workers, so forbid them. |
6760 | */ |
6761 | if (IsInParallelMode() && changeVal && action != GUC_ACTION_SAVE) |
6762 | ereport(elevel, |
6763 | (errcode(ERRCODE_INVALID_TRANSACTION_STATE), |
6764 | errmsg("cannot set parameters during a parallel operation" ))); |
6765 | |
6766 | record = find_option(name, true, elevel); |
6767 | if (record == NULL) |
6768 | { |
6769 | ereport(elevel, |
6770 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
6771 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
6772 | return 0; |
6773 | } |
6774 | |
6775 | /* |
6776 | * Check if the option can be set at this time. See guc.h for the precise |
6777 | * rules. |
6778 | */ |
6779 | switch (record->context) |
6780 | { |
6781 | case PGC_INTERNAL: |
6782 | if (context != PGC_INTERNAL) |
6783 | { |
6784 | ereport(elevel, |
6785 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
6786 | errmsg("parameter \"%s\" cannot be changed" , |
6787 | name))); |
6788 | return 0; |
6789 | } |
6790 | break; |
6791 | case PGC_POSTMASTER: |
6792 | if (context == PGC_SIGHUP) |
6793 | { |
6794 | /* |
6795 | * We are re-reading a PGC_POSTMASTER variable from |
6796 | * postgresql.conf. We can't change the setting, so we should |
6797 | * give a warning if the DBA tries to change it. However, |
6798 | * because of variant formats, canonicalization by check |
6799 | * hooks, etc, we can't just compare the given string directly |
6800 | * to what's stored. Set a flag to check below after we have |
6801 | * the final storable value. |
6802 | */ |
6803 | prohibitValueChange = true; |
6804 | } |
6805 | else if (context != PGC_POSTMASTER) |
6806 | { |
6807 | ereport(elevel, |
6808 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
6809 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
6810 | name))); |
6811 | return 0; |
6812 | } |
6813 | break; |
6814 | case PGC_SIGHUP: |
6815 | if (context != PGC_SIGHUP && context != PGC_POSTMASTER) |
6816 | { |
6817 | ereport(elevel, |
6818 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
6819 | errmsg("parameter \"%s\" cannot be changed now" , |
6820 | name))); |
6821 | return 0; |
6822 | } |
6823 | |
6824 | /* |
6825 | * Hmm, the idea of the SIGHUP context is "ought to be global, but |
6826 | * can be changed after postmaster start". But there's nothing |
6827 | * that prevents a crafty administrator from sending SIGHUP |
6828 | * signals to individual backends only. |
6829 | */ |
6830 | break; |
6831 | case PGC_SU_BACKEND: |
6832 | /* Reject if we're connecting but user is not superuser */ |
6833 | if (context == PGC_BACKEND) |
6834 | { |
6835 | ereport(elevel, |
6836 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
6837 | errmsg("permission denied to set parameter \"%s\"" , |
6838 | name))); |
6839 | return 0; |
6840 | } |
6841 | /* fall through to process the same as PGC_BACKEND */ |
6842 | /* FALLTHROUGH */ |
6843 | case PGC_BACKEND: |
6844 | if (context == PGC_SIGHUP) |
6845 | { |
6846 | /* |
6847 | * If a PGC_BACKEND or PGC_SU_BACKEND parameter is changed in |
6848 | * the config file, we want to accept the new value in the |
6849 | * postmaster (whence it will propagate to |
6850 | * subsequently-started backends), but ignore it in existing |
6851 | * backends. This is a tad klugy, but necessary because we |
6852 | * don't re-read the config file during backend start. |
6853 | * |
6854 | * In EXEC_BACKEND builds, this works differently: we load all |
6855 | * non-default settings from the CONFIG_EXEC_PARAMS file |
6856 | * during backend start. In that case we must accept |
6857 | * PGC_SIGHUP settings, so as to have the same value as if |
6858 | * we'd forked from the postmaster. This can also happen when |
6859 | * using RestoreGUCState() within a background worker that |
6860 | * needs to have the same settings as the user backend that |
6861 | * started it. is_reload will be true when either situation |
6862 | * applies. |
6863 | */ |
6864 | if (IsUnderPostmaster && !is_reload) |
6865 | return -1; |
6866 | } |
6867 | else if (context != PGC_POSTMASTER && |
6868 | context != PGC_BACKEND && |
6869 | context != PGC_SU_BACKEND && |
6870 | source != PGC_S_CLIENT) |
6871 | { |
6872 | ereport(elevel, |
6873 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
6874 | errmsg("parameter \"%s\" cannot be set after connection start" , |
6875 | name))); |
6876 | return 0; |
6877 | } |
6878 | break; |
6879 | case PGC_SUSET: |
6880 | if (context == PGC_USERSET || context == PGC_BACKEND) |
6881 | { |
6882 | ereport(elevel, |
6883 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
6884 | errmsg("permission denied to set parameter \"%s\"" , |
6885 | name))); |
6886 | return 0; |
6887 | } |
6888 | break; |
6889 | case PGC_USERSET: |
6890 | /* always okay */ |
6891 | break; |
6892 | } |
6893 | |
6894 | /* |
6895 | * Disallow changing GUC_NOT_WHILE_SEC_REST values if we are inside a |
6896 | * security restriction context. We can reject this regardless of the GUC |
6897 | * context or source, mainly because sources that it might be reasonable |
6898 | * to override for won't be seen while inside a function. |
6899 | * |
6900 | * Note: variables marked GUC_NOT_WHILE_SEC_REST should usually be marked |
6901 | * GUC_NO_RESET_ALL as well, because ResetAllOptions() doesn't check this. |
6902 | * An exception might be made if the reset value is assumed to be "safe". |
6903 | * |
6904 | * Note: this flag is currently used for "session_authorization" and |
6905 | * "role". We need to prohibit changing these inside a local userid |
6906 | * context because when we exit it, GUC won't be notified, leaving things |
6907 | * out of sync. (This could be fixed by forcing a new GUC nesting level, |
6908 | * but that would change behavior in possibly-undesirable ways.) Also, we |
6909 | * prohibit changing these in a security-restricted operation because |
6910 | * otherwise RESET could be used to regain the session user's privileges. |
6911 | */ |
6912 | if (record->flags & GUC_NOT_WHILE_SEC_REST) |
6913 | { |
6914 | if (InLocalUserIdChange()) |
6915 | { |
6916 | /* |
6917 | * Phrasing of this error message is historical, but it's the most |
6918 | * common case. |
6919 | */ |
6920 | ereport(elevel, |
6921 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
6922 | errmsg("cannot set parameter \"%s\" within security-definer function" , |
6923 | name))); |
6924 | return 0; |
6925 | } |
6926 | if (InSecurityRestrictedOperation()) |
6927 | { |
6928 | ereport(elevel, |
6929 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
6930 | errmsg("cannot set parameter \"%s\" within security-restricted operation" , |
6931 | name))); |
6932 | return 0; |
6933 | } |
6934 | } |
6935 | |
6936 | /* |
6937 | * Should we set reset/stacked values? (If so, the behavior is not |
6938 | * transactional.) This is done either when we get a default value from |
6939 | * the database's/user's/client's default settings or when we reset a |
6940 | * value to its default. |
6941 | */ |
6942 | makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && |
6943 | ((value != NULL) || source == PGC_S_DEFAULT); |
6944 | |
6945 | /* |
6946 | * Ignore attempted set if overridden by previously processed setting. |
6947 | * However, if changeVal is false then plow ahead anyway since we are |
6948 | * trying to find out if the value is potentially good, not actually use |
6949 | * it. Also keep going if makeDefault is true, since we may want to set |
6950 | * the reset/stacked values even if we can't set the variable itself. |
6951 | */ |
6952 | if (record->source > source) |
6953 | { |
6954 | if (changeVal && !makeDefault) |
6955 | { |
6956 | elog(DEBUG3, "\"%s\": setting ignored because previous source is higher priority" , |
6957 | name); |
6958 | return -1; |
6959 | } |
6960 | changeVal = false; |
6961 | } |
6962 | |
6963 | /* |
6964 | * Evaluate value and set variable. |
6965 | */ |
6966 | switch (record->vartype) |
6967 | { |
6968 | case PGC_BOOL: |
6969 | { |
6970 | struct config_bool *conf = (struct config_bool *) record; |
6971 | |
6972 | #define newval (newval_union.boolval) |
6973 | |
6974 | if (value) |
6975 | { |
6976 | if (!parse_and_validate_value(record, name, value, |
6977 | source, elevel, |
6978 | &newval_union, &newextra)) |
6979 | return 0; |
6980 | } |
6981 | else if (source == PGC_S_DEFAULT) |
6982 | { |
6983 | newval = conf->boot_val; |
6984 | if (!call_bool_check_hook(conf, &newval, &newextra, |
6985 | source, elevel)) |
6986 | return 0; |
6987 | } |
6988 | else |
6989 | { |
6990 | newval = conf->reset_val; |
6991 | newextra = conf->reset_extra; |
6992 | source = conf->gen.reset_source; |
6993 | context = conf->gen.reset_scontext; |
6994 | } |
6995 | |
6996 | if (prohibitValueChange) |
6997 | { |
6998 | if (*conf->variable != newval) |
6999 | { |
7000 | record->status |= GUC_PENDING_RESTART; |
7001 | ereport(elevel, |
7002 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7003 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
7004 | name))); |
7005 | return 0; |
7006 | } |
7007 | record->status &= ~GUC_PENDING_RESTART; |
7008 | return -1; |
7009 | } |
7010 | |
7011 | if (changeVal) |
7012 | { |
7013 | /* Save old value to support transaction abort */ |
7014 | if (!makeDefault) |
7015 | push_old_value(&conf->gen, action); |
7016 | |
7017 | if (conf->assign_hook) |
7018 | conf->assign_hook(newval, newextra); |
7019 | *conf->variable = newval; |
7020 | set_extra_field(&conf->gen, &conf->gen.extra, |
7021 | newextra); |
7022 | conf->gen.source = source; |
7023 | conf->gen.scontext = context; |
7024 | } |
7025 | if (makeDefault) |
7026 | { |
7027 | GucStack *stack; |
7028 | |
7029 | if (conf->gen.reset_source <= source) |
7030 | { |
7031 | conf->reset_val = newval; |
7032 | set_extra_field(&conf->gen, &conf->reset_extra, |
7033 | newextra); |
7034 | conf->gen.reset_source = source; |
7035 | conf->gen.reset_scontext = context; |
7036 | } |
7037 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
7038 | { |
7039 | if (stack->source <= source) |
7040 | { |
7041 | stack->prior.val.boolval = newval; |
7042 | set_extra_field(&conf->gen, &stack->prior.extra, |
7043 | newextra); |
7044 | stack->source = source; |
7045 | stack->scontext = context; |
7046 | } |
7047 | } |
7048 | } |
7049 | |
7050 | /* Perhaps we didn't install newextra anywhere */ |
7051 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
7052 | free(newextra); |
7053 | break; |
7054 | |
7055 | #undef newval |
7056 | } |
7057 | |
7058 | case PGC_INT: |
7059 | { |
7060 | struct config_int *conf = (struct config_int *) record; |
7061 | |
7062 | #define newval (newval_union.intval) |
7063 | |
7064 | if (value) |
7065 | { |
7066 | if (!parse_and_validate_value(record, name, value, |
7067 | source, elevel, |
7068 | &newval_union, &newextra)) |
7069 | return 0; |
7070 | } |
7071 | else if (source == PGC_S_DEFAULT) |
7072 | { |
7073 | newval = conf->boot_val; |
7074 | if (!call_int_check_hook(conf, &newval, &newextra, |
7075 | source, elevel)) |
7076 | return 0; |
7077 | } |
7078 | else |
7079 | { |
7080 | newval = conf->reset_val; |
7081 | newextra = conf->reset_extra; |
7082 | source = conf->gen.reset_source; |
7083 | context = conf->gen.reset_scontext; |
7084 | } |
7085 | |
7086 | if (prohibitValueChange) |
7087 | { |
7088 | if (*conf->variable != newval) |
7089 | { |
7090 | record->status |= GUC_PENDING_RESTART; |
7091 | ereport(elevel, |
7092 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7093 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
7094 | name))); |
7095 | return 0; |
7096 | } |
7097 | record->status &= ~GUC_PENDING_RESTART; |
7098 | return -1; |
7099 | } |
7100 | |
7101 | if (changeVal) |
7102 | { |
7103 | /* Save old value to support transaction abort */ |
7104 | if (!makeDefault) |
7105 | push_old_value(&conf->gen, action); |
7106 | |
7107 | if (conf->assign_hook) |
7108 | conf->assign_hook(newval, newextra); |
7109 | *conf->variable = newval; |
7110 | set_extra_field(&conf->gen, &conf->gen.extra, |
7111 | newextra); |
7112 | conf->gen.source = source; |
7113 | conf->gen.scontext = context; |
7114 | } |
7115 | if (makeDefault) |
7116 | { |
7117 | GucStack *stack; |
7118 | |
7119 | if (conf->gen.reset_source <= source) |
7120 | { |
7121 | conf->reset_val = newval; |
7122 | set_extra_field(&conf->gen, &conf->reset_extra, |
7123 | newextra); |
7124 | conf->gen.reset_source = source; |
7125 | conf->gen.reset_scontext = context; |
7126 | } |
7127 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
7128 | { |
7129 | if (stack->source <= source) |
7130 | { |
7131 | stack->prior.val.intval = newval; |
7132 | set_extra_field(&conf->gen, &stack->prior.extra, |
7133 | newextra); |
7134 | stack->source = source; |
7135 | stack->scontext = context; |
7136 | } |
7137 | } |
7138 | } |
7139 | |
7140 | /* Perhaps we didn't install newextra anywhere */ |
7141 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
7142 | free(newextra); |
7143 | break; |
7144 | |
7145 | #undef newval |
7146 | } |
7147 | |
7148 | case PGC_REAL: |
7149 | { |
7150 | struct config_real *conf = (struct config_real *) record; |
7151 | |
7152 | #define newval (newval_union.realval) |
7153 | |
7154 | if (value) |
7155 | { |
7156 | if (!parse_and_validate_value(record, name, value, |
7157 | source, elevel, |
7158 | &newval_union, &newextra)) |
7159 | return 0; |
7160 | } |
7161 | else if (source == PGC_S_DEFAULT) |
7162 | { |
7163 | newval = conf->boot_val; |
7164 | if (!call_real_check_hook(conf, &newval, &newextra, |
7165 | source, elevel)) |
7166 | return 0; |
7167 | } |
7168 | else |
7169 | { |
7170 | newval = conf->reset_val; |
7171 | newextra = conf->reset_extra; |
7172 | source = conf->gen.reset_source; |
7173 | context = conf->gen.reset_scontext; |
7174 | } |
7175 | |
7176 | if (prohibitValueChange) |
7177 | { |
7178 | if (*conf->variable != newval) |
7179 | { |
7180 | record->status |= GUC_PENDING_RESTART; |
7181 | ereport(elevel, |
7182 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7183 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
7184 | name))); |
7185 | return 0; |
7186 | } |
7187 | record->status &= ~GUC_PENDING_RESTART; |
7188 | return -1; |
7189 | } |
7190 | |
7191 | if (changeVal) |
7192 | { |
7193 | /* Save old value to support transaction abort */ |
7194 | if (!makeDefault) |
7195 | push_old_value(&conf->gen, action); |
7196 | |
7197 | if (conf->assign_hook) |
7198 | conf->assign_hook(newval, newextra); |
7199 | *conf->variable = newval; |
7200 | set_extra_field(&conf->gen, &conf->gen.extra, |
7201 | newextra); |
7202 | conf->gen.source = source; |
7203 | conf->gen.scontext = context; |
7204 | } |
7205 | if (makeDefault) |
7206 | { |
7207 | GucStack *stack; |
7208 | |
7209 | if (conf->gen.reset_source <= source) |
7210 | { |
7211 | conf->reset_val = newval; |
7212 | set_extra_field(&conf->gen, &conf->reset_extra, |
7213 | newextra); |
7214 | conf->gen.reset_source = source; |
7215 | conf->gen.reset_scontext = context; |
7216 | } |
7217 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
7218 | { |
7219 | if (stack->source <= source) |
7220 | { |
7221 | stack->prior.val.realval = newval; |
7222 | set_extra_field(&conf->gen, &stack->prior.extra, |
7223 | newextra); |
7224 | stack->source = source; |
7225 | stack->scontext = context; |
7226 | } |
7227 | } |
7228 | } |
7229 | |
7230 | /* Perhaps we didn't install newextra anywhere */ |
7231 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
7232 | free(newextra); |
7233 | break; |
7234 | |
7235 | #undef newval |
7236 | } |
7237 | |
7238 | case PGC_STRING: |
7239 | { |
7240 | struct config_string *conf = (struct config_string *) record; |
7241 | |
7242 | #define newval (newval_union.stringval) |
7243 | |
7244 | if (value) |
7245 | { |
7246 | if (!parse_and_validate_value(record, name, value, |
7247 | source, elevel, |
7248 | &newval_union, &newextra)) |
7249 | return 0; |
7250 | } |
7251 | else if (source == PGC_S_DEFAULT) |
7252 | { |
7253 | /* non-NULL boot_val must always get strdup'd */ |
7254 | if (conf->boot_val != NULL) |
7255 | { |
7256 | newval = guc_strdup(elevel, conf->boot_val); |
7257 | if (newval == NULL) |
7258 | return 0; |
7259 | } |
7260 | else |
7261 | newval = NULL; |
7262 | |
7263 | if (!call_string_check_hook(conf, &newval, &newextra, |
7264 | source, elevel)) |
7265 | { |
7266 | free(newval); |
7267 | return 0; |
7268 | } |
7269 | } |
7270 | else |
7271 | { |
7272 | /* |
7273 | * strdup not needed, since reset_val is already under |
7274 | * guc.c's control |
7275 | */ |
7276 | newval = conf->reset_val; |
7277 | newextra = conf->reset_extra; |
7278 | source = conf->gen.reset_source; |
7279 | context = conf->gen.reset_scontext; |
7280 | } |
7281 | |
7282 | if (prohibitValueChange) |
7283 | { |
7284 | /* newval shouldn't be NULL, so we're a bit sloppy here */ |
7285 | if (*conf->variable == NULL || newval == NULL || |
7286 | strcmp(*conf->variable, newval) != 0) |
7287 | { |
7288 | record->status |= GUC_PENDING_RESTART; |
7289 | ereport(elevel, |
7290 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7291 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
7292 | name))); |
7293 | return 0; |
7294 | } |
7295 | record->status &= ~GUC_PENDING_RESTART; |
7296 | return -1; |
7297 | } |
7298 | |
7299 | if (changeVal) |
7300 | { |
7301 | /* Save old value to support transaction abort */ |
7302 | if (!makeDefault) |
7303 | push_old_value(&conf->gen, action); |
7304 | |
7305 | if (conf->assign_hook) |
7306 | conf->assign_hook(newval, newextra); |
7307 | set_string_field(conf, conf->variable, newval); |
7308 | set_extra_field(&conf->gen, &conf->gen.extra, |
7309 | newextra); |
7310 | conf->gen.source = source; |
7311 | conf->gen.scontext = context; |
7312 | } |
7313 | |
7314 | if (makeDefault) |
7315 | { |
7316 | GucStack *stack; |
7317 | |
7318 | if (conf->gen.reset_source <= source) |
7319 | { |
7320 | set_string_field(conf, &conf->reset_val, newval); |
7321 | set_extra_field(&conf->gen, &conf->reset_extra, |
7322 | newextra); |
7323 | conf->gen.reset_source = source; |
7324 | conf->gen.reset_scontext = context; |
7325 | } |
7326 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
7327 | { |
7328 | if (stack->source <= source) |
7329 | { |
7330 | set_string_field(conf, &stack->prior.val.stringval, |
7331 | newval); |
7332 | set_extra_field(&conf->gen, &stack->prior.extra, |
7333 | newextra); |
7334 | stack->source = source; |
7335 | stack->scontext = context; |
7336 | } |
7337 | } |
7338 | } |
7339 | |
7340 | /* Perhaps we didn't install newval anywhere */ |
7341 | if (newval && !string_field_used(conf, newval)) |
7342 | free(newval); |
7343 | /* Perhaps we didn't install newextra anywhere */ |
7344 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
7345 | free(newextra); |
7346 | break; |
7347 | |
7348 | #undef newval |
7349 | } |
7350 | |
7351 | case PGC_ENUM: |
7352 | { |
7353 | struct config_enum *conf = (struct config_enum *) record; |
7354 | |
7355 | #define newval (newval_union.enumval) |
7356 | |
7357 | if (value) |
7358 | { |
7359 | if (!parse_and_validate_value(record, name, value, |
7360 | source, elevel, |
7361 | &newval_union, &newextra)) |
7362 | return 0; |
7363 | } |
7364 | else if (source == PGC_S_DEFAULT) |
7365 | { |
7366 | newval = conf->boot_val; |
7367 | if (!call_enum_check_hook(conf, &newval, &newextra, |
7368 | source, elevel)) |
7369 | return 0; |
7370 | } |
7371 | else |
7372 | { |
7373 | newval = conf->reset_val; |
7374 | newextra = conf->reset_extra; |
7375 | source = conf->gen.reset_source; |
7376 | context = conf->gen.reset_scontext; |
7377 | } |
7378 | |
7379 | if (prohibitValueChange) |
7380 | { |
7381 | if (*conf->variable != newval) |
7382 | { |
7383 | record->status |= GUC_PENDING_RESTART; |
7384 | ereport(elevel, |
7385 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7386 | errmsg("parameter \"%s\" cannot be changed without restarting the server" , |
7387 | name))); |
7388 | return 0; |
7389 | } |
7390 | record->status &= ~GUC_PENDING_RESTART; |
7391 | return -1; |
7392 | } |
7393 | |
7394 | if (changeVal) |
7395 | { |
7396 | /* Save old value to support transaction abort */ |
7397 | if (!makeDefault) |
7398 | push_old_value(&conf->gen, action); |
7399 | |
7400 | if (conf->assign_hook) |
7401 | conf->assign_hook(newval, newextra); |
7402 | *conf->variable = newval; |
7403 | set_extra_field(&conf->gen, &conf->gen.extra, |
7404 | newextra); |
7405 | conf->gen.source = source; |
7406 | conf->gen.scontext = context; |
7407 | } |
7408 | if (makeDefault) |
7409 | { |
7410 | GucStack *stack; |
7411 | |
7412 | if (conf->gen.reset_source <= source) |
7413 | { |
7414 | conf->reset_val = newval; |
7415 | set_extra_field(&conf->gen, &conf->reset_extra, |
7416 | newextra); |
7417 | conf->gen.reset_source = source; |
7418 | conf->gen.reset_scontext = context; |
7419 | } |
7420 | for (stack = conf->gen.stack; stack; stack = stack->prev) |
7421 | { |
7422 | if (stack->source <= source) |
7423 | { |
7424 | stack->prior.val.enumval = newval; |
7425 | set_extra_field(&conf->gen, &stack->prior.extra, |
7426 | newextra); |
7427 | stack->source = source; |
7428 | stack->scontext = context; |
7429 | } |
7430 | } |
7431 | } |
7432 | |
7433 | /* Perhaps we didn't install newextra anywhere */ |
7434 | if (newextra && !extra_field_used(&conf->gen, newextra)) |
7435 | free(newextra); |
7436 | break; |
7437 | |
7438 | #undef newval |
7439 | } |
7440 | } |
7441 | |
7442 | if (changeVal && (record->flags & GUC_REPORT)) |
7443 | ReportGUCOption(record); |
7444 | |
7445 | return changeVal ? 1 : -1; |
7446 | } |
7447 | |
7448 | |
7449 | /* |
7450 | * Set the fields for source file and line number the setting came from. |
7451 | */ |
7452 | static void |
7453 | set_config_sourcefile(const char *name, char *sourcefile, int sourceline) |
7454 | { |
7455 | struct config_generic *record; |
7456 | int elevel; |
7457 | |
7458 | /* |
7459 | * To avoid cluttering the log, only the postmaster bleats loudly about |
7460 | * problems with the config file. |
7461 | */ |
7462 | elevel = IsUnderPostmaster ? DEBUG3 : LOG; |
7463 | |
7464 | record = find_option(name, true, elevel); |
7465 | /* should not happen */ |
7466 | if (record == NULL) |
7467 | elog(ERROR, "unrecognized configuration parameter \"%s\"" , name); |
7468 | |
7469 | sourcefile = guc_strdup(elevel, sourcefile); |
7470 | if (record->sourcefile) |
7471 | free(record->sourcefile); |
7472 | record->sourcefile = sourcefile; |
7473 | record->sourceline = sourceline; |
7474 | } |
7475 | |
7476 | /* |
7477 | * Set a config option to the given value. |
7478 | * |
7479 | * See also set_config_option; this is just the wrapper to be called from |
7480 | * outside GUC. (This function should be used when possible, because its API |
7481 | * is more stable than set_config_option's.) |
7482 | * |
7483 | * Note: there is no support here for setting source file/line, as it |
7484 | * is currently not needed. |
7485 | */ |
7486 | void |
7487 | SetConfigOption(const char *name, const char *value, |
7488 | GucContext context, GucSource source) |
7489 | { |
7490 | (void) set_config_option(name, value, context, source, |
7491 | GUC_ACTION_SET, true, 0, false); |
7492 | } |
7493 | |
7494 | |
7495 | |
7496 | /* |
7497 | * Fetch the current value of the option `name', as a string. |
7498 | * |
7499 | * If the option doesn't exist, return NULL if missing_ok is true (NOTE that |
7500 | * this cannot be distinguished from a string variable with a NULL value!), |
7501 | * otherwise throw an ereport and don't return. |
7502 | * |
7503 | * If restrict_privileged is true, we also enforce that only superusers and |
7504 | * members of the pg_read_all_settings role can see GUC_SUPERUSER_ONLY |
7505 | * variables. This should only be passed as true in user-driven calls. |
7506 | * |
7507 | * The string is *not* allocated for modification and is really only |
7508 | * valid until the next call to configuration related functions. |
7509 | */ |
7510 | const char * |
7511 | GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged) |
7512 | { |
7513 | struct config_generic *record; |
7514 | static char buffer[256]; |
7515 | |
7516 | record = find_option(name, false, ERROR); |
7517 | if (record == NULL) |
7518 | { |
7519 | if (missing_ok) |
7520 | return NULL; |
7521 | ereport(ERROR, |
7522 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
7523 | errmsg("unrecognized configuration parameter \"%s\"" , |
7524 | name))); |
7525 | } |
7526 | if (restrict_privileged && |
7527 | (record->flags & GUC_SUPERUSER_ONLY) && |
7528 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
7529 | ereport(ERROR, |
7530 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
7531 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
7532 | name))); |
7533 | |
7534 | switch (record->vartype) |
7535 | { |
7536 | case PGC_BOOL: |
7537 | return *((struct config_bool *) record)->variable ? "on" : "off" ; |
7538 | |
7539 | case PGC_INT: |
7540 | snprintf(buffer, sizeof(buffer), "%d" , |
7541 | *((struct config_int *) record)->variable); |
7542 | return buffer; |
7543 | |
7544 | case PGC_REAL: |
7545 | snprintf(buffer, sizeof(buffer), "%g" , |
7546 | *((struct config_real *) record)->variable); |
7547 | return buffer; |
7548 | |
7549 | case PGC_STRING: |
7550 | return *((struct config_string *) record)->variable; |
7551 | |
7552 | case PGC_ENUM: |
7553 | return config_enum_lookup_by_value((struct config_enum *) record, |
7554 | *((struct config_enum *) record)->variable); |
7555 | } |
7556 | return NULL; |
7557 | } |
7558 | |
7559 | /* |
7560 | * Get the RESET value associated with the given option. |
7561 | * |
7562 | * Note: this is not re-entrant, due to use of static result buffer; |
7563 | * not to mention that a string variable could have its reset_val changed. |
7564 | * Beware of assuming the result value is good for very long. |
7565 | */ |
7566 | const char * |
7567 | GetConfigOptionResetString(const char *name) |
7568 | { |
7569 | struct config_generic *record; |
7570 | static char buffer[256]; |
7571 | |
7572 | record = find_option(name, false, ERROR); |
7573 | if (record == NULL) |
7574 | ereport(ERROR, |
7575 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
7576 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
7577 | if ((record->flags & GUC_SUPERUSER_ONLY) && |
7578 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
7579 | ereport(ERROR, |
7580 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
7581 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
7582 | name))); |
7583 | |
7584 | switch (record->vartype) |
7585 | { |
7586 | case PGC_BOOL: |
7587 | return ((struct config_bool *) record)->reset_val ? "on" : "off" ; |
7588 | |
7589 | case PGC_INT: |
7590 | snprintf(buffer, sizeof(buffer), "%d" , |
7591 | ((struct config_int *) record)->reset_val); |
7592 | return buffer; |
7593 | |
7594 | case PGC_REAL: |
7595 | snprintf(buffer, sizeof(buffer), "%g" , |
7596 | ((struct config_real *) record)->reset_val); |
7597 | return buffer; |
7598 | |
7599 | case PGC_STRING: |
7600 | return ((struct config_string *) record)->reset_val; |
7601 | |
7602 | case PGC_ENUM: |
7603 | return config_enum_lookup_by_value((struct config_enum *) record, |
7604 | ((struct config_enum *) record)->reset_val); |
7605 | } |
7606 | return NULL; |
7607 | } |
7608 | |
7609 | /* |
7610 | * Get the GUC flags associated with the given option. |
7611 | * |
7612 | * If the option doesn't exist, return 0 if missing_ok is true, |
7613 | * otherwise throw an ereport and don't return. |
7614 | */ |
7615 | int |
7616 | GetConfigOptionFlags(const char *name, bool missing_ok) |
7617 | { |
7618 | struct config_generic *record; |
7619 | |
7620 | record = find_option(name, false, WARNING); |
7621 | if (record == NULL) |
7622 | { |
7623 | if (missing_ok) |
7624 | return 0; |
7625 | ereport(ERROR, |
7626 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
7627 | errmsg("unrecognized configuration parameter \"%s\"" , |
7628 | name))); |
7629 | } |
7630 | return record->flags; |
7631 | } |
7632 | |
7633 | |
7634 | /* |
7635 | * flatten_set_variable_args |
7636 | * Given a parsenode List as emitted by the grammar for SET, |
7637 | * convert to the flat string representation used by GUC. |
7638 | * |
7639 | * We need to be told the name of the variable the args are for, because |
7640 | * the flattening rules vary (ugh). |
7641 | * |
7642 | * The result is NULL if args is NIL (i.e., SET ... TO DEFAULT), otherwise |
7643 | * a palloc'd string. |
7644 | */ |
7645 | static char * |
7646 | flatten_set_variable_args(const char *name, List *args) |
7647 | { |
7648 | struct config_generic *record; |
7649 | int flags; |
7650 | StringInfoData buf; |
7651 | ListCell *l; |
7652 | |
7653 | /* Fast path if just DEFAULT */ |
7654 | if (args == NIL) |
7655 | return NULL; |
7656 | |
7657 | /* |
7658 | * Get flags for the variable; if it's not known, use default flags. |
7659 | * (Caller might throw error later, but not our business to do so here.) |
7660 | */ |
7661 | record = find_option(name, false, WARNING); |
7662 | if (record) |
7663 | flags = record->flags; |
7664 | else |
7665 | flags = 0; |
7666 | |
7667 | /* Complain if list input and non-list variable */ |
7668 | if ((flags & GUC_LIST_INPUT) == 0 && |
7669 | list_length(args) != 1) |
7670 | ereport(ERROR, |
7671 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
7672 | errmsg("SET %s takes only one argument" , name))); |
7673 | |
7674 | initStringInfo(&buf); |
7675 | |
7676 | /* |
7677 | * Each list member may be a plain A_Const node, or an A_Const within a |
7678 | * TypeCast; the latter case is supported only for ConstInterval arguments |
7679 | * (for SET TIME ZONE). |
7680 | */ |
7681 | foreach(l, args) |
7682 | { |
7683 | Node *arg = (Node *) lfirst(l); |
7684 | char *val; |
7685 | TypeName *typeName = NULL; |
7686 | A_Const *con; |
7687 | |
7688 | if (l != list_head(args)) |
7689 | appendStringInfoString(&buf, ", " ); |
7690 | |
7691 | if (IsA(arg, TypeCast)) |
7692 | { |
7693 | TypeCast *tc = (TypeCast *) arg; |
7694 | |
7695 | arg = tc->arg; |
7696 | typeName = tc->typeName; |
7697 | } |
7698 | |
7699 | if (!IsA(arg, A_Const)) |
7700 | elog(ERROR, "unrecognized node type: %d" , (int) nodeTag(arg)); |
7701 | con = (A_Const *) arg; |
7702 | |
7703 | switch (nodeTag(&con->val)) |
7704 | { |
7705 | case T_Integer: |
7706 | appendStringInfo(&buf, "%d" , intVal(&con->val)); |
7707 | break; |
7708 | case T_Float: |
7709 | /* represented as a string, so just copy it */ |
7710 | appendStringInfoString(&buf, strVal(&con->val)); |
7711 | break; |
7712 | case T_String: |
7713 | val = strVal(&con->val); |
7714 | if (typeName != NULL) |
7715 | { |
7716 | /* |
7717 | * Must be a ConstInterval argument for TIME ZONE. Coerce |
7718 | * to interval and back to normalize the value and account |
7719 | * for any typmod. |
7720 | */ |
7721 | Oid typoid; |
7722 | int32 typmod; |
7723 | Datum interval; |
7724 | char *intervalout; |
7725 | |
7726 | typenameTypeIdAndMod(NULL, typeName, &typoid, &typmod); |
7727 | Assert(typoid == INTERVALOID); |
7728 | |
7729 | interval = |
7730 | DirectFunctionCall3(interval_in, |
7731 | CStringGetDatum(val), |
7732 | ObjectIdGetDatum(InvalidOid), |
7733 | Int32GetDatum(typmod)); |
7734 | |
7735 | intervalout = |
7736 | DatumGetCString(DirectFunctionCall1(interval_out, |
7737 | interval)); |
7738 | appendStringInfo(&buf, "INTERVAL '%s'" , intervalout); |
7739 | } |
7740 | else |
7741 | { |
7742 | /* |
7743 | * Plain string literal or identifier. For quote mode, |
7744 | * quote it if it's not a vanilla identifier. |
7745 | */ |
7746 | if (flags & GUC_LIST_QUOTE) |
7747 | appendStringInfoString(&buf, quote_identifier(val)); |
7748 | else |
7749 | appendStringInfoString(&buf, val); |
7750 | } |
7751 | break; |
7752 | default: |
7753 | elog(ERROR, "unrecognized node type: %d" , |
7754 | (int) nodeTag(&con->val)); |
7755 | break; |
7756 | } |
7757 | } |
7758 | |
7759 | return buf.data; |
7760 | } |
7761 | |
7762 | /* |
7763 | * Write updated configuration parameter values into a temporary file. |
7764 | * This function traverses the list of parameters and quotes the string |
7765 | * values before writing them. |
7766 | */ |
7767 | static void |
7768 | write_auto_conf_file(int fd, const char *filename, ConfigVariable *head) |
7769 | { |
7770 | StringInfoData buf; |
7771 | ConfigVariable *item; |
7772 | |
7773 | initStringInfo(&buf); |
7774 | |
7775 | /* Emit file header containing warning comment */ |
7776 | appendStringInfoString(&buf, "# Do not edit this file manually!\n" ); |
7777 | appendStringInfoString(&buf, "# It will be overwritten by the ALTER SYSTEM command.\n" ); |
7778 | |
7779 | errno = 0; |
7780 | if (write(fd, buf.data, buf.len) != buf.len) |
7781 | { |
7782 | /* if write didn't set errno, assume problem is no disk space */ |
7783 | if (errno == 0) |
7784 | errno = ENOSPC; |
7785 | ereport(ERROR, |
7786 | (errcode_for_file_access(), |
7787 | errmsg("could not write to file \"%s\": %m" , filename))); |
7788 | } |
7789 | |
7790 | /* Emit each parameter, properly quoting the value */ |
7791 | for (item = head; item != NULL; item = item->next) |
7792 | { |
7793 | char *escaped; |
7794 | |
7795 | resetStringInfo(&buf); |
7796 | |
7797 | appendStringInfoString(&buf, item->name); |
7798 | appendStringInfoString(&buf, " = '" ); |
7799 | |
7800 | escaped = escape_single_quotes_ascii(item->value); |
7801 | if (!escaped) |
7802 | ereport(ERROR, |
7803 | (errcode(ERRCODE_OUT_OF_MEMORY), |
7804 | errmsg("out of memory" ))); |
7805 | appendStringInfoString(&buf, escaped); |
7806 | free(escaped); |
7807 | |
7808 | appendStringInfoString(&buf, "'\n" ); |
7809 | |
7810 | errno = 0; |
7811 | if (write(fd, buf.data, buf.len) != buf.len) |
7812 | { |
7813 | /* if write didn't set errno, assume problem is no disk space */ |
7814 | if (errno == 0) |
7815 | errno = ENOSPC; |
7816 | ereport(ERROR, |
7817 | (errcode_for_file_access(), |
7818 | errmsg("could not write to file \"%s\": %m" , filename))); |
7819 | } |
7820 | } |
7821 | |
7822 | /* fsync before considering the write to be successful */ |
7823 | if (pg_fsync(fd) != 0) |
7824 | ereport(ERROR, |
7825 | (errcode_for_file_access(), |
7826 | errmsg("could not fsync file \"%s\": %m" , filename))); |
7827 | |
7828 | pfree(buf.data); |
7829 | } |
7830 | |
7831 | /* |
7832 | * Update the given list of configuration parameters, adding, replacing |
7833 | * or deleting the entry for item "name" (delete if "value" == NULL). |
7834 | */ |
7835 | static void |
7836 | replace_auto_config_value(ConfigVariable **head_p, ConfigVariable **tail_p, |
7837 | const char *name, const char *value) |
7838 | { |
7839 | ConfigVariable *item, |
7840 | *next, |
7841 | *prev = NULL; |
7842 | |
7843 | /* |
7844 | * Remove any existing match(es) for "name". Normally there'd be at most |
7845 | * one, but if external tools have modified the config file, there could |
7846 | * be more. |
7847 | */ |
7848 | for (item = *head_p; item != NULL; item = next) |
7849 | { |
7850 | next = item->next; |
7851 | if (guc_name_compare(item->name, name) == 0) |
7852 | { |
7853 | /* found a match, delete it */ |
7854 | if (prev) |
7855 | prev->next = next; |
7856 | else |
7857 | *head_p = next; |
7858 | if (next == NULL) |
7859 | *tail_p = prev; |
7860 | |
7861 | pfree(item->name); |
7862 | pfree(item->value); |
7863 | pfree(item->filename); |
7864 | pfree(item); |
7865 | } |
7866 | else |
7867 | prev = item; |
7868 | } |
7869 | |
7870 | /* Done if we're trying to delete it */ |
7871 | if (value == NULL) |
7872 | return; |
7873 | |
7874 | /* OK, append a new entry */ |
7875 | item = palloc(sizeof *item); |
7876 | item->name = pstrdup(name); |
7877 | item->value = pstrdup(value); |
7878 | item->errmsg = NULL; |
7879 | item->filename = pstrdup("" ); /* new item has no location */ |
7880 | item->sourceline = 0; |
7881 | item->ignore = false; |
7882 | item->applied = false; |
7883 | item->next = NULL; |
7884 | |
7885 | if (*head_p == NULL) |
7886 | *head_p = item; |
7887 | else |
7888 | (*tail_p)->next = item; |
7889 | *tail_p = item; |
7890 | } |
7891 | |
7892 | |
7893 | /* |
7894 | * Execute ALTER SYSTEM statement. |
7895 | * |
7896 | * Read the old PG_AUTOCONF_FILENAME file, merge in the new variable value, |
7897 | * and write out an updated file. If the command is ALTER SYSTEM RESET ALL, |
7898 | * we can skip reading the old file and just write an empty file. |
7899 | * |
7900 | * An LWLock is used to serialize updates of the configuration file. |
7901 | * |
7902 | * In case of an error, we leave the original automatic |
7903 | * configuration file (PG_AUTOCONF_FILENAME) intact. |
7904 | */ |
7905 | void |
7906 | AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt) |
7907 | { |
7908 | char *name; |
7909 | char *value; |
7910 | bool resetall = false; |
7911 | ConfigVariable *head = NULL; |
7912 | ConfigVariable *tail = NULL; |
7913 | volatile int Tmpfd; |
7914 | char AutoConfFileName[MAXPGPATH]; |
7915 | char AutoConfTmpFileName[MAXPGPATH]; |
7916 | |
7917 | if (!superuser()) |
7918 | ereport(ERROR, |
7919 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
7920 | (errmsg("must be superuser to execute ALTER SYSTEM command" )))); |
7921 | |
7922 | /* |
7923 | * Extract statement arguments |
7924 | */ |
7925 | name = altersysstmt->setstmt->name; |
7926 | |
7927 | switch (altersysstmt->setstmt->kind) |
7928 | { |
7929 | case VAR_SET_VALUE: |
7930 | value = ExtractSetVariableArgs(altersysstmt->setstmt); |
7931 | break; |
7932 | |
7933 | case VAR_SET_DEFAULT: |
7934 | case VAR_RESET: |
7935 | value = NULL; |
7936 | break; |
7937 | |
7938 | case VAR_RESET_ALL: |
7939 | value = NULL; |
7940 | resetall = true; |
7941 | break; |
7942 | |
7943 | default: |
7944 | elog(ERROR, "unrecognized alter system stmt type: %d" , |
7945 | altersysstmt->setstmt->kind); |
7946 | break; |
7947 | } |
7948 | |
7949 | /* |
7950 | * Unless it's RESET_ALL, validate the target variable and value |
7951 | */ |
7952 | if (!resetall) |
7953 | { |
7954 | struct config_generic *record; |
7955 | |
7956 | record = find_option(name, false, ERROR); |
7957 | if (record == NULL) |
7958 | ereport(ERROR, |
7959 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
7960 | errmsg("unrecognized configuration parameter \"%s\"" , |
7961 | name))); |
7962 | |
7963 | /* |
7964 | * Don't allow parameters that can't be set in configuration files to |
7965 | * be set in PG_AUTOCONF_FILENAME file. |
7966 | */ |
7967 | if ((record->context == PGC_INTERNAL) || |
7968 | (record->flags & GUC_DISALLOW_IN_FILE) || |
7969 | (record->flags & GUC_DISALLOW_IN_AUTO_FILE)) |
7970 | ereport(ERROR, |
7971 | (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), |
7972 | errmsg("parameter \"%s\" cannot be changed" , |
7973 | name))); |
7974 | |
7975 | /* |
7976 | * If a value is specified, verify that it's sane. |
7977 | */ |
7978 | if (value) |
7979 | { |
7980 | union config_var_val newval; |
7981 | void * = NULL; |
7982 | |
7983 | /* Check that it's acceptable for the indicated parameter */ |
7984 | if (!parse_and_validate_value(record, name, value, |
7985 | PGC_S_FILE, ERROR, |
7986 | &newval, &newextra)) |
7987 | ereport(ERROR, |
7988 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
7989 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
7990 | name, value))); |
7991 | |
7992 | if (record->vartype == PGC_STRING && newval.stringval != NULL) |
7993 | free(newval.stringval); |
7994 | if (newextra) |
7995 | free(newextra); |
7996 | |
7997 | /* |
7998 | * We must also reject values containing newlines, because the |
7999 | * grammar for config files doesn't support embedded newlines in |
8000 | * string literals. |
8001 | */ |
8002 | if (strchr(value, '\n')) |
8003 | ereport(ERROR, |
8004 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
8005 | errmsg("parameter value for ALTER SYSTEM must not contain a newline" ))); |
8006 | } |
8007 | } |
8008 | |
8009 | /* |
8010 | * PG_AUTOCONF_FILENAME and its corresponding temporary file are always in |
8011 | * the data directory, so we can reference them by simple relative paths. |
8012 | */ |
8013 | snprintf(AutoConfFileName, sizeof(AutoConfFileName), "%s" , |
8014 | PG_AUTOCONF_FILENAME); |
8015 | snprintf(AutoConfTmpFileName, sizeof(AutoConfTmpFileName), "%s.%s" , |
8016 | AutoConfFileName, |
8017 | "tmp" ); |
8018 | |
8019 | /* |
8020 | * Only one backend is allowed to operate on PG_AUTOCONF_FILENAME at a |
8021 | * time. Use AutoFileLock to ensure that. We must hold the lock while |
8022 | * reading the old file contents. |
8023 | */ |
8024 | LWLockAcquire(AutoFileLock, LW_EXCLUSIVE); |
8025 | |
8026 | /* |
8027 | * If we're going to reset everything, then no need to open or parse the |
8028 | * old file. We'll just write out an empty list. |
8029 | */ |
8030 | if (!resetall) |
8031 | { |
8032 | struct stat st; |
8033 | |
8034 | if (stat(AutoConfFileName, &st) == 0) |
8035 | { |
8036 | /* open old file PG_AUTOCONF_FILENAME */ |
8037 | FILE *infile; |
8038 | |
8039 | infile = AllocateFile(AutoConfFileName, "r" ); |
8040 | if (infile == NULL) |
8041 | ereport(ERROR, |
8042 | (errcode_for_file_access(), |
8043 | errmsg("could not open file \"%s\": %m" , |
8044 | AutoConfFileName))); |
8045 | |
8046 | /* parse it */ |
8047 | if (!ParseConfigFp(infile, AutoConfFileName, 0, LOG, &head, &tail)) |
8048 | ereport(ERROR, |
8049 | (errcode(ERRCODE_CONFIG_FILE_ERROR), |
8050 | errmsg("could not parse contents of file \"%s\"" , |
8051 | AutoConfFileName))); |
8052 | |
8053 | FreeFile(infile); |
8054 | } |
8055 | |
8056 | /* |
8057 | * Now, replace any existing entry with the new value, or add it if |
8058 | * not present. |
8059 | */ |
8060 | replace_auto_config_value(&head, &tail, name, value); |
8061 | } |
8062 | |
8063 | /* |
8064 | * To ensure crash safety, first write the new file data to a temp file, |
8065 | * then atomically rename it into place. |
8066 | * |
8067 | * If there is a temp file left over due to a previous crash, it's okay to |
8068 | * truncate and reuse it. |
8069 | */ |
8070 | Tmpfd = BasicOpenFile(AutoConfTmpFileName, |
8071 | O_CREAT | O_RDWR | O_TRUNC); |
8072 | if (Tmpfd < 0) |
8073 | ereport(ERROR, |
8074 | (errcode_for_file_access(), |
8075 | errmsg("could not open file \"%s\": %m" , |
8076 | AutoConfTmpFileName))); |
8077 | |
8078 | /* |
8079 | * Use a TRY block to clean up the file if we fail. Since we need a TRY |
8080 | * block anyway, OK to use BasicOpenFile rather than OpenTransientFile. |
8081 | */ |
8082 | PG_TRY(); |
8083 | { |
8084 | /* Write and sync the new contents to the temporary file */ |
8085 | write_auto_conf_file(Tmpfd, AutoConfTmpFileName, head); |
8086 | |
8087 | /* Close before renaming; may be required on some platforms */ |
8088 | close(Tmpfd); |
8089 | Tmpfd = -1; |
8090 | |
8091 | /* |
8092 | * As the rename is atomic operation, if any problem occurs after this |
8093 | * at worst it can lose the parameters set by last ALTER SYSTEM |
8094 | * command. |
8095 | */ |
8096 | durable_rename(AutoConfTmpFileName, AutoConfFileName, ERROR); |
8097 | } |
8098 | PG_CATCH(); |
8099 | { |
8100 | /* Close file first, else unlink might fail on some platforms */ |
8101 | if (Tmpfd >= 0) |
8102 | close(Tmpfd); |
8103 | |
8104 | /* Unlink, but ignore any error */ |
8105 | (void) unlink(AutoConfTmpFileName); |
8106 | |
8107 | PG_RE_THROW(); |
8108 | } |
8109 | PG_END_TRY(); |
8110 | |
8111 | FreeConfigVariables(head); |
8112 | |
8113 | LWLockRelease(AutoFileLock); |
8114 | } |
8115 | |
8116 | /* |
8117 | * SET command |
8118 | */ |
8119 | void |
8120 | ExecSetVariableStmt(VariableSetStmt *stmt, bool isTopLevel) |
8121 | { |
8122 | GucAction action = stmt->is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET; |
8123 | |
8124 | /* |
8125 | * Workers synchronize these parameters at the start of the parallel |
8126 | * operation; then, we block SET during the operation. |
8127 | */ |
8128 | if (IsInParallelMode()) |
8129 | ereport(ERROR, |
8130 | (errcode(ERRCODE_INVALID_TRANSACTION_STATE), |
8131 | errmsg("cannot set parameters during a parallel operation" ))); |
8132 | |
8133 | switch (stmt->kind) |
8134 | { |
8135 | case VAR_SET_VALUE: |
8136 | case VAR_SET_CURRENT: |
8137 | if (stmt->is_local) |
8138 | WarnNoTransactionBlock(isTopLevel, "SET LOCAL" ); |
8139 | (void) set_config_option(stmt->name, |
8140 | ExtractSetVariableArgs(stmt), |
8141 | (superuser() ? PGC_SUSET : PGC_USERSET), |
8142 | PGC_S_SESSION, |
8143 | action, true, 0, false); |
8144 | break; |
8145 | case VAR_SET_MULTI: |
8146 | |
8147 | /* |
8148 | * Special-case SQL syntaxes. The TRANSACTION and SESSION |
8149 | * CHARACTERISTICS cases effectively set more than one variable |
8150 | * per statement. TRANSACTION SNAPSHOT only takes one argument, |
8151 | * but we put it here anyway since it's a special case and not |
8152 | * related to any GUC variable. |
8153 | */ |
8154 | if (strcmp(stmt->name, "TRANSACTION" ) == 0) |
8155 | { |
8156 | ListCell *head; |
8157 | |
8158 | WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION" ); |
8159 | |
8160 | foreach(head, stmt->args) |
8161 | { |
8162 | DefElem *item = (DefElem *) lfirst(head); |
8163 | |
8164 | if (strcmp(item->defname, "transaction_isolation" ) == 0) |
8165 | SetPGVariable("transaction_isolation" , |
8166 | list_make1(item->arg), stmt->is_local); |
8167 | else if (strcmp(item->defname, "transaction_read_only" ) == 0) |
8168 | SetPGVariable("transaction_read_only" , |
8169 | list_make1(item->arg), stmt->is_local); |
8170 | else if (strcmp(item->defname, "transaction_deferrable" ) == 0) |
8171 | SetPGVariable("transaction_deferrable" , |
8172 | list_make1(item->arg), stmt->is_local); |
8173 | else |
8174 | elog(ERROR, "unexpected SET TRANSACTION element: %s" , |
8175 | item->defname); |
8176 | } |
8177 | } |
8178 | else if (strcmp(stmt->name, "SESSION CHARACTERISTICS" ) == 0) |
8179 | { |
8180 | ListCell *head; |
8181 | |
8182 | foreach(head, stmt->args) |
8183 | { |
8184 | DefElem *item = (DefElem *) lfirst(head); |
8185 | |
8186 | if (strcmp(item->defname, "transaction_isolation" ) == 0) |
8187 | SetPGVariable("default_transaction_isolation" , |
8188 | list_make1(item->arg), stmt->is_local); |
8189 | else if (strcmp(item->defname, "transaction_read_only" ) == 0) |
8190 | SetPGVariable("default_transaction_read_only" , |
8191 | list_make1(item->arg), stmt->is_local); |
8192 | else if (strcmp(item->defname, "transaction_deferrable" ) == 0) |
8193 | SetPGVariable("default_transaction_deferrable" , |
8194 | list_make1(item->arg), stmt->is_local); |
8195 | else |
8196 | elog(ERROR, "unexpected SET SESSION element: %s" , |
8197 | item->defname); |
8198 | } |
8199 | } |
8200 | else if (strcmp(stmt->name, "TRANSACTION SNAPSHOT" ) == 0) |
8201 | { |
8202 | A_Const *con = linitial_node(A_Const, stmt->args); |
8203 | |
8204 | if (stmt->is_local) |
8205 | ereport(ERROR, |
8206 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
8207 | errmsg("SET LOCAL TRANSACTION SNAPSHOT is not implemented" ))); |
8208 | |
8209 | WarnNoTransactionBlock(isTopLevel, "SET TRANSACTION" ); |
8210 | Assert(nodeTag(&con->val) == T_String); |
8211 | ImportSnapshot(strVal(&con->val)); |
8212 | } |
8213 | else |
8214 | elog(ERROR, "unexpected SET MULTI element: %s" , |
8215 | stmt->name); |
8216 | break; |
8217 | case VAR_SET_DEFAULT: |
8218 | if (stmt->is_local) |
8219 | WarnNoTransactionBlock(isTopLevel, "SET LOCAL" ); |
8220 | /* fall through */ |
8221 | case VAR_RESET: |
8222 | if (strcmp(stmt->name, "transaction_isolation" ) == 0) |
8223 | WarnNoTransactionBlock(isTopLevel, "RESET TRANSACTION" ); |
8224 | |
8225 | (void) set_config_option(stmt->name, |
8226 | NULL, |
8227 | (superuser() ? PGC_SUSET : PGC_USERSET), |
8228 | PGC_S_SESSION, |
8229 | action, true, 0, false); |
8230 | break; |
8231 | case VAR_RESET_ALL: |
8232 | ResetAllOptions(); |
8233 | break; |
8234 | } |
8235 | } |
8236 | |
8237 | /* |
8238 | * Get the value to assign for a VariableSetStmt, or NULL if it's RESET. |
8239 | * The result is palloc'd. |
8240 | * |
8241 | * This is exported for use by actions such as ALTER ROLE SET. |
8242 | */ |
8243 | char * |
8244 | (VariableSetStmt *stmt) |
8245 | { |
8246 | switch (stmt->kind) |
8247 | { |
8248 | case VAR_SET_VALUE: |
8249 | return flatten_set_variable_args(stmt->name, stmt->args); |
8250 | case VAR_SET_CURRENT: |
8251 | return GetConfigOptionByName(stmt->name, NULL, false); |
8252 | default: |
8253 | return NULL; |
8254 | } |
8255 | } |
8256 | |
8257 | /* |
8258 | * SetPGVariable - SET command exported as an easily-C-callable function. |
8259 | * |
8260 | * This provides access to SET TO value, as well as SET TO DEFAULT (expressed |
8261 | * by passing args == NIL), but not SET FROM CURRENT functionality. |
8262 | */ |
8263 | void |
8264 | SetPGVariable(const char *name, List *args, bool is_local) |
8265 | { |
8266 | char *argstring = flatten_set_variable_args(name, args); |
8267 | |
8268 | /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */ |
8269 | (void) set_config_option(name, |
8270 | argstring, |
8271 | (superuser() ? PGC_SUSET : PGC_USERSET), |
8272 | PGC_S_SESSION, |
8273 | is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET, |
8274 | true, 0, false); |
8275 | } |
8276 | |
8277 | /* |
8278 | * SET command wrapped as a SQL callable function. |
8279 | */ |
8280 | Datum |
8281 | set_config_by_name(PG_FUNCTION_ARGS) |
8282 | { |
8283 | char *name; |
8284 | char *value; |
8285 | char *new_value; |
8286 | bool is_local; |
8287 | |
8288 | if (PG_ARGISNULL(0)) |
8289 | ereport(ERROR, |
8290 | (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
8291 | errmsg("SET requires parameter name" ))); |
8292 | |
8293 | /* Get the GUC variable name */ |
8294 | name = TextDatumGetCString(PG_GETARG_DATUM(0)); |
8295 | |
8296 | /* Get the desired value or set to NULL for a reset request */ |
8297 | if (PG_ARGISNULL(1)) |
8298 | value = NULL; |
8299 | else |
8300 | value = TextDatumGetCString(PG_GETARG_DATUM(1)); |
8301 | |
8302 | /* |
8303 | * Get the desired state of is_local. Default to false if provided value |
8304 | * is NULL |
8305 | */ |
8306 | if (PG_ARGISNULL(2)) |
8307 | is_local = false; |
8308 | else |
8309 | is_local = PG_GETARG_BOOL(2); |
8310 | |
8311 | /* Note SET DEFAULT (argstring == NULL) is equivalent to RESET */ |
8312 | (void) set_config_option(name, |
8313 | value, |
8314 | (superuser() ? PGC_SUSET : PGC_USERSET), |
8315 | PGC_S_SESSION, |
8316 | is_local ? GUC_ACTION_LOCAL : GUC_ACTION_SET, |
8317 | true, 0, false); |
8318 | |
8319 | /* get the new current value */ |
8320 | new_value = GetConfigOptionByName(name, NULL, false); |
8321 | |
8322 | /* Convert return string to text */ |
8323 | PG_RETURN_TEXT_P(cstring_to_text(new_value)); |
8324 | } |
8325 | |
8326 | |
8327 | /* |
8328 | * Common code for DefineCustomXXXVariable subroutines: allocate the |
8329 | * new variable's config struct and fill in generic fields. |
8330 | */ |
8331 | static struct config_generic * |
8332 | init_custom_variable(const char *name, |
8333 | const char *short_desc, |
8334 | const char *long_desc, |
8335 | GucContext context, |
8336 | int flags, |
8337 | enum config_type type, |
8338 | size_t sz) |
8339 | { |
8340 | struct config_generic *gen; |
8341 | |
8342 | /* |
8343 | * Only allow custom PGC_POSTMASTER variables to be created during shared |
8344 | * library preload; any later than that, we can't ensure that the value |
8345 | * doesn't change after startup. This is a fatal elog if it happens; just |
8346 | * erroring out isn't safe because we don't know what the calling loadable |
8347 | * module might already have hooked into. |
8348 | */ |
8349 | if (context == PGC_POSTMASTER && |
8350 | !process_shared_preload_libraries_in_progress) |
8351 | elog(FATAL, "cannot create PGC_POSTMASTER variables after startup" ); |
8352 | |
8353 | /* |
8354 | * We can't support custom GUC_LIST_QUOTE variables, because the wrong |
8355 | * things would happen if such a variable were set or pg_dump'd when the |
8356 | * defining extension isn't loaded. Again, treat this as fatal because |
8357 | * the loadable module may be partly initialized already. |
8358 | */ |
8359 | if (flags & GUC_LIST_QUOTE) |
8360 | elog(FATAL, "extensions cannot define GUC_LIST_QUOTE variables" ); |
8361 | |
8362 | /* |
8363 | * Before pljava commit 398f3b876ed402bdaec8bc804f29e2be95c75139 |
8364 | * (2015-12-15), two of that module's PGC_USERSET variables facilitated |
8365 | * trivial escalation to superuser privileges. Restrict the variables to |
8366 | * protect sites that have yet to upgrade pljava. |
8367 | */ |
8368 | if (context == PGC_USERSET && |
8369 | (strcmp(name, "pljava.classpath" ) == 0 || |
8370 | strcmp(name, "pljava.vmoptions" ) == 0)) |
8371 | context = PGC_SUSET; |
8372 | |
8373 | gen = (struct config_generic *) guc_malloc(ERROR, sz); |
8374 | memset(gen, 0, sz); |
8375 | |
8376 | gen->name = guc_strdup(ERROR, name); |
8377 | gen->context = context; |
8378 | gen->group = CUSTOM_OPTIONS; |
8379 | gen->short_desc = short_desc; |
8380 | gen->long_desc = long_desc; |
8381 | gen->flags = flags; |
8382 | gen->vartype = type; |
8383 | |
8384 | return gen; |
8385 | } |
8386 | |
8387 | /* |
8388 | * Common code for DefineCustomXXXVariable subroutines: insert the new |
8389 | * variable into the GUC variable array, replacing any placeholder. |
8390 | */ |
8391 | static void |
8392 | define_custom_variable(struct config_generic *variable) |
8393 | { |
8394 | const char *name = variable->name; |
8395 | const char **nameAddr = &name; |
8396 | struct config_string *pHolder; |
8397 | struct config_generic **res; |
8398 | |
8399 | /* |
8400 | * See if there's a placeholder by the same name. |
8401 | */ |
8402 | res = (struct config_generic **) bsearch((void *) &nameAddr, |
8403 | (void *) guc_variables, |
8404 | num_guc_variables, |
8405 | sizeof(struct config_generic *), |
8406 | guc_var_compare); |
8407 | if (res == NULL) |
8408 | { |
8409 | /* |
8410 | * No placeholder to replace, so we can just add it ... but first, |
8411 | * make sure it's initialized to its default value. |
8412 | */ |
8413 | InitializeOneGUCOption(variable); |
8414 | add_guc_variable(variable, ERROR); |
8415 | return; |
8416 | } |
8417 | |
8418 | /* |
8419 | * This better be a placeholder |
8420 | */ |
8421 | if (((*res)->flags & GUC_CUSTOM_PLACEHOLDER) == 0) |
8422 | ereport(ERROR, |
8423 | (errcode(ERRCODE_INTERNAL_ERROR), |
8424 | errmsg("attempt to redefine parameter \"%s\"" , name))); |
8425 | |
8426 | Assert((*res)->vartype == PGC_STRING); |
8427 | pHolder = (struct config_string *) (*res); |
8428 | |
8429 | /* |
8430 | * First, set the variable to its default value. We must do this even |
8431 | * though we intend to immediately apply a new value, since it's possible |
8432 | * that the new value is invalid. |
8433 | */ |
8434 | InitializeOneGUCOption(variable); |
8435 | |
8436 | /* |
8437 | * Replace the placeholder. We aren't changing the name, so no re-sorting |
8438 | * is necessary |
8439 | */ |
8440 | *res = variable; |
8441 | |
8442 | /* |
8443 | * Assign the string value(s) stored in the placeholder to the real |
8444 | * variable. Essentially, we need to duplicate all the active and stacked |
8445 | * values, but with appropriate validation and datatype adjustment. |
8446 | * |
8447 | * If an assignment fails, we report a WARNING and keep going. We don't |
8448 | * want to throw ERROR for bad values, because it'd bollix the add-on |
8449 | * module that's presumably halfway through getting loaded. In such cases |
8450 | * the default or previous state will become active instead. |
8451 | */ |
8452 | |
8453 | /* First, apply the reset value if any */ |
8454 | if (pHolder->reset_val) |
8455 | (void) set_config_option(name, pHolder->reset_val, |
8456 | pHolder->gen.reset_scontext, |
8457 | pHolder->gen.reset_source, |
8458 | GUC_ACTION_SET, true, WARNING, false); |
8459 | /* That should not have resulted in stacking anything */ |
8460 | Assert(variable->stack == NULL); |
8461 | |
8462 | /* Now, apply current and stacked values, in the order they were stacked */ |
8463 | reapply_stacked_values(variable, pHolder, pHolder->gen.stack, |
8464 | *(pHolder->variable), |
8465 | pHolder->gen.scontext, pHolder->gen.source); |
8466 | |
8467 | /* Also copy over any saved source-location information */ |
8468 | if (pHolder->gen.sourcefile) |
8469 | set_config_sourcefile(name, pHolder->gen.sourcefile, |
8470 | pHolder->gen.sourceline); |
8471 | |
8472 | /* |
8473 | * Free up as much as we conveniently can of the placeholder structure. |
8474 | * (This neglects any stack items, so it's possible for some memory to be |
8475 | * leaked. Since this can only happen once per session per variable, it |
8476 | * doesn't seem worth spending much code on.) |
8477 | */ |
8478 | set_string_field(pHolder, pHolder->variable, NULL); |
8479 | set_string_field(pHolder, &pHolder->reset_val, NULL); |
8480 | |
8481 | free(pHolder); |
8482 | } |
8483 | |
8484 | /* |
8485 | * Recursive subroutine for define_custom_variable: reapply non-reset values |
8486 | * |
8487 | * We recurse so that the values are applied in the same order as originally. |
8488 | * At each recursion level, apply the upper-level value (passed in) in the |
8489 | * fashion implied by the stack entry. |
8490 | */ |
8491 | static void |
8492 | reapply_stacked_values(struct config_generic *variable, |
8493 | struct config_string *pHolder, |
8494 | GucStack *stack, |
8495 | const char *curvalue, |
8496 | GucContext curscontext, GucSource cursource) |
8497 | { |
8498 | const char *name = variable->name; |
8499 | GucStack *oldvarstack = variable->stack; |
8500 | |
8501 | if (stack != NULL) |
8502 | { |
8503 | /* First, recurse, so that stack items are processed bottom to top */ |
8504 | reapply_stacked_values(variable, pHolder, stack->prev, |
8505 | stack->prior.val.stringval, |
8506 | stack->scontext, stack->source); |
8507 | |
8508 | /* See how to apply the passed-in value */ |
8509 | switch (stack->state) |
8510 | { |
8511 | case GUC_SAVE: |
8512 | (void) set_config_option(name, curvalue, |
8513 | curscontext, cursource, |
8514 | GUC_ACTION_SAVE, true, |
8515 | WARNING, false); |
8516 | break; |
8517 | |
8518 | case GUC_SET: |
8519 | (void) set_config_option(name, curvalue, |
8520 | curscontext, cursource, |
8521 | GUC_ACTION_SET, true, |
8522 | WARNING, false); |
8523 | break; |
8524 | |
8525 | case GUC_LOCAL: |
8526 | (void) set_config_option(name, curvalue, |
8527 | curscontext, cursource, |
8528 | GUC_ACTION_LOCAL, true, |
8529 | WARNING, false); |
8530 | break; |
8531 | |
8532 | case GUC_SET_LOCAL: |
8533 | /* first, apply the masked value as SET */ |
8534 | (void) set_config_option(name, stack->masked.val.stringval, |
8535 | stack->masked_scontext, PGC_S_SESSION, |
8536 | GUC_ACTION_SET, true, |
8537 | WARNING, false); |
8538 | /* then apply the current value as LOCAL */ |
8539 | (void) set_config_option(name, curvalue, |
8540 | curscontext, cursource, |
8541 | GUC_ACTION_LOCAL, true, |
8542 | WARNING, false); |
8543 | break; |
8544 | } |
8545 | |
8546 | /* If we successfully made a stack entry, adjust its nest level */ |
8547 | if (variable->stack != oldvarstack) |
8548 | variable->stack->nest_level = stack->nest_level; |
8549 | } |
8550 | else |
8551 | { |
8552 | /* |
8553 | * We are at the end of the stack. If the active/previous value is |
8554 | * different from the reset value, it must represent a previously |
8555 | * committed session value. Apply it, and then drop the stack entry |
8556 | * that set_config_option will have created under the impression that |
8557 | * this is to be just a transactional assignment. (We leak the stack |
8558 | * entry.) |
8559 | */ |
8560 | if (curvalue != pHolder->reset_val || |
8561 | curscontext != pHolder->gen.reset_scontext || |
8562 | cursource != pHolder->gen.reset_source) |
8563 | { |
8564 | (void) set_config_option(name, curvalue, |
8565 | curscontext, cursource, |
8566 | GUC_ACTION_SET, true, WARNING, false); |
8567 | variable->stack = NULL; |
8568 | } |
8569 | } |
8570 | } |
8571 | |
8572 | void |
8573 | DefineCustomBoolVariable(const char *name, |
8574 | const char *short_desc, |
8575 | const char *long_desc, |
8576 | bool *valueAddr, |
8577 | bool bootValue, |
8578 | GucContext context, |
8579 | int flags, |
8580 | GucBoolCheckHook check_hook, |
8581 | GucBoolAssignHook assign_hook, |
8582 | GucShowHook show_hook) |
8583 | { |
8584 | struct config_bool *var; |
8585 | |
8586 | var = (struct config_bool *) |
8587 | init_custom_variable(name, short_desc, long_desc, context, flags, |
8588 | PGC_BOOL, sizeof(struct config_bool)); |
8589 | var->variable = valueAddr; |
8590 | var->boot_val = bootValue; |
8591 | var->reset_val = bootValue; |
8592 | var->check_hook = check_hook; |
8593 | var->assign_hook = assign_hook; |
8594 | var->show_hook = show_hook; |
8595 | define_custom_variable(&var->gen); |
8596 | } |
8597 | |
8598 | void |
8599 | DefineCustomIntVariable(const char *name, |
8600 | const char *short_desc, |
8601 | const char *long_desc, |
8602 | int *valueAddr, |
8603 | int bootValue, |
8604 | int minValue, |
8605 | int maxValue, |
8606 | GucContext context, |
8607 | int flags, |
8608 | GucIntCheckHook check_hook, |
8609 | GucIntAssignHook assign_hook, |
8610 | GucShowHook show_hook) |
8611 | { |
8612 | struct config_int *var; |
8613 | |
8614 | var = (struct config_int *) |
8615 | init_custom_variable(name, short_desc, long_desc, context, flags, |
8616 | PGC_INT, sizeof(struct config_int)); |
8617 | var->variable = valueAddr; |
8618 | var->boot_val = bootValue; |
8619 | var->reset_val = bootValue; |
8620 | var->min = minValue; |
8621 | var->max = maxValue; |
8622 | var->check_hook = check_hook; |
8623 | var->assign_hook = assign_hook; |
8624 | var->show_hook = show_hook; |
8625 | define_custom_variable(&var->gen); |
8626 | } |
8627 | |
8628 | void |
8629 | DefineCustomRealVariable(const char *name, |
8630 | const char *short_desc, |
8631 | const char *long_desc, |
8632 | double *valueAddr, |
8633 | double bootValue, |
8634 | double minValue, |
8635 | double maxValue, |
8636 | GucContext context, |
8637 | int flags, |
8638 | GucRealCheckHook check_hook, |
8639 | GucRealAssignHook assign_hook, |
8640 | GucShowHook show_hook) |
8641 | { |
8642 | struct config_real *var; |
8643 | |
8644 | var = (struct config_real *) |
8645 | init_custom_variable(name, short_desc, long_desc, context, flags, |
8646 | PGC_REAL, sizeof(struct config_real)); |
8647 | var->variable = valueAddr; |
8648 | var->boot_val = bootValue; |
8649 | var->reset_val = bootValue; |
8650 | var->min = minValue; |
8651 | var->max = maxValue; |
8652 | var->check_hook = check_hook; |
8653 | var->assign_hook = assign_hook; |
8654 | var->show_hook = show_hook; |
8655 | define_custom_variable(&var->gen); |
8656 | } |
8657 | |
8658 | void |
8659 | DefineCustomStringVariable(const char *name, |
8660 | const char *short_desc, |
8661 | const char *long_desc, |
8662 | char **valueAddr, |
8663 | const char *bootValue, |
8664 | GucContext context, |
8665 | int flags, |
8666 | GucStringCheckHook check_hook, |
8667 | GucStringAssignHook assign_hook, |
8668 | GucShowHook show_hook) |
8669 | { |
8670 | struct config_string *var; |
8671 | |
8672 | var = (struct config_string *) |
8673 | init_custom_variable(name, short_desc, long_desc, context, flags, |
8674 | PGC_STRING, sizeof(struct config_string)); |
8675 | var->variable = valueAddr; |
8676 | var->boot_val = bootValue; |
8677 | var->check_hook = check_hook; |
8678 | var->assign_hook = assign_hook; |
8679 | var->show_hook = show_hook; |
8680 | define_custom_variable(&var->gen); |
8681 | } |
8682 | |
8683 | void |
8684 | (const char *name, |
8685 | const char *short_desc, |
8686 | const char *long_desc, |
8687 | int *valueAddr, |
8688 | int bootValue, |
8689 | const struct config_enum_entry *options, |
8690 | GucContext context, |
8691 | int flags, |
8692 | GucEnumCheckHook check_hook, |
8693 | GucEnumAssignHook assign_hook, |
8694 | GucShowHook show_hook) |
8695 | { |
8696 | struct config_enum *var; |
8697 | |
8698 | var = (struct config_enum *) |
8699 | init_custom_variable(name, short_desc, long_desc, context, flags, |
8700 | PGC_ENUM, sizeof(struct config_enum)); |
8701 | var->variable = valueAddr; |
8702 | var->boot_val = bootValue; |
8703 | var->reset_val = bootValue; |
8704 | var->options = options; |
8705 | var->check_hook = check_hook; |
8706 | var->assign_hook = assign_hook; |
8707 | var->show_hook = show_hook; |
8708 | define_custom_variable(&var->gen); |
8709 | } |
8710 | |
8711 | void |
8712 | EmitWarningsOnPlaceholders(const char *className) |
8713 | { |
8714 | int classLen = strlen(className); |
8715 | int i; |
8716 | |
8717 | for (i = 0; i < num_guc_variables; i++) |
8718 | { |
8719 | struct config_generic *var = guc_variables[i]; |
8720 | |
8721 | if ((var->flags & GUC_CUSTOM_PLACEHOLDER) != 0 && |
8722 | strncmp(className, var->name, classLen) == 0 && |
8723 | var->name[classLen] == GUC_QUALIFIER_SEPARATOR) |
8724 | { |
8725 | ereport(WARNING, |
8726 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
8727 | errmsg("unrecognized configuration parameter \"%s\"" , |
8728 | var->name))); |
8729 | } |
8730 | } |
8731 | } |
8732 | |
8733 | |
8734 | /* |
8735 | * SHOW command |
8736 | */ |
8737 | void |
8738 | GetPGVariable(const char *name, DestReceiver *dest) |
8739 | { |
8740 | if (guc_name_compare(name, "all" ) == 0) |
8741 | ShowAllGUCConfig(dest); |
8742 | else |
8743 | ShowGUCConfigOption(name, dest); |
8744 | } |
8745 | |
8746 | TupleDesc |
8747 | GetPGVariableResultDesc(const char *name) |
8748 | { |
8749 | TupleDesc tupdesc; |
8750 | |
8751 | if (guc_name_compare(name, "all" ) == 0) |
8752 | { |
8753 | /* need a tuple descriptor representing three TEXT columns */ |
8754 | tupdesc = CreateTemplateTupleDesc(3); |
8755 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name" , |
8756 | TEXTOID, -1, 0); |
8757 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting" , |
8758 | TEXTOID, -1, 0); |
8759 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "description" , |
8760 | TEXTOID, -1, 0); |
8761 | } |
8762 | else |
8763 | { |
8764 | const char *varname; |
8765 | |
8766 | /* Get the canonical spelling of name */ |
8767 | (void) GetConfigOptionByName(name, &varname, false); |
8768 | |
8769 | /* need a tuple descriptor representing a single TEXT column */ |
8770 | tupdesc = CreateTemplateTupleDesc(1); |
8771 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, varname, |
8772 | TEXTOID, -1, 0); |
8773 | } |
8774 | return tupdesc; |
8775 | } |
8776 | |
8777 | |
8778 | /* |
8779 | * SHOW command |
8780 | */ |
8781 | static void |
8782 | ShowGUCConfigOption(const char *name, DestReceiver *dest) |
8783 | { |
8784 | TupOutputState *tstate; |
8785 | TupleDesc tupdesc; |
8786 | const char *varname; |
8787 | char *value; |
8788 | |
8789 | /* Get the value and canonical spelling of name */ |
8790 | value = GetConfigOptionByName(name, &varname, false); |
8791 | |
8792 | /* need a tuple descriptor representing a single TEXT column */ |
8793 | tupdesc = CreateTemplateTupleDesc(1); |
8794 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, varname, |
8795 | TEXTOID, -1, 0); |
8796 | |
8797 | /* prepare for projection of tuples */ |
8798 | tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); |
8799 | |
8800 | /* Send it */ |
8801 | do_text_output_oneline(tstate, value); |
8802 | |
8803 | end_tup_output(tstate); |
8804 | } |
8805 | |
8806 | /* |
8807 | * SHOW ALL command |
8808 | */ |
8809 | static void |
8810 | ShowAllGUCConfig(DestReceiver *dest) |
8811 | { |
8812 | int i; |
8813 | TupOutputState *tstate; |
8814 | TupleDesc tupdesc; |
8815 | Datum values[3]; |
8816 | bool isnull[3] = {false, false, false}; |
8817 | |
8818 | /* need a tuple descriptor representing three TEXT columns */ |
8819 | tupdesc = CreateTemplateTupleDesc(3); |
8820 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "name" , |
8821 | TEXTOID, -1, 0); |
8822 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "setting" , |
8823 | TEXTOID, -1, 0); |
8824 | TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "description" , |
8825 | TEXTOID, -1, 0); |
8826 | |
8827 | /* prepare for projection of tuples */ |
8828 | tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual); |
8829 | |
8830 | for (i = 0; i < num_guc_variables; i++) |
8831 | { |
8832 | struct config_generic *conf = guc_variables[i]; |
8833 | char *setting; |
8834 | |
8835 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
8836 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
8837 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
8838 | continue; |
8839 | |
8840 | /* assign to the values array */ |
8841 | values[0] = PointerGetDatum(cstring_to_text(conf->name)); |
8842 | |
8843 | setting = _ShowOption(conf, true); |
8844 | if (setting) |
8845 | { |
8846 | values[1] = PointerGetDatum(cstring_to_text(setting)); |
8847 | isnull[1] = false; |
8848 | } |
8849 | else |
8850 | { |
8851 | values[1] = PointerGetDatum(NULL); |
8852 | isnull[1] = true; |
8853 | } |
8854 | |
8855 | values[2] = PointerGetDatum(cstring_to_text(conf->short_desc)); |
8856 | |
8857 | /* send it to dest */ |
8858 | do_tup_output(tstate, values, isnull); |
8859 | |
8860 | /* clean up */ |
8861 | pfree(DatumGetPointer(values[0])); |
8862 | if (setting) |
8863 | { |
8864 | pfree(setting); |
8865 | pfree(DatumGetPointer(values[1])); |
8866 | } |
8867 | pfree(DatumGetPointer(values[2])); |
8868 | } |
8869 | |
8870 | end_tup_output(tstate); |
8871 | } |
8872 | |
8873 | /* |
8874 | * Returns an array of modified GUC options to show in EXPLAIN. Only options |
8875 | * related to query planning (marked with GUC_EXPLAIN), with values different |
8876 | * from built-in defaults. |
8877 | */ |
8878 | struct config_generic ** |
8879 | get_explain_guc_options(int *num) |
8880 | { |
8881 | int i; |
8882 | struct config_generic **result; |
8883 | |
8884 | *num = 0; |
8885 | |
8886 | /* |
8887 | * Allocate enough space to fit all GUC_EXPLAIN options. We may not need |
8888 | * all the space, but there are fairly few such options so we don't waste |
8889 | * a lot of memory. |
8890 | */ |
8891 | result = palloc(sizeof(struct config_generic *) * num_guc_explain_variables); |
8892 | |
8893 | for (i = 0; i < num_guc_variables; i++) |
8894 | { |
8895 | bool modified; |
8896 | struct config_generic *conf = guc_variables[i]; |
8897 | |
8898 | /* return only options visible to the user */ |
8899 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
8900 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
8901 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
8902 | continue; |
8903 | |
8904 | /* only parameters explicitly marked for inclusion in explain */ |
8905 | if (!(conf->flags & GUC_EXPLAIN)) |
8906 | continue; |
8907 | |
8908 | /* return only options that were modified (w.r.t. config file) */ |
8909 | modified = false; |
8910 | |
8911 | switch (conf->vartype) |
8912 | { |
8913 | case PGC_BOOL: |
8914 | { |
8915 | struct config_bool *lconf = (struct config_bool *) conf; |
8916 | |
8917 | modified = (lconf->boot_val != *(lconf->variable)); |
8918 | } |
8919 | break; |
8920 | |
8921 | case PGC_INT: |
8922 | { |
8923 | struct config_int *lconf = (struct config_int *) conf; |
8924 | |
8925 | modified = (lconf->boot_val != *(lconf->variable)); |
8926 | } |
8927 | break; |
8928 | |
8929 | case PGC_REAL: |
8930 | { |
8931 | struct config_real *lconf = (struct config_real *) conf; |
8932 | |
8933 | modified = (lconf->boot_val != *(lconf->variable)); |
8934 | } |
8935 | break; |
8936 | |
8937 | case PGC_STRING: |
8938 | { |
8939 | struct config_string *lconf = (struct config_string *) conf; |
8940 | |
8941 | modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0); |
8942 | } |
8943 | break; |
8944 | |
8945 | case PGC_ENUM: |
8946 | { |
8947 | struct config_enum *lconf = (struct config_enum *) conf; |
8948 | |
8949 | modified = (lconf->boot_val != *(lconf->variable)); |
8950 | } |
8951 | break; |
8952 | |
8953 | default: |
8954 | elog(ERROR, "unexpected GUC type: %d" , conf->vartype); |
8955 | } |
8956 | |
8957 | /* skip GUC variables that match the built-in default */ |
8958 | if (!modified) |
8959 | continue; |
8960 | |
8961 | /* assign to the values array */ |
8962 | result[*num] = conf; |
8963 | *num = *num + 1; |
8964 | |
8965 | Assert(*num <= num_guc_explain_variables); |
8966 | } |
8967 | |
8968 | return result; |
8969 | } |
8970 | |
8971 | /* |
8972 | * Return GUC variable value by name; optionally return canonical form of |
8973 | * name. If the GUC is unset, then throw an error unless missing_ok is true, |
8974 | * in which case return NULL. Return value is palloc'd (but *varname isn't). |
8975 | */ |
8976 | char * |
8977 | GetConfigOptionByName(const char *name, const char **varname, bool missing_ok) |
8978 | { |
8979 | struct config_generic *record; |
8980 | |
8981 | record = find_option(name, false, ERROR); |
8982 | if (record == NULL) |
8983 | { |
8984 | if (missing_ok) |
8985 | { |
8986 | if (varname) |
8987 | *varname = NULL; |
8988 | return NULL; |
8989 | } |
8990 | |
8991 | ereport(ERROR, |
8992 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
8993 | errmsg("unrecognized configuration parameter \"%s\"" , name))); |
8994 | } |
8995 | |
8996 | if ((record->flags & GUC_SUPERUSER_ONLY) && |
8997 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
8998 | ereport(ERROR, |
8999 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
9000 | errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"" , |
9001 | name))); |
9002 | |
9003 | if (varname) |
9004 | *varname = record->name; |
9005 | |
9006 | return _ShowOption(record, true); |
9007 | } |
9008 | |
9009 | /* |
9010 | * Return GUC variable value by variable number; optionally return canonical |
9011 | * form of name. Return value is palloc'd. |
9012 | */ |
9013 | void |
9014 | GetConfigOptionByNum(int varnum, const char **values, bool *noshow) |
9015 | { |
9016 | char buffer[256]; |
9017 | struct config_generic *conf; |
9018 | |
9019 | /* check requested variable number valid */ |
9020 | Assert((varnum >= 0) && (varnum < num_guc_variables)); |
9021 | |
9022 | conf = guc_variables[varnum]; |
9023 | |
9024 | if (noshow) |
9025 | { |
9026 | if ((conf->flags & GUC_NO_SHOW_ALL) || |
9027 | ((conf->flags & GUC_SUPERUSER_ONLY) && |
9028 | !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))) |
9029 | *noshow = true; |
9030 | else |
9031 | *noshow = false; |
9032 | } |
9033 | |
9034 | /* first get the generic attributes */ |
9035 | |
9036 | /* name */ |
9037 | values[0] = conf->name; |
9038 | |
9039 | /* setting: use _ShowOption in order to avoid duplicating the logic */ |
9040 | values[1] = _ShowOption(conf, false); |
9041 | |
9042 | /* unit, if any (NULL is fine) */ |
9043 | values[2] = get_config_unit_name(conf->flags); |
9044 | |
9045 | /* group */ |
9046 | values[3] = _(config_group_names[conf->group]); |
9047 | |
9048 | /* short_desc */ |
9049 | values[4] = _(conf->short_desc); |
9050 | |
9051 | /* extra_desc */ |
9052 | values[5] = _(conf->long_desc); |
9053 | |
9054 | /* context */ |
9055 | values[6] = GucContext_Names[conf->context]; |
9056 | |
9057 | /* vartype */ |
9058 | values[7] = config_type_names[conf->vartype]; |
9059 | |
9060 | /* source */ |
9061 | values[8] = GucSource_Names[conf->source]; |
9062 | |
9063 | /* now get the type specific attributes */ |
9064 | switch (conf->vartype) |
9065 | { |
9066 | case PGC_BOOL: |
9067 | { |
9068 | struct config_bool *lconf = (struct config_bool *) conf; |
9069 | |
9070 | /* min_val */ |
9071 | values[9] = NULL; |
9072 | |
9073 | /* max_val */ |
9074 | values[10] = NULL; |
9075 | |
9076 | /* enumvals */ |
9077 | values[11] = NULL; |
9078 | |
9079 | /* boot_val */ |
9080 | values[12] = pstrdup(lconf->boot_val ? "on" : "off" ); |
9081 | |
9082 | /* reset_val */ |
9083 | values[13] = pstrdup(lconf->reset_val ? "on" : "off" ); |
9084 | } |
9085 | break; |
9086 | |
9087 | case PGC_INT: |
9088 | { |
9089 | struct config_int *lconf = (struct config_int *) conf; |
9090 | |
9091 | /* min_val */ |
9092 | snprintf(buffer, sizeof(buffer), "%d" , lconf->min); |
9093 | values[9] = pstrdup(buffer); |
9094 | |
9095 | /* max_val */ |
9096 | snprintf(buffer, sizeof(buffer), "%d" , lconf->max); |
9097 | values[10] = pstrdup(buffer); |
9098 | |
9099 | /* enumvals */ |
9100 | values[11] = NULL; |
9101 | |
9102 | /* boot_val */ |
9103 | snprintf(buffer, sizeof(buffer), "%d" , lconf->boot_val); |
9104 | values[12] = pstrdup(buffer); |
9105 | |
9106 | /* reset_val */ |
9107 | snprintf(buffer, sizeof(buffer), "%d" , lconf->reset_val); |
9108 | values[13] = pstrdup(buffer); |
9109 | } |
9110 | break; |
9111 | |
9112 | case PGC_REAL: |
9113 | { |
9114 | struct config_real *lconf = (struct config_real *) conf; |
9115 | |
9116 | /* min_val */ |
9117 | snprintf(buffer, sizeof(buffer), "%g" , lconf->min); |
9118 | values[9] = pstrdup(buffer); |
9119 | |
9120 | /* max_val */ |
9121 | snprintf(buffer, sizeof(buffer), "%g" , lconf->max); |
9122 | values[10] = pstrdup(buffer); |
9123 | |
9124 | /* enumvals */ |
9125 | values[11] = NULL; |
9126 | |
9127 | /* boot_val */ |
9128 | snprintf(buffer, sizeof(buffer), "%g" , lconf->boot_val); |
9129 | values[12] = pstrdup(buffer); |
9130 | |
9131 | /* reset_val */ |
9132 | snprintf(buffer, sizeof(buffer), "%g" , lconf->reset_val); |
9133 | values[13] = pstrdup(buffer); |
9134 | } |
9135 | break; |
9136 | |
9137 | case PGC_STRING: |
9138 | { |
9139 | struct config_string *lconf = (struct config_string *) conf; |
9140 | |
9141 | /* min_val */ |
9142 | values[9] = NULL; |
9143 | |
9144 | /* max_val */ |
9145 | values[10] = NULL; |
9146 | |
9147 | /* enumvals */ |
9148 | values[11] = NULL; |
9149 | |
9150 | /* boot_val */ |
9151 | if (lconf->boot_val == NULL) |
9152 | values[12] = NULL; |
9153 | else |
9154 | values[12] = pstrdup(lconf->boot_val); |
9155 | |
9156 | /* reset_val */ |
9157 | if (lconf->reset_val == NULL) |
9158 | values[13] = NULL; |
9159 | else |
9160 | values[13] = pstrdup(lconf->reset_val); |
9161 | } |
9162 | break; |
9163 | |
9164 | case PGC_ENUM: |
9165 | { |
9166 | struct config_enum *lconf = (struct config_enum *) conf; |
9167 | |
9168 | /* min_val */ |
9169 | values[9] = NULL; |
9170 | |
9171 | /* max_val */ |
9172 | values[10] = NULL; |
9173 | |
9174 | /* enumvals */ |
9175 | |
9176 | /* |
9177 | * NOTE! enumvals with double quotes in them are not |
9178 | * supported! |
9179 | */ |
9180 | values[11] = config_enum_get_options((struct config_enum *) conf, |
9181 | "{\"" , "\"}" , "\",\"" ); |
9182 | |
9183 | /* boot_val */ |
9184 | values[12] = pstrdup(config_enum_lookup_by_value(lconf, |
9185 | lconf->boot_val)); |
9186 | |
9187 | /* reset_val */ |
9188 | values[13] = pstrdup(config_enum_lookup_by_value(lconf, |
9189 | lconf->reset_val)); |
9190 | } |
9191 | break; |
9192 | |
9193 | default: |
9194 | { |
9195 | /* |
9196 | * should never get here, but in case we do, set 'em to NULL |
9197 | */ |
9198 | |
9199 | /* min_val */ |
9200 | values[9] = NULL; |
9201 | |
9202 | /* max_val */ |
9203 | values[10] = NULL; |
9204 | |
9205 | /* enumvals */ |
9206 | values[11] = NULL; |
9207 | |
9208 | /* boot_val */ |
9209 | values[12] = NULL; |
9210 | |
9211 | /* reset_val */ |
9212 | values[13] = NULL; |
9213 | } |
9214 | break; |
9215 | } |
9216 | |
9217 | /* |
9218 | * If the setting came from a config file, set the source location. For |
9219 | * security reasons, we don't show source file/line number for |
9220 | * insufficiently-privileged users. |
9221 | */ |
9222 | if (conf->source == PGC_S_FILE && |
9223 | is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)) |
9224 | { |
9225 | values[14] = conf->sourcefile; |
9226 | snprintf(buffer, sizeof(buffer), "%d" , conf->sourceline); |
9227 | values[15] = pstrdup(buffer); |
9228 | } |
9229 | else |
9230 | { |
9231 | values[14] = NULL; |
9232 | values[15] = NULL; |
9233 | } |
9234 | |
9235 | values[16] = (conf->status & GUC_PENDING_RESTART) ? "t" : "f" ; |
9236 | } |
9237 | |
9238 | /* |
9239 | * Return the total number of GUC variables |
9240 | */ |
9241 | int |
9242 | GetNumConfigOptions(void) |
9243 | { |
9244 | return num_guc_variables; |
9245 | } |
9246 | |
9247 | /* |
9248 | * show_config_by_name - equiv to SHOW X command but implemented as |
9249 | * a function. |
9250 | */ |
9251 | Datum |
9252 | show_config_by_name(PG_FUNCTION_ARGS) |
9253 | { |
9254 | char *varname = TextDatumGetCString(PG_GETARG_DATUM(0)); |
9255 | char *varval; |
9256 | |
9257 | /* Get the value */ |
9258 | varval = GetConfigOptionByName(varname, NULL, false); |
9259 | |
9260 | /* Convert to text */ |
9261 | PG_RETURN_TEXT_P(cstring_to_text(varval)); |
9262 | } |
9263 | |
9264 | /* |
9265 | * show_config_by_name_missing_ok - equiv to SHOW X command but implemented as |
9266 | * a function. If X does not exist, suppress the error and just return NULL |
9267 | * if missing_ok is true. |
9268 | */ |
9269 | Datum |
9270 | show_config_by_name_missing_ok(PG_FUNCTION_ARGS) |
9271 | { |
9272 | char *varname = TextDatumGetCString(PG_GETARG_DATUM(0)); |
9273 | bool missing_ok = PG_GETARG_BOOL(1); |
9274 | char *varval; |
9275 | |
9276 | /* Get the value */ |
9277 | varval = GetConfigOptionByName(varname, NULL, missing_ok); |
9278 | |
9279 | /* return NULL if no such variable */ |
9280 | if (varval == NULL) |
9281 | PG_RETURN_NULL(); |
9282 | |
9283 | /* Convert to text */ |
9284 | PG_RETURN_TEXT_P(cstring_to_text(varval)); |
9285 | } |
9286 | |
9287 | /* |
9288 | * show_all_settings - equiv to SHOW ALL command but implemented as |
9289 | * a Table Function. |
9290 | */ |
9291 | #define NUM_PG_SETTINGS_ATTS 17 |
9292 | |
9293 | Datum |
9294 | show_all_settings(PG_FUNCTION_ARGS) |
9295 | { |
9296 | FuncCallContext *funcctx; |
9297 | TupleDesc tupdesc; |
9298 | int call_cntr; |
9299 | int max_calls; |
9300 | AttInMetadata *attinmeta; |
9301 | MemoryContext oldcontext; |
9302 | |
9303 | /* stuff done only on the first call of the function */ |
9304 | if (SRF_IS_FIRSTCALL()) |
9305 | { |
9306 | /* create a function context for cross-call persistence */ |
9307 | funcctx = SRF_FIRSTCALL_INIT(); |
9308 | |
9309 | /* |
9310 | * switch to memory context appropriate for multiple function calls |
9311 | */ |
9312 | oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); |
9313 | |
9314 | /* |
9315 | * need a tuple descriptor representing NUM_PG_SETTINGS_ATTS columns |
9316 | * of the appropriate types |
9317 | */ |
9318 | tupdesc = CreateTemplateTupleDesc(NUM_PG_SETTINGS_ATTS); |
9319 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name" , |
9320 | TEXTOID, -1, 0); |
9321 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting" , |
9322 | TEXTOID, -1, 0); |
9323 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "unit" , |
9324 | TEXTOID, -1, 0); |
9325 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "category" , |
9326 | TEXTOID, -1, 0); |
9327 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "short_desc" , |
9328 | TEXTOID, -1, 0); |
9329 | TupleDescInitEntry(tupdesc, (AttrNumber) 6, "extra_desc" , |
9330 | TEXTOID, -1, 0); |
9331 | TupleDescInitEntry(tupdesc, (AttrNumber) 7, "context" , |
9332 | TEXTOID, -1, 0); |
9333 | TupleDescInitEntry(tupdesc, (AttrNumber) 8, "vartype" , |
9334 | TEXTOID, -1, 0); |
9335 | TupleDescInitEntry(tupdesc, (AttrNumber) 9, "source" , |
9336 | TEXTOID, -1, 0); |
9337 | TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_val" , |
9338 | TEXTOID, -1, 0); |
9339 | TupleDescInitEntry(tupdesc, (AttrNumber) 11, "max_val" , |
9340 | TEXTOID, -1, 0); |
9341 | TupleDescInitEntry(tupdesc, (AttrNumber) 12, "enumvals" , |
9342 | TEXTARRAYOID, -1, 0); |
9343 | TupleDescInitEntry(tupdesc, (AttrNumber) 13, "boot_val" , |
9344 | TEXTOID, -1, 0); |
9345 | TupleDescInitEntry(tupdesc, (AttrNumber) 14, "reset_val" , |
9346 | TEXTOID, -1, 0); |
9347 | TupleDescInitEntry(tupdesc, (AttrNumber) 15, "sourcefile" , |
9348 | TEXTOID, -1, 0); |
9349 | TupleDescInitEntry(tupdesc, (AttrNumber) 16, "sourceline" , |
9350 | INT4OID, -1, 0); |
9351 | TupleDescInitEntry(tupdesc, (AttrNumber) 17, "pending_restart" , |
9352 | BOOLOID, -1, 0); |
9353 | |
9354 | /* |
9355 | * Generate attribute metadata needed later to produce tuples from raw |
9356 | * C strings |
9357 | */ |
9358 | attinmeta = TupleDescGetAttInMetadata(tupdesc); |
9359 | funcctx->attinmeta = attinmeta; |
9360 | |
9361 | /* total number of tuples to be returned */ |
9362 | funcctx->max_calls = GetNumConfigOptions(); |
9363 | |
9364 | MemoryContextSwitchTo(oldcontext); |
9365 | } |
9366 | |
9367 | /* stuff done on every call of the function */ |
9368 | funcctx = SRF_PERCALL_SETUP(); |
9369 | |
9370 | call_cntr = funcctx->call_cntr; |
9371 | max_calls = funcctx->max_calls; |
9372 | attinmeta = funcctx->attinmeta; |
9373 | |
9374 | if (call_cntr < max_calls) /* do when there is more left to send */ |
9375 | { |
9376 | char *values[NUM_PG_SETTINGS_ATTS]; |
9377 | bool noshow; |
9378 | HeapTuple tuple; |
9379 | Datum result; |
9380 | |
9381 | /* |
9382 | * Get the next visible GUC variable name and value |
9383 | */ |
9384 | do |
9385 | { |
9386 | GetConfigOptionByNum(call_cntr, (const char **) values, &noshow); |
9387 | if (noshow) |
9388 | { |
9389 | /* bump the counter and get the next config setting */ |
9390 | call_cntr = ++funcctx->call_cntr; |
9391 | |
9392 | /* make sure we haven't gone too far now */ |
9393 | if (call_cntr >= max_calls) |
9394 | SRF_RETURN_DONE(funcctx); |
9395 | } |
9396 | } while (noshow); |
9397 | |
9398 | /* build a tuple */ |
9399 | tuple = BuildTupleFromCStrings(attinmeta, values); |
9400 | |
9401 | /* make the tuple into a datum */ |
9402 | result = HeapTupleGetDatum(tuple); |
9403 | |
9404 | SRF_RETURN_NEXT(funcctx, result); |
9405 | } |
9406 | else |
9407 | { |
9408 | /* do when there is no more left */ |
9409 | SRF_RETURN_DONE(funcctx); |
9410 | } |
9411 | } |
9412 | |
9413 | /* |
9414 | * show_all_file_settings |
9415 | * |
9416 | * Returns a table of all parameter settings in all configuration files |
9417 | * which includes the config file pathname, the line number, a sequence number |
9418 | * indicating the order in which the settings were encountered, the parameter |
9419 | * name and value, a bool showing if the value could be applied, and possibly |
9420 | * an associated error message. (For problems such as syntax errors, the |
9421 | * parameter name/value might be NULL.) |
9422 | * |
9423 | * Note: no filtering is done here, instead we depend on the GRANT system |
9424 | * to prevent unprivileged users from accessing this function or the view |
9425 | * built on top of it. |
9426 | */ |
9427 | Datum |
9428 | show_all_file_settings(PG_FUNCTION_ARGS) |
9429 | { |
9430 | #define NUM_PG_FILE_SETTINGS_ATTS 7 |
9431 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; |
9432 | TupleDesc tupdesc; |
9433 | Tuplestorestate *tupstore; |
9434 | ConfigVariable *conf; |
9435 | int seqno; |
9436 | MemoryContext per_query_ctx; |
9437 | MemoryContext oldcontext; |
9438 | |
9439 | /* Check to see if caller supports us returning a tuplestore */ |
9440 | if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) |
9441 | ereport(ERROR, |
9442 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
9443 | errmsg("set-valued function called in context that cannot accept a set" ))); |
9444 | if (!(rsinfo->allowedModes & SFRM_Materialize)) |
9445 | ereport(ERROR, |
9446 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
9447 | errmsg("materialize mode required, but it is not " \ |
9448 | "allowed in this context" ))); |
9449 | |
9450 | /* Scan the config files using current context as workspace */ |
9451 | conf = ProcessConfigFileInternal(PGC_SIGHUP, false, DEBUG3); |
9452 | |
9453 | /* Switch into long-lived context to construct returned data structures */ |
9454 | per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; |
9455 | oldcontext = MemoryContextSwitchTo(per_query_ctx); |
9456 | |
9457 | /* Build a tuple descriptor for our result type */ |
9458 | tupdesc = CreateTemplateTupleDesc(NUM_PG_FILE_SETTINGS_ATTS); |
9459 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "sourcefile" , |
9460 | TEXTOID, -1, 0); |
9461 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "sourceline" , |
9462 | INT4OID, -1, 0); |
9463 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "seqno" , |
9464 | INT4OID, -1, 0); |
9465 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "name" , |
9466 | TEXTOID, -1, 0); |
9467 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "setting" , |
9468 | TEXTOID, -1, 0); |
9469 | TupleDescInitEntry(tupdesc, (AttrNumber) 6, "applied" , |
9470 | BOOLOID, -1, 0); |
9471 | TupleDescInitEntry(tupdesc, (AttrNumber) 7, "error" , |
9472 | TEXTOID, -1, 0); |
9473 | |
9474 | /* Build a tuplestore to return our results in */ |
9475 | tupstore = tuplestore_begin_heap(true, false, work_mem); |
9476 | rsinfo->returnMode = SFRM_Materialize; |
9477 | rsinfo->setResult = tupstore; |
9478 | rsinfo->setDesc = tupdesc; |
9479 | |
9480 | /* The rest can be done in short-lived context */ |
9481 | MemoryContextSwitchTo(oldcontext); |
9482 | |
9483 | /* Process the results and create a tuplestore */ |
9484 | for (seqno = 1; conf != NULL; conf = conf->next, seqno++) |
9485 | { |
9486 | Datum values[NUM_PG_FILE_SETTINGS_ATTS]; |
9487 | bool nulls[NUM_PG_FILE_SETTINGS_ATTS]; |
9488 | |
9489 | memset(values, 0, sizeof(values)); |
9490 | memset(nulls, 0, sizeof(nulls)); |
9491 | |
9492 | /* sourcefile */ |
9493 | if (conf->filename) |
9494 | values[0] = PointerGetDatum(cstring_to_text(conf->filename)); |
9495 | else |
9496 | nulls[0] = true; |
9497 | |
9498 | /* sourceline (not meaningful if no sourcefile) */ |
9499 | if (conf->filename) |
9500 | values[1] = Int32GetDatum(conf->sourceline); |
9501 | else |
9502 | nulls[1] = true; |
9503 | |
9504 | /* seqno */ |
9505 | values[2] = Int32GetDatum(seqno); |
9506 | |
9507 | /* name */ |
9508 | if (conf->name) |
9509 | values[3] = PointerGetDatum(cstring_to_text(conf->name)); |
9510 | else |
9511 | nulls[3] = true; |
9512 | |
9513 | /* setting */ |
9514 | if (conf->value) |
9515 | values[4] = PointerGetDatum(cstring_to_text(conf->value)); |
9516 | else |
9517 | nulls[4] = true; |
9518 | |
9519 | /* applied */ |
9520 | values[5] = BoolGetDatum(conf->applied); |
9521 | |
9522 | /* error */ |
9523 | if (conf->errmsg) |
9524 | values[6] = PointerGetDatum(cstring_to_text(conf->errmsg)); |
9525 | else |
9526 | nulls[6] = true; |
9527 | |
9528 | /* shove row into tuplestore */ |
9529 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); |
9530 | } |
9531 | |
9532 | tuplestore_donestoring(tupstore); |
9533 | |
9534 | return (Datum) 0; |
9535 | } |
9536 | |
9537 | static char * |
9538 | _ShowOption(struct config_generic *record, bool use_units) |
9539 | { |
9540 | char buffer[256]; |
9541 | const char *val; |
9542 | |
9543 | switch (record->vartype) |
9544 | { |
9545 | case PGC_BOOL: |
9546 | { |
9547 | struct config_bool *conf = (struct config_bool *) record; |
9548 | |
9549 | if (conf->show_hook) |
9550 | val = conf->show_hook(); |
9551 | else |
9552 | val = *conf->variable ? "on" : "off" ; |
9553 | } |
9554 | break; |
9555 | |
9556 | case PGC_INT: |
9557 | { |
9558 | struct config_int *conf = (struct config_int *) record; |
9559 | |
9560 | if (conf->show_hook) |
9561 | val = conf->show_hook(); |
9562 | else |
9563 | { |
9564 | /* |
9565 | * Use int64 arithmetic to avoid overflows in units |
9566 | * conversion. |
9567 | */ |
9568 | int64 result = *conf->variable; |
9569 | const char *unit; |
9570 | |
9571 | if (use_units && result > 0 && (record->flags & GUC_UNIT)) |
9572 | convert_int_from_base_unit(result, |
9573 | record->flags & GUC_UNIT, |
9574 | &result, &unit); |
9575 | else |
9576 | unit = "" ; |
9577 | |
9578 | snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s" , |
9579 | result, unit); |
9580 | val = buffer; |
9581 | } |
9582 | } |
9583 | break; |
9584 | |
9585 | case PGC_REAL: |
9586 | { |
9587 | struct config_real *conf = (struct config_real *) record; |
9588 | |
9589 | if (conf->show_hook) |
9590 | val = conf->show_hook(); |
9591 | else |
9592 | { |
9593 | double result = *conf->variable; |
9594 | const char *unit; |
9595 | |
9596 | if (use_units && result > 0 && (record->flags & GUC_UNIT)) |
9597 | convert_real_from_base_unit(result, |
9598 | record->flags & GUC_UNIT, |
9599 | &result, &unit); |
9600 | else |
9601 | unit = "" ; |
9602 | |
9603 | snprintf(buffer, sizeof(buffer), "%g%s" , |
9604 | result, unit); |
9605 | val = buffer; |
9606 | } |
9607 | } |
9608 | break; |
9609 | |
9610 | case PGC_STRING: |
9611 | { |
9612 | struct config_string *conf = (struct config_string *) record; |
9613 | |
9614 | if (conf->show_hook) |
9615 | val = conf->show_hook(); |
9616 | else if (*conf->variable && **conf->variable) |
9617 | val = *conf->variable; |
9618 | else |
9619 | val = "" ; |
9620 | } |
9621 | break; |
9622 | |
9623 | case PGC_ENUM: |
9624 | { |
9625 | struct config_enum *conf = (struct config_enum *) record; |
9626 | |
9627 | if (conf->show_hook) |
9628 | val = conf->show_hook(); |
9629 | else |
9630 | val = config_enum_lookup_by_value(conf, *conf->variable); |
9631 | } |
9632 | break; |
9633 | |
9634 | default: |
9635 | /* just to keep compiler quiet */ |
9636 | val = "???" ; |
9637 | break; |
9638 | } |
9639 | |
9640 | return pstrdup(val); |
9641 | } |
9642 | |
9643 | |
9644 | #ifdef EXEC_BACKEND |
9645 | |
9646 | /* |
9647 | * These routines dump out all non-default GUC options into a binary |
9648 | * file that is read by all exec'ed backends. The format is: |
9649 | * |
9650 | * variable name, string, null terminated |
9651 | * variable value, string, null terminated |
9652 | * variable sourcefile, string, null terminated (empty if none) |
9653 | * variable sourceline, integer |
9654 | * variable source, integer |
9655 | * variable scontext, integer |
9656 | */ |
9657 | static void |
9658 | write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) |
9659 | { |
9660 | if (gconf->source == PGC_S_DEFAULT) |
9661 | return; |
9662 | |
9663 | fprintf(fp, "%s" , gconf->name); |
9664 | fputc(0, fp); |
9665 | |
9666 | switch (gconf->vartype) |
9667 | { |
9668 | case PGC_BOOL: |
9669 | { |
9670 | struct config_bool *conf = (struct config_bool *) gconf; |
9671 | |
9672 | if (*conf->variable) |
9673 | fprintf(fp, "true" ); |
9674 | else |
9675 | fprintf(fp, "false" ); |
9676 | } |
9677 | break; |
9678 | |
9679 | case PGC_INT: |
9680 | { |
9681 | struct config_int *conf = (struct config_int *) gconf; |
9682 | |
9683 | fprintf(fp, "%d" , *conf->variable); |
9684 | } |
9685 | break; |
9686 | |
9687 | case PGC_REAL: |
9688 | { |
9689 | struct config_real *conf = (struct config_real *) gconf; |
9690 | |
9691 | fprintf(fp, "%.17g" , *conf->variable); |
9692 | } |
9693 | break; |
9694 | |
9695 | case PGC_STRING: |
9696 | { |
9697 | struct config_string *conf = (struct config_string *) gconf; |
9698 | |
9699 | fprintf(fp, "%s" , *conf->variable); |
9700 | } |
9701 | break; |
9702 | |
9703 | case PGC_ENUM: |
9704 | { |
9705 | struct config_enum *conf = (struct config_enum *) gconf; |
9706 | |
9707 | fprintf(fp, "%s" , |
9708 | config_enum_lookup_by_value(conf, *conf->variable)); |
9709 | } |
9710 | break; |
9711 | } |
9712 | |
9713 | fputc(0, fp); |
9714 | |
9715 | if (gconf->sourcefile) |
9716 | fprintf(fp, "%s" , gconf->sourcefile); |
9717 | fputc(0, fp); |
9718 | |
9719 | fwrite(&gconf->sourceline, 1, sizeof(gconf->sourceline), fp); |
9720 | fwrite(&gconf->source, 1, sizeof(gconf->source), fp); |
9721 | fwrite(&gconf->scontext, 1, sizeof(gconf->scontext), fp); |
9722 | } |
9723 | |
9724 | void |
9725 | write_nondefault_variables(GucContext context) |
9726 | { |
9727 | int elevel; |
9728 | FILE *fp; |
9729 | int i; |
9730 | |
9731 | Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP); |
9732 | |
9733 | elevel = (context == PGC_SIGHUP) ? LOG : ERROR; |
9734 | |
9735 | /* |
9736 | * Open file |
9737 | */ |
9738 | fp = AllocateFile(CONFIG_EXEC_PARAMS_NEW, "w" ); |
9739 | if (!fp) |
9740 | { |
9741 | ereport(elevel, |
9742 | (errcode_for_file_access(), |
9743 | errmsg("could not write to file \"%s\": %m" , |
9744 | CONFIG_EXEC_PARAMS_NEW))); |
9745 | return; |
9746 | } |
9747 | |
9748 | for (i = 0; i < num_guc_variables; i++) |
9749 | { |
9750 | write_one_nondefault_variable(fp, guc_variables[i]); |
9751 | } |
9752 | |
9753 | if (FreeFile(fp)) |
9754 | { |
9755 | ereport(elevel, |
9756 | (errcode_for_file_access(), |
9757 | errmsg("could not write to file \"%s\": %m" , |
9758 | CONFIG_EXEC_PARAMS_NEW))); |
9759 | return; |
9760 | } |
9761 | |
9762 | /* |
9763 | * Put new file in place. This could delay on Win32, but we don't hold |
9764 | * any exclusive locks. |
9765 | */ |
9766 | rename(CONFIG_EXEC_PARAMS_NEW, CONFIG_EXEC_PARAMS); |
9767 | } |
9768 | |
9769 | |
9770 | /* |
9771 | * Read string, including null byte from file |
9772 | * |
9773 | * Return NULL on EOF and nothing read |
9774 | */ |
9775 | static char * |
9776 | read_string_with_null(FILE *fp) |
9777 | { |
9778 | int i = 0, |
9779 | ch, |
9780 | maxlen = 256; |
9781 | char *str = NULL; |
9782 | |
9783 | do |
9784 | { |
9785 | if ((ch = fgetc(fp)) == EOF) |
9786 | { |
9787 | if (i == 0) |
9788 | return NULL; |
9789 | else |
9790 | elog(FATAL, "invalid format of exec config params file" ); |
9791 | } |
9792 | if (i == 0) |
9793 | str = guc_malloc(FATAL, maxlen); |
9794 | else if (i == maxlen) |
9795 | str = guc_realloc(FATAL, str, maxlen *= 2); |
9796 | str[i++] = ch; |
9797 | } while (ch != 0); |
9798 | |
9799 | return str; |
9800 | } |
9801 | |
9802 | |
9803 | /* |
9804 | * This routine loads a previous postmaster dump of its non-default |
9805 | * settings. |
9806 | */ |
9807 | void |
9808 | read_nondefault_variables(void) |
9809 | { |
9810 | FILE *fp; |
9811 | char *varname, |
9812 | *varvalue, |
9813 | *varsourcefile; |
9814 | int varsourceline; |
9815 | GucSource varsource; |
9816 | GucContext varscontext; |
9817 | |
9818 | /* |
9819 | * Assert that PGC_BACKEND/PGC_SU_BACKEND case in set_config_option() will |
9820 | * do the right thing. |
9821 | */ |
9822 | Assert(IsInitProcessingMode()); |
9823 | |
9824 | /* |
9825 | * Open file |
9826 | */ |
9827 | fp = AllocateFile(CONFIG_EXEC_PARAMS, "r" ); |
9828 | if (!fp) |
9829 | { |
9830 | /* File not found is fine */ |
9831 | if (errno != ENOENT) |
9832 | ereport(FATAL, |
9833 | (errcode_for_file_access(), |
9834 | errmsg("could not read from file \"%s\": %m" , |
9835 | CONFIG_EXEC_PARAMS))); |
9836 | return; |
9837 | } |
9838 | |
9839 | for (;;) |
9840 | { |
9841 | struct config_generic *record; |
9842 | |
9843 | if ((varname = read_string_with_null(fp)) == NULL) |
9844 | break; |
9845 | |
9846 | if ((record = find_option(varname, true, FATAL)) == NULL) |
9847 | elog(FATAL, "failed to locate variable \"%s\" in exec config params file" , varname); |
9848 | |
9849 | if ((varvalue = read_string_with_null(fp)) == NULL) |
9850 | elog(FATAL, "invalid format of exec config params file" ); |
9851 | if ((varsourcefile = read_string_with_null(fp)) == NULL) |
9852 | elog(FATAL, "invalid format of exec config params file" ); |
9853 | if (fread(&varsourceline, 1, sizeof(varsourceline), fp) != sizeof(varsourceline)) |
9854 | elog(FATAL, "invalid format of exec config params file" ); |
9855 | if (fread(&varsource, 1, sizeof(varsource), fp) != sizeof(varsource)) |
9856 | elog(FATAL, "invalid format of exec config params file" ); |
9857 | if (fread(&varscontext, 1, sizeof(varscontext), fp) != sizeof(varscontext)) |
9858 | elog(FATAL, "invalid format of exec config params file" ); |
9859 | |
9860 | (void) set_config_option(varname, varvalue, |
9861 | varscontext, varsource, |
9862 | GUC_ACTION_SET, true, 0, true); |
9863 | if (varsourcefile[0]) |
9864 | set_config_sourcefile(varname, varsourcefile, varsourceline); |
9865 | |
9866 | free(varname); |
9867 | free(varvalue); |
9868 | free(varsourcefile); |
9869 | } |
9870 | |
9871 | FreeFile(fp); |
9872 | } |
9873 | #endif /* EXEC_BACKEND */ |
9874 | |
9875 | /* |
9876 | * can_skip_gucvar: |
9877 | * When serializing, determine whether to skip this GUC. When restoring, the |
9878 | * negation of this test determines whether to restore the compiled-in default |
9879 | * value before processing serialized values. |
9880 | * |
9881 | * A PGC_S_DEFAULT setting on the serialize side will typically match new |
9882 | * postmaster children, but that can be false when got_SIGHUP == true and the |
9883 | * pending configuration change modifies this setting. Nonetheless, we omit |
9884 | * PGC_S_DEFAULT settings from serialization and make up for that by restoring |
9885 | * defaults before applying serialized values. |
9886 | * |
9887 | * PGC_POSTMASTER variables always have the same value in every child of a |
9888 | * particular postmaster. Most PGC_INTERNAL variables are compile-time |
9889 | * constants; a few, like server_encoding and lc_ctype, are handled specially |
9890 | * outside the serialize/restore procedure. Therefore, SerializeGUCState() |
9891 | * never sends these, and RestoreGUCState() never changes them. |
9892 | * |
9893 | * Role is a special variable in the sense that its current value can be an |
9894 | * invalid value and there are multiple ways by which that can happen (like |
9895 | * after setting the role, someone drops it). So we handle it outside of |
9896 | * serialize/restore machinery. |
9897 | */ |
9898 | static bool |
9899 | can_skip_gucvar(struct config_generic *gconf) |
9900 | { |
9901 | return gconf->context == PGC_POSTMASTER || |
9902 | gconf->context == PGC_INTERNAL || gconf->source == PGC_S_DEFAULT || |
9903 | strcmp(gconf->name, "role" ) == 0; |
9904 | } |
9905 | |
9906 | /* |
9907 | * estimate_variable_size: |
9908 | * Compute space needed for dumping the given GUC variable. |
9909 | * |
9910 | * It's OK to overestimate, but not to underestimate. |
9911 | */ |
9912 | static Size |
9913 | estimate_variable_size(struct config_generic *gconf) |
9914 | { |
9915 | Size size; |
9916 | Size valsize = 0; |
9917 | |
9918 | if (can_skip_gucvar(gconf)) |
9919 | return 0; |
9920 | |
9921 | /* Name, plus trailing zero byte. */ |
9922 | size = strlen(gconf->name) + 1; |
9923 | |
9924 | /* Get the maximum display length of the GUC value. */ |
9925 | switch (gconf->vartype) |
9926 | { |
9927 | case PGC_BOOL: |
9928 | { |
9929 | valsize = 5; /* max(strlen('true'), strlen('false')) */ |
9930 | } |
9931 | break; |
9932 | |
9933 | case PGC_INT: |
9934 | { |
9935 | struct config_int *conf = (struct config_int *) gconf; |
9936 | |
9937 | /* |
9938 | * Instead of getting the exact display length, use max |
9939 | * length. Also reduce the max length for typical ranges of |
9940 | * small values. Maximum value is 2147483647, i.e. 10 chars. |
9941 | * Include one byte for sign. |
9942 | */ |
9943 | if (Abs(*conf->variable) < 1000) |
9944 | valsize = 3 + 1; |
9945 | else |
9946 | valsize = 10 + 1; |
9947 | } |
9948 | break; |
9949 | |
9950 | case PGC_REAL: |
9951 | { |
9952 | /* |
9953 | * We are going to print it with %e with REALTYPE_PRECISION |
9954 | * fractional digits. Account for sign, leading digit, |
9955 | * decimal point, and exponent with up to 3 digits. E.g. |
9956 | * -3.99329042340000021e+110 |
9957 | */ |
9958 | valsize = 1 + 1 + 1 + REALTYPE_PRECISION + 5; |
9959 | } |
9960 | break; |
9961 | |
9962 | case PGC_STRING: |
9963 | { |
9964 | struct config_string *conf = (struct config_string *) gconf; |
9965 | |
9966 | /* |
9967 | * If the value is NULL, we transmit it as an empty string. |
9968 | * Although this is not physically the same value, GUC |
9969 | * generally treats a NULL the same as empty string. |
9970 | */ |
9971 | if (*conf->variable) |
9972 | valsize = strlen(*conf->variable); |
9973 | else |
9974 | valsize = 0; |
9975 | } |
9976 | break; |
9977 | |
9978 | case PGC_ENUM: |
9979 | { |
9980 | struct config_enum *conf = (struct config_enum *) gconf; |
9981 | |
9982 | valsize = strlen(config_enum_lookup_by_value(conf, *conf->variable)); |
9983 | } |
9984 | break; |
9985 | } |
9986 | |
9987 | /* Allow space for terminating zero-byte for value */ |
9988 | size = add_size(size, valsize + 1); |
9989 | |
9990 | if (gconf->sourcefile) |
9991 | size = add_size(size, strlen(gconf->sourcefile)); |
9992 | |
9993 | /* Allow space for terminating zero-byte for sourcefile */ |
9994 | size = add_size(size, 1); |
9995 | |
9996 | /* Include line whenever file is nonempty. */ |
9997 | if (gconf->sourcefile && gconf->sourcefile[0]) |
9998 | size = add_size(size, sizeof(gconf->sourceline)); |
9999 | |
10000 | size = add_size(size, sizeof(gconf->source)); |
10001 | size = add_size(size, sizeof(gconf->scontext)); |
10002 | |
10003 | return size; |
10004 | } |
10005 | |
10006 | /* |
10007 | * EstimateGUCStateSpace: |
10008 | * Returns the size needed to store the GUC state for the current process |
10009 | */ |
10010 | Size |
10011 | EstimateGUCStateSpace(void) |
10012 | { |
10013 | Size size; |
10014 | int i; |
10015 | |
10016 | /* Add space reqd for saving the data size of the guc state */ |
10017 | size = sizeof(Size); |
10018 | |
10019 | /* Add up the space needed for each GUC variable */ |
10020 | for (i = 0; i < num_guc_variables; i++) |
10021 | size = add_size(size, |
10022 | estimate_variable_size(guc_variables[i])); |
10023 | |
10024 | return size; |
10025 | } |
10026 | |
10027 | /* |
10028 | * do_serialize: |
10029 | * Copies the formatted string into the destination. Moves ahead the |
10030 | * destination pointer, and decrements the maxbytes by that many bytes. If |
10031 | * maxbytes is not sufficient to copy the string, error out. |
10032 | */ |
10033 | static void |
10034 | do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) |
10035 | { |
10036 | va_list vargs; |
10037 | int n; |
10038 | |
10039 | if (*maxbytes <= 0) |
10040 | elog(ERROR, "not enough space to serialize GUC state" ); |
10041 | |
10042 | va_start(vargs, fmt); |
10043 | n = vsnprintf(*destptr, *maxbytes, fmt, vargs); |
10044 | va_end(vargs); |
10045 | |
10046 | if (n < 0) |
10047 | { |
10048 | /* Shouldn't happen. Better show errno description. */ |
10049 | elog(ERROR, "vsnprintf failed: %m with format string \"%s\"" , fmt); |
10050 | } |
10051 | if (n >= *maxbytes) |
10052 | { |
10053 | /* This shouldn't happen either, really. */ |
10054 | elog(ERROR, "not enough space to serialize GUC state" ); |
10055 | } |
10056 | |
10057 | /* Shift the destptr ahead of the null terminator */ |
10058 | *destptr += n + 1; |
10059 | *maxbytes -= n + 1; |
10060 | } |
10061 | |
10062 | /* Binary copy version of do_serialize() */ |
10063 | static void |
10064 | do_serialize_binary(char **destptr, Size *maxbytes, void *val, Size valsize) |
10065 | { |
10066 | if (valsize > *maxbytes) |
10067 | elog(ERROR, "not enough space to serialize GUC state" ); |
10068 | |
10069 | memcpy(*destptr, val, valsize); |
10070 | *destptr += valsize; |
10071 | *maxbytes -= valsize; |
10072 | } |
10073 | |
10074 | /* |
10075 | * serialize_variable: |
10076 | * Dumps name, value and other information of a GUC variable into destptr. |
10077 | */ |
10078 | static void |
10079 | serialize_variable(char **destptr, Size *maxbytes, |
10080 | struct config_generic *gconf) |
10081 | { |
10082 | if (can_skip_gucvar(gconf)) |
10083 | return; |
10084 | |
10085 | do_serialize(destptr, maxbytes, "%s" , gconf->name); |
10086 | |
10087 | switch (gconf->vartype) |
10088 | { |
10089 | case PGC_BOOL: |
10090 | { |
10091 | struct config_bool *conf = (struct config_bool *) gconf; |
10092 | |
10093 | do_serialize(destptr, maxbytes, |
10094 | (*conf->variable ? "true" : "false" )); |
10095 | } |
10096 | break; |
10097 | |
10098 | case PGC_INT: |
10099 | { |
10100 | struct config_int *conf = (struct config_int *) gconf; |
10101 | |
10102 | do_serialize(destptr, maxbytes, "%d" , *conf->variable); |
10103 | } |
10104 | break; |
10105 | |
10106 | case PGC_REAL: |
10107 | { |
10108 | struct config_real *conf = (struct config_real *) gconf; |
10109 | |
10110 | do_serialize(destptr, maxbytes, "%.*e" , |
10111 | REALTYPE_PRECISION, *conf->variable); |
10112 | } |
10113 | break; |
10114 | |
10115 | case PGC_STRING: |
10116 | { |
10117 | struct config_string *conf = (struct config_string *) gconf; |
10118 | |
10119 | /* NULL becomes empty string, see estimate_variable_size() */ |
10120 | do_serialize(destptr, maxbytes, "%s" , |
10121 | *conf->variable ? *conf->variable : "" ); |
10122 | } |
10123 | break; |
10124 | |
10125 | case PGC_ENUM: |
10126 | { |
10127 | struct config_enum *conf = (struct config_enum *) gconf; |
10128 | |
10129 | do_serialize(destptr, maxbytes, "%s" , |
10130 | config_enum_lookup_by_value(conf, *conf->variable)); |
10131 | } |
10132 | break; |
10133 | } |
10134 | |
10135 | do_serialize(destptr, maxbytes, "%s" , |
10136 | (gconf->sourcefile ? gconf->sourcefile : "" )); |
10137 | |
10138 | if (gconf->sourcefile && gconf->sourcefile[0]) |
10139 | do_serialize_binary(destptr, maxbytes, &gconf->sourceline, |
10140 | sizeof(gconf->sourceline)); |
10141 | |
10142 | do_serialize_binary(destptr, maxbytes, &gconf->source, |
10143 | sizeof(gconf->source)); |
10144 | do_serialize_binary(destptr, maxbytes, &gconf->scontext, |
10145 | sizeof(gconf->scontext)); |
10146 | } |
10147 | |
10148 | /* |
10149 | * SerializeGUCState: |
10150 | * Dumps the complete GUC state onto the memory location at start_address. |
10151 | */ |
10152 | void |
10153 | SerializeGUCState(Size maxsize, char *start_address) |
10154 | { |
10155 | char *curptr; |
10156 | Size actual_size; |
10157 | Size bytes_left; |
10158 | int i; |
10159 | |
10160 | /* Reserve space for saving the actual size of the guc state */ |
10161 | Assert(maxsize > sizeof(actual_size)); |
10162 | curptr = start_address + sizeof(actual_size); |
10163 | bytes_left = maxsize - sizeof(actual_size); |
10164 | |
10165 | for (i = 0; i < num_guc_variables; i++) |
10166 | serialize_variable(&curptr, &bytes_left, guc_variables[i]); |
10167 | |
10168 | /* Store actual size without assuming alignment of start_address. */ |
10169 | actual_size = maxsize - bytes_left - sizeof(actual_size); |
10170 | memcpy(start_address, &actual_size, sizeof(actual_size)); |
10171 | } |
10172 | |
10173 | /* |
10174 | * read_gucstate: |
10175 | * Actually it does not read anything, just returns the srcptr. But it does |
10176 | * move the srcptr past the terminating zero byte, so that the caller is ready |
10177 | * to read the next string. |
10178 | */ |
10179 | static char * |
10180 | read_gucstate(char **srcptr, char *srcend) |
10181 | { |
10182 | char *retptr = *srcptr; |
10183 | char *ptr; |
10184 | |
10185 | if (*srcptr >= srcend) |
10186 | elog(ERROR, "incomplete GUC state" ); |
10187 | |
10188 | /* The string variables are all null terminated */ |
10189 | for (ptr = *srcptr; ptr < srcend && *ptr != '\0'; ptr++) |
10190 | ; |
10191 | |
10192 | if (ptr >= srcend) |
10193 | elog(ERROR, "could not find null terminator in GUC state" ); |
10194 | |
10195 | /* Set the new position to the byte following the terminating NUL */ |
10196 | *srcptr = ptr + 1; |
10197 | |
10198 | return retptr; |
10199 | } |
10200 | |
10201 | /* Binary read version of read_gucstate(). Copies into dest */ |
10202 | static void |
10203 | read_gucstate_binary(char **srcptr, char *srcend, void *dest, Size size) |
10204 | { |
10205 | if (*srcptr + size > srcend) |
10206 | elog(ERROR, "incomplete GUC state" ); |
10207 | |
10208 | memcpy(dest, *srcptr, size); |
10209 | *srcptr += size; |
10210 | } |
10211 | |
10212 | /* |
10213 | * RestoreGUCState: |
10214 | * Reads the GUC state at the specified address and updates the GUCs with the |
10215 | * values read from the GUC state. |
10216 | */ |
10217 | void |
10218 | RestoreGUCState(void *gucstate) |
10219 | { |
10220 | char *varname, |
10221 | *varvalue, |
10222 | *varsourcefile; |
10223 | int varsourceline; |
10224 | GucSource varsource; |
10225 | GucContext varscontext; |
10226 | char *srcptr = (char *) gucstate; |
10227 | char *srcend; |
10228 | Size len; |
10229 | int i; |
10230 | |
10231 | /* See comment at can_skip_gucvar(). */ |
10232 | for (i = 0; i < num_guc_variables; i++) |
10233 | if (!can_skip_gucvar(guc_variables[i])) |
10234 | InitializeOneGUCOption(guc_variables[i]); |
10235 | |
10236 | /* First item is the length of the subsequent data */ |
10237 | memcpy(&len, gucstate, sizeof(len)); |
10238 | |
10239 | srcptr += sizeof(len); |
10240 | srcend = srcptr + len; |
10241 | |
10242 | while (srcptr < srcend) |
10243 | { |
10244 | int result; |
10245 | |
10246 | varname = read_gucstate(&srcptr, srcend); |
10247 | varvalue = read_gucstate(&srcptr, srcend); |
10248 | varsourcefile = read_gucstate(&srcptr, srcend); |
10249 | if (varsourcefile[0]) |
10250 | read_gucstate_binary(&srcptr, srcend, |
10251 | &varsourceline, sizeof(varsourceline)); |
10252 | else |
10253 | varsourceline = 0; |
10254 | read_gucstate_binary(&srcptr, srcend, |
10255 | &varsource, sizeof(varsource)); |
10256 | read_gucstate_binary(&srcptr, srcend, |
10257 | &varscontext, sizeof(varscontext)); |
10258 | |
10259 | result = set_config_option(varname, varvalue, varscontext, varsource, |
10260 | GUC_ACTION_SET, true, ERROR, true); |
10261 | if (result <= 0) |
10262 | ereport(ERROR, |
10263 | (errcode(ERRCODE_INTERNAL_ERROR), |
10264 | errmsg("parameter \"%s\" could not be set" , varname))); |
10265 | if (varsourcefile[0]) |
10266 | set_config_sourcefile(varname, varsourcefile, varsourceline); |
10267 | } |
10268 | } |
10269 | |
10270 | /* |
10271 | * A little "long argument" simulation, although not quite GNU |
10272 | * compliant. Takes a string of the form "some-option=some value" and |
10273 | * returns name = "some_option" and value = "some value" in malloc'ed |
10274 | * storage. Note that '-' is converted to '_' in the option name. If |
10275 | * there is no '=' in the input string then value will be NULL. |
10276 | */ |
10277 | void |
10278 | ParseLongOption(const char *string, char **name, char **value) |
10279 | { |
10280 | size_t equal_pos; |
10281 | char *cp; |
10282 | |
10283 | AssertArg(string); |
10284 | AssertArg(name); |
10285 | AssertArg(value); |
10286 | |
10287 | equal_pos = strcspn(string, "=" ); |
10288 | |
10289 | if (string[equal_pos] == '=') |
10290 | { |
10291 | *name = guc_malloc(FATAL, equal_pos + 1); |
10292 | strlcpy(*name, string, equal_pos + 1); |
10293 | |
10294 | *value = guc_strdup(FATAL, &string[equal_pos + 1]); |
10295 | } |
10296 | else |
10297 | { |
10298 | /* no equal sign in string */ |
10299 | *name = guc_strdup(FATAL, string); |
10300 | *value = NULL; |
10301 | } |
10302 | |
10303 | for (cp = *name; *cp; cp++) |
10304 | if (*cp == '-') |
10305 | *cp = '_'; |
10306 | } |
10307 | |
10308 | |
10309 | /* |
10310 | * Handle options fetched from pg_db_role_setting.setconfig, |
10311 | * pg_proc.proconfig, etc. Caller must specify proper context/source/action. |
10312 | * |
10313 | * The array parameter must be an array of TEXT (it must not be NULL). |
10314 | */ |
10315 | void |
10316 | ProcessGUCArray(ArrayType *array, |
10317 | GucContext context, GucSource source, GucAction action) |
10318 | { |
10319 | int i; |
10320 | |
10321 | Assert(array != NULL); |
10322 | Assert(ARR_ELEMTYPE(array) == TEXTOID); |
10323 | Assert(ARR_NDIM(array) == 1); |
10324 | Assert(ARR_LBOUND(array)[0] == 1); |
10325 | |
10326 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
10327 | { |
10328 | Datum d; |
10329 | bool isnull; |
10330 | char *s; |
10331 | char *name; |
10332 | char *value; |
10333 | |
10334 | d = array_ref(array, 1, &i, |
10335 | -1 /* varlenarray */ , |
10336 | -1 /* TEXT's typlen */ , |
10337 | false /* TEXT's typbyval */ , |
10338 | 'i' /* TEXT's typalign */ , |
10339 | &isnull); |
10340 | |
10341 | if (isnull) |
10342 | continue; |
10343 | |
10344 | s = TextDatumGetCString(d); |
10345 | |
10346 | ParseLongOption(s, &name, &value); |
10347 | if (!value) |
10348 | { |
10349 | ereport(WARNING, |
10350 | (errcode(ERRCODE_SYNTAX_ERROR), |
10351 | errmsg("could not parse setting for parameter \"%s\"" , |
10352 | name))); |
10353 | free(name); |
10354 | continue; |
10355 | } |
10356 | |
10357 | (void) set_config_option(name, value, |
10358 | context, source, |
10359 | action, true, 0, false); |
10360 | |
10361 | free(name); |
10362 | if (value) |
10363 | free(value); |
10364 | pfree(s); |
10365 | } |
10366 | } |
10367 | |
10368 | |
10369 | /* |
10370 | * Add an entry to an option array. The array parameter may be NULL |
10371 | * to indicate the current table entry is NULL. |
10372 | */ |
10373 | ArrayType * |
10374 | GUCArrayAdd(ArrayType *array, const char *name, const char *value) |
10375 | { |
10376 | struct config_generic *record; |
10377 | Datum datum; |
10378 | char *newval; |
10379 | ArrayType *a; |
10380 | |
10381 | Assert(name); |
10382 | Assert(value); |
10383 | |
10384 | /* test if the option is valid and we're allowed to set it */ |
10385 | (void) validate_option_array_item(name, value, false); |
10386 | |
10387 | /* normalize name (converts obsolete GUC names to modern spellings) */ |
10388 | record = find_option(name, false, WARNING); |
10389 | if (record) |
10390 | name = record->name; |
10391 | |
10392 | /* build new item for array */ |
10393 | newval = psprintf("%s=%s" , name, value); |
10394 | datum = CStringGetTextDatum(newval); |
10395 | |
10396 | if (array) |
10397 | { |
10398 | int index; |
10399 | bool isnull; |
10400 | int i; |
10401 | |
10402 | Assert(ARR_ELEMTYPE(array) == TEXTOID); |
10403 | Assert(ARR_NDIM(array) == 1); |
10404 | Assert(ARR_LBOUND(array)[0] == 1); |
10405 | |
10406 | index = ARR_DIMS(array)[0] + 1; /* add after end */ |
10407 | |
10408 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
10409 | { |
10410 | Datum d; |
10411 | char *current; |
10412 | |
10413 | d = array_ref(array, 1, &i, |
10414 | -1 /* varlenarray */ , |
10415 | -1 /* TEXT's typlen */ , |
10416 | false /* TEXT's typbyval */ , |
10417 | 'i' /* TEXT's typalign */ , |
10418 | &isnull); |
10419 | if (isnull) |
10420 | continue; |
10421 | current = TextDatumGetCString(d); |
10422 | |
10423 | /* check for match up through and including '=' */ |
10424 | if (strncmp(current, newval, strlen(name) + 1) == 0) |
10425 | { |
10426 | index = i; |
10427 | break; |
10428 | } |
10429 | } |
10430 | |
10431 | a = array_set(array, 1, &index, |
10432 | datum, |
10433 | false, |
10434 | -1 /* varlena array */ , |
10435 | -1 /* TEXT's typlen */ , |
10436 | false /* TEXT's typbyval */ , |
10437 | 'i' /* TEXT's typalign */ ); |
10438 | } |
10439 | else |
10440 | a = construct_array(&datum, 1, |
10441 | TEXTOID, |
10442 | -1, false, 'i'); |
10443 | |
10444 | return a; |
10445 | } |
10446 | |
10447 | |
10448 | /* |
10449 | * Delete an entry from an option array. The array parameter may be NULL |
10450 | * to indicate the current table entry is NULL. Also, if the return value |
10451 | * is NULL then a null should be stored. |
10452 | */ |
10453 | ArrayType * |
10454 | GUCArrayDelete(ArrayType *array, const char *name) |
10455 | { |
10456 | struct config_generic *record; |
10457 | ArrayType *newarray; |
10458 | int i; |
10459 | int index; |
10460 | |
10461 | Assert(name); |
10462 | |
10463 | /* test if the option is valid and we're allowed to set it */ |
10464 | (void) validate_option_array_item(name, NULL, false); |
10465 | |
10466 | /* normalize name (converts obsolete GUC names to modern spellings) */ |
10467 | record = find_option(name, false, WARNING); |
10468 | if (record) |
10469 | name = record->name; |
10470 | |
10471 | /* if array is currently null, then surely nothing to delete */ |
10472 | if (!array) |
10473 | return NULL; |
10474 | |
10475 | newarray = NULL; |
10476 | index = 1; |
10477 | |
10478 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
10479 | { |
10480 | Datum d; |
10481 | char *val; |
10482 | bool isnull; |
10483 | |
10484 | d = array_ref(array, 1, &i, |
10485 | -1 /* varlenarray */ , |
10486 | -1 /* TEXT's typlen */ , |
10487 | false /* TEXT's typbyval */ , |
10488 | 'i' /* TEXT's typalign */ , |
10489 | &isnull); |
10490 | if (isnull) |
10491 | continue; |
10492 | val = TextDatumGetCString(d); |
10493 | |
10494 | /* ignore entry if it's what we want to delete */ |
10495 | if (strncmp(val, name, strlen(name)) == 0 |
10496 | && val[strlen(name)] == '=') |
10497 | continue; |
10498 | |
10499 | /* else add it to the output array */ |
10500 | if (newarray) |
10501 | newarray = array_set(newarray, 1, &index, |
10502 | d, |
10503 | false, |
10504 | -1 /* varlenarray */ , |
10505 | -1 /* TEXT's typlen */ , |
10506 | false /* TEXT's typbyval */ , |
10507 | 'i' /* TEXT's typalign */ ); |
10508 | else |
10509 | newarray = construct_array(&d, 1, |
10510 | TEXTOID, |
10511 | -1, false, 'i'); |
10512 | |
10513 | index++; |
10514 | } |
10515 | |
10516 | return newarray; |
10517 | } |
10518 | |
10519 | |
10520 | /* |
10521 | * Given a GUC array, delete all settings from it that our permission |
10522 | * level allows: if superuser, delete them all; if regular user, only |
10523 | * those that are PGC_USERSET |
10524 | */ |
10525 | ArrayType * |
10526 | GUCArrayReset(ArrayType *array) |
10527 | { |
10528 | ArrayType *newarray; |
10529 | int i; |
10530 | int index; |
10531 | |
10532 | /* if array is currently null, nothing to do */ |
10533 | if (!array) |
10534 | return NULL; |
10535 | |
10536 | /* if we're superuser, we can delete everything, so just do it */ |
10537 | if (superuser()) |
10538 | return NULL; |
10539 | |
10540 | newarray = NULL; |
10541 | index = 1; |
10542 | |
10543 | for (i = 1; i <= ARR_DIMS(array)[0]; i++) |
10544 | { |
10545 | Datum d; |
10546 | char *val; |
10547 | char *eqsgn; |
10548 | bool isnull; |
10549 | |
10550 | d = array_ref(array, 1, &i, |
10551 | -1 /* varlenarray */ , |
10552 | -1 /* TEXT's typlen */ , |
10553 | false /* TEXT's typbyval */ , |
10554 | 'i' /* TEXT's typalign */ , |
10555 | &isnull); |
10556 | if (isnull) |
10557 | continue; |
10558 | val = TextDatumGetCString(d); |
10559 | |
10560 | eqsgn = strchr(val, '='); |
10561 | *eqsgn = '\0'; |
10562 | |
10563 | /* skip if we have permission to delete it */ |
10564 | if (validate_option_array_item(val, NULL, true)) |
10565 | continue; |
10566 | |
10567 | /* else add it to the output array */ |
10568 | if (newarray) |
10569 | newarray = array_set(newarray, 1, &index, |
10570 | d, |
10571 | false, |
10572 | -1 /* varlenarray */ , |
10573 | -1 /* TEXT's typlen */ , |
10574 | false /* TEXT's typbyval */ , |
10575 | 'i' /* TEXT's typalign */ ); |
10576 | else |
10577 | newarray = construct_array(&d, 1, |
10578 | TEXTOID, |
10579 | -1, false, 'i'); |
10580 | |
10581 | index++; |
10582 | pfree(val); |
10583 | } |
10584 | |
10585 | return newarray; |
10586 | } |
10587 | |
10588 | /* |
10589 | * Validate a proposed option setting for GUCArrayAdd/Delete/Reset. |
10590 | * |
10591 | * name is the option name. value is the proposed value for the Add case, |
10592 | * or NULL for the Delete/Reset cases. If skipIfNoPermissions is true, it's |
10593 | * not an error to have no permissions to set the option. |
10594 | * |
10595 | * Returns true if OK, false if skipIfNoPermissions is true and user does not |
10596 | * have permission to change this option (all other error cases result in an |
10597 | * error being thrown). |
10598 | */ |
10599 | static bool |
10600 | validate_option_array_item(const char *name, const char *value, |
10601 | bool skipIfNoPermissions) |
10602 | |
10603 | { |
10604 | struct config_generic *gconf; |
10605 | |
10606 | /* |
10607 | * There are three cases to consider: |
10608 | * |
10609 | * name is a known GUC variable. Check the value normally, check |
10610 | * permissions normally (i.e., allow if variable is USERSET, or if it's |
10611 | * SUSET and user is superuser). |
10612 | * |
10613 | * name is not known, but exists or can be created as a placeholder (i.e., |
10614 | * it has a prefixed name). We allow this case if you're a superuser, |
10615 | * otherwise not. Superusers are assumed to know what they're doing. We |
10616 | * can't allow it for other users, because when the placeholder is |
10617 | * resolved it might turn out to be a SUSET variable; |
10618 | * define_custom_variable assumes we checked that. |
10619 | * |
10620 | * name is not known and can't be created as a placeholder. Throw error, |
10621 | * unless skipIfNoPermissions is true, in which case return false. |
10622 | */ |
10623 | gconf = find_option(name, true, WARNING); |
10624 | if (!gconf) |
10625 | { |
10626 | /* not known, failed to make a placeholder */ |
10627 | if (skipIfNoPermissions) |
10628 | return false; |
10629 | ereport(ERROR, |
10630 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
10631 | errmsg("unrecognized configuration parameter \"%s\"" , |
10632 | name))); |
10633 | } |
10634 | |
10635 | if (gconf->flags & GUC_CUSTOM_PLACEHOLDER) |
10636 | { |
10637 | /* |
10638 | * We cannot do any meaningful check on the value, so only permissions |
10639 | * are useful to check. |
10640 | */ |
10641 | if (superuser()) |
10642 | return true; |
10643 | if (skipIfNoPermissions) |
10644 | return false; |
10645 | ereport(ERROR, |
10646 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
10647 | errmsg("permission denied to set parameter \"%s\"" , name))); |
10648 | } |
10649 | |
10650 | /* manual permissions check so we can avoid an error being thrown */ |
10651 | if (gconf->context == PGC_USERSET) |
10652 | /* ok */ ; |
10653 | else if (gconf->context == PGC_SUSET && superuser()) |
10654 | /* ok */ ; |
10655 | else if (skipIfNoPermissions) |
10656 | return false; |
10657 | /* if a permissions error should be thrown, let set_config_option do it */ |
10658 | |
10659 | /* test for permissions and valid option value */ |
10660 | (void) set_config_option(name, value, |
10661 | superuser() ? PGC_SUSET : PGC_USERSET, |
10662 | PGC_S_TEST, GUC_ACTION_SET, false, 0, false); |
10663 | |
10664 | return true; |
10665 | } |
10666 | |
10667 | |
10668 | /* |
10669 | * Called by check_hooks that want to override the normal |
10670 | * ERRCODE_INVALID_PARAMETER_VALUE SQLSTATE for check hook failures. |
10671 | * |
10672 | * Note that GUC_check_errmsg() etc are just macros that result in a direct |
10673 | * assignment to the associated variables. That is ugly, but forced by the |
10674 | * limitations of C's macro mechanisms. |
10675 | */ |
10676 | void |
10677 | GUC_check_errcode(int sqlerrcode) |
10678 | { |
10679 | GUC_check_errcode_value = sqlerrcode; |
10680 | } |
10681 | |
10682 | |
10683 | /* |
10684 | * Convenience functions to manage calling a variable's check_hook. |
10685 | * These mostly take care of the protocol for letting check hooks supply |
10686 | * portions of the error report on failure. |
10687 | */ |
10688 | |
10689 | static bool |
10690 | call_bool_check_hook(struct config_bool *conf, bool *newval, void **, |
10691 | GucSource source, int elevel) |
10692 | { |
10693 | /* Quick success if no hook */ |
10694 | if (!conf->check_hook) |
10695 | return true; |
10696 | |
10697 | /* Reset variables that might be set by hook */ |
10698 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
10699 | GUC_check_errmsg_string = NULL; |
10700 | GUC_check_errdetail_string = NULL; |
10701 | GUC_check_errhint_string = NULL; |
10702 | |
10703 | if (!conf->check_hook(newval, extra, source)) |
10704 | { |
10705 | ereport(elevel, |
10706 | (errcode(GUC_check_errcode_value), |
10707 | GUC_check_errmsg_string ? |
10708 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
10709 | errmsg("invalid value for parameter \"%s\": %d" , |
10710 | conf->gen.name, (int) *newval), |
10711 | GUC_check_errdetail_string ? |
10712 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
10713 | GUC_check_errhint_string ? |
10714 | errhint("%s" , GUC_check_errhint_string) : 0)); |
10715 | /* Flush any strings created in ErrorContext */ |
10716 | FlushErrorState(); |
10717 | return false; |
10718 | } |
10719 | |
10720 | return true; |
10721 | } |
10722 | |
10723 | static bool |
10724 | call_int_check_hook(struct config_int *conf, int *newval, void **, |
10725 | GucSource source, int elevel) |
10726 | { |
10727 | /* Quick success if no hook */ |
10728 | if (!conf->check_hook) |
10729 | return true; |
10730 | |
10731 | /* Reset variables that might be set by hook */ |
10732 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
10733 | GUC_check_errmsg_string = NULL; |
10734 | GUC_check_errdetail_string = NULL; |
10735 | GUC_check_errhint_string = NULL; |
10736 | |
10737 | if (!conf->check_hook(newval, extra, source)) |
10738 | { |
10739 | ereport(elevel, |
10740 | (errcode(GUC_check_errcode_value), |
10741 | GUC_check_errmsg_string ? |
10742 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
10743 | errmsg("invalid value for parameter \"%s\": %d" , |
10744 | conf->gen.name, *newval), |
10745 | GUC_check_errdetail_string ? |
10746 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
10747 | GUC_check_errhint_string ? |
10748 | errhint("%s" , GUC_check_errhint_string) : 0)); |
10749 | /* Flush any strings created in ErrorContext */ |
10750 | FlushErrorState(); |
10751 | return false; |
10752 | } |
10753 | |
10754 | return true; |
10755 | } |
10756 | |
10757 | static bool |
10758 | call_real_check_hook(struct config_real *conf, double *newval, void **, |
10759 | GucSource source, int elevel) |
10760 | { |
10761 | /* Quick success if no hook */ |
10762 | if (!conf->check_hook) |
10763 | return true; |
10764 | |
10765 | /* Reset variables that might be set by hook */ |
10766 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
10767 | GUC_check_errmsg_string = NULL; |
10768 | GUC_check_errdetail_string = NULL; |
10769 | GUC_check_errhint_string = NULL; |
10770 | |
10771 | if (!conf->check_hook(newval, extra, source)) |
10772 | { |
10773 | ereport(elevel, |
10774 | (errcode(GUC_check_errcode_value), |
10775 | GUC_check_errmsg_string ? |
10776 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
10777 | errmsg("invalid value for parameter \"%s\": %g" , |
10778 | conf->gen.name, *newval), |
10779 | GUC_check_errdetail_string ? |
10780 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
10781 | GUC_check_errhint_string ? |
10782 | errhint("%s" , GUC_check_errhint_string) : 0)); |
10783 | /* Flush any strings created in ErrorContext */ |
10784 | FlushErrorState(); |
10785 | return false; |
10786 | } |
10787 | |
10788 | return true; |
10789 | } |
10790 | |
10791 | static bool |
10792 | call_string_check_hook(struct config_string *conf, char **newval, void **, |
10793 | GucSource source, int elevel) |
10794 | { |
10795 | /* Quick success if no hook */ |
10796 | if (!conf->check_hook) |
10797 | return true; |
10798 | |
10799 | /* Reset variables that might be set by hook */ |
10800 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
10801 | GUC_check_errmsg_string = NULL; |
10802 | GUC_check_errdetail_string = NULL; |
10803 | GUC_check_errhint_string = NULL; |
10804 | |
10805 | if (!conf->check_hook(newval, extra, source)) |
10806 | { |
10807 | ereport(elevel, |
10808 | (errcode(GUC_check_errcode_value), |
10809 | GUC_check_errmsg_string ? |
10810 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
10811 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
10812 | conf->gen.name, *newval ? *newval : "" ), |
10813 | GUC_check_errdetail_string ? |
10814 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
10815 | GUC_check_errhint_string ? |
10816 | errhint("%s" , GUC_check_errhint_string) : 0)); |
10817 | /* Flush any strings created in ErrorContext */ |
10818 | FlushErrorState(); |
10819 | return false; |
10820 | } |
10821 | |
10822 | return true; |
10823 | } |
10824 | |
10825 | static bool |
10826 | call_enum_check_hook(struct config_enum *conf, int *newval, void **, |
10827 | GucSource source, int elevel) |
10828 | { |
10829 | /* Quick success if no hook */ |
10830 | if (!conf->check_hook) |
10831 | return true; |
10832 | |
10833 | /* Reset variables that might be set by hook */ |
10834 | GUC_check_errcode_value = ERRCODE_INVALID_PARAMETER_VALUE; |
10835 | GUC_check_errmsg_string = NULL; |
10836 | GUC_check_errdetail_string = NULL; |
10837 | GUC_check_errhint_string = NULL; |
10838 | |
10839 | if (!conf->check_hook(newval, extra, source)) |
10840 | { |
10841 | ereport(elevel, |
10842 | (errcode(GUC_check_errcode_value), |
10843 | GUC_check_errmsg_string ? |
10844 | errmsg_internal("%s" , GUC_check_errmsg_string) : |
10845 | errmsg("invalid value for parameter \"%s\": \"%s\"" , |
10846 | conf->gen.name, |
10847 | config_enum_lookup_by_value(conf, *newval)), |
10848 | GUC_check_errdetail_string ? |
10849 | errdetail_internal("%s" , GUC_check_errdetail_string) : 0, |
10850 | GUC_check_errhint_string ? |
10851 | errhint("%s" , GUC_check_errhint_string) : 0)); |
10852 | /* Flush any strings created in ErrorContext */ |
10853 | FlushErrorState(); |
10854 | return false; |
10855 | } |
10856 | |
10857 | return true; |
10858 | } |
10859 | |
10860 | |
10861 | /* |
10862 | * check_hook, assign_hook and show_hook subroutines |
10863 | */ |
10864 | |
10865 | static bool |
10866 | check_wal_consistency_checking(char **newval, void **, GucSource source) |
10867 | { |
10868 | char *rawstring; |
10869 | List *elemlist; |
10870 | ListCell *l; |
10871 | bool newwalconsistency[RM_MAX_ID + 1]; |
10872 | |
10873 | /* Initialize the array */ |
10874 | MemSet(newwalconsistency, 0, (RM_MAX_ID + 1) * sizeof(bool)); |
10875 | |
10876 | /* Need a modifiable copy of string */ |
10877 | rawstring = pstrdup(*newval); |
10878 | |
10879 | /* Parse string into list of identifiers */ |
10880 | if (!SplitIdentifierString(rawstring, ',', &elemlist)) |
10881 | { |
10882 | /* syntax error in list */ |
10883 | GUC_check_errdetail("List syntax is invalid." ); |
10884 | pfree(rawstring); |
10885 | list_free(elemlist); |
10886 | return false; |
10887 | } |
10888 | |
10889 | foreach(l, elemlist) |
10890 | { |
10891 | char *tok = (char *) lfirst(l); |
10892 | bool found = false; |
10893 | RmgrId rmid; |
10894 | |
10895 | /* Check for 'all'. */ |
10896 | if (pg_strcasecmp(tok, "all" ) == 0) |
10897 | { |
10898 | for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
10899 | if (RmgrTable[rmid].rm_mask != NULL) |
10900 | newwalconsistency[rmid] = true; |
10901 | found = true; |
10902 | } |
10903 | else |
10904 | { |
10905 | /* |
10906 | * Check if the token matches with any individual resource |
10907 | * manager. |
10908 | */ |
10909 | for (rmid = 0; rmid <= RM_MAX_ID; rmid++) |
10910 | { |
10911 | if (pg_strcasecmp(tok, RmgrTable[rmid].rm_name) == 0 && |
10912 | RmgrTable[rmid].rm_mask != NULL) |
10913 | { |
10914 | newwalconsistency[rmid] = true; |
10915 | found = true; |
10916 | } |
10917 | } |
10918 | } |
10919 | |
10920 | /* If a valid resource manager is found, check for the next one. */ |
10921 | if (!found) |
10922 | { |
10923 | GUC_check_errdetail("Unrecognized key word: \"%s\"." , tok); |
10924 | pfree(rawstring); |
10925 | list_free(elemlist); |
10926 | return false; |
10927 | } |
10928 | } |
10929 | |
10930 | pfree(rawstring); |
10931 | list_free(elemlist); |
10932 | |
10933 | /* assign new value */ |
10934 | *extra = guc_malloc(ERROR, (RM_MAX_ID + 1) * sizeof(bool)); |
10935 | memcpy(*extra, newwalconsistency, (RM_MAX_ID + 1) * sizeof(bool)); |
10936 | return true; |
10937 | } |
10938 | |
10939 | static void |
10940 | assign_wal_consistency_checking(const char *newval, void *) |
10941 | { |
10942 | wal_consistency_checking = (bool *) extra; |
10943 | } |
10944 | |
10945 | static bool |
10946 | check_log_destination(char **newval, void **, GucSource source) |
10947 | { |
10948 | char *rawstring; |
10949 | List *elemlist; |
10950 | ListCell *l; |
10951 | int newlogdest = 0; |
10952 | int *; |
10953 | |
10954 | /* Need a modifiable copy of string */ |
10955 | rawstring = pstrdup(*newval); |
10956 | |
10957 | /* Parse string into list of identifiers */ |
10958 | if (!SplitIdentifierString(rawstring, ',', &elemlist)) |
10959 | { |
10960 | /* syntax error in list */ |
10961 | GUC_check_errdetail("List syntax is invalid." ); |
10962 | pfree(rawstring); |
10963 | list_free(elemlist); |
10964 | return false; |
10965 | } |
10966 | |
10967 | foreach(l, elemlist) |
10968 | { |
10969 | char *tok = (char *) lfirst(l); |
10970 | |
10971 | if (pg_strcasecmp(tok, "stderr" ) == 0) |
10972 | newlogdest |= LOG_DESTINATION_STDERR; |
10973 | else if (pg_strcasecmp(tok, "csvlog" ) == 0) |
10974 | newlogdest |= LOG_DESTINATION_CSVLOG; |
10975 | #ifdef HAVE_SYSLOG |
10976 | else if (pg_strcasecmp(tok, "syslog" ) == 0) |
10977 | newlogdest |= LOG_DESTINATION_SYSLOG; |
10978 | #endif |
10979 | #ifdef WIN32 |
10980 | else if (pg_strcasecmp(tok, "eventlog" ) == 0) |
10981 | newlogdest |= LOG_DESTINATION_EVENTLOG; |
10982 | #endif |
10983 | else |
10984 | { |
10985 | GUC_check_errdetail("Unrecognized key word: \"%s\"." , tok); |
10986 | pfree(rawstring); |
10987 | list_free(elemlist); |
10988 | return false; |
10989 | } |
10990 | } |
10991 | |
10992 | pfree(rawstring); |
10993 | list_free(elemlist); |
10994 | |
10995 | myextra = (int *) guc_malloc(ERROR, sizeof(int)); |
10996 | *myextra = newlogdest; |
10997 | *extra = (void *) myextra; |
10998 | |
10999 | return true; |
11000 | } |
11001 | |
11002 | static void |
11003 | assign_log_destination(const char *newval, void *) |
11004 | { |
11005 | Log_destination = *((int *) extra); |
11006 | } |
11007 | |
11008 | static void |
11009 | assign_syslog_facility(int newval, void *) |
11010 | { |
11011 | #ifdef HAVE_SYSLOG |
11012 | set_syslog_parameters(syslog_ident_str ? syslog_ident_str : "postgres" , |
11013 | newval); |
11014 | #endif |
11015 | /* Without syslog support, just ignore it */ |
11016 | } |
11017 | |
11018 | static void |
11019 | assign_syslog_ident(const char *newval, void *) |
11020 | { |
11021 | #ifdef HAVE_SYSLOG |
11022 | set_syslog_parameters(newval, syslog_facility); |
11023 | #endif |
11024 | /* Without syslog support, it will always be set to "none", so ignore */ |
11025 | } |
11026 | |
11027 | |
11028 | static void |
11029 | assign_session_replication_role(int newval, void *) |
11030 | { |
11031 | /* |
11032 | * Must flush the plan cache when changing replication role; but don't |
11033 | * flush unnecessarily. |
11034 | */ |
11035 | if (SessionReplicationRole != newval) |
11036 | ResetPlanCache(); |
11037 | } |
11038 | |
11039 | static bool |
11040 | check_temp_buffers(int *newval, void **, GucSource source) |
11041 | { |
11042 | /* |
11043 | * Once local buffers have been initialized, it's too late to change this. |
11044 | */ |
11045 | if (NLocBuffer && NLocBuffer != *newval) |
11046 | { |
11047 | GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session." ); |
11048 | return false; |
11049 | } |
11050 | return true; |
11051 | } |
11052 | |
11053 | static bool |
11054 | check_bonjour(bool *newval, void **, GucSource source) |
11055 | { |
11056 | #ifndef USE_BONJOUR |
11057 | if (*newval) |
11058 | { |
11059 | GUC_check_errmsg("Bonjour is not supported by this build" ); |
11060 | return false; |
11061 | } |
11062 | #endif |
11063 | return true; |
11064 | } |
11065 | |
11066 | static bool |
11067 | check_ssl(bool *newval, void **, GucSource source) |
11068 | { |
11069 | #ifndef USE_SSL |
11070 | if (*newval) |
11071 | { |
11072 | GUC_check_errmsg("SSL is not supported by this build" ); |
11073 | return false; |
11074 | } |
11075 | #endif |
11076 | return true; |
11077 | } |
11078 | |
11079 | static bool |
11080 | check_stage_log_stats(bool *newval, void **, GucSource source) |
11081 | { |
11082 | if (*newval && log_statement_stats) |
11083 | { |
11084 | GUC_check_errdetail("Cannot enable parameter when \"log_statement_stats\" is true." ); |
11085 | return false; |
11086 | } |
11087 | return true; |
11088 | } |
11089 | |
11090 | static bool |
11091 | check_log_stats(bool *newval, void **, GucSource source) |
11092 | { |
11093 | if (*newval && |
11094 | (log_parser_stats || log_planner_stats || log_executor_stats)) |
11095 | { |
11096 | GUC_check_errdetail("Cannot enable \"log_statement_stats\" when " |
11097 | "\"log_parser_stats\", \"log_planner_stats\", " |
11098 | "or \"log_executor_stats\" is true." ); |
11099 | return false; |
11100 | } |
11101 | return true; |
11102 | } |
11103 | |
11104 | static bool |
11105 | check_canonical_path(char **newval, void **, GucSource source) |
11106 | { |
11107 | /* |
11108 | * Since canonicalize_path never enlarges the string, we can just modify |
11109 | * newval in-place. But watch out for NULL, which is the default value |
11110 | * for external_pid_file. |
11111 | */ |
11112 | if (*newval) |
11113 | canonicalize_path(*newval); |
11114 | return true; |
11115 | } |
11116 | |
11117 | static bool |
11118 | check_timezone_abbreviations(char **newval, void **, GucSource source) |
11119 | { |
11120 | /* |
11121 | * The boot_val given above for timezone_abbreviations is NULL. When we |
11122 | * see this we just do nothing. If this value isn't overridden from the |
11123 | * config file then pg_timezone_abbrev_initialize() will eventually |
11124 | * replace it with "Default". This hack has two purposes: to avoid |
11125 | * wasting cycles loading values that might soon be overridden from the |
11126 | * config file, and to avoid trying to read the timezone abbrev files |
11127 | * during InitializeGUCOptions(). The latter doesn't work in an |
11128 | * EXEC_BACKEND subprocess because my_exec_path hasn't been set yet and so |
11129 | * we can't locate PGSHAREDIR. |
11130 | */ |
11131 | if (*newval == NULL) |
11132 | { |
11133 | Assert(source == PGC_S_DEFAULT); |
11134 | return true; |
11135 | } |
11136 | |
11137 | /* OK, load the file and produce a malloc'd TimeZoneAbbrevTable */ |
11138 | *extra = load_tzoffsets(*newval); |
11139 | |
11140 | /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */ |
11141 | if (!*extra) |
11142 | return false; |
11143 | |
11144 | return true; |
11145 | } |
11146 | |
11147 | static void |
11148 | assign_timezone_abbreviations(const char *newval, void *) |
11149 | { |
11150 | /* Do nothing for the boot_val default of NULL */ |
11151 | if (!extra) |
11152 | return; |
11153 | |
11154 | InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra); |
11155 | } |
11156 | |
11157 | /* |
11158 | * pg_timezone_abbrev_initialize --- set default value if not done already |
11159 | * |
11160 | * This is called after initial loading of postgresql.conf. If no |
11161 | * timezone_abbreviations setting was found therein, select default. |
11162 | * If a non-default value is already installed, nothing will happen. |
11163 | * |
11164 | * This can also be called from ProcessConfigFile to establish the default |
11165 | * value after a postgresql.conf entry for it is removed. |
11166 | */ |
11167 | static void |
11168 | pg_timezone_abbrev_initialize(void) |
11169 | { |
11170 | SetConfigOption("timezone_abbreviations" , "Default" , |
11171 | PGC_POSTMASTER, PGC_S_DYNAMIC_DEFAULT); |
11172 | } |
11173 | |
11174 | static const char * |
11175 | show_archive_command(void) |
11176 | { |
11177 | if (XLogArchivingActive()) |
11178 | return XLogArchiveCommand; |
11179 | else |
11180 | return "(disabled)" ; |
11181 | } |
11182 | |
11183 | static void |
11184 | assign_tcp_keepalives_idle(int newval, void *) |
11185 | { |
11186 | /* |
11187 | * The kernel API provides no way to test a value without setting it; and |
11188 | * once we set it we might fail to unset it. So there seems little point |
11189 | * in fully implementing the check-then-assign GUC API for these |
11190 | * variables. Instead we just do the assignment on demand. pqcomm.c |
11191 | * reports any problems via elog(LOG). |
11192 | * |
11193 | * This approach means that the GUC value might have little to do with the |
11194 | * actual kernel value, so we use a show_hook that retrieves the kernel |
11195 | * value rather than trusting GUC's copy. |
11196 | */ |
11197 | (void) pq_setkeepalivesidle(newval, MyProcPort); |
11198 | } |
11199 | |
11200 | static const char * |
11201 | show_tcp_keepalives_idle(void) |
11202 | { |
11203 | /* See comments in assign_tcp_keepalives_idle */ |
11204 | static char nbuf[16]; |
11205 | |
11206 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivesidle(MyProcPort)); |
11207 | return nbuf; |
11208 | } |
11209 | |
11210 | static void |
11211 | assign_tcp_keepalives_interval(int newval, void *) |
11212 | { |
11213 | /* See comments in assign_tcp_keepalives_idle */ |
11214 | (void) pq_setkeepalivesinterval(newval, MyProcPort); |
11215 | } |
11216 | |
11217 | static const char * |
11218 | show_tcp_keepalives_interval(void) |
11219 | { |
11220 | /* See comments in assign_tcp_keepalives_idle */ |
11221 | static char nbuf[16]; |
11222 | |
11223 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivesinterval(MyProcPort)); |
11224 | return nbuf; |
11225 | } |
11226 | |
11227 | static void |
11228 | assign_tcp_keepalives_count(int newval, void *) |
11229 | { |
11230 | /* See comments in assign_tcp_keepalives_idle */ |
11231 | (void) pq_setkeepalivescount(newval, MyProcPort); |
11232 | } |
11233 | |
11234 | static const char * |
11235 | show_tcp_keepalives_count(void) |
11236 | { |
11237 | /* See comments in assign_tcp_keepalives_idle */ |
11238 | static char nbuf[16]; |
11239 | |
11240 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_getkeepalivescount(MyProcPort)); |
11241 | return nbuf; |
11242 | } |
11243 | |
11244 | static void |
11245 | assign_tcp_user_timeout(int newval, void *) |
11246 | { |
11247 | /* See comments in assign_tcp_keepalives_idle */ |
11248 | (void) pq_settcpusertimeout(newval, MyProcPort); |
11249 | } |
11250 | |
11251 | static const char * |
11252 | show_tcp_user_timeout(void) |
11253 | { |
11254 | /* See comments in assign_tcp_keepalives_idle */ |
11255 | static char nbuf[16]; |
11256 | |
11257 | snprintf(nbuf, sizeof(nbuf), "%d" , pq_gettcpusertimeout(MyProcPort)); |
11258 | return nbuf; |
11259 | } |
11260 | |
11261 | static bool |
11262 | check_maxconnections(int *newval, void **, GucSource source) |
11263 | { |
11264 | if (*newval + autovacuum_max_workers + 1 + |
11265 | max_worker_processes + max_wal_senders > MAX_BACKENDS) |
11266 | return false; |
11267 | return true; |
11268 | } |
11269 | |
11270 | static bool |
11271 | check_autovacuum_max_workers(int *newval, void **, GucSource source) |
11272 | { |
11273 | if (MaxConnections + *newval + 1 + |
11274 | max_worker_processes + max_wal_senders > MAX_BACKENDS) |
11275 | return false; |
11276 | return true; |
11277 | } |
11278 | |
11279 | static bool |
11280 | check_max_wal_senders(int *newval, void **, GucSource source) |
11281 | { |
11282 | if (MaxConnections + autovacuum_max_workers + 1 + |
11283 | max_worker_processes + *newval > MAX_BACKENDS) |
11284 | return false; |
11285 | return true; |
11286 | } |
11287 | |
11288 | static bool |
11289 | check_autovacuum_work_mem(int *newval, void **, GucSource source) |
11290 | { |
11291 | /* |
11292 | * -1 indicates fallback. |
11293 | * |
11294 | * If we haven't yet changed the boot_val default of -1, just let it be. |
11295 | * Autovacuum will look to maintenance_work_mem instead. |
11296 | */ |
11297 | if (*newval == -1) |
11298 | return true; |
11299 | |
11300 | /* |
11301 | * We clamp manually-set values to at least 1MB. Since |
11302 | * maintenance_work_mem is always set to at least this value, do the same |
11303 | * here. |
11304 | */ |
11305 | if (*newval < 1024) |
11306 | *newval = 1024; |
11307 | |
11308 | return true; |
11309 | } |
11310 | |
11311 | static bool |
11312 | check_max_worker_processes(int *newval, void **, GucSource source) |
11313 | { |
11314 | if (MaxConnections + autovacuum_max_workers + 1 + |
11315 | *newval + max_wal_senders > MAX_BACKENDS) |
11316 | return false; |
11317 | return true; |
11318 | } |
11319 | |
11320 | static bool |
11321 | check_effective_io_concurrency(int *newval, void **, GucSource source) |
11322 | { |
11323 | #ifdef USE_PREFETCH |
11324 | double new_prefetch_pages; |
11325 | |
11326 | if (ComputeIoConcurrency(*newval, &new_prefetch_pages)) |
11327 | { |
11328 | int * = (int *) guc_malloc(ERROR, sizeof(int)); |
11329 | |
11330 | *myextra = (int) rint(new_prefetch_pages); |
11331 | *extra = (void *) myextra; |
11332 | |
11333 | return true; |
11334 | } |
11335 | else |
11336 | return false; |
11337 | #else |
11338 | if (*newval != 0) |
11339 | { |
11340 | GUC_check_errdetail("effective_io_concurrency must be set to 0 on platforms that lack posix_fadvise()." ); |
11341 | return false; |
11342 | } |
11343 | return true; |
11344 | #endif /* USE_PREFETCH */ |
11345 | } |
11346 | |
11347 | static void |
11348 | assign_effective_io_concurrency(int newval, void *) |
11349 | { |
11350 | #ifdef USE_PREFETCH |
11351 | target_prefetch_pages = *((int *) extra); |
11352 | #endif /* USE_PREFETCH */ |
11353 | } |
11354 | |
11355 | static void |
11356 | assign_pgstat_temp_directory(const char *newval, void *) |
11357 | { |
11358 | /* check_canonical_path already canonicalized newval for us */ |
11359 | char *dname; |
11360 | char *tname; |
11361 | char *fname; |
11362 | |
11363 | /* directory */ |
11364 | dname = guc_malloc(ERROR, strlen(newval) + 1); /* runtime dir */ |
11365 | sprintf(dname, "%s" , newval); |
11366 | |
11367 | /* global stats */ |
11368 | tname = guc_malloc(ERROR, strlen(newval) + 12); /* /global.tmp */ |
11369 | sprintf(tname, "%s/global.tmp" , newval); |
11370 | fname = guc_malloc(ERROR, strlen(newval) + 13); /* /global.stat */ |
11371 | sprintf(fname, "%s/global.stat" , newval); |
11372 | |
11373 | if (pgstat_stat_directory) |
11374 | free(pgstat_stat_directory); |
11375 | pgstat_stat_directory = dname; |
11376 | if (pgstat_stat_tmpname) |
11377 | free(pgstat_stat_tmpname); |
11378 | pgstat_stat_tmpname = tname; |
11379 | if (pgstat_stat_filename) |
11380 | free(pgstat_stat_filename); |
11381 | pgstat_stat_filename = fname; |
11382 | } |
11383 | |
11384 | static bool |
11385 | check_application_name(char **newval, void **, GucSource source) |
11386 | { |
11387 | /* Only allow clean ASCII chars in the application name */ |
11388 | pg_clean_ascii(*newval); |
11389 | |
11390 | return true; |
11391 | } |
11392 | |
11393 | static void |
11394 | assign_application_name(const char *newval, void *) |
11395 | { |
11396 | /* Update the pg_stat_activity view */ |
11397 | pgstat_report_appname(newval); |
11398 | } |
11399 | |
11400 | static bool |
11401 | check_cluster_name(char **newval, void **, GucSource source) |
11402 | { |
11403 | /* Only allow clean ASCII chars in the cluster name */ |
11404 | pg_clean_ascii(*newval); |
11405 | |
11406 | return true; |
11407 | } |
11408 | |
11409 | static const char * |
11410 | show_unix_socket_permissions(void) |
11411 | { |
11412 | static char buf[12]; |
11413 | |
11414 | snprintf(buf, sizeof(buf), "%04o" , Unix_socket_permissions); |
11415 | return buf; |
11416 | } |
11417 | |
11418 | static const char * |
11419 | show_log_file_mode(void) |
11420 | { |
11421 | static char buf[12]; |
11422 | |
11423 | snprintf(buf, sizeof(buf), "%04o" , Log_file_mode); |
11424 | return buf; |
11425 | } |
11426 | |
11427 | static const char * |
11428 | show_data_directory_mode(void) |
11429 | { |
11430 | static char buf[12]; |
11431 | |
11432 | snprintf(buf, sizeof(buf), "%04o" , data_directory_mode); |
11433 | return buf; |
11434 | } |
11435 | |
11436 | static bool |
11437 | check_recovery_target_timeline(char **newval, void **, GucSource source) |
11438 | { |
11439 | RecoveryTargetTimeLineGoal rttg; |
11440 | RecoveryTargetTimeLineGoal *; |
11441 | |
11442 | if (strcmp(*newval, "current" ) == 0) |
11443 | rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE; |
11444 | else if (strcmp(*newval, "latest" ) == 0) |
11445 | rttg = RECOVERY_TARGET_TIMELINE_LATEST; |
11446 | else |
11447 | { |
11448 | rttg = RECOVERY_TARGET_TIMELINE_NUMERIC; |
11449 | |
11450 | errno = 0; |
11451 | strtoul(*newval, NULL, 0); |
11452 | if (errno == EINVAL || errno == ERANGE) |
11453 | { |
11454 | GUC_check_errdetail("recovery_target_timeline is not a valid number." ); |
11455 | return false; |
11456 | } |
11457 | } |
11458 | |
11459 | myextra = (RecoveryTargetTimeLineGoal *) guc_malloc(ERROR, sizeof(RecoveryTargetTimeLineGoal)); |
11460 | *myextra = rttg; |
11461 | *extra = (void *) myextra; |
11462 | |
11463 | return true; |
11464 | } |
11465 | |
11466 | static void |
11467 | assign_recovery_target_timeline(const char *newval, void *) |
11468 | { |
11469 | recoveryTargetTimeLineGoal = *((RecoveryTargetTimeLineGoal *) extra); |
11470 | if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC) |
11471 | recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0); |
11472 | else |
11473 | recoveryTargetTLIRequested = 0; |
11474 | } |
11475 | |
11476 | /* |
11477 | * Recovery target settings: Only one of the several recovery_target* settings |
11478 | * may be set. Setting a second one results in an error. The global variable |
11479 | * recoveryTarget tracks which kind of recovery target was chosen. Other |
11480 | * variables store the actual target value (for example a string or a xid). |
11481 | * The assign functions of the parameters check whether a competing parameter |
11482 | * was already set. But we want to allow setting the same parameter multiple |
11483 | * times. We also want to allow unsetting a parameter and setting a different |
11484 | * one, so we unset recoveryTarget when the parameter is set to an empty |
11485 | * string. |
11486 | */ |
11487 | |
11488 | static void |
11489 | pg_attribute_noreturn() |
11490 | error_multiple_recovery_targets(void) |
11491 | { |
11492 | ereport(ERROR, |
11493 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
11494 | errmsg("multiple recovery targets specified" ), |
11495 | errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set." ))); |
11496 | } |
11497 | |
11498 | static bool |
11499 | check_recovery_target(char **newval, void **, GucSource source) |
11500 | { |
11501 | if (strcmp(*newval, "immediate" ) != 0 && strcmp(*newval, "" ) != 0) |
11502 | { |
11503 | GUC_check_errdetail("The only allowed value is \"immediate\"." ); |
11504 | return false; |
11505 | } |
11506 | return true; |
11507 | } |
11508 | |
11509 | static void |
11510 | assign_recovery_target(const char *newval, void *) |
11511 | { |
11512 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
11513 | recoveryTarget != RECOVERY_TARGET_IMMEDIATE) |
11514 | error_multiple_recovery_targets(); |
11515 | |
11516 | if (newval && strcmp(newval, "" ) != 0) |
11517 | recoveryTarget = RECOVERY_TARGET_IMMEDIATE; |
11518 | else |
11519 | recoveryTarget = RECOVERY_TARGET_UNSET; |
11520 | } |
11521 | |
11522 | static bool |
11523 | check_recovery_target_xid(char **newval, void **, GucSource source) |
11524 | { |
11525 | if (strcmp(*newval, "" ) != 0) |
11526 | { |
11527 | TransactionId xid; |
11528 | TransactionId *; |
11529 | |
11530 | errno = 0; |
11531 | xid = (TransactionId) strtoul(*newval, NULL, 0); |
11532 | if (errno == EINVAL || errno == ERANGE) |
11533 | return false; |
11534 | |
11535 | myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId)); |
11536 | *myextra = xid; |
11537 | *extra = (void *) myextra; |
11538 | } |
11539 | return true; |
11540 | } |
11541 | |
11542 | static void |
11543 | assign_recovery_target_xid(const char *newval, void *) |
11544 | { |
11545 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
11546 | recoveryTarget != RECOVERY_TARGET_XID) |
11547 | error_multiple_recovery_targets(); |
11548 | |
11549 | if (newval && strcmp(newval, "" ) != 0) |
11550 | { |
11551 | recoveryTarget = RECOVERY_TARGET_XID; |
11552 | recoveryTargetXid = *((TransactionId *) extra); |
11553 | } |
11554 | else |
11555 | recoveryTarget = RECOVERY_TARGET_UNSET; |
11556 | } |
11557 | |
11558 | /* |
11559 | * The interpretation of the recovery_target_time string can depend on the |
11560 | * time zone setting, so we need to wait until after all GUC processing is |
11561 | * done before we can do the final parsing of the string. This check function |
11562 | * only does a parsing pass to catch syntax errors, but we store the string |
11563 | * and parse it again when we need to use it. |
11564 | */ |
11565 | static bool |
11566 | check_recovery_target_time(char **newval, void **, GucSource source) |
11567 | { |
11568 | if (strcmp(*newval, "" ) != 0) |
11569 | { |
11570 | /* reject some special values */ |
11571 | if (strcmp(*newval, "now" ) == 0 || |
11572 | strcmp(*newval, "today" ) == 0 || |
11573 | strcmp(*newval, "tomorrow" ) == 0 || |
11574 | strcmp(*newval, "yesterday" ) == 0) |
11575 | { |
11576 | return false; |
11577 | } |
11578 | |
11579 | /* |
11580 | * parse timestamp value (see also timestamptz_in()) |
11581 | */ |
11582 | { |
11583 | char *str = *newval; |
11584 | fsec_t fsec; |
11585 | struct pg_tm tt, |
11586 | *tm = &tt; |
11587 | int tz; |
11588 | int dtype; |
11589 | int nf; |
11590 | int dterr; |
11591 | char *field[MAXDATEFIELDS]; |
11592 | int ftype[MAXDATEFIELDS]; |
11593 | char workbuf[MAXDATELEN + MAXDATEFIELDS]; |
11594 | TimestampTz timestamp; |
11595 | |
11596 | dterr = ParseDateTime(str, workbuf, sizeof(workbuf), |
11597 | field, ftype, MAXDATEFIELDS, &nf); |
11598 | if (dterr == 0) |
11599 | dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz); |
11600 | if (dterr != 0) |
11601 | return false; |
11602 | if (dtype != DTK_DATE) |
11603 | return false; |
11604 | |
11605 | if (tm2timestamp(tm, fsec, &tz, ×tamp) != 0) |
11606 | { |
11607 | GUC_check_errdetail("timestamp out of range: \"%s\"" , str); |
11608 | return false; |
11609 | } |
11610 | } |
11611 | } |
11612 | return true; |
11613 | } |
11614 | |
11615 | static void |
11616 | assign_recovery_target_time(const char *newval, void *) |
11617 | { |
11618 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
11619 | recoveryTarget != RECOVERY_TARGET_TIME) |
11620 | error_multiple_recovery_targets(); |
11621 | |
11622 | if (newval && strcmp(newval, "" ) != 0) |
11623 | recoveryTarget = RECOVERY_TARGET_TIME; |
11624 | else |
11625 | recoveryTarget = RECOVERY_TARGET_UNSET; |
11626 | } |
11627 | |
11628 | static bool |
11629 | check_recovery_target_name(char **newval, void **, GucSource source) |
11630 | { |
11631 | /* Use the value of newval directly */ |
11632 | if (strlen(*newval) >= MAXFNAMELEN) |
11633 | { |
11634 | GUC_check_errdetail("%s is too long (maximum %d characters)." , |
11635 | "recovery_target_name" , MAXFNAMELEN - 1); |
11636 | return false; |
11637 | } |
11638 | return true; |
11639 | } |
11640 | |
11641 | static void |
11642 | assign_recovery_target_name(const char *newval, void *) |
11643 | { |
11644 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
11645 | recoveryTarget != RECOVERY_TARGET_NAME) |
11646 | error_multiple_recovery_targets(); |
11647 | |
11648 | if (newval && strcmp(newval, "" ) != 0) |
11649 | { |
11650 | recoveryTarget = RECOVERY_TARGET_NAME; |
11651 | recoveryTargetName = newval; |
11652 | } |
11653 | else |
11654 | recoveryTarget = RECOVERY_TARGET_UNSET; |
11655 | } |
11656 | |
11657 | static bool |
11658 | check_recovery_target_lsn(char **newval, void **, GucSource source) |
11659 | { |
11660 | if (strcmp(*newval, "" ) != 0) |
11661 | { |
11662 | XLogRecPtr lsn; |
11663 | XLogRecPtr *; |
11664 | bool have_error = false; |
11665 | |
11666 | lsn = pg_lsn_in_internal(*newval, &have_error); |
11667 | if (have_error) |
11668 | return false; |
11669 | |
11670 | myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr)); |
11671 | *myextra = lsn; |
11672 | *extra = (void *) myextra; |
11673 | } |
11674 | return true; |
11675 | } |
11676 | |
11677 | static void |
11678 | assign_recovery_target_lsn(const char *newval, void *) |
11679 | { |
11680 | if (recoveryTarget != RECOVERY_TARGET_UNSET && |
11681 | recoveryTarget != RECOVERY_TARGET_LSN) |
11682 | error_multiple_recovery_targets(); |
11683 | |
11684 | if (newval && strcmp(newval, "" ) != 0) |
11685 | { |
11686 | recoveryTarget = RECOVERY_TARGET_LSN; |
11687 | recoveryTargetLSN = *((XLogRecPtr *) extra); |
11688 | } |
11689 | else |
11690 | recoveryTarget = RECOVERY_TARGET_UNSET; |
11691 | } |
11692 | |
11693 | static bool |
11694 | check_primary_slot_name(char **newval, void **, GucSource source) |
11695 | { |
11696 | if (*newval && strcmp(*newval, "" ) != 0 && |
11697 | !ReplicationSlotValidateName(*newval, WARNING)) |
11698 | return false; |
11699 | |
11700 | return true; |
11701 | } |
11702 | |
11703 | static bool |
11704 | check_default_with_oids(bool *newval, void **, GucSource source) |
11705 | { |
11706 | if (*newval) |
11707 | { |
11708 | /* check the GUC's definition for an explanation */ |
11709 | GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED); |
11710 | GUC_check_errmsg("tables declared WITH OIDS are not supported" ); |
11711 | |
11712 | return false; |
11713 | } |
11714 | |
11715 | return true; |
11716 | } |
11717 | |
11718 | #include "guc-file.c" |
11719 | |