Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / backend / commands / variable.c
blob44796bf15ad4f80e5316e6796ee9b65792087c2c
1 /*-------------------------------------------------------------------------
3 * variable.c
4 * Routines for handling specialized SET variables.
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * src/backend/commands/variable.c
14 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include <ctype.h>
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"
45 * DATESTYLE
49 * check_datestyle: GUC check_hook for datestyle
51 bool
52 check_datestyle(char **newval, void **extra, GucSource source)
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;
65 /* Need a modifiable copy of string */
66 rawstring = pstrdup(*newval);
68 /* Parse string into list of identifiers */
69 if (!SplitIdentifierString(rawstring, ',', &elemlist))
71 /* syntax error in list */
72 GUC_check_errdetail("List syntax is invalid.");
73 pfree(rawstring);
74 list_free(elemlist);
75 return false;
78 foreach(l, elemlist)
80 char *tok = (char *) lfirst(l);
82 /* Ugh. Somebody ought to write a table driven version -- mjl */
84 if (pg_strcasecmp(tok, "ISO") == 0)
86 if (have_style && newDateStyle != USE_ISO_DATES)
87 ok = false; /* conflicting styles */
88 newDateStyle = USE_ISO_DATES;
89 have_style = true;
91 else if (pg_strcasecmp(tok, "SQL") == 0)
93 if (have_style && newDateStyle != USE_SQL_DATES)
94 ok = false; /* conflicting styles */
95 newDateStyle = USE_SQL_DATES;
96 have_style = true;
98 else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
100 if (have_style && newDateStyle != USE_POSTGRES_DATES)
101 ok = false; /* conflicting styles */
102 newDateStyle = USE_POSTGRES_DATES;
103 have_style = true;
105 else if (pg_strcasecmp(tok, "GERMAN") == 0)
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;
115 else if (pg_strcasecmp(tok, "YMD") == 0)
117 if (have_order && newDateOrder != DATEORDER_YMD)
118 ok = false; /* conflicting orders */
119 newDateOrder = DATEORDER_YMD;
120 have_order = true;
122 else if (pg_strcasecmp(tok, "DMY") == 0 ||
123 pg_strncasecmp(tok, "EURO", 4) == 0)
125 if (have_order && newDateOrder != DATEORDER_DMY)
126 ok = false; /* conflicting orders */
127 newDateOrder = DATEORDER_DMY;
128 have_order = true;
130 else if (pg_strcasecmp(tok, "MDY") == 0 ||
131 pg_strcasecmp(tok, "US") == 0 ||
132 pg_strncasecmp(tok, "NONEURO", 7) == 0)
134 if (have_order && newDateOrder != DATEORDER_MDY)
135 ok = false; /* conflicting orders */
136 newDateOrder = DATEORDER_MDY;
137 have_order = true;
139 else if (pg_strcasecmp(tok, "DEFAULT") == 0)
142 * Easiest way to get the current DEFAULT state is to fetch the
143 * DEFAULT string from guc.c and recursively parse it.
145 * We can't simply "return check_datestyle(...)" because we need
146 * to handle constructs like "DEFAULT, ISO".
148 char *subval;
149 void *subextra = NULL;
151 subval = guc_strdup(LOG, GetConfigOptionResetString("datestyle"));
152 if (!subval)
154 ok = false;
155 break;
157 if (!check_datestyle(&subval, &subextra, source))
159 guc_free(subval);
160 ok = false;
161 break;
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);
171 else
173 GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
174 pfree(rawstring);
175 list_free(elemlist);
176 return false;
180 pfree(rawstring);
181 list_free(elemlist);
183 if (!ok)
185 GUC_check_errdetail("Conflicting \"DateStyle\" specifications.");
186 return false;
190 * Prepare the canonical string to return. GUC wants it guc_malloc'd.
192 result = (char *) guc_malloc(LOG, 32);
193 if (!result)
194 return false;
196 switch (newDateStyle)
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;
211 switch (newDateOrder)
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;
224 guc_free(*newval);
225 *newval = result;
228 * Set up the "extra" struct actually used by assign_datestyle.
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;
237 return true;
241 * assign_datestyle: GUC assign_hook for datestyle
243 void
244 assign_datestyle(const char *newval, void *extra)
246 int *myextra = (int *) extra;
248 DateStyle = myextra[0];
249 DateOrder = myextra[1];
254 * TIMEZONE
258 * check_timezone: GUC check_hook for timezone
260 bool
261 check_timezone(char **newval, void **extra, GucSource source)
263 pg_tz *new_tz;
264 long gmtoffset;
265 char *endptr;
266 double hours;
268 if (pg_strncasecmp(*newval, "interval", 8) == 0)
271 * Support INTERVAL 'foo'. This is for SQL spec compliance, not
272 * because it has any actual real-world usefulness.
274 const char *valueptr = *newval;
275 char *val;
276 Interval *interval;
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')
288 pfree(val);
289 return false;
291 *endptr = '\0';
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.
299 interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
300 CStringGetDatum(val),
301 ObjectIdGetDatum(InvalidOid),
302 Int32GetDatum(-1)));
304 pfree(val);
305 if (interval->month != 0)
307 GUC_check_errdetail("Cannot specify months in time zone interval.");
308 pfree(interval);
309 return false;
311 if (interval->day != 0)
313 GUC_check_errdetail("Cannot specify days in time zone interval.");
314 pfree(interval);
315 return false;
318 /* Here we change from SQL to Unix sign convention */
319 gmtoffset = -(interval->time / USECS_PER_SEC);
320 new_tz = pg_tzset_offset(gmtoffset);
322 pfree(interval);
324 else
327 * Try it as a numeric number of hours (possibly fractional).
329 hours = strtod(*newval, &endptr);
330 if (endptr != *newval && *endptr == '\0')
332 /* Here we change from SQL to Unix sign convention */
333 gmtoffset = -hours * SECS_PER_HOUR;
334 new_tz = pg_tzset_offset(gmtoffset);
336 else
339 * Otherwise assume it is a timezone name, and try to load it.
341 new_tz = pg_tzset(*newval);
343 if (!new_tz)
345 /* Doesn't seem to be any great value in errdetail here */
346 return false;
349 if (!pg_tz_acceptable(new_tz))
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;
359 /* Test for failure in pg_tzset_offset, which we assume is out-of-range */
360 if (!new_tz)
362 GUC_check_errdetail("UTC timezone offset is out of range.");
363 return false;
367 * Pass back data for assign_timezone to use
369 *extra = guc_malloc(LOG, sizeof(pg_tz *));
370 if (!*extra)
371 return false;
372 *((pg_tz **) *extra) = new_tz;
374 return true;
378 * assign_timezone: GUC assign_hook for timezone
380 void
381 assign_timezone(const char *newval, void *extra)
383 session_timezone = *((pg_tz **) extra);
387 * show_timezone: GUC show_hook for timezone
389 const char *
390 show_timezone(void)
392 const char *tzn;
394 /* Always show the zone's canonical name */
395 tzn = pg_get_timezone_name(session_timezone);
397 if (tzn != NULL)
398 return tzn;
400 return "unknown";
405 * LOG_TIMEZONE
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.
413 * check_log_timezone: GUC check_hook for log_timezone
415 bool
416 check_log_timezone(char **newval, void **extra, GucSource source)
418 pg_tz *new_tz;
421 * Assume it is a timezone name, and try to load it.
423 new_tz = pg_tzset(*newval);
425 if (!new_tz)
427 /* Doesn't seem to be any great value in errdetail here */
428 return false;
431 if (!pg_tz_acceptable(new_tz))
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;
440 * Pass back data for assign_log_timezone to use
442 *extra = guc_malloc(LOG, sizeof(pg_tz *));
443 if (!*extra)
444 return false;
445 *((pg_tz **) *extra) = new_tz;
447 return true;
451 * assign_log_timezone: GUC assign_hook for log_timezone
453 void
454 assign_log_timezone(const char *newval, void *extra)
456 log_timezone = *((pg_tz **) extra);
460 * show_log_timezone: GUC show_hook for log_timezone
462 const char *
463 show_log_timezone(void)
465 const char *tzn;
467 /* Always show the zone's canonical name */
468 tzn = pg_get_timezone_name(log_timezone);
470 if (tzn != NULL)
471 return tzn;
473 return "unknown";
478 * TIMEZONE_ABBREVIATIONS
482 * GUC check_hook for timezone_abbreviations
484 bool
485 check_timezone_abbreviations(char **newval, void **extra, GucSource source)
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.
497 if (*newval == NULL)
499 Assert(source == PGC_S_DEFAULT);
500 return true;
503 /* OK, load the file and produce a guc_malloc'd TimeZoneAbbrevTable */
504 *extra = load_tzoffsets(*newval);
506 /* tzparser.c returns NULL on failure, reporting via GUC_check_errmsg */
507 if (!*extra)
508 return false;
510 return true;
514 * GUC assign_hook for timezone_abbreviations
516 void
517 assign_timezone_abbreviations(const char *newval, void *extra)
519 /* Do nothing for the boot_val default of NULL */
520 if (!extra)
521 return;
523 InstallTimeZoneAbbrevs((TimeZoneAbbrevTable *) extra);
528 * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
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.
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.)
543 bool
544 check_transaction_read_only(bool *newval, void **extra, GucSource source)
546 if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
548 /* Can't go to r/w mode inside a r/o transaction */
549 if (IsSubTransaction())
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;
555 /* Top level transaction can't change to r/w after first snapshot. */
556 if (FirstSnapshotSet)
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;
562 /* Can't go to r/w mode while recovery is still active */
563 if (RecoveryInProgress())
565 GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
566 GUC_check_errmsg("cannot set transaction read-write mode during recovery");
567 return false;
571 return true;
575 * SET TRANSACTION ISOLATION LEVEL
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.
580 * As in check_transaction_read_only, allow it if not inside a transaction,
581 * or if restoring state in a parallel worker.
583 bool
584 check_transaction_isolation(int *newval, void **extra, GucSource source)
586 int newXactIsoLevel = *newval;
588 if (newXactIsoLevel != XactIsoLevel &&
589 IsTransactionState() && !InitializingParallelWorker)
591 if (FirstSnapshotSet)
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;
597 /* We ignore a subtransaction setting it to the existing value. */
598 if (IsSubTransaction())
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;
604 /* Can't go to serializable mode while recovery is still active */
605 if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
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;
614 return true;
618 * SET TRANSACTION [NOT] DEFERRABLE
621 bool
622 check_transaction_deferrable(bool *newval, void **extra, GucSource source)
624 /* Just accept the value when restoring state in a parallel worker */
625 if (InitializingParallelWorker)
626 return true;
628 if (IsSubTransaction())
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;
634 if (FirstSnapshotSet)
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;
641 return true;
645 * Random number seed
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.
653 bool
654 check_random_seed(double *newval, void **extra, GucSource source)
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);
662 return true;
665 void
666 assign_random_seed(double newval, void *extra)
668 /* We'll do this at most once for any setting of the GUC variable */
669 if (*((int *) extra))
670 DirectFunctionCall1(setseed, Float8GetDatum(newval));
671 *((int *) extra) = 0;
674 const char *
675 show_random_seed(void)
677 return "unavailable";
682 * SET CLIENT_ENCODING
685 bool
686 check_client_encoding(char **newval, void **extra, GucSource source)
688 int encoding;
689 const char *canonical_name;
691 /* Look up the encoding by name */
692 encoding = pg_valid_client_encoding(*newval);
693 if (encoding < 0)
694 return false;
696 /* Get the canonical name (no aliases, uniform case) */
697 canonical_name = pg_encoding_to_char(encoding);
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.
710 if (IsParallelWorker() && !InitializingParallelWorker)
712 GUC_check_errcode(ERRCODE_INVALID_TRANSACTION_STATE);
713 GUC_check_errdetail("Cannot change \"client_encoding\" during a parallel operation.");
714 return false;
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.
727 * In a parallel worker, we might as well skip PrepareClientEncoding since
728 * we're not going to use its results.
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.
734 if (!IsParallelWorker() &&
735 PrepareClientEncoding(encoding) < 0)
737 if (IsTransactionState())
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,
743 GetDatabaseEncodingName());
745 else
747 /* Provide a useful complaint */
748 GUC_check_errdetail("Cannot change \"client_encoding\" now.");
750 return false;
754 * Replace the user-supplied string with the encoding's canonical name.
755 * This gets rid of aliases and case-folding variations.
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.
763 if (strcmp(*newval, canonical_name) != 0 &&
764 strcmp(*newval, "UNICODE") != 0)
766 guc_free(*newval);
767 *newval = guc_strdup(LOG, canonical_name);
768 if (!*newval)
769 return false;
773 * Save the encoding's ID in *extra, for use by assign_client_encoding.
775 *extra = guc_malloc(LOG, sizeof(int));
776 if (!*extra)
777 return false;
778 *((int *) *extra) = encoding;
780 return true;
783 void
784 assign_client_encoding(const char *newval, void *extra)
786 int encoding = *((int *) extra);
789 * In a parallel worker, we never override the client encoding that was
790 * set by ParallelWorkerMain().
792 if (IsParallelWorker())
793 return;
795 /* We do not expect an error if PrepareClientEncoding succeeded */
796 if (SetClientEncoding(encoding) < 0)
797 elog(LOG, "SetClientEncoding(%d) failed", encoding);
802 * SET SESSION AUTHORIZATION
805 typedef struct
807 /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
808 Oid roleid;
809 bool is_superuser;
810 } role_auth_extra;
812 bool
813 check_session_authorization(char **newval, void **extra, GucSource source)
815 HeapTuple roleTup;
816 Form_pg_authid roleform;
817 Oid roleid;
818 bool is_superuser;
819 role_auth_extra *myextra;
821 /* Do nothing for the boot_val default of NULL */
822 if (*newval == NULL)
823 return true;
825 if (InitializingParallelWorker)
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.
832 roleid = GetSessionUserId();
833 is_superuser = GetSessionUserIsSuperuser();
835 else
837 if (!IsTransactionState())
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.
845 return false;
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.
854 /* Look up the username */
855 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
856 if (!HeapTupleIsValid(roleTup))
858 if (source == PGC_S_TEST)
860 ereport(NOTICE,
861 (errcode(ERRCODE_UNDEFINED_OBJECT),
862 errmsg("role \"%s\" does not exist", *newval)));
863 return true;
865 GUC_check_errmsg("role \"%s\" does not exist", *newval);
866 return false;
869 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
870 roleid = roleform->oid;
871 is_superuser = roleform->rolsuper;
873 ReleaseSysCache(roleTup);
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.
880 if (roleid != GetAuthenticatedUserId() &&
881 !superuser_arg(GetAuthenticatedUserId()))
883 if (source == PGC_S_TEST)
885 ereport(NOTICE,
886 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
887 errmsg("permission will be denied to set session authorization \"%s\"",
888 *newval)));
889 return true;
891 GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
892 GUC_check_errmsg("permission denied to set session authorization \"%s\"",
893 *newval);
894 return false;
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;
906 return true;
909 void
910 assign_session_authorization(const char *newval, void *extra)
912 role_auth_extra *myextra = (role_auth_extra *) extra;
914 /* Do nothing for the boot_val default of NULL */
915 if (!myextra)
916 return;
918 SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
923 * SET ROLE
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.
930 bool
931 check_role(char **newval, void **extra, GucSource source)
933 HeapTuple roleTup;
934 Oid roleid;
935 bool is_superuser;
936 role_auth_extra *myextra;
937 Form_pg_authid roleform;
939 if (strcmp(*newval, "none") == 0)
941 /* hardwired translation */
942 roleid = InvalidOid;
943 is_superuser = false;
945 else if (InitializingParallelWorker)
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.
952 roleid = GetCurrentRoleId();
953 is_superuser = current_role_is_superuser;
955 else
957 if (!IsTransactionState())
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.
964 return false;
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.
973 /* Look up the username */
974 roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
975 if (!HeapTupleIsValid(roleTup))
977 if (source == PGC_S_TEST)
979 ereport(NOTICE,
980 (errcode(ERRCODE_UNDEFINED_OBJECT),
981 errmsg("role \"%s\" does not exist", *newval)));
982 return true;
984 GUC_check_errmsg("role \"%s\" does not exist", *newval);
985 return false;
988 roleform = (Form_pg_authid) GETSTRUCT(roleTup);
989 roleid = roleform->oid;
990 is_superuser = roleform->rolsuper;
992 ReleaseSysCache(roleTup);
994 /* Verify that session user is allowed to become this role */
995 if (!member_can_set_role(GetSessionUserId(), roleid))
997 if (source == PGC_S_TEST)
999 ereport(NOTICE,
1000 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1001 errmsg("permission will be denied to set role \"%s\"",
1002 *newval)));
1003 return true;
1005 GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
1006 GUC_check_errmsg("permission denied to set role \"%s\"",
1007 *newval);
1008 return false;
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;
1020 return true;
1023 void
1024 assign_role(const char *newval, void *extra)
1026 role_auth_extra *myextra = (role_auth_extra *) extra;
1028 SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
1031 const char *
1032 show_role(void)
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).
1041 if (!OidIsValid(GetCurrentRoleId()))
1042 return "none";
1044 /* Otherwise we can just use the GUC string */
1045 return role_string ? role_string : "none";
1050 * PATH VARIABLES
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.
1056 bool
1057 check_canonical_path(char **newval, void **extra, GucSource source)
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.
1064 if (*newval)
1065 canonicalize_path(*newval);
1066 return true;
1071 * MISCELLANEOUS
1075 * GUC check_hook for application_name
1077 bool
1078 check_application_name(char **newval, void **extra, GucSource source)
1080 char *clean;
1081 char *ret;
1083 /* Only allow clean ASCII chars in the application name */
1084 clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1085 if (!clean)
1086 return false;
1088 ret = guc_strdup(WARNING, clean);
1089 if (!ret)
1091 pfree(clean);
1092 return false;
1095 guc_free(*newval);
1097 pfree(clean);
1098 *newval = ret;
1099 return true;
1103 * GUC assign_hook for application_name
1105 void
1106 assign_application_name(const char *newval, void *extra)
1108 /* Update the pg_stat_activity view */
1109 pgstat_report_appname(newval);
1113 * GUC check_hook for cluster_name
1115 bool
1116 check_cluster_name(char **newval, void **extra, GucSource source)
1118 char *clean;
1119 char *ret;
1121 /* Only allow clean ASCII chars in the cluster name */
1122 clean = pg_clean_ascii(*newval, MCXT_ALLOC_NO_OOM);
1123 if (!clean)
1124 return false;
1126 ret = guc_strdup(WARNING, clean);
1127 if (!ret)
1129 pfree(clean);
1130 return false;
1133 guc_free(*newval);
1135 pfree(clean);
1136 *newval = ret;
1137 return true;
1141 * GUC assign_hook for maintenance_io_concurrency
1143 void
1144 assign_maintenance_io_concurrency(int newval, void *extra)
1146 #ifdef USE_PREFETCH
1148 * Reconfigure recovery prefetching, because a setting it depends on
1149 * changed.
1151 maintenance_io_concurrency = newval;
1152 if (AmStartupProcess())
1153 XLogPrefetchReconfigure();
1154 #endif
1159 * These show hooks just exist because we want to show the values in octal.
1163 * GUC show_hook for data_directory_mode
1165 const char *
1166 show_data_directory_mode(void)
1168 static char buf[12];
1170 snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1171 return buf;
1175 * GUC show_hook for log_file_mode
1177 const char *
1178 show_log_file_mode(void)
1180 static char buf[12];
1182 snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1183 return buf;
1187 * GUC show_hook for unix_socket_permissions
1189 const char *
1190 show_unix_socket_permissions(void)
1192 static char buf[12];
1194 snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1195 return buf;
1200 * These check hooks do nothing more than reject non-default settings
1201 * in builds that don't support them.
1204 bool
1205 check_bonjour(bool *newval, void **extra, GucSource source)
1207 #ifndef USE_BONJOUR
1208 if (*newval)
1210 GUC_check_errmsg("Bonjour is not supported by this build");
1211 return false;
1213 #endif
1214 return true;
1217 bool
1218 check_default_with_oids(bool *newval, void **extra, GucSource source)
1220 if (*newval)
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");
1226 return false;
1229 return true;
1232 bool
1233 check_effective_io_concurrency(int *newval, void **extra, GucSource source)
1235 #ifndef USE_PREFETCH
1236 if (*newval != 0)
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;
1242 #endif /* USE_PREFETCH */
1243 return true;
1246 bool
1247 check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
1249 #ifndef USE_PREFETCH
1250 if (*newval != 0)
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;
1256 #endif /* USE_PREFETCH */
1257 return true;
1260 bool
1261 check_ssl(bool *newval, void **extra, GucSource source)
1263 #ifndef USE_SSL
1264 if (*newval)
1266 GUC_check_errmsg("SSL is not supported by this build");
1267 return false;
1269 #endif
1270 return true;