PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2016, 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 "catalog/pg_authid.h"
26 #include "commands/variable.h"
27 #include "miscadmin.h"
28 #include "utils/acl.h"
29 #include "utils/builtins.h"
30 #include "utils/syscache.h"
31 #include "utils/snapmgr.h"
32 #include "utils/timestamp.h"
33 #include "mb/pg_wchar.h"
34 
35 /*
36  * DATESTYLE
37  */
38 
39 /*
40  * check_datestyle: GUC check_hook for datestyle
41  */
42 bool
43 check_datestyle(char **newval, void **extra, GucSource source)
44 {
45  int newDateStyle = DateStyle;
46  int newDateOrder = DateOrder;
47  bool have_style = false;
48  bool have_order = false;
49  bool ok = true;
50  char *rawstring;
51  int *myextra;
52  char *result;
53  List *elemlist;
54  ListCell *l;
55 
56  /* Need a modifiable copy of string */
57  rawstring = pstrdup(*newval);
58 
59  /* Parse string into list of identifiers */
60  if (!SplitIdentifierString(rawstring, ',', &elemlist))
61  {
62  /* syntax error in list */
63  GUC_check_errdetail("List syntax is invalid.");
64  pfree(rawstring);
65  list_free(elemlist);
66  return false;
67  }
68 
69  foreach(l, elemlist)
70  {
71  char *tok = (char *) lfirst(l);
72 
73  /* Ugh. Somebody ought to write a table driven version -- mjl */
74 
75  if (pg_strcasecmp(tok, "ISO") == 0)
76  {
77  if (have_style && newDateStyle != USE_ISO_DATES)
78  ok = false; /* conflicting styles */
79  newDateStyle = USE_ISO_DATES;
80  have_style = true;
81  }
82  else if (pg_strcasecmp(tok, "SQL") == 0)
83  {
84  if (have_style && newDateStyle != USE_SQL_DATES)
85  ok = false; /* conflicting styles */
86  newDateStyle = USE_SQL_DATES;
87  have_style = true;
88  }
89  else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
90  {
91  if (have_style && newDateStyle != USE_POSTGRES_DATES)
92  ok = false; /* conflicting styles */
93  newDateStyle = USE_POSTGRES_DATES;
94  have_style = true;
95  }
96  else if (pg_strcasecmp(tok, "GERMAN") == 0)
97  {
98  if (have_style && newDateStyle != USE_GERMAN_DATES)
99  ok = false; /* conflicting styles */
100  newDateStyle = USE_GERMAN_DATES;
101  have_style = true;
102  /* GERMAN also sets DMY, unless explicitly overridden */
103  if (!have_order)
104  newDateOrder = DATEORDER_DMY;
105  }
106  else if (pg_strcasecmp(tok, "YMD") == 0)
107  {
108  if (have_order && newDateOrder != DATEORDER_YMD)
109  ok = false; /* conflicting orders */
110  newDateOrder = DATEORDER_YMD;
111  have_order = true;
112  }
113  else if (pg_strcasecmp(tok, "DMY") == 0 ||
114  pg_strncasecmp(tok, "EURO", 4) == 0)
115  {
116  if (have_order && newDateOrder != DATEORDER_DMY)
117  ok = false; /* conflicting orders */
118  newDateOrder = DATEORDER_DMY;
119  have_order = true;
120  }
121  else if (pg_strcasecmp(tok, "MDY") == 0 ||
122  pg_strcasecmp(tok, "US") == 0 ||
123  pg_strncasecmp(tok, "NONEURO", 7) == 0)
124  {
125  if (have_order && newDateOrder != DATEORDER_MDY)
126  ok = false; /* conflicting orders */
127  newDateOrder = DATEORDER_MDY;
128  have_order = true;
129  }
130  else if (pg_strcasecmp(tok, "DEFAULT") == 0)
131  {
132  /*
133  * Easiest way to get the current DEFAULT state is to fetch the
134  * DEFAULT string from guc.c and recursively parse it.
135  *
136  * We can't simply "return check_datestyle(...)" because we need
137  * to handle constructs like "DEFAULT, ISO".
138  */
139  char *subval;
140  void *subextra = NULL;
141 
142  subval = strdup(GetConfigOptionResetString("datestyle"));
143  if (!subval)
144  {
145  ok = false;
146  break;
147  }
148  if (!check_datestyle(&subval, &subextra, source))
149  {
150  free(subval);
151  ok = false;
152  break;
153  }
154  myextra = (int *) subextra;
155  if (!have_style)
156  newDateStyle = myextra[0];
157  if (!have_order)
158  newDateOrder = myextra[1];
159  free(subval);
160  free(subextra);
161  }
162  else
163  {
164  GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
165  pfree(rawstring);
166  list_free(elemlist);
167  return false;
168  }
169  }
170 
171  pfree(rawstring);
172  list_free(elemlist);
173 
174  if (!ok)
175  {
176  GUC_check_errdetail("Conflicting \"datestyle\" specifications.");
177  return false;
178  }
179 
180  /*
181  * Prepare the canonical string to return. GUC wants it malloc'd.
182  */
183  result = (char *) malloc(32);
184  if (!result)
185  return false;
186 
187  switch (newDateStyle)
188  {
189  case USE_ISO_DATES:
190  strcpy(result, "ISO");
191  break;
192  case USE_SQL_DATES:
193  strcpy(result, "SQL");
194  break;
195  case USE_GERMAN_DATES:
196  strcpy(result, "German");
197  break;
198  default:
199  strcpy(result, "Postgres");
200  break;
201  }
202  switch (newDateOrder)
203  {
204  case DATEORDER_YMD:
205  strcat(result, ", YMD");
206  break;
207  case DATEORDER_DMY:
208  strcat(result, ", DMY");
209  break;
210  default:
211  strcat(result, ", MDY");
212  break;
213  }
214 
215  free(*newval);
216  *newval = result;
217 
218  /*
219  * Set up the "extra" struct actually used by assign_datestyle.
220  */
221  myextra = (int *) malloc(2 * sizeof(int));
222  if (!myextra)
223  return false;
224  myextra[0] = newDateStyle;
225  myextra[1] = newDateOrder;
226  *extra = (void *) myextra;
227 
228  return true;
229 }
230 
231 /*
232  * assign_datestyle: GUC assign_hook for datestyle
233  */
234 void
235 assign_datestyle(const char *newval, void *extra)
236 {
237  int *myextra = (int *) extra;
238 
239  DateStyle = myextra[0];
240  DateOrder = myextra[1];
241 }
242 
243 
244 /*
245  * TIMEZONE
246  */
247 
248 /*
249  * check_timezone: GUC check_hook for timezone
250  */
251 bool
252 check_timezone(char **newval, void **extra, GucSource source)
253 {
254  pg_tz *new_tz;
255  long gmtoffset;
256  char *endptr;
257  double hours;
258 
259  if (pg_strncasecmp(*newval, "interval", 8) == 0)
260  {
261  /*
262  * Support INTERVAL 'foo'. This is for SQL spec compliance, not
263  * because it has any actual real-world usefulness.
264  */
265  const char *valueptr = *newval;
266  char *val;
268 
269  valueptr += 8;
270  while (isspace((unsigned char) *valueptr))
271  valueptr++;
272  if (*valueptr++ != '\'')
273  return false;
274  val = pstrdup(valueptr);
275  /* Check and remove trailing quote */
276  endptr = strchr(val, '\'');
277  if (!endptr || endptr[1] != '\0')
278  {
279  pfree(val);
280  return false;
281  }
282  *endptr = '\0';
283 
284  /*
285  * Try to parse it. XXX an invalid interval format will result in
286  * ereport(ERROR), which is not desirable for GUC. We did what we
287  * could to guard against this in flatten_set_variable_args, but a
288  * string coming in from postgresql.conf might contain anything.
289  */
291  CStringGetDatum(val),
293  Int32GetDatum(-1)));
294 
295  pfree(val);
296  if (interval->month != 0)
297  {
298  GUC_check_errdetail("Cannot specify months in time zone interval.");
299  pfree(interval);
300  return false;
301  }
302  if (interval->day != 0)
303  {
304  GUC_check_errdetail("Cannot specify days in time zone interval.");
305  pfree(interval);
306  return false;
307  }
308 
309  /* Here we change from SQL to Unix sign convention */
310 #ifdef HAVE_INT64_TIMESTAMP
311  gmtoffset = -(interval->time / USECS_PER_SEC);
312 #else
313  gmtoffset = -interval->time;
314 #endif
315  new_tz = pg_tzset_offset(gmtoffset);
316 
317  pfree(interval);
318  }
319  else
320  {
321  /*
322  * Try it as a numeric number of hours (possibly fractional).
323  */
324  hours = strtod(*newval, &endptr);
325  if (endptr != *newval && *endptr == '\0')
326  {
327  /* Here we change from SQL to Unix sign convention */
328  gmtoffset = -hours * SECS_PER_HOUR;
329  new_tz = pg_tzset_offset(gmtoffset);
330  }
331  else
332  {
333  /*
334  * Otherwise assume it is a timezone name, and try to load it.
335  */
336  new_tz = pg_tzset(*newval);
337 
338  if (!new_tz)
339  {
340  /* Doesn't seem to be any great value in errdetail here */
341  return false;
342  }
343 
344  if (!pg_tz_acceptable(new_tz))
345  {
346  GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
347  *newval);
348  GUC_check_errdetail("PostgreSQL does not support leap seconds.");
349  return false;
350  }
351  }
352  }
353 
354  /* Test for failure in pg_tzset_offset, which we assume is out-of-range */
355  if (!new_tz)
356  {
357  GUC_check_errdetail("UTC timezone offset is out of range.");
358  return false;
359  }
360 
361  /*
362  * Pass back data for assign_timezone to use
363  */
364  *extra = malloc(sizeof(pg_tz *));
365  if (!*extra)
366  return false;
367  *((pg_tz **) *extra) = new_tz;
368 
369  return true;
370 }
371 
372 /*
373  * assign_timezone: GUC assign_hook for timezone
374  */
375 void
376 assign_timezone(const char *newval, void *extra)
377 {
378  session_timezone = *((pg_tz **) extra);
379 }
380 
381 /*
382  * show_timezone: GUC show_hook for timezone
383  */
384 const char *
386 {
387  const char *tzn;
388 
389  /* Always show the zone's canonical name */
391 
392  if (tzn != NULL)
393  return tzn;
394 
395  return "unknown";
396 }
397 
398 
399 /*
400  * LOG_TIMEZONE
401  *
402  * For log_timezone, we don't support the interval-based methods of setting a
403  * zone, which are only there for SQL spec compliance not because they're
404  * actually useful.
405  */
406 
407 /*
408  * check_log_timezone: GUC check_hook for log_timezone
409  */
410 bool
411 check_log_timezone(char **newval, void **extra, GucSource source)
412 {
413  pg_tz *new_tz;
414 
415  /*
416  * Assume it is a timezone name, and try to load it.
417  */
418  new_tz = pg_tzset(*newval);
419 
420  if (!new_tz)
421  {
422  /* Doesn't seem to be any great value in errdetail here */
423  return false;
424  }
425 
426  if (!pg_tz_acceptable(new_tz))
427  {
428  GUC_check_errmsg("time zone \"%s\" appears to use leap seconds",
429  *newval);
430  GUC_check_errdetail("PostgreSQL does not support leap seconds.");
431  return false;
432  }
433 
434  /*
435  * Pass back data for assign_log_timezone to use
436  */
437  *extra = malloc(sizeof(pg_tz *));
438  if (!*extra)
439  return false;
440  *((pg_tz **) *extra) = new_tz;
441 
442  return true;
443 }
444 
445 /*
446  * assign_log_timezone: GUC assign_hook for log_timezone
447  */
448 void
449 assign_log_timezone(const char *newval, void *extra)
450 {
451  log_timezone = *((pg_tz **) extra);
452 }
453 
454 /*
455  * show_log_timezone: GUC show_hook for log_timezone
456  */
457 const char *
459 {
460  const char *tzn;
461 
462  /* Always show the zone's canonical name */
464 
465  if (tzn != NULL)
466  return tzn;
467 
468  return "unknown";
469 }
470 
471 
472 /*
473  * SET TRANSACTION READ ONLY and SET TRANSACTION READ WRITE
474  *
475  * We allow idempotent changes (r/w -> r/w and r/o -> r/o) at any time, and
476  * we also always allow changes from read-write to read-only. However,
477  * read-only may be changed to read-write only when in a top-level transaction
478  * that has not yet taken an initial snapshot. Can't do it in a hot standby
479  * slave, either.
480  *
481  * If we are not in a transaction at all, just allow the change; it means
482  * nothing since XactReadOnly will be reset by the next StartTransaction().
483  * The IsTransactionState() test protects us against trying to check
484  * RecoveryInProgress() in contexts where shared memory is not accessible.
485  * (Similarly, if we're restoring state in a parallel worker, just allow
486  * the change.)
487  */
488 bool
489 check_transaction_read_only(bool *newval, void **extra, GucSource source)
490 {
491  if (*newval == false && XactReadOnly && IsTransactionState() && !InitializingParallelWorker)
492  {
493  /* Can't go to r/w mode inside a r/o transaction */
494  if (IsSubTransaction())
495  {
496  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
497  GUC_check_errmsg("cannot set transaction read-write mode inside a read-only transaction");
498  return false;
499  }
500  /* Top level transaction can't change to r/w after first snapshot. */
501  if (FirstSnapshotSet)
502  {
503  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
504  GUC_check_errmsg("transaction read-write mode must be set before any query");
505  return false;
506  }
507  /* Can't go to r/w mode while recovery is still active */
508  if (RecoveryInProgress())
509  {
510  GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
511  GUC_check_errmsg("cannot set transaction read-write mode during recovery");
512  return false;
513  }
514  }
515 
516  return true;
517 }
518 
519 /*
520  * SET TRANSACTION ISOLATION LEVEL
521  *
522  * We allow idempotent changes at any time, but otherwise this can only be
523  * changed in a toplevel transaction that has not yet taken a snapshot.
524  *
525  * As in check_transaction_read_only, allow it if not inside a transaction.
526  */
527 bool
528 check_XactIsoLevel(char **newval, void **extra, GucSource source)
529 {
530  int newXactIsoLevel;
531 
532  if (strcmp(*newval, "serializable") == 0)
533  {
534  newXactIsoLevel = XACT_SERIALIZABLE;
535  }
536  else if (strcmp(*newval, "repeatable read") == 0)
537  {
538  newXactIsoLevel = XACT_REPEATABLE_READ;
539  }
540  else if (strcmp(*newval, "read committed") == 0)
541  {
542  newXactIsoLevel = XACT_READ_COMMITTED;
543  }
544  else if (strcmp(*newval, "read uncommitted") == 0)
545  {
546  newXactIsoLevel = XACT_READ_UNCOMMITTED;
547  }
548  else if (strcmp(*newval, "default") == 0)
549  {
550  newXactIsoLevel = DefaultXactIsoLevel;
551  }
552  else
553  return false;
554 
555  if (newXactIsoLevel != XactIsoLevel && IsTransactionState())
556  {
557  if (FirstSnapshotSet)
558  {
559  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
560  GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query");
561  return false;
562  }
563  /* We ignore a subtransaction setting it to the existing value. */
564  if (IsSubTransaction())
565  {
566  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
567  GUC_check_errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction");
568  return false;
569  }
570  /* Can't go to serializable mode while recovery is still active */
571  if (newXactIsoLevel == XACT_SERIALIZABLE && RecoveryInProgress())
572  {
573  GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
574  GUC_check_errmsg("cannot use serializable mode in a hot standby");
575  GUC_check_errhint("You can use REPEATABLE READ instead.");
576  return false;
577  }
578  }
579 
580  *extra = malloc(sizeof(int));
581  if (!*extra)
582  return false;
583  *((int *) *extra) = newXactIsoLevel;
584 
585  return true;
586 }
587 
588 void
589 assign_XactIsoLevel(const char *newval, void *extra)
590 {
591  XactIsoLevel = *((int *) extra);
592 }
593 
594 const char *
596 {
597  /* We need this because we don't want to show "default". */
598  switch (XactIsoLevel)
599  {
601  return "read uncommitted";
602  case XACT_READ_COMMITTED:
603  return "read committed";
605  return "repeatable read";
606  case XACT_SERIALIZABLE:
607  return "serializable";
608  default:
609  return "bogus";
610  }
611 }
612 
613 /*
614  * SET TRANSACTION [NOT] DEFERRABLE
615  */
616 
617 bool
618 check_transaction_deferrable(bool *newval, void **extra, GucSource source)
619 {
620  if (IsSubTransaction())
621  {
622  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
623  GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE cannot be called within a subtransaction");
624  return false;
625  }
626  if (FirstSnapshotSet)
627  {
628  GUC_check_errcode(ERRCODE_ACTIVE_SQL_TRANSACTION);
629  GUC_check_errmsg("SET TRANSACTION [NOT] DEFERRABLE must be called before any query");
630  return false;
631  }
632 
633  return true;
634 }
635 
636 /*
637  * Random number seed
638  *
639  * We can't roll back the random sequence on error, and we don't want
640  * config file reloads to affect it, so we only want interactive SET SEED
641  * commands to set it. We use the "extra" storage to ensure that rollbacks
642  * don't try to do the operation again.
643  */
644 
645 bool
646 check_random_seed(double *newval, void **extra, GucSource source)
647 {
648  *extra = malloc(sizeof(int));
649  if (!*extra)
650  return false;
651  /* Arm the assign only if source of value is an interactive SET */
652  *((int *) *extra) = (source >= PGC_S_INTERACTIVE);
653 
654  return true;
655 }
656 
657 void
658 assign_random_seed(double newval, void *extra)
659 {
660  /* We'll do this at most once for any setting of the GUC variable */
661  if (*((int *) extra))
663  *((int *) extra) = 0;
664 }
665 
666 const char *
668 {
669  return "unavailable";
670 }
671 
672 
673 /*
674  * SET CLIENT_ENCODING
675  */
676 
677 bool
678 check_client_encoding(char **newval, void **extra, GucSource source)
679 {
680  int encoding;
681  const char *canonical_name;
682 
683  /* Look up the encoding by name */
684  encoding = pg_valid_client_encoding(*newval);
685  if (encoding < 0)
686  return false;
687 
688  /* Get the canonical name (no aliases, uniform case) */
689  canonical_name = pg_encoding_to_char(encoding);
690 
691  /*
692  * If we are not within a transaction then PrepareClientEncoding will not
693  * be able to look up the necessary conversion procs. If we are still
694  * starting up, it will return "OK" anyway, and InitializeClientEncoding
695  * will fix things once initialization is far enough along. After
696  * startup, we'll fail. This would only happen if someone tries to change
697  * client_encoding in postgresql.conf and then SIGHUP existing sessions.
698  * It seems like a bad idea for client_encoding to change that way anyhow,
699  * so we don't go out of our way to support it.
700  *
701  * Note: in the postmaster, or any other process that never calls
702  * InitializeClientEncoding, PrepareClientEncoding will always succeed,
703  * and so will SetClientEncoding; but they won't do anything, which is OK.
704  */
705  if (PrepareClientEncoding(encoding) < 0)
706  {
707  if (IsTransactionState())
708  {
709  /* Must be a genuine no-such-conversion problem */
710  GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED);
711  GUC_check_errdetail("Conversion between %s and %s is not supported.",
712  canonical_name,
714  }
715  else
716  {
717  /* Provide a useful complaint */
718  GUC_check_errdetail("Cannot change \"client_encoding\" now.");
719  }
720  return false;
721  }
722 
723  /*
724  * Replace the user-supplied string with the encoding's canonical name.
725  * This gets rid of aliases and case-folding variations.
726  *
727  * XXX Although canonicalizing seems like a good idea in the abstract, it
728  * breaks pre-9.1 JDBC drivers, which expect that if they send "UNICODE"
729  * as the client_encoding setting then it will read back the same way. As
730  * a workaround, don't replace the string if it's "UNICODE". Remove that
731  * hack when pre-9.1 JDBC drivers are no longer in use.
732  */
733  if (strcmp(*newval, canonical_name) != 0 &&
734  strcmp(*newval, "UNICODE") != 0)
735  {
736  free(*newval);
737  *newval = strdup(canonical_name);
738  if (!*newval)
739  return false;
740  }
741 
742  /*
743  * Save the encoding's ID in *extra, for use by assign_client_encoding.
744  */
745  *extra = malloc(sizeof(int));
746  if (!*extra)
747  return false;
748  *((int *) *extra) = encoding;
749 
750  return true;
751 }
752 
753 void
754 assign_client_encoding(const char *newval, void *extra)
755 {
756  int encoding = *((int *) extra);
757 
758  /*
759  * Parallel workers send data to the leader, not the client. They always
760  * send data using the database encoding.
761  */
762  if (IsParallelWorker())
763  {
764  /*
765  * During parallel worker startup, we want to accept the leader's
766  * client_encoding setting so that anyone who looks at the value in
767  * the worker sees the same value that they would see in the leader.
768  */
770  return;
771 
772  /*
773  * A change other than during startup, for example due to a SET clause
774  * attached to a function definition, should be rejected, as there is
775  * nothing we can do inside the worker to make it take effect.
776  */
777  ereport(ERROR,
778  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
779  errmsg("cannot change client_encoding in a parallel worker")));
780  }
781 
782  /* We do not expect an error if PrepareClientEncoding succeeded */
783  if (SetClientEncoding(encoding) < 0)
784  elog(LOG, "SetClientEncoding(%d) failed", encoding);
785 }
786 
787 
788 /*
789  * SET SESSION AUTHORIZATION
790  */
791 
792 typedef struct
793 {
794  /* This is the "extra" state for both SESSION AUTHORIZATION and ROLE */
798 
799 bool
800 check_session_authorization(char **newval, void **extra, GucSource source)
801 {
802  HeapTuple roleTup;
803  Oid roleid;
804  bool is_superuser;
805  role_auth_extra *myextra;
806 
807  /* Do nothing for the boot_val default of NULL */
808  if (*newval == NULL)
809  return true;
810 
811  if (!IsTransactionState())
812  {
813  /*
814  * Can't do catalog lookups, so fail. The result of this is that
815  * session_authorization cannot be set in postgresql.conf, which seems
816  * like a good thing anyway, so we don't work hard to avoid it.
817  */
818  return false;
819  }
820 
821  /* Look up the username */
822  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
823  if (!HeapTupleIsValid(roleTup))
824  {
825  GUC_check_errmsg("role \"%s\" does not exist", *newval);
826  return false;
827  }
828 
829  roleid = HeapTupleGetOid(roleTup);
830  is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
831 
832  ReleaseSysCache(roleTup);
833 
834  /* Set up "extra" struct for assign_session_authorization to use */
835  myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
836  if (!myextra)
837  return false;
838  myextra->roleid = roleid;
839  myextra->is_superuser = is_superuser;
840  *extra = (void *) myextra;
841 
842  return true;
843 }
844 
845 void
846 assign_session_authorization(const char *newval, void *extra)
847 {
848  role_auth_extra *myextra = (role_auth_extra *) extra;
849 
850  /* Do nothing for the boot_val default of NULL */
851  if (!myextra)
852  return;
853 
854  SetSessionAuthorization(myextra->roleid, myextra->is_superuser);
855 }
856 
857 
858 /*
859  * SET ROLE
860  *
861  * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
862  * a translation of "none" to InvalidOid. Otherwise this is much like
863  * SET SESSION AUTHORIZATION.
864  */
865 extern char *role_string; /* in guc.c */
866 
867 bool
868 check_role(char **newval, void **extra, GucSource source)
869 {
870  HeapTuple roleTup;
871  Oid roleid;
872  bool is_superuser;
873  role_auth_extra *myextra;
874 
875  if (strcmp(*newval, "none") == 0)
876  {
877  /* hardwired translation */
878  roleid = InvalidOid;
879  is_superuser = false;
880  }
881  else
882  {
883  if (!IsTransactionState())
884  {
885  /*
886  * Can't do catalog lookups, so fail. The result of this is that
887  * role cannot be set in postgresql.conf, which seems like a good
888  * thing anyway, so we don't work hard to avoid it.
889  */
890  return false;
891  }
892 
893  /* Look up the username */
894  roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(*newval));
895  if (!HeapTupleIsValid(roleTup))
896  {
897  GUC_check_errmsg("role \"%s\" does not exist", *newval);
898  return false;
899  }
900 
901  roleid = HeapTupleGetOid(roleTup);
902  is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
903 
904  ReleaseSysCache(roleTup);
905 
906  /*
907  * Verify that session user is allowed to become this role, but skip
908  * this in parallel mode, where we must blindly recreate the parallel
909  * leader's state.
910  */
913  {
914  GUC_check_errcode(ERRCODE_INSUFFICIENT_PRIVILEGE);
915  GUC_check_errmsg("permission denied to set role \"%s\"",
916  *newval);
917  return false;
918  }
919  }
920 
921  /* Set up "extra" struct for assign_role to use */
922  myextra = (role_auth_extra *) malloc(sizeof(role_auth_extra));
923  if (!myextra)
924  return false;
925  myextra->roleid = roleid;
926  myextra->is_superuser = is_superuser;
927  *extra = (void *) myextra;
928 
929  return true;
930 }
931 
932 void
933 assign_role(const char *newval, void *extra)
934 {
935  role_auth_extra *myextra = (role_auth_extra *) extra;
936 
937  SetCurrentRoleId(myextra->roleid, myextra->is_superuser);
938 }
939 
940 const char *
942 {
943  /*
944  * Check whether SET ROLE is active; if not return "none". This is a
945  * kluge to deal with the fact that SET SESSION AUTHORIZATION logically
946  * resets SET ROLE to NONE, but we cannot set the GUC role variable from
947  * assign_session_authorization (because we haven't got enough info to
948  * call set_config_option).
949  */
951  return "none";
952 
953  /* Otherwise we can just use the GUC string */
954  return role_string ? role_string : "none";
955 }
bool check_transaction_deferrable(bool *newval, void **extra, GucSource source)
Definition: variable.c:618
void assign_timezone(const char *newval, void *extra)
Definition: variable.c:376
void assign_client_encoding(const char *newval, void *extra)
Definition: variable.c:754
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define DatumGetIntervalP(X)
Definition: timestamp.h:49
int PrepareClientEncoding(int encoding)
Definition: mbutils.c:114
bool check_random_seed(double *newval, void **extra, GucSource source)
Definition: variable.c:646
#define USECS_PER_SEC
Definition: timestamp.h:106
#define GUC_check_errdetail
Definition: guc.h:408
#define PointerGetDatum(X)
Definition: postgres.h:564
Datum interval_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:928
void assign_XactIsoLevel(const char *newval, void *extra)
Definition: variable.c:589
char * pstrdup(const char *in)
Definition: mcxt.c:1168
#define XACT_REPEATABLE_READ
Definition: xact.h:30
#define XACT_READ_UNCOMMITTED
Definition: xact.h:28
int pg_valid_client_encoding(const char *name)
Definition: encnames.c:411
int errcode(int sqlerrcode)
Definition: elog.c:575
#define GUC_check_errmsg
Definition: guc.h:404
void assign_datestyle(const char *newval, void *extra)
Definition: variable.c:235
#define USE_SQL_DATES
Definition: miscadmin.h:210
bool check_transaction_read_only(bool *newval, void **extra, GucSource source)
Definition: variable.c:489
int DefaultXactIsoLevel
Definition: xact.c:71
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:548
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
bool check_timezone(char **newval, void **extra, GucSource source)
Definition: variable.c:252
#define LOG
Definition: elog.h:26
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:7547
#define OidIsValid(objectId)
Definition: c.h:530
void GUC_check_errcode(int sqlerrcode)
Definition: guc.c:9651
Oid GetSessionUserId(void)
Definition: miscinit.c:316
void assign_session_authorization(const char *newval, void *extra)
Definition: variable.c:846
bool check_XactIsoLevel(char **newval, void **extra, GucSource source)
Definition: variable.c:528
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:141
#define XACT_SERIALIZABLE
Definition: xact.h:31
#define USE_ISO_DATES
Definition: miscadmin.h:209
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:2193
int32 day
Definition: timestamp.h:60
GucSource
Definition: guc.h:105
pg_tz * log_timezone
Definition: pgtz.c:30
Oid GetCurrentRoleId(void)
Definition: miscinit.c:634
#define malloc(a)
Definition: header.h:45
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
FormData_pg_authid * Form_pg_authid
Definition: pg_authid.h:72
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
void pfree(void *pointer)
Definition: mcxt.c:995
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
void SetSessionAuthorization(Oid userid, bool is_superuser)
Definition: miscinit.c:609
bool FirstSnapshotSet
Definition: snapmgr.c:202
const char * show_XactIsoLevel(void)
Definition: variable.c:595
Datum setseed(PG_FUNCTION_ARGS)
Definition: float.c:2433
const char * pg_get_timezone_name(pg_tz *tz)
Definition: localtime.c:1771
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3128
#define CStringGetDatum(X)
Definition: postgres.h:586
TimeOffset time
Definition: timestamp.h:58
#define USE_POSTGRES_DATES
Definition: miscadmin.h:208
int SetClientEncoding(int encoding)
Definition: mbutils.c:212
#define ereport(elevel, rest)
Definition: elog.h:122
int DateOrder
Definition: globals.c:107
#define IsParallelWorker()
Definition: parallel.h:54
#define SECS_PER_HOUR
Definition: timestamp.h:99
pg_tz * pg_tzset_offset(long gmtoffset)
Definition: pgtz.c:304
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:552
#define DATEORDER_YMD
Definition: miscadmin.h:215
int32 month
Definition: timestamp.h:61
const char * show_timezone(void)
Definition: variable.c:385
void assign_log_timezone(const char *newval, void *extra)
Definition: variable.c:449
const char * show_role(void)
Definition: variable.c:941
bool pg_tz_acceptable(pg_tz *tz)
Definition: localtime.c:1786
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:990
bool check_client_encoding(char **newval, void **extra, GucSource source)
Definition: variable.c:678
Definition: pgtz.h:59
bool check_session_authorization(char **newval, void **extra, GucSource source)
Definition: variable.c:800
bool check_role(char **newval, void **extra, GucSource source)
Definition: variable.c:868
bool check_datestyle(char **newval, void **extra, GucSource source)
Definition: variable.c:43
#define DATEORDER_DMY
Definition: miscadmin.h:216
#define InvalidOid
Definition: postgres_ext.h:36
#define DATEORDER_MDY
Definition: miscadmin.h:217
bool XactReadOnly
Definition: xact.c:75
bool is_superuser(void)
Definition: common.c:1930
static char * encoding
Definition: initdb.c:125
#define free(a)
Definition: header.h:60
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:4854
const char * pg_encoding_to_char(int encoding)
Definition: encnames.c:531
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
const char * GetDatabaseEncodingName(void)
Definition: mbutils.c:1021
#define XACT_READ_COMMITTED
Definition: xact.h:29
#define newval
int XactIsoLevel
Definition: xact.c:72
bool IsTransactionState(void)
Definition: xact.c:347
int DateStyle
Definition: globals.c:106
bool IsSubTransaction(void)
Definition: xact.c:4372
#define Int32GetDatum(X)
Definition: postgres.h:487
char * role_string
Definition: guc.c:500
#define GUC_check_errhint
Definition: guc.h:412
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define USE_GERMAN_DATES
Definition: miscadmin.h:211
void SetCurrentRoleId(Oid roleid, bool is_superuser)
Definition: miscinit.c:655
void list_free(List *list)
Definition: list.c:1133
bool InitializingParallelWorker
Definition: parallel.c:100
void assign_role(const char *newval, void *extra)
Definition: variable.c:933
pg_tz * session_timezone
Definition: pgtz.c:27
#define elog
Definition: elog.h:218
void assign_random_seed(double newval, void *extra)
Definition: variable.c:658
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Definition: pg_list.h:45
long val
Definition: informix.c:689
const char * GetConfigOptionResetString(const char *name)
Definition: guc.c:6650
const char * show_random_seed(void)
Definition: variable.c:667
const char * show_log_timezone(void)
Definition: variable.c:458
bool is_superuser
Definition: variable.c:796
bool check_log_timezone(char **newval, void **extra, GucSource source)
Definition: variable.c:411