PostgreSQL Source Code  git master
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"
25 #include "access/xlogprefetcher.h"
26 #include "catalog/pg_authid.h"
27 #include "common/string.h"
28 #include "mb/pg_wchar.h"
29 #include "miscadmin.h"
30 #include "postmaster/postmaster.h"
31 #include "postmaster/syslogger.h"
32 #include "storage/bufmgr.h"
33 #include "utils/acl.h"
34 #include "utils/backend_status.h"
35 #include "utils/datetime.h"
36 #include "utils/fmgrprotos.h"
37 #include "utils/guc_hooks.h"
38 #include "utils/snapmgr.h"
39 #include "utils/syscache.h"
40 #include "utils/timestamp.h"
41 #include "utils/tzparser.h"
42 #include "utils/varlena.h"
43 
44 /*
45  * DATESTYLE
46  */
47 
48 /*
49  * check_datestyle: GUC check_hook for datestyle
50  */
51 bool
52 check_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 
224  guc_free(*newval);
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 = (void *) myextra;
236 
237  return true;
238 }
239 
240 /*
241  * assign_datestyle: GUC assign_hook for datestyle
242  */
243 void
244 assign_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  */
260 bool
261 check_timezone(char **newval, void **extra, GucSource source)
262 {
263  pg_tz *new_tz;
264  long gmtoffset;
265  char *endptr;
266  double hours;
267 
268  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.");
308  pfree(interval);
309  return false;
310  }
311  if (interval->day != 0)
312  {
313  GUC_check_errdetail("Cannot specify days in time zone interval.");
314  pfree(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 
322  pfree(interval);
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  */
380 void
381 assign_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  */
389 const 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  */
415 bool
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  */
453 void
454 assign_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  */
462 const 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 assign_timezone_abbreviations
483  */
484 bool
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 assign_timezone_abbreviations
515  */
516 void
517 assign_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  */
543 bool
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. */
556  if (FirstSnapshotSet)
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  */
583 bool
585 {
586  int newXactIsoLevel = *newval;
587 
588  if (newXactIsoLevel != XactIsoLevel &&
590  {
591  if (FirstSnapshotSet)
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 
621 bool
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  }
634  if (FirstSnapshotSet)
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 
653 bool
654 check_random_seed(double *newval, void **extra, GucSource source)
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 
665 void
666 assign_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 
674 const char *
676 {
677  return "unavailable";
678 }
679 
680 
681 /*
682  * SET CLIENT_ENCODING
683  */
684 
685 bool
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  {
766  guc_free(*newval);
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 
783 void
784 assign_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 */
796  if (SetClientEncoding(encoding) < 0)
797  elog(LOG, "SetClientEncoding(%d) failed", encoding);
798 }
799 
800 
801 /*
802  * SET SESSION AUTHORIZATION
803  */
804 
805 typedef struct
806 {
807  /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
811 
812 bool
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 
825  if (!IsTransactionState())
826  {
827  /*
828  * Can't do catalog lookups, so fail. The result of this is that
829  * session_authorization cannot be set in postgresql.conf, which seems
830  * like a good thing anyway, so we don't work hard to avoid it.
831  */
832  return false;
833  }
834 
835  /*
836  * When source == PGC_S_TEST, we don't throw a hard error for a
837  * nonexistent user name or insufficient privileges, only a NOTICE. See
838  * comments in guc.h.
839  */
840 
841  /* Look up the username */
842  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
843  if (!HeapTupleIsValid(roleTup))
844  {
845  if (source == PGC_S_TEST)
846  {
847  ereport(NOTICE,
848  (errcode(ERRCODE_UNDEFINED_OBJECT),
849  errmsg("role \"%s\" does not exist", *newval)));
850  return true;
851  }
852  GUC_check_errmsg("role \"%s\" does not exist", *newval);
853  return false;
854  }
855 
856  roleform = (Form_pg_authid) GETSTRUCT(roleTup);
857  roleid = roleform->oid;
858  is_superuser = roleform->rolsuper;
859 
860  ReleaseSysCache(roleTup);
861 
862  /*
863  * Only superusers may SET SESSION AUTHORIZATION a role other than itself.
864  * Note that in case of multiple SETs in a single session, the original
865  * authenticated user's superuserness is what matters.
866  */
867  if (roleid != GetAuthenticatedUserId() &&
869  {
870  if (source == PGC_S_TEST)
871  {
872  ereport(NOTICE,
873  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
874  errmsg("permission will be denied to set session authorization \"%s\"",
875  *newval)));
876  return true;
877  }
878  GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
879  GUC_check_errmsg("permission denied to set session authorization \"%s\"",
880  *newval);
881  return false;
882  }
883 
884  /* Set up "extra" struct for assign_session_authorization to use */
885  myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
886  if (!myextra)
887  return false;
888  myextra->roleid = roleid;
889  myextra->is_superuser = is_superuser;
890  *extra = (void *) myextra;
891 
892  return true;
893 }
894 
895 void
896 assign_session_authorization(const char *newval, void *extra)
897 {
898  role_auth_extra *myextra = (role_auth_extra *) extra;
899 
900  /* Do nothing for the boot_val default of NULL */
901  if (!myextra)
902  return;
903 
904  SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
905 }
906 
907 
908 /*
909  * SET ROLE
910  *
911  * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
912  * a translation of "none" to InvalidOid. Otherwise this is much like
913  * SET SESSION AUTHORIZATION.
914  */
915 
916 bool
917 check_role(char **newval, void **extra, GucSource source)
918 {
919  HeapTuple roleTup;
920  Oid roleid;
921  bool is_superuser;
922  role_auth_extra *myextra;
923  Form_pg_authid roleform;
924 
925  if (strcmp(*newval, "none") == 0)
926  {
927  /* hardwired translation */
928  roleid = InvalidOid;
929  is_superuser = false;
930  }
931  else
932  {
933  if (!IsTransactionState())
934  {
935  /*
936  * Can't do catalog lookups, so fail. The result of this is that
937  * role cannot be set in postgresql.conf, which seems like a good
938  * thing anyway, so we don't work hard to avoid it.
939  */
940  return false;
941  }
942 
943  /*
944  * When source == PGC_S_TEST, we don't throw a hard error for a
945  * nonexistent user name or insufficient privileges, only a NOTICE.
946  * See comments in guc.h.
947  */
948 
949  /* Look up the username */
950  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
951  if (!HeapTupleIsValid(roleTup))
952  {
953  if (source == PGC_S_TEST)
954  {
955  ereport(NOTICE,
956  (errcode(ERRCODE_UNDEFINED_OBJECT),
957  errmsg("role \"%s\" does not exist", *newval)));
958  return true;
959  }
960  GUC_check_errmsg("role \"%s\" does not exist", *newval);
961  return false;
962  }
963 
964  roleform = (Form_pg_authid) GETSTRUCT(roleTup);
965  roleid = roleform->oid;
966  is_superuser = roleform->rolsuper;
967 
968  ReleaseSysCache(roleTup);
969 
970  /*
971  * Verify that session user is allowed to become this role, but skip
972  * this in parallel mode, where we must blindly recreate the parallel
973  * leader's state.
974  */
977  {
978  if (source == PGC_S_TEST)
979  {
980  ereport(NOTICE,
981  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
982  errmsg("permission will be denied to set role \"%s\"",
983  *newval)));
984  return true;
985  }
986  GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
987  GUC_check_errmsg("permission denied to set role \"%s\"",
988  *newval);
989  return false;
990  }
991  }
992 
993  /* Set up "extra" struct for assign_role to use */
994  myextra = (role_auth_extra *) guc_malloc(LOG, sizeof(role_auth_extra));
995  if (!myextra)
996  return false;
997  myextra->roleid = roleid;
998  myextra->is_superuser = is_superuser;
999  *extra = (void *) myextra;
1000 
1001  return true;
1002 }
1003 
1004 void
1005 assign_role(const char *newval, void *extra)
1006 {
1007  role_auth_extra *myextra = (role_auth_extra *) extra;
1008 
1009  SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
1010 }
1011 
1012 const char *
1014 {
1015  /*
1016  * Check whether SET ROLE is active; if not return "none". This is a
1017  * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
1018  * resets SET ROLE to NONE, but we cannot set the GUC role variable from
1019  * assign_session_authorization (because we haven't got enough info to
1020  * call set_config_option).
1021  */
1022  if (!OidIsValid(GetCurrentRoleId()))
1023  return "none";
1024 
1025  /* Otherwise we can just use the GUC string */
1026  return role_string ? role_string : "none";
1027 }
1028 
1029 
1030 /*
1031  * PATH VARIABLES
1032  *
1033  * check_canonical_path is used for log_directory and some other GUCs where
1034  * all we want to do is canonicalize the represented path name.
1035  */
1036 
1037 bool
1039 {
1040  /*
1041  * Since canonicalize_path never enlarges the string, we can just modify
1042  * newval in-place. But watch out for NULL, which is the default value
1043  * for external_pid_file.
1044  */
1045  if (*newval)
1047  return true;
1048 }
1049 
1050 
1051 /*
1052  * MISCELLANEOUS
1053  */
1054 
1055 /*
1056  * GUC check_hook for application_name
1057  */
1058 bool
1060 {
1061  char *clean;
1062  char *ret;
1063 
1064  /* Only allow clean ASCII chars in the application name */
1066  if (!clean)
1067  return false;
1068 
1069  ret = guc_strdup(WARNING, clean);
1070  if (!ret)
1071  {
1072  pfree(clean);
1073  return false;
1074  }
1075 
1076  pfree(clean);
1077  *newval = ret;
1078  return true;
1079 }
1080 
1081 /*
1082  * GUC assign_hook for application_name
1083  */
1084 void
1085 assign_application_name(const char *newval, void *extra)
1086 {
1087  /* Update the pg_stat_activity view */
1089 }
1090 
1091 /*
1092  * GUC check_hook for cluster_name
1093  */
1094 bool
1096 {
1097  char *clean;
1098  char *ret;
1099 
1100  /* Only allow clean ASCII chars in the cluster name */
1102  if (!clean)
1103  return false;
1104 
1105  ret = guc_strdup(WARNING, clean);
1106  if (!ret)
1107  {
1108  pfree(clean);
1109  return false;
1110  }
1111 
1112  pfree(clean);
1113  *newval = ret;
1114  return true;
1115 }
1116 
1117 /*
1118  * GUC assign_hook for maintenance_io_concurrency
1119  */
1120 void
1122 {
1123 #ifdef USE_PREFETCH
1124  /*
1125  * Reconfigure recovery prefetching, because a setting it depends on
1126  * changed.
1127  */
1129  if (AmStartupProcess())
1131 #endif
1132 }
1133 
1134 
1135 /*
1136  * These show hooks just exist because we want to show the values in octal.
1137  */
1138 
1139 /*
1140  * GUC show_hook for data_directory_mode
1141  */
1142 const char *
1144 {
1145  static char buf[12];
1146 
1147  snprintf(buf, sizeof(buf), "%04o", data_directory_mode);
1148  return buf;
1149 }
1150 
1151 /*
1152  * GUC show_hook for log_file_mode
1153  */
1154 const char *
1156 {
1157  static char buf[12];
1158 
1159  snprintf(buf, sizeof(buf), "%04o", Log_file_mode);
1160  return buf;
1161 }
1162 
1163 /*
1164  * GUC show_hook for unix_socket_permissions
1165  */
1166 const char *
1168 {
1169  static char buf[12];
1170 
1171  snprintf(buf, sizeof(buf), "%04o", Unix_socket_permissions);
1172  return buf;
1173 }
1174 
1175 
1176 /*
1177  * These check hooks do nothing more than reject non-default settings
1178  * in builds that don't support them.
1179  */
1180 
1181 bool
1182 check_bonjour(bool *newval, void **extra, GucSource source)
1183 {
1184 #ifndef USE_BONJOUR
1185  if (*newval)
1186  {
1187  GUC_check_errmsg("Bonjour is not supported by this build");
1188  return false;
1189  }
1190 #endif
1191  return true;
1192 }
1193 
1194 bool
1196 {
1197  if (*newval)
1198  {
1199  /* check the GUC's definition for an explanation */
1200  GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
1201  GUC_check_errmsg("tables declared WITH OIDS are not supported");
1202 
1203  return false;
1204  }
1205 
1206  return true;
1207 }
1208 
1209 bool
1211 {
1212 #ifndef USE_PREFETCH
1213  if (*newval != 0)
1214  {
1215  GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1216  "effective_io_concurrency");
1217  return false;
1218  }
1219 #endif /* USE_PREFETCH */
1220  return true;
1221 }
1222 
1223 bool
1225 {
1226 #ifndef USE_PREFETCH
1227  if (*newval != 0)
1228  {
1229  GUC_check_errdetail("\"%s\" must be set to 0 on platforms that lack support for issuing read-ahead advice.",
1230  "maintenance_io_concurrency");
1231  return false;
1232  }
1233 #endif /* USE_PREFETCH */
1234  return true;
1235 }
1236 
1237 bool
1238 check_ssl(bool *newval, void **extra, GucSource source)
1239 {
1240 #ifndef USE_SSL
1241  if (*newval)
1242  {
1243  GUC_check_errmsg("SSL is not supported by this build");
1244  return false;
1245  }
1246 #endif
1247  return true;
1248 }
bool member_can_set_role(Oid member, Oid role)
Definition: acl.c:5302
bool InitializingParallelWorker
Definition: parallel.c:118
const char * show_unix_socket_permissions(void)
Definition: variable.c:1167
void assign_application_name(const char *newval, void *extra)
Definition: variable.c:1085
bool check_bonjour(bool *newval, void **extra, GucSource source)
Definition: variable.c:1182
bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source)
Definition: variable.c:1224
void assign_session_authorization(const char *newval, void *extra)
Definition: variable.c:896
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:1038
const char * show_timezone(void)
Definition: variable.c:390
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:1195
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:1210
bool check_application_name(char **newval, void **extra, GucSource source)
Definition: variable.c:1059
void assign_timezone(const char *newval, void *extra)
Definition: variable.c:381
bool check_role(char **newval, void **extra, GucSource source)
Definition: variable.c:917
bool check_cluster_name(char **newval, void **extra, GucSource source)
Definition: variable.c:1095
const char * show_log_timezone(void)
Definition: variable.c:463
bool check_session_authorization(char **newval, void **extra, GucSource source)
Definition: variable.c:813
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:1121
bool check_timezone_abbreviations(char **newval, void **extra, GucSource source)
Definition: variable.c:485
void assign_client_encoding(const char *newval, void *extra)
Definition: variable.c:784
void assign_role(const char *newval, void *extra)
Definition: variable.c:1005
bool check_timezone(char **newval, void **extra, GucSource source)
Definition: variable.c:261
const char * show_random_seed(void)
Definition: variable.c:675
bool check_ssl(bool *newval, void **extra, GucSource source)
Definition: variable.c:1238
void assign_datestyle(const char *newval, void *extra)
Definition: variable.c:244
void assign_random_seed(double newval, void *extra)
Definition: variable.c:666
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_role(void)
Definition: variable.c:1013
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_log_file_mode(void)
Definition: variable.c:1155
const char * show_data_directory_mode(void)
Definition: variable.c:1143
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:861
#define OidIsValid(objectId)
Definition: c.h:778
#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:17
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:6750
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:637
void guc_free(void *ptr)
Definition: guc.c:688
#define newval
const char * GetConfigOptionResetString(const char *name)
Definition: guc.c:4364
char * guc_strdup(int elevel, const char *src)
Definition: guc.c:676
#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
#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
int SetClientEncoding(int encoding)
Definition: mbutils.c:208
int PrepareClientEncoding(int encoding)
Definition: mbutils.c:110
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1267
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
#define AmStartupProcess()
Definition: miscadmin.h:379
#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:908
Oid GetSessionUserId(void)
Definition: miscinit.c:548
void SetCurrentRoleId(Oid roleid, bool is_superuser)
Definition: miscinit.c:945
Oid GetAuthenticatedUserId(void)
Definition: miscinit.c:583
Oid GetCurrentRoleId(void)
Definition: miscinit.c:924
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:4789
#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:73
#define pg_encoding_to_char
Definition: pg_wchar.h:630
bool pg_tz_acceptable(pg_tz *tz)
Definition: localtime.c:1890
pg_tz * pg_tzset_offset(long gmtoffset)
Definition: pgtz.c:320
const char * pg_get_timezone_name(pg_tz *tz)
Definition: localtime.c:1875
PGDLLIMPORT pg_tz * session_timezone
Definition: pgtz.c:28
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:234
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:135
char * pg_clean_ascii(const char *str, int alloc_flags)
Definition: string.c:86
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:5037
#define XACT_SERIALIZABLE
Definition: xact.h:39
bool RecoveryInProgress(void)
Definition: xlog.c:6333
void XLogPrefetchReconfigure(void)