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-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"
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}
385
386/*
387 * show_timezone: GUC show_hook for timezone
388 */
389const char *
391{
392 const char *tzn;
393
394 /* Always show the zone's canonical name */
396
397 if (tzn != NULL)
398 return tzn;
399
400 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 */
415bool
417{
418 pg_tz *new_tz;
419
420 /*
421 * Assume it is a timezone name, and try to load it.
422 */
423 new_tz = pg_tzset(*newval);
424
425 if (!new_tz)
426 {
427 /* Doesn't seem to be any great value in errdetail here */
428 return false;
429 }
430
431 if (!pg_tz_acceptable(new_tz))
432 {
433 GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
434 *newval);
435 GUC_check_errdetail("PostgreSQL does not support leap seconds.");
436 return false;
437 }
438
439 /*
440 * Pass back data for assign_log_timezone to use
441 */
442 *extra = guc_malloc(LOG, sizeof(pg_tz *));
443 if (!*extra)
444 return false;
445 *((pg_tz **) *extra) = new_tz;
446
447 return true;
448}
449
450/*
451 * assign_log_timezone: GUC assign_hook for log_timezone
452 */
453void
454assign_log_timezone(const char *newval, void *extra)
455{
456 log_timezone = *((pg_tz **) extra);
457}
458
459/*
460 * show_log_timezone: GUC show_hook for log_timezone
461 */
462const char *
464{
465 const char *tzn;
466
467 /* Always show the zone's canonical name */
469
470 if (tzn != NULL)
471 return tzn;
472
473 return "unknown";
474}
475
476
477/*
478 * TIMEZONE_ABBREVIATIONS
479 */
480
481/*
482 * GUC check_hook for timezone_abbreviations
483 */
484bool
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 if (*newval == NULL)
498 {
500 return true;
501 }
502
503 /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
504 *extra = load_tzoffsets(*newval);
505
506 /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
507 if (!*extra)
508 return false;
509
510 return true;
511}
512
513/*
514 * GUC assign_hook for timezone_abbreviations
515 */
516void
517assign_timezone_abbreviations(const char *newval, void *extra)
518{
519 /* Do nothing for the boot_val default of NULL */
520 if (!extra)
521 return;
522
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 */
543bool
545{
547 {
548 /* Can't go to r/w mode inside a r/o transaction */
549 if (IsSubTransaction())
550 {
551 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
552 GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
553 return false;
554 }
555 /* Top level transaction can't change to r/w after first snapshot. */
557 {
558 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
559 GUC_check_errmsg("transaction read-write mode must be set before any query");
560 return false;
561 }
562 /* Can't go to r/w mode while recovery is still active */
563 if (RecoveryInProgress())
564 {
565 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
566 GUC_check_errmsg("cannot set transaction read-write mode during recovery");
567 return false;
568 }
569 }
570
571 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 */
583bool
585{
586 int newXactIsoLevel = *newval;
587
588 if (newXactIsoLevel != XactIsoLevel &&
590 {
592 {
593 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
594 GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
595 return false;
596 }
597 /* We ignore a subtransaction setting it to the existing value. */
598 if (IsSubTransaction())
599 {
600 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
601 GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
602 return false;
603 }
604 /* Can't go to serializable mode while recovery is still active */
605 if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
606 {
607 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
608 GUC_check_errmsg("cannot use serializable mode in a hot standby");
609 GUC_check_errhint("You can use REPEATABLE READ instead.");
610 return false;
611 }
612 }
613
614 return true;
615}
616
617/*
618 * SET TRANSACTION [NOT] DEFERRABLE
619 */
620
621bool
623{
624 /* Just accept the value when restoring state in a parallel worker */
626 return true;
627
628 if (IsSubTransaction())
629 {
630 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
631 GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
632 return false;
633 }
635 {
636 GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
637 GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
638 return false;
639 }
640
641 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
653bool
655{
656 *extra = guc_malloc(LOG, sizeof(int));
657 if (!*extra)
658 return false;
659 /* Arm the assign only if source of value is an interactive SET */
660 *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
661
662 return true;
663}
664
665void
666assign_random_seed(double newval, void *extra)
667{
668 /* We'll do this at most once for any setting of the GUC variable */
669 if (*((int *) extra))
671 *((int *) extra) = 0;
672}
673
674const char *
676{
677 return "unavailable";
678}
679
680
681/*
682 * SET CLIENT_ENCODING
683 */
684
685bool
687{
688 int encoding;
689 const char *canonical_name;
690
691 /* Look up the encoding by name */
693 if (encoding < 0)
694 return false;
695
696 /* Get the canonical name (no aliases, uniform case) */
697 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 */
711 {
712 GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
713 GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
714 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 if (!IsParallelWorker() &&
736 {
737 if (IsTransactionState())
738 {
739 /* Must be a genuine no-such-conversion problem */
740 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
741 GUC_check_errdetail("Conversion between %s and %s is not supported.",
742 canonical_name,
744 }
745 else
746 {
747 /* Provide a useful complaint */
748 GUC_check_errdetail("Cannot change \"client_encoding\" now.");
749 }
750 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 if (strcmp(*newval, canonical_name) != 0 &&
764 strcmp(*newval, "UNICODE") != 0)
765 {
767 *newval = guc_strdup(LOG, canonical_name);
768 if (!*newval)
769 return false;
770 }
771
772 /*
773 * Save the encoding's ID in *extra, for use by assign_client_encoding.
774 */
775 *extra = guc_malloc(LOG, sizeof(int));
776 if (!*extra)
777 return false;
778 *((int *) *extra) = encoding;
779
780 return true;
781}
782
783void
784assign_client_encoding(const char *newval, void *extra)
785{
786 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 if (IsParallelWorker())
793 return;
794
795 /* We do not expect an error if PrepareClientEncoding succeeded */
797 elog(LOG, "SetClientEncoding(%d) failed", encoding);
798}
799
800
801/*
802 * SET SESSION AUTHORIZATION
803 */
804
805typedef struct
806{
807 /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
811
812bool
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 if (*newval == NULL)
823 return true;
824
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 roleid = GetSessionUserId();
834 }
835 else
836 {
837 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 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 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
856 if (!HeapTupleIsValid(roleTup))
857 {
858 if (source == PGC_S_TEST)
859 {
861 (errcode(ERRCODE_UNDEFINED_OBJECT),
862 errmsg("role \"%s\" does not exist", *newval)));
863 return true;
864 }
865 GUC_check_errmsg("role \"%s\" does not exist", *newval);
866 return false;
867 }
868
869 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
870 roleid = roleform->oid;
871 is_superuser = roleform->rolsuper;
872
873 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 if (roleid != GetAuthenticatedUserId() &&
882 {
883 if (source == PGC_S_TEST)
884 {
886 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
887 errmsg("permission will be denied to set session authorization \"%s\"",
888 *newval)));
889 return true;
890 }
891 GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
892 GUC_check_errmsg("permission denied to set session authorization \"%s\"",
893 *newval);
894 return false;
895 }
896 }
897
898 /* Set up "extra" struct for assign_session_authorization to use */
899 myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
900 if (!myextra)
901 return false;
902 myextra->roleid = roleid;
903 myextra->is_superuser = is_superuser;
904 *extra = myextra;
905
906 return true;
907}
908
909void
910assign_session_authorization(const char *newval, void *extra)
911{
912 role_auth_extra *myextra = (role_auth_extra *) extra;
913
914 /* Do nothing for the boot_val default of NULL */
915 if (!myextra)
916 return;
917
918 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
930bool
931check_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 if (strcmp(*newval, "none") == 0)
940 {
941 /* hardwired translation */
942 roleid = InvalidOid;
943 is_superuser = false;
944 }
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 roleid = GetCurrentRoleId();
954 }
955 else
956 {
957 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 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 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
975 if (!HeapTupleIsValid(roleTup))
976 {
977 if (source == PGC_S_TEST)
978 {
980 (errcode(ERRCODE_UNDEFINED_OBJECT),
981 errmsg("role \"%s\" does not exist", *newval)));
982 return true;
983 }
984 GUC_check_errmsg("role \"%s\" does not exist", *newval);
985 return false;
986 }
987
988 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
989 roleid = roleform->oid;
990 is_superuser = roleform->rolsuper;
991
992 ReleaseSysCache(roleTup);
993
994 /* Verify that session user is allowed to become this role */
996 {
997 if (source == PGC_S_TEST)
998 {
1000 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1001 errmsg("permission will be denied to set role \"%s\"",
1002 *newval)));
1003 return true;
1004 }
1005 GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
1006 GUC_check_errmsg("permission denied to set role \"%s\"",
1007 *newval);
1008 return false;
1009 }
1010 }
1011
1012 /* Set up "extra" struct for assign_role to use */
1013 myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
1014 if (!myextra)
1015 return false;
1016 myextra->roleid = roleid;
1017 myextra->is_superuser = is_superuser;
1018 *extra = myextra;
1019
1020 return true;
1021}
1022
1023void
1024assign_role(const char *newval, void *extra)
1025{
1026 role_auth_extra *myextra = (role_auth_extra *) extra;
1027
1028 SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
1029}
1030
1031const char *
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 */
1042 return "none";
1043
1044 /* Otherwise we can just use the GUC string */
1045 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
1056bool
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 if (*newval)
1066 return true;
1067}
1068
1069
1070/*
1071 * MISCELLANEOUS
1072 */
1073
1074/*
1075 * GUC check_hook for application_name
1076 */
1077bool
1079{
1080 char *clean;
1081 char *ret;
1082
1083 /* Only allow clean ASCII chars in the application name */
1085 if (!clean)
1086 return false;
1087
1088 ret = guc_strdup(WARNING, clean);
1089 if (!ret)
1090 {
1091 pfree(clean);
1092 return false;
1093 }
1094
1095 guc_free(*newval);
1096
1097 pfree(clean);
1098 *newval = ret;
1099 return true;
1100}
1101
1102/*
1103 * GUC assign_hook for application_name
1104 */
1105void
1106assign_application_name(const char *newval, void *extra)
1107{
1108 /* Update the pg_stat_activity view */
1110}
1111
1112/*
1113 * GUC check_hook for cluster_name
1114 */
1115bool
1117{
1118 char *clean;
1119 char *ret;
1120
1121 /* Only allow clean ASCII chars in the cluster name */
1123 if (!clean)
1124 return false;
1125
1126 ret = guc_strdup(WARNING, clean);
1127 if (!ret)
1128 {
1129 pfree(clean);
1130 return false;
1131 }
1132
1133 guc_free(*newval);
1134
1135 pfree(clean);
1136 *newval = ret;
1137 return true;
1138}
1139
1140/*
1141 * GUC assign_hook for maintenance_io_concurrency
1142 */
1143void
1145{
1146#ifdef USE_PREFETCH
1147 /*
1148 * Reconfigure recovery prefetching, because a setting it depends on
1149 * changed.
1150 */
1152 if (AmStartupProcess())
1154#endif
1155}
1156
1157
1158/*
1159 * These show hooks just exist because we want to show the values in octal.
1160 */
1161
1162/*
1163 * GUC show_hook for data_directory_mode
1164 */
1165const char *
1167{
1168 static char buf[12];
1169
1170 snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1171 return buf;
1172}
1173
1174/*
1175 * GUC show_hook for log_file_mode
1176 */
1177const char *
1179{
1180 static char buf[12];
1181
1182 snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1183 return buf;
1184}
1185
1186/*
1187 * GUC show_hook for unix_socket_permissions
1188 */
1189const char *
1191{
1192 static char buf[12];
1193
1194 snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1195 return buf;
1196}
1197
1198
1199/*
1200 * These check hooks do nothing more than reject non-default settings
1201 * in builds that don't support them.
1202 */
1203
1204bool
1206{
1207#ifndef USE_BONJOUR
1208 if (*newval)
1209 {
1210 GUC_check_errmsg("Bonjour is not supported by this build");
1211 return false;
1212 }
1213#endif
1214 return true;
1215}
1216
1217bool
1219{
1220 if (*newval)
1221 {
1222 /* check the GUC's definition for an explanation */
1223 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
1224 GUC_check_errmsg("tables declared WITH OIDS are not supported");
1225
1226 return false;
1227 }
1228
1229 return true;
1230}
1231
1232bool
1234{
1235#ifndef USE_PREFETCH
1236 if (*newval != 0)
1237 {
1238 GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1239 "effective_io_concurrency");
1240 return false;
1241 }
1242#endif /* USE_PREFETCH */
1243 return true;
1244}
1245
1246bool
1248{
1249#ifndef USE_PREFETCH
1250 if (*newval != 0)
1251 {
1252 GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1253 "maintenance_io_concurrency");
1254 return false;
1255 }
1256#endif /* USE_PREFETCH */
1257 return true;
1258}
1259
1260bool
1261check_ssl(bool *newval, void **extra, GucSource source)
1262{
1263#ifndef USE_SSL
1264 if (*newval)
1265 {
1266 GUC_check_errmsg("SSL is not supported by this build");
1267 return false;
1268 }
1269#endif
1270 return true;
1271}
bool member_can_set_role(Oid member, Oid role)
Definition: acl.c:5302
bool InitializingParallelWorker
Definition: parallel.c:120
void assign_application_name(const char *newval, void *extra)
Definition: variable.c:1106
bool check_bonjour(bool *newval, void **extra, GucSource source)
Definition: variable.c:1205
bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
Definition: variable.c:1247
void assign_session_authorization(const char *newval, void *extra)
Definition: variable.c:910
bool check_transaction_deferrable(bool *newval, void **extra, GucSource source)
Definition: variable.c:622
bool check_canonical_path(char **newval, void **extra, GucSource source)
Definition: variable.c:1057
bool check_transaction_isolation(int *newval, void **extra, GucSource source)
Definition: variable.c:584
bool check_default_with_oids(bool *newval, void **extra, GucSource source)
Definition: variable.c:1218
void assign_timezone_abbreviations(const char *newval, void *extra)
Definition: variable.c:517
bool check_effective_io_concurrency(int *newval, void **extra, GucSource source)
Definition: variable.c:1233
bool check_application_name(char **newval, void **extra, GucSource source)
Definition: variable.c:1078
void assign_timezone(const char *newval, void *extra)
Definition: variable.c:381
bool check_role(char **newval, void **extra, GucSource source)
Definition: variable.c:931
bool check_cluster_name(char **newval, void **extra, GucSource source)
Definition: variable.c:1116
const char * show_random_seed(void)
Definition: variable.c:675
bool check_session_authorization(char **newval, void **extra, GucSource source)
Definition: variable.c:813
const char * show_log_file_mode(void)
Definition: variable.c:1178
bool check_transaction_read_only(bool *newval, void **extra, GucSource source)
Definition: variable.c:544
void assign_maintenance_io_concurrency(int newval, void *extra)
Definition: variable.c:1144
bool check_timezone_abbreviations(char **newval, void **extra, GucSource source)
Definition: variable.c:485
const char * show_log_timezone(void)
Definition: variable.c:463
void assign_client_encoding(const char *newval, void *extra)
Definition: variable.c:784
void assign_role(const char *newval, void *extra)
Definition: variable.c:1024
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:1261
void assign_datestyle(const char *newval, void *extra)
Definition: variable.c:244
void assign_random_seed(double newval, void *extra)
Definition: variable.c:666
const char * show_role(void)
Definition: variable.c:1032
bool check_log_timezone(char **newval, void **extra, GucSource source)
Definition: variable.c:416
bool check_random_seed(double *newval, void **extra, GucSource source)
Definition: variable.c:654
const char * show_unix_socket_permissions(void)
Definition: variable.c:1190
const char * show_timezone(void)
Definition: variable.c:390
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:686
const char * show_data_directory_mode(void)
Definition: variable.c:1166
void assign_log_timezone(const char *newval, void *extra)
Definition: variable.c:454
void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
Definition: datetime.c:4957
Datum interval_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:890
void pgstat_report_appname(const char *appname)
int maintenance_io_concurrency
Definition: bufmgr.c:158
#define Assert(condition)
Definition: c.h:812
#define OidIsValid(objectId)
Definition: c.h:729
#define SECS_PER_HOUR
Definition: timestamp.h:127
#define USECS_PER_SEC
Definition: timestamp.h:134
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:225
#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:641
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:645
int DateStyle
Definition: globals.c:124
int data_directory_mode
Definition: globals.c:76
int DateOrder
Definition: globals.c:125
void GUC_check_errcode(int sqlerrcode)
Definition: guc.c:6785
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:472
#define GUC_check_errdetail
Definition: guc.h:476
GucSource
Definition: guc.h:108
@ PGC_S_DEFAULT
Definition: guc.h:109
@ PGC_S_TEST
Definition: guc.h:121
@ PGC_S_INTERACTIVE
Definition: guc.h:120
#define GUC_check_errhint
Definition: guc.h:480
char * role_string
Definition: guc_tables.c:619
bool current_role_is_superuser
Definition: guc_tables.c:519
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#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:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
#define AmStartupProcess()
Definition: miscadmin.h:388
#define USE_SQL_DATES
Definition: miscadmin.h:237
#define USE_POSTGRES_DATES
Definition: miscadmin.h:235
#define USE_ISO_DATES
Definition: miscadmin.h:236
#define DATEORDER_DMY
Definition: miscadmin.h:243
#define DATEORDER_MDY
Definition: miscadmin.h:244
#define DATEORDER_YMD
Definition: miscadmin.h:242
#define USE_GERMAN_DATES
Definition: miscadmin.h:238
void SetSessionAuthorization(Oid userid, bool is_superuser)
Definition: miscinit.c:968
bool GetSessionUserIsSuperuser(void)
Definition: miscinit.c:563
Oid GetSessionUserId(void)
Definition: miscinit.c:556
void SetCurrentRoleId(Oid roleid, bool is_superuser)
Definition: miscinit.c:1004
Oid GetAuthenticatedUserId(void)
Definition: miscinit.c:593
Oid GetCurrentRoleId(void)
Definition: miscinit.c:983
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:4806
#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:1890
const char * pg_get_timezone_name(pg_tz *tz)
Definition: localtime.c:1875
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:265
#define snprintf
Definition: port.h:238
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:322
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
int Unix_socket_permissions
Definition: pqcomm.c:106
Datum setseed(PG_FUNCTION_ARGS)
bool FirstSnapshotSet
Definition: snapmgr.c:133
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:809
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:3432
bool XactReadOnly
Definition: xact.c:81
bool IsTransactionState(void)
Definition: xact.c:386
int XactIsoLevel
Definition: xact.c:78
bool IsSubTransaction(void)
Definition: xact.c:5036
#define XACT_SERIALIZABLE
Definition: xact.h:39
bool RecoveryInProgress(void)
Definition: xlog.c:6334
void XLogPrefetchReconfigure(void)