Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * variable.c
4 : * Routines for handling specialized SET variables.
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/commands/variable.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 :
17 : #include "postgres.h"
18 :
19 : #include <ctype.h>
20 :
21 : #include "access/htup_details.h"
22 : #include "access/parallel.h"
23 : #include "access/xact.h"
24 : #include "access/xlog.h"
25 : #include "access/xlogprefetcher.h"
26 : #include "catalog/pg_authid.h"
27 : #include "common/string.h"
28 : #include "mb/pg_wchar.h"
29 : #include "miscadmin.h"
30 : #include "postmaster/postmaster.h"
31 : #include "postmaster/syslogger.h"
32 : #include "storage/bufmgr.h"
33 : #include "utils/acl.h"
34 : #include "utils/backend_status.h"
35 : #include "utils/datetime.h"
36 : #include "utils/fmgrprotos.h"
37 : #include "utils/guc_hooks.h"
38 : #include "utils/snapmgr.h"
39 : #include "utils/syscache.h"
40 : #include "utils/timestamp.h"
41 : #include "utils/tzparser.h"
42 : #include "utils/varlena.h"
43 :
44 : /*
45 : * DATESTYLE
46 : */
47 :
48 : /*
49 : * check_datestyle: GUC check_hook for datestyle
50 : */
51 : bool
52 24238 : check_datestyle(char **newval, void **extra, GucSource source)
53 : {
54 24238 : int newDateStyle = DateStyle;
55 24238 : int newDateOrder = DateOrder;
56 24238 : bool have_style = false;
57 24238 : bool have_order = false;
58 24238 : bool ok = true;
59 : char *rawstring;
60 : int *myextra;
61 : char *result;
62 : List *elemlist;
63 : ListCell *l;
64 :
65 : /* Need a modifiable copy of string */
66 24238 : rawstring = pstrdup(*newval);
67 :
68 : /* Parse string into list of identifiers */
69 24238 : if (!SplitIdentifierString(rawstring, ',', &elemlist))
70 : {
71 : /* syntax error in list */
72 0 : GUC_check_errdetail("List syntax is invalid.");
73 0 : pfree(rawstring);
74 0 : list_free(elemlist);
75 0 : return false;
76 : }
77 :
78 63000 : foreach(l, elemlist)
79 : {
80 38762 : char *tok = (char *) lfirst(l);
81 :
82 : /* Ugh. Somebody ought to write a table driven version -- mjl */
83 :
84 38762 : if (pg_strcasecmp(tok, "ISO") == 0)
85 : {
86 16914 : if (have_style && newDateStyle != USE_ISO_DATES)
87 0 : ok = false; /* conflicting styles */
88 16914 : newDateStyle = USE_ISO_DATES;
89 16914 : have_style = true;
90 : }
91 21848 : else if (pg_strcasecmp(tok, "SQL") == 0)
92 : {
93 30 : if (have_style && newDateStyle != USE_SQL_DATES)
94 0 : ok = false; /* conflicting styles */
95 30 : newDateStyle = USE_SQL_DATES;
96 30 : have_style = true;
97 : }
98 21818 : else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
99 : {
100 7196 : if (have_style && newDateStyle != USE_POSTGRES_DATES)
101 0 : ok = false; /* conflicting styles */
102 7196 : newDateStyle = USE_POSTGRES_DATES;
103 7196 : have_style = true;
104 : }
105 14622 : else if (pg_strcasecmp(tok, "GERMAN") == 0)
106 : {
107 48 : if (have_style && newDateStyle != USE_GERMAN_DATES)
108 0 : ok = false; /* conflicting styles */
109 48 : newDateStyle = USE_GERMAN_DATES;
110 48 : have_style = true;
111 : /* GERMAN also sets DMY, unless explicitly overridden */
112 48 : if (!have_order)
113 48 : newDateOrder = DATEORDER_DMY;
114 : }
115 14574 : else if (pg_strcasecmp(tok, "YMD") == 0)
116 : {
117 42 : if (have_order && newDateOrder != DATEORDER_YMD)
118 0 : ok = false; /* conflicting orders */
119 42 : newDateOrder = DATEORDER_YMD;
120 42 : have_order = true;
121 : }
122 29016 : else if (pg_strcasecmp(tok, "DMY") == 0 ||
123 14484 : pg_strncasecmp(tok, "EURO", 4) == 0)
124 : {
125 66 : if (have_order && newDateOrder != DATEORDER_DMY)
126 0 : ok = false; /* conflicting orders */
127 66 : newDateOrder = DATEORDER_DMY;
128 66 : have_order = true;
129 : }
130 14484 : else if (pg_strcasecmp(tok, "MDY") == 0 ||
131 18 : pg_strcasecmp(tok, "US") == 0 ||
132 0 : pg_strncasecmp(tok, "NONEURO", 7) == 0)
133 : {
134 14466 : if (have_order && newDateOrder != DATEORDER_MDY)
135 0 : ok = false; /* conflicting orders */
136 14466 : newDateOrder = DATEORDER_MDY;
137 14466 : have_order = true;
138 : }
139 0 : else if (pg_strcasecmp(tok, "DEFAULT") == 0)
140 : {
141 : /*
142 : * Easiest way to get the current DEFAULT state is to fetch the
143 : * DEFAULT string from guc.c and recursively parse it.
144 : *
145 : * We can't simply "return check_datestyle(...)" because we need
146 : * to handle constructs like "DEFAULT, ISO".
147 : */
148 : char *subval;
149 0 : void *subextra = NULL;
150 :
151 0 : subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
152 0 : if (!subval)
153 : {
154 0 : ok = false;
155 0 : break;
156 : }
157 0 : if (!check_datestyle(&subval, &subextra, source))
158 : {
159 0 : guc_free(subval);
160 0 : ok = false;
161 0 : break;
162 : }
163 0 : myextra = (int *) subextra;
164 0 : if (!have_style)
165 0 : newDateStyle = myextra[0];
166 0 : if (!have_order)
167 0 : newDateOrder = myextra[1];
168 0 : guc_free(subval);
169 0 : guc_free(subextra);
170 : }
171 : else
172 : {
173 0 : GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
174 0 : pfree(rawstring);
175 0 : list_free(elemlist);
176 0 : return false;
177 : }
178 : }
179 :
180 24238 : pfree(rawstring);
181 24238 : list_free(elemlist);
182 :
183 24238 : if (!ok)
184 : {
185 0 : GUC_check_errdetail("Conflicting \"DateStyle\" specifications.");
186 0 : return false;
187 : }
188 :
189 : /*
190 : * Prepare the canonical string to return. GUC wants it guc_malloc'd.
191 : */
192 24238 : result = (char *) guc_malloc(LOG, 32);
193 24238 : if (!result)
194 0 : return false;
195 :
196 24238 : switch (newDateStyle)
197 : {
198 16938 : case USE_ISO_DATES:
199 16938 : strcpy(result, "ISO");
200 16938 : break;
201 30 : case USE_SQL_DATES:
202 30 : strcpy(result, "SQL");
203 30 : break;
204 48 : case USE_GERMAN_DATES:
205 48 : strcpy(result, "German");
206 48 : break;
207 7222 : default:
208 7222 : strcpy(result, "Postgres");
209 7222 : break;
210 : }
211 24238 : switch (newDateOrder)
212 : {
213 54 : case DATEORDER_YMD:
214 54 : strcat(result, ", YMD");
215 54 : break;
216 94 : case DATEORDER_DMY:
217 94 : strcat(result, ", DMY");
218 94 : break;
219 24090 : default:
220 24090 : strcat(result, ", MDY");
221 24090 : break;
222 : }
223 :
224 24238 : guc_free(*newval);
225 24238 : *newval = result;
226 :
227 : /*
228 : * Set up the "extra" struct actually used by assign_datestyle.
229 : */
230 24238 : myextra = (int *) guc_malloc(LOG, 2 * sizeof(int));
231 24238 : if (!myextra)
232 0 : return false;
233 24238 : myextra[0] = newDateStyle;
234 24238 : myextra[1] = newDateOrder;
235 24238 : *extra = (void *) myextra;
236 :
237 24238 : return true;
238 : }
239 :
240 : /*
241 : * assign_datestyle: GUC assign_hook for datestyle
242 : */
243 : void
244 32366 : assign_datestyle(const char *newval, void *extra)
245 : {
246 32366 : int *myextra = (int *) extra;
247 :
248 32366 : DateStyle = myextra[0];
249 32366 : DateOrder = myextra[1];
250 32366 : }
251 :
252 :
253 : /*
254 : * TIMEZONE
255 : */
256 :
257 : /*
258 : * check_timezone: GUC check_hook for timezone
259 : */
260 : bool
261 14584 : check_timezone(char **newval, void **extra, GucSource source)
262 : {
263 : pg_tz *new_tz;
264 : long gmtoffset;
265 : char *endptr;
266 : double hours;
267 :
268 14584 : if (pg_strncasecmp(*newval, "interval", 8) == 0)
269 : {
270 : /*
271 : * Support INTERVAL 'foo'. This is for SQL spec compliance, not
272 : * because it has any actual real-world usefulness.
273 : */
274 0 : const char *valueptr = *newval;
275 : char *val;
276 : Interval *interval;
277 :
278 0 : valueptr += 8;
279 0 : while (isspace((unsigned char) *valueptr))
280 0 : valueptr++;
281 0 : if (*valueptr++ != '\'')
282 0 : return false;
283 0 : val = pstrdup(valueptr);
284 : /* Check and remove trailing quote */
285 0 : endptr = strchr(val, '\'');
286 0 : if (!endptr || endptr[1] != '\0')
287 : {
288 0 : pfree(val);
289 0 : return false;
290 : }
291 0 : *endptr = '\0';
292 :
293 : /*
294 : * Try to parse it. XXX an invalid interval format will result in
295 : * ereport(ERROR), which is not desirable for GUC. We did what we
296 : * could to guard against this in flatten_set_variable_args, but a
297 : * string coming in from postgresql.conf might contain anything.
298 : */
299 0 : interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
300 : CStringGetDatum(val),
301 : ObjectIdGetDatum(InvalidOid),
302 : Int32GetDatum(-1)));
303 :
304 0 : pfree(val);
305 0 : if (interval->month != 0)
306 : {
307 0 : GUC_check_errdetail("Cannot specify months in time zone interval.");
308 0 : pfree(interval);
309 0 : return false;
310 : }
311 0 : if (interval->day != 0)
312 : {
313 0 : GUC_check_errdetail("Cannot specify days in time zone interval.");
314 0 : pfree(interval);
315 0 : return false;
316 : }
317 :
318 : /* Here we change from SQL to Unix sign convention */
319 0 : gmtoffset = -(interval->time / USECS_PER_SEC);
320 0 : new_tz = pg_tzset_offset(gmtoffset);
321 :
322 0 : pfree(interval);
323 : }
324 : else
325 : {
326 : /*
327 : * Try it as a numeric number of hours (possibly fractional).
328 : */
329 14584 : hours = strtod(*newval, &endptr);
330 14584 : if (endptr != *newval && *endptr == '\0')
331 : {
332 : /* Here we change from SQL to Unix sign convention */
333 72 : gmtoffset = -hours * SECS_PER_HOUR;
334 72 : new_tz = pg_tzset_offset(gmtoffset);
335 : }
336 : else
337 : {
338 : /*
339 : * Otherwise assume it is a timezone name, and try to load it.
340 : */
341 14512 : new_tz = pg_tzset(*newval);
342 :
343 14512 : if (!new_tz)
344 : {
345 : /* Doesn't seem to be any great value in errdetail here */
346 0 : return false;
347 : }
348 :
349 14512 : if (!pg_tz_acceptable(new_tz))
350 : {
351 0 : GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
352 : *newval);
353 0 : GUC_check_errdetail("PostgreSQL does not support leap seconds.");
354 0 : return false;
355 : }
356 : }
357 : }
358 :
359 : /* Test for failure in pg_tzset_offset, which we assume is out-of-range */
360 14584 : if (!new_tz)
361 : {
362 0 : GUC_check_errdetail("UTC timezone offset is out of range.");
363 0 : return false;
364 : }
365 :
366 : /*
367 : * Pass back data for assign_timezone to use
368 : */
369 14584 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
370 14584 : if (!*extra)
371 0 : return false;
372 14584 : *((pg_tz **) *extra) = new_tz;
373 :
374 14584 : return true;
375 : }
376 :
377 : /*
378 : * assign_timezone: GUC assign_hook for timezone
379 : */
380 : void
381 14702 : assign_timezone(const char *newval, void *extra)
382 : {
383 14702 : session_timezone = *((pg_tz **) extra);
384 14702 : }
385 :
386 : /*
387 : * show_timezone: GUC show_hook for timezone
388 : */
389 : const char *
390 53424 : show_timezone(void)
391 : {
392 : const char *tzn;
393 :
394 : /* Always show the zone's canonical name */
395 53424 : tzn = pg_get_timezone_name(session_timezone);
396 :
397 53424 : if (tzn != NULL)
398 53424 : return tzn;
399 :
400 0 : return "unknown";
401 : }
402 :
403 :
404 : /*
405 : * LOG_TIMEZONE
406 : *
407 : * For log_timezone, we don't support the interval-based methods of setting a
408 : * zone, which are only there for SQL spec compliance not because they're
409 : * actually useful.
410 : */
411 :
412 : /*
413 : * check_log_timezone: GUC check_hook for log_timezone
414 : */
415 : bool
416 9938 : check_log_timezone(char **newval, void **extra, GucSource source)
417 : {
418 : pg_tz *new_tz;
419 :
420 : /*
421 : * Assume it is a timezone name, and try to load it.
422 : */
423 9938 : new_tz = pg_tzset(*newval);
424 :
425 9938 : if (!new_tz)
426 : {
427 : /* Doesn't seem to be any great value in errdetail here */
428 0 : return false;
429 : }
430 :
431 9938 : if (!pg_tz_acceptable(new_tz))
432 : {
433 0 : GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
434 : *newval);
435 0 : GUC_check_errdetail("PostgreSQL does not support leap seconds.");
436 0 : return false;
437 : }
438 :
439 : /*
440 : * Pass back data for assign_log_timezone to use
441 : */
442 9938 : *extra = guc_malloc(LOG, sizeof(pg_tz *));
443 9938 : if (!*extra)
444 0 : return false;
445 9938 : *((pg_tz **) *extra) = new_tz;
446 :
447 9938 : return true;
448 : }
449 :
450 : /*
451 : * assign_log_timezone: GUC assign_hook for log_timezone
452 : */
453 : void
454 9932 : assign_log_timezone(const char *newval, void *extra)
455 : {
456 9932 : log_timezone = *((pg_tz **) extra);
457 9932 : }
458 :
459 : /*
460 : * show_log_timezone: GUC show_hook for log_timezone
461 : */
462 : const char *
463 3400 : show_log_timezone(void)
464 : {
465 : const char *tzn;
466 :
467 : /* Always show the zone's canonical name */
468 3400 : tzn = pg_get_timezone_name(log_timezone);
469 :
470 3400 : if (tzn != NULL)
471 3400 : return tzn;
472 :
473 0 : return "unknown";
474 : }
475 :
476 :
477 : /*
478 : * TIMEZONE_ABBREVIATIONS
479 : */
480 :
481 : /*
482 : * GUC check_hook for assign_timezone_abbreviations
483 : */
484 : bool
485 16908 : check_timezone_abbreviations(char **newval, void **extra, GucSource source)
486 : {
487 : /*
488 : * The boot_val for timezone_abbreviations is NULL. When we see that we
489 : * just do nothing. If the value isn't overridden from the config file
490 : * then pg_timezone_abbrev_initialize() will eventually replace it with
491 : * "Default". This hack has two purposes: to avoid wasting cycles loading
492 : * values that might soon be overridden from the config file, and to avoid
493 : * trying to read the timezone abbrev files during InitializeGUCOptions().
494 : * The latter doesn't work in an EXEC_BACKEND subprocess because
495 : * my_exec_path hasn't been set yet and so we can't locate PGSHAREDIR.
496 : */
497 16908 : if (*newval == NULL)
498 : {
499 : Assert(source == PGC_S_DEFAULT);
500 4678 : return true;
501 : }
502 :
503 : /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
504 12230 : *extra = load_tzoffsets(*newval);
505 :
506 : /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
507 12230 : if (!*extra)
508 0 : return false;
509 :
510 12230 : return true;
511 : }
512 :
513 : /*
514 : * GUC assign_hook for assign_timezone_abbreviations
515 : */
516 : void
517 16720 : assign_timezone_abbreviations(const char *newval, void *extra)
518 : {
519 : /* Do nothing for the boot_val default of NULL */
520 16720 : if (!extra)
521 4678 : return;
522 :
523 12042 : InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
524 : }
525 :
526 :
527 : /*
528 : * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
529 : *
530 : * We allow idempotent changes (r/w -> r/w and r/o -> r/o) at any time, and
531 : * we also always allow changes from read-write to read-only. However,
532 : * read-only may be changed to read-write only when in a top-level transaction
533 : * that has not yet taken an initial snapshot. Can't do it in a hot standby,
534 : * either.
535 : *
536 : * If we are not in a transaction at all, just allow the change; it means
537 : * nothing since XactReadOnly will be reset by the next StartTransaction().
538 : * The IsTransactionState() test protects us against trying to check
539 : * RecoveryInProgress() in contexts where shared memory is not accessible.
540 : * (Similarly, if we're restoring state in a parallel worker, just allow
541 : * the change.)
542 : */
543 : bool
544 10736 : check_transaction_read_only(bool *newval, void **extra, GucSource source)
545 : {
546 10736 : if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
547 : {
548 : /* Can't go to r/w mode inside a r/o transaction */
549 64 : if (IsSubTransaction())
550 : {
551 12 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
552 12 : GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
553 12 : return false;
554 : }
555 : /* Top level transaction can't change to r/w after first snapshot. */
556 52 : if (FirstSnapshotSet)
557 : {
558 6 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
559 6 : GUC_check_errmsg("transaction read-write mode must be set before any query");
560 6 : return false;
561 : }
562 : /* Can't go to r/w mode while recovery is still active */
563 46 : if (RecoveryInProgress())
564 : {
565 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
566 0 : GUC_check_errmsg("cannot set transaction read-write mode during recovery");
567 0 : return false;
568 : }
569 : }
570 :
571 10718 : return true;
572 : }
573 :
574 : /*
575 : * SET TRANSACTION ISOLATION LEVEL
576 : *
577 : * We allow idempotent changes at any time, but otherwise this can only be
578 : * changed in a toplevel transaction that has not yet taken a snapshot.
579 : *
580 : * As in check_transaction_read_only, allow it if not inside a transaction,
581 : * or if restoring state in a parallel worker.
582 : */
583 : bool
584 15974 : check_transaction_isolation(int *newval, void **extra, GucSource source)
585 : {
586 15974 : int newXactIsoLevel = *newval;
587 :
588 21764 : if (newXactIsoLevel != XactIsoLevel &&
589 11580 : IsTransactionState() && !InitializingParallelWorker)
590 : {
591 5710 : if (FirstSnapshotSet)
592 : {
593 2 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
594 2 : GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
595 2 : return false;
596 : }
597 : /* We ignore a subtransaction setting it to the existing value. */
598 5708 : if (IsSubTransaction())
599 : {
600 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
601 0 : GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
602 0 : return false;
603 : }
604 : /* Can't go to serializable mode while recovery is still active */
605 5708 : if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
606 : {
607 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
608 0 : GUC_check_errmsg("cannot use serializable mode in a hot standby");
609 0 : GUC_check_errhint("You can use REPEATABLE READ instead.");
610 0 : return false;
611 : }
612 : }
613 :
614 15972 : return true;
615 : }
616 :
617 : /*
618 : * SET TRANSACTION [NOT] DEFERRABLE
619 : */
620 :
621 : bool
622 9410 : check_transaction_deferrable(bool *newval, void **extra, GucSource source)
623 : {
624 : /* Just accept the value when restoring state in a parallel worker */
625 9410 : if (InitializingParallelWorker)
626 5424 : return true;
627 :
628 3986 : if (IsSubTransaction())
629 : {
630 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
631 0 : GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
632 0 : return false;
633 : }
634 3986 : if (FirstSnapshotSet)
635 : {
636 0 : GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
637 0 : GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
638 0 : return false;
639 : }
640 :
641 3986 : return true;
642 : }
643 :
644 : /*
645 : * Random number seed
646 : *
647 : * We can't roll back the random sequence on error, and we don't want
648 : * config file reloads to affect it, so we only want interactive SET SEED
649 : * commands to set it. We use the "extra" storage to ensure that rollbacks
650 : * don't try to do the operation again.
651 : */
652 :
653 : bool
654 1966 : check_random_seed(double *newval, void **extra, GucSource source)
655 : {
656 1966 : *extra = guc_malloc(LOG, sizeof(int));
657 1966 : if (!*extra)
658 0 : return false;
659 : /* Arm the assign only if source of value is an interactive SET */
660 1966 : *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
661 :
662 1966 : return true;
663 : }
664 :
665 : void
666 1966 : assign_random_seed(double newval, void *extra)
667 : {
668 : /* We'll do this at most once for any setting of the GUC variable */
669 1966 : if (*((int *) extra))
670 0 : DirectFunctionCall1(setseed, Float8GetDatum(newval));
671 1966 : *((int *) extra) = 0;
672 1966 : }
673 :
674 : const char *
675 0 : show_random_seed(void)
676 : {
677 0 : return "unavailable";
678 : }
679 :
680 :
681 : /*
682 : * SET CLIENT_ENCODING
683 : */
684 :
685 : bool
686 38252 : check_client_encoding(char **newval, void **extra, GucSource source)
687 : {
688 : int encoding;
689 : const char *canonical_name;
690 :
691 : /* Look up the encoding by name */
692 38252 : encoding = pg_valid_client_encoding(*newval);
693 38252 : if (encoding < 0)
694 0 : return false;
695 :
696 : /* Get the canonical name (no aliases, uniform case) */
697 38252 : canonical_name = pg_encoding_to_char(encoding);
698 :
699 : /*
700 : * Parallel workers send data to the leader, not the client. They always
701 : * send data using the database encoding; therefore, we should never
702 : * actually change the client encoding in a parallel worker. However,
703 : * during parallel worker startup, we want to accept the leader's
704 : * client_encoding setting so that anyone who looks at the value in the
705 : * worker sees the same value that they would see in the leader. A change
706 : * other than during startup, for example due to a SET clause attached to
707 : * a function definition, should be rejected, as there is nothing we can
708 : * do inside the worker to make it take effect.
709 : */
710 38252 : if (IsParallelWorker() && !InitializingParallelWorker)
711 : {
712 0 : GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
713 0 : GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
714 0 : return false;
715 : }
716 :
717 : /*
718 : * If we are not within a transaction then PrepareClientEncoding will not
719 : * be able to look up the necessary conversion procs. If we are still
720 : * starting up, it will return "OK" anyway, and InitializeClientEncoding
721 : * will fix things once initialization is far enough along. After
722 : * startup, we'll fail. This would only happen if someone tries to change
723 : * client_encoding in postgresql.conf and then SIGHUP existing sessions.
724 : * It seems like a bad idea for client_encoding to change that way anyhow,
725 : * so we don't go out of our way to support it.
726 : *
727 : * In a parallel worker, we might as well skip PrepareClientEncoding since
728 : * we're not going to use its results.
729 : *
730 : * Note: in the postmaster, or any other process that never calls
731 : * InitializeClientEncoding, PrepareClientEncoding will always succeed,
732 : * and so will SetClientEncoding; but they won't do anything, which is OK.
733 : */
734 68368 : if (!IsParallelWorker() &&
735 30116 : PrepareClientEncoding(encoding) < 0)
736 : {
737 0 : if (IsTransactionState())
738 : {
739 : /* Must be a genuine no-such-conversion problem */
740 0 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
741 0 : GUC_check_errdetail("Conversion between %s and %s is not supported.",
742 : canonical_name,
743 : GetDatabaseEncodingName());
744 : }
745 : else
746 : {
747 : /* Provide a useful complaint */
748 0 : GUC_check_errdetail("Cannot change \"client_encoding\" now.");
749 : }
750 0 : return false;
751 : }
752 :
753 : /*
754 : * Replace the user-supplied string with the encoding's canonical name.
755 : * This gets rid of aliases and case-folding variations.
756 : *
757 : * XXX Although canonicalizing seems like a good idea in the abstract, it
758 : * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
759 : * as the client_encoding setting then it will read back the same way. As
760 : * a workaround, don't replace the string if it's "UNICODE". Remove that
761 : * hack when pre-9.1 JDBC drivers are no longer in use.
762 : */
763 38252 : if (strcmp(*newval, canonical_name) != 0 &&
764 34 : strcmp(*newval, "UNICODE") != 0)
765 : {
766 34 : guc_free(*newval);
767 34 : *newval = guc_strdup(LOG, canonical_name);
768 34 : if (!*newval)
769 0 : return false;
770 : }
771 :
772 : /*
773 : * Save the encoding's ID in *extra, for use by assign_client_encoding.
774 : */
775 38252 : *extra = guc_malloc(LOG, sizeof(int));
776 38252 : if (!*extra)
777 0 : return false;
778 38252 : *((int *) *extra) = encoding;
779 :
780 38252 : return true;
781 : }
782 :
783 : void
784 38064 : assign_client_encoding(const char *newval, void *extra)
785 : {
786 38064 : int encoding = *((int *) extra);
787 :
788 : /*
789 : * In a parallel worker, we never override the client encoding that was
790 : * set by ParallelWorkerMain().
791 : */
792 38064 : if (IsParallelWorker())
793 8136 : return;
794 :
795 : /* We do not expect an error if PrepareClientEncoding succeeded */
796 29928 : if (SetClientEncoding(encoding) < 0)
797 0 : elog(LOG, "SetClientEncoding(%d) failed", encoding);
798 : }
799 :
800 :
801 : /*
802 : * SET SESSION AUTHORIZATION
803 : */
804 :
805 : typedef struct
806 : {
807 : /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
808 : Oid roleid;
809 : bool is_superuser;
810 : } role_auth_extra;
811 :
812 : bool
813 32716 : check_session_authorization(char **newval, void **extra, GucSource source)
814 : {
815 : HeapTuple roleTup;
816 : Form_pg_authid roleform;
817 : Oid roleid;
818 : bool is_superuser;
819 : role_auth_extra *myextra;
820 :
821 : /* Do nothing for the boot_val default of NULL */
822 32716 : if (*newval == NULL)
823 1966 : return true;
824 :
825 30750 : if (InitializingParallelWorker)
826 : {
827 : /*
828 : * In parallel worker initialization, we want to copy the leader's
829 : * state even if it no longer matches the catalogs. ParallelWorkerMain
830 : * already installed the correct role OID and superuser state.
831 : */
832 2712 : roleid = GetSessionUserId();
833 2712 : is_superuser = GetSessionUserIsSuperuser();
834 : }
835 : else
836 : {
837 28038 : if (!IsTransactionState())
838 : {
839 : /*
840 : * Can't do catalog lookups, so fail. The result of this is that
841 : * session_authorization cannot be set in postgresql.conf, which
842 : * seems like a good thing anyway, so we don't work hard to avoid
843 : * it.
844 : */
845 0 : return false;
846 : }
847 :
848 : /*
849 : * When source == PGC_S_TEST, we don't throw a hard error for a
850 : * nonexistent user name or insufficient privileges, only a NOTICE.
851 : * See comments in guc.h.
852 : */
853 :
854 : /* Look up the username */
855 28038 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
856 28038 : if (!HeapTupleIsValid(roleTup))
857 : {
858 0 : if (source == PGC_S_TEST)
859 : {
860 0 : ereport(NOTICE,
861 : (errcode(ERRCODE_UNDEFINED_OBJECT),
862 : errmsg("role \"%s\" does not exist", *newval)));
863 0 : return true;
864 : }
865 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
866 0 : return false;
867 : }
868 :
869 28038 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
870 28038 : roleid = roleform->oid;
871 28038 : is_superuser = roleform->rolsuper;
872 :
873 28038 : ReleaseSysCache(roleTup);
874 :
875 : /*
876 : * Only superusers may SET SESSION AUTHORIZATION a role other than
877 : * itself. Note that in case of multiple SETs in a single session, the
878 : * original authenticated user's superuserness is what matters.
879 : */
880 28038 : if (roleid != GetAuthenticatedUserId() &&
881 2542 : !superuser_arg(GetAuthenticatedUserId()))
882 : {
883 0 : if (source == PGC_S_TEST)
884 : {
885 0 : ereport(NOTICE,
886 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
887 : errmsg("permission will be denied to set session authorization \"%s\"",
888 : *newval)));
889 0 : return true;
890 : }
891 0 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
892 0 : GUC_check_errmsg("permission denied to set session authorization \"%s\"",
893 : *newval);
894 0 : return false;
895 : }
896 : }
897 :
898 : /* Set up "extra" struct for assign_session_authorization to use */
899 30750 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
900 30750 : if (!myextra)
901 0 : return false;
902 30750 : myextra->roleid = roleid;
903 30750 : myextra->is_superuser = is_superuser;
904 30750 : *extra = (void *) myextra;
905 :
906 30750 : return true;
907 : }
908 :
909 : void
910 33614 : assign_session_authorization(const char *newval, void *extra)
911 : {
912 33614 : role_auth_extra *myextra = (role_auth_extra *) extra;
913 :
914 : /* Do nothing for the boot_val default of NULL */
915 33614 : if (!myextra)
916 1966 : return;
917 :
918 31648 : SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
919 : }
920 :
921 :
922 : /*
923 : * SET ROLE
924 : *
925 : * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
926 : * a translation of "none" to InvalidOid. Otherwise this is much like
927 : * SET SESSION AUTHORIZATION.
928 : */
929 :
930 : bool
931 33680 : check_role(char **newval, void **extra, GucSource source)
932 : {
933 : HeapTuple roleTup;
934 : Oid roleid;
935 : bool is_superuser;
936 : role_auth_extra *myextra;
937 : Form_pg_authid roleform;
938 :
939 33680 : if (strcmp(*newval, "none") == 0)
940 : {
941 : /* hardwired translation */
942 32700 : roleid = InvalidOid;
943 32700 : is_superuser = false;
944 : }
945 980 : else if (InitializingParallelWorker)
946 : {
947 : /*
948 : * In parallel worker initialization, we want to copy the leader's
949 : * state even if it no longer matches the catalogs. ParallelWorkerMain
950 : * already installed the correct role OID and superuser state.
951 : */
952 12 : roleid = GetCurrentRoleId();
953 12 : is_superuser = current_role_is_superuser;
954 : }
955 : else
956 : {
957 968 : if (!IsTransactionState())
958 : {
959 : /*
960 : * Can't do catalog lookups, so fail. The result of this is that
961 : * role cannot be set in postgresql.conf, which seems like a good
962 : * thing anyway, so we don't work hard to avoid it.
963 : */
964 0 : return false;
965 : }
966 :
967 : /*
968 : * When source == PGC_S_TEST, we don't throw a hard error for a
969 : * nonexistent user name or insufficient privileges, only a NOTICE.
970 : * See comments in guc.h.
971 : */
972 :
973 : /* Look up the username */
974 968 : roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
975 968 : if (!HeapTupleIsValid(roleTup))
976 : {
977 0 : if (source == PGC_S_TEST)
978 : {
979 0 : ereport(NOTICE,
980 : (errcode(ERRCODE_UNDEFINED_OBJECT),
981 : errmsg("role \"%s\" does not exist", *newval)));
982 0 : return true;
983 : }
984 0 : GUC_check_errmsg("role \"%s\" does not exist", *newval);
985 0 : return false;
986 : }
987 :
988 968 : roleform = (Form_pg_authid) GETSTRUCT(roleTup);
989 968 : roleid = roleform->oid;
990 968 : is_superuser = roleform->rolsuper;
991 :
992 968 : ReleaseSysCache(roleTup);
993 :
994 : /* Verify that session user is allowed to become this role */
995 968 : if (!member_can_set_role(GetSessionUserId(), roleid))
996 : {
997 12 : if (source == PGC_S_TEST)
998 : {
999 0 : ereport(NOTICE,
1000 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1001 : errmsg("permission will be denied to set role \"%s\"",
1002 : *newval)));
1003 0 : return true;
1004 : }
1005 12 : GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
1006 12 : GUC_check_errmsg("permission denied to set role \"%s\"",
1007 : *newval);
1008 12 : return false;
1009 : }
1010 : }
1011 :
1012 : /* Set up "extra" struct for assign_role to use */
1013 33668 : myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
1014 33668 : if (!myextra)
1015 0 : return false;
1016 33668 : myextra->roleid = roleid;
1017 33668 : myextra->is_superuser = is_superuser;
1018 33668 : *extra = (void *) myextra;
1019 :
1020 33668 : return true;
1021 : }
1022 :
1023 : void
1024 35226 : assign_role(const char *newval, void *extra)
1025 : {
1026 35226 : role_auth_extra *myextra = (role_auth_extra *) extra;
1027 :
1028 35226 : SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
1029 35226 : }
1030 :
1031 : const char *
1032 60 : show_role(void)
1033 : {
1034 : /*
1035 : * Check whether SET ROLE is active; if not return "none". This is a
1036 : * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
1037 : * resets SET ROLE to NONE, but we cannot set the GUC role variable from
1038 : * assign_session_authorization (because we haven't got enough info to
1039 : * call set_config_option).
1040 : */
1041 60 : if (!OidIsValid(GetCurrentRoleId()))
1042 24 : return "none";
1043 :
1044 : /* Otherwise we can just use the GUC string */
1045 36 : return role_string ? role_string : "none";
1046 : }
1047 :
1048 :
1049 : /*
1050 : * PATH VARIABLES
1051 : *
1052 : * check_canonical_path is used for log_directory and some other GUCs where
1053 : * all we want to do is canonicalize the represented path name.
1054 : */
1055 :
1056 : bool
1057 3932 : check_canonical_path(char **newval, void **extra, GucSource source)
1058 : {
1059 : /*
1060 : * Since canonicalize_path never enlarges the string, we can just modify
1061 : * newval in-place. But watch out for NULL, which is the default value
1062 : * for external_pid_file.
1063 : */
1064 3932 : if (*newval)
1065 1966 : canonicalize_path(*newval);
1066 3932 : return true;
1067 : }
1068 :
1069 :
1070 : /*
1071 : * MISCELLANEOUS
1072 : */
1073 :
1074 : /*
1075 : * GUC check_hook for application_name
1076 : */
1077 : bool
1078 30350 : check_application_name(char **newval, void **extra, GucSource source)
1079 : {
1080 : char *clean;
1081 : char *ret;
1082 :
1083 : /* Only allow clean ASCII chars in the application name */
1084 30350 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1085 30350 : if (!clean)
1086 0 : return false;
1087 :
1088 30350 : ret = guc_strdup(WARNING, clean);
1089 30350 : if (!ret)
1090 : {
1091 0 : pfree(clean);
1092 0 : return false;
1093 : }
1094 :
1095 30350 : pfree(clean);
1096 30350 : *newval = ret;
1097 30350 : return true;
1098 : }
1099 :
1100 : /*
1101 : * GUC assign_hook for application_name
1102 : */
1103 : void
1104 30322 : assign_application_name(const char *newval, void *extra)
1105 : {
1106 : /* Update the pg_stat_activity view */
1107 30322 : pgstat_report_appname(newval);
1108 30322 : }
1109 :
1110 : /*
1111 : * GUC check_hook for cluster_name
1112 : */
1113 : bool
1114 3234 : check_cluster_name(char **newval, void **extra, GucSource source)
1115 : {
1116 : char *clean;
1117 : char *ret;
1118 :
1119 : /* Only allow clean ASCII chars in the cluster name */
1120 3234 : clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1121 3234 : if (!clean)
1122 0 : return false;
1123 :
1124 3234 : ret = guc_strdup(WARNING, clean);
1125 3234 : if (!ret)
1126 : {
1127 0 : pfree(clean);
1128 0 : return false;
1129 : }
1130 :
1131 3234 : pfree(clean);
1132 3234 : *newval = ret;
1133 3234 : return true;
1134 : }
1135 :
1136 : /*
1137 : * GUC assign_hook for maintenance_io_concurrency
1138 : */
1139 : void
1140 1966 : assign_maintenance_io_concurrency(int newval, void *extra)
1141 : {
1142 : #ifdef USE_PREFETCH
1143 : /*
1144 : * Reconfigure recovery prefetching, because a setting it depends on
1145 : * changed.
1146 : */
1147 1966 : maintenance_io_concurrency = newval;
1148 1966 : if (AmStartupProcess())
1149 0 : XLogPrefetchReconfigure();
1150 : #endif
1151 1966 : }
1152 :
1153 :
1154 : /*
1155 : * These show hooks just exist because we want to show the values in octal.
1156 : */
1157 :
1158 : /*
1159 : * GUC show_hook for data_directory_mode
1160 : */
1161 : const char *
1162 4120 : show_data_directory_mode(void)
1163 : {
1164 : static char buf[12];
1165 :
1166 4120 : snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1167 4120 : return buf;
1168 : }
1169 :
1170 : /*
1171 : * GUC show_hook for log_file_mode
1172 : */
1173 : const char *
1174 3400 : show_log_file_mode(void)
1175 : {
1176 : static char buf[12];
1177 :
1178 3400 : snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1179 3400 : return buf;
1180 : }
1181 :
1182 : /*
1183 : * GUC show_hook for unix_socket_permissions
1184 : */
1185 : const char *
1186 3400 : show_unix_socket_permissions(void)
1187 : {
1188 : static char buf[12];
1189 :
1190 3400 : snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1191 3400 : return buf;
1192 : }
1193 :
1194 :
1195 : /*
1196 : * These check hooks do nothing more than reject non-default settings
1197 : * in builds that don't support them.
1198 : */
1199 :
1200 : bool
1201 1966 : check_bonjour(bool *newval, void **extra, GucSource source)
1202 : {
1203 : #ifndef USE_BONJOUR
1204 1966 : if (*newval)
1205 : {
1206 0 : GUC_check_errmsg("Bonjour is not supported by this build");
1207 0 : return false;
1208 : }
1209 : #endif
1210 1966 : return true;
1211 : }
1212 :
1213 : bool
1214 1978 : check_default_with_oids(bool *newval, void **extra, GucSource source)
1215 : {
1216 1978 : if (*newval)
1217 : {
1218 : /* check the GUC's definition for an explanation */
1219 6 : GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
1220 6 : GUC_check_errmsg("tables declared WITH OIDS are not supported");
1221 :
1222 6 : return false;
1223 : }
1224 :
1225 1972 : return true;
1226 : }
1227 :
1228 : bool
1229 2578 : check_effective_io_concurrency(int *newval, void **extra, GucSource source)
1230 : {
1231 : #ifndef USE_PREFETCH
1232 : if (*newval != 0)
1233 : {
1234 : GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1235 : "effective_io_concurrency");
1236 : return false;
1237 : }
1238 : #endif /* USE_PREFETCH */
1239 2578 : return true;
1240 : }
1241 :
1242 : bool
1243 1966 : check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
1244 : {
1245 : #ifndef USE_PREFETCH
1246 : if (*newval != 0)
1247 : {
1248 : GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1249 : "maintenance_io_concurrency");
1250 : return false;
1251 : }
1252 : #endif /* USE_PREFETCH */
1253 1966 : return true;
1254 : }
1255 :
1256 : bool
1257 2056 : check_ssl(bool *newval, void **extra, GucSource source)
1258 : {
1259 : #ifndef USE_SSL
1260 : if (*newval)
1261 : {
1262 : GUC_check_errmsg("SSL is not supported by this build");
1263 : return false;
1264 : }
1265 : #endif
1266 2056 : return true;
1267 : }
|