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