1 /*-------------------------------------------------------------------------
4 * Routines for handling specialized SET variables.
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.129 2009/01/01 17:23:40 momjian Exp $
14 *-------------------------------------------------------------------------
21 #include "access/xact.h"
22 #include "catalog/pg_authid.h"
23 #include "commands/variable.h"
24 #include "miscadmin.h"
25 #include "utils/acl.h"
26 #include "utils/builtins.h"
27 #include "utils/syscache.h"
28 #include "utils/snapmgr.h"
29 #include "mb/pg_wchar.h"
36 * assign_datestyle: GUC assign_hook for datestyle
39 assign_datestyle(const char *value, bool doit, GucSource source)
41 int newDateStyle = DateStyle;
42 int newDateOrder = DateOrder;
43 bool have_style = false;
44 bool have_order = false;
51 /* Need a modifiable copy of string */
52 rawstring = pstrdup(value);
54 /* Parse string into list of identifiers */
55 if (!SplitIdentifierString(rawstring, ',', &elemlist))
57 /* syntax error in list */
60 ereport(GUC_complaint_elevel(source),
61 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
62 errmsg("invalid list syntax for parameter \"datestyle\"")));
68 char *tok = (char *) lfirst(l);
70 /* Ugh. Somebody ought to write a table driven version -- mjl */
72 if (pg_strcasecmp(tok, "ISO") == 0)
74 if (have_style && newDateStyle != USE_ISO_DATES)
75 ok = false; /* conflicting styles */
76 newDateStyle = USE_ISO_DATES;
79 else if (pg_strcasecmp(tok, "SQL") == 0)
81 if (have_style && newDateStyle != USE_SQL_DATES)
82 ok = false; /* conflicting styles */
83 newDateStyle = USE_SQL_DATES;
86 else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
88 if (have_style && newDateStyle != USE_POSTGRES_DATES)
89 ok = false; /* conflicting styles */
90 newDateStyle = USE_POSTGRES_DATES;
93 else if (pg_strcasecmp(tok, "GERMAN") == 0)
95 if (have_style && newDateStyle != USE_GERMAN_DATES)
96 ok = false; /* conflicting styles */
97 newDateStyle = USE_GERMAN_DATES;
99 /* GERMAN also sets DMY, unless explicitly overridden */
101 newDateOrder = DATEORDER_DMY;
103 else if (pg_strcasecmp(tok, "YMD") == 0)
105 if (have_order && newDateOrder != DATEORDER_YMD)
106 ok = false; /* conflicting orders */
107 newDateOrder = DATEORDER_YMD;
110 else if (pg_strcasecmp(tok, "DMY") == 0 ||
111 pg_strncasecmp(tok, "EURO", 4) == 0)
113 if (have_order && newDateOrder != DATEORDER_DMY)
114 ok = false; /* conflicting orders */
115 newDateOrder = DATEORDER_DMY;
118 else if (pg_strcasecmp(tok, "MDY") == 0 ||
119 pg_strcasecmp(tok, "US") == 0 ||
120 pg_strncasecmp(tok, "NONEURO", 7) == 0)
122 if (have_order && newDateOrder != DATEORDER_MDY)
123 ok = false; /* conflicting orders */
124 newDateOrder = DATEORDER_MDY;
127 else if (pg_strcasecmp(tok, "DEFAULT") == 0)
130 * Easiest way to get the current DEFAULT state is to fetch the
131 * DEFAULT string from guc.c and recursively parse it.
133 * We can't simply "return assign_datestyle(...)" because we need
134 * to handle constructs like "DEFAULT, ISO".
136 int saveDateStyle = DateStyle;
137 int saveDateOrder = DateOrder;
140 subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
143 newDateStyle = DateStyle;
145 newDateOrder = DateOrder;
146 DateStyle = saveDateStyle;
147 DateOrder = saveDateOrder;
153 /* Here we know that our own return value is always malloc'd */
154 /* when doit is true */
155 free((char *) subval);
159 ereport(GUC_complaint_elevel(source),
160 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
161 errmsg("unrecognized \"datestyle\" key word: \"%s\"",
173 ereport(GUC_complaint_elevel(source),
174 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
175 errmsg("conflicting \"datestyle\" specifications")));
180 * If we aren't going to do the assignment, just return OK indicator.
186 * Prepare the canonical string to return. GUC wants it malloc'd.
188 result = (char *) malloc(32);
192 switch (newDateStyle)
195 strcpy(result, "ISO");
198 strcpy(result, "SQL");
200 case USE_GERMAN_DATES:
201 strcpy(result, "German");
204 strcpy(result, "Postgres");
207 switch (newDateOrder)
210 strcat(result, ", YMD");
213 strcat(result, ", DMY");
216 strcat(result, ", MDY");
221 * Finally, it's safe to assign to the global variables; the assignment
224 DateStyle = newDateStyle;
225 DateOrder = newDateOrder;
236 * assign_timezone: GUC assign_hook for timezone
239 assign_timezone(const char *value, bool doit, GucSource source)
246 * Check for INTERVAL 'foo'
248 if (pg_strncasecmp(value, "interval", 8) == 0)
250 const char *valueptr = value;
255 while (isspace((unsigned char) *valueptr))
257 if (*valueptr++ != '\'')
259 val = pstrdup(valueptr);
260 /* Check and remove trailing quote */
261 endptr = strchr(val, '\'');
262 if (!endptr || endptr[1] != '\0')
270 * Try to parse it. XXX an invalid interval format will result in
271 * ereport(ERROR), which is not desirable for GUC. We did what we
272 * could to guard against this in flatten_set_variable_args, but a
273 * string coming in from postgresql.conf might contain anything.
275 interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
276 CStringGetDatum(val),
277 ObjectIdGetDatum(InvalidOid),
281 if (interval->month != 0)
283 ereport(GUC_complaint_elevel(source),
284 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
285 errmsg("invalid interval value for time zone: month not allowed")));
289 if (interval->day != 0)
291 ereport(GUC_complaint_elevel(source),
292 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
293 errmsg("invalid interval value for time zone: day not allowed")));
299 /* Here we change from SQL to Unix sign convention */
300 #ifdef HAVE_INT64_TIMESTAMP
301 CTimeZone = -(interval->time / USECS_PER_SEC);
303 CTimeZone = -interval->time;
313 * Try it as a numeric number of hours (possibly fractional).
315 hours = strtod(value, &endptr);
316 if (endptr != value && *endptr == '\0')
320 /* Here we change from SQL to Unix sign convention */
321 CTimeZone = -hours * SECS_PER_HOUR;
325 else if (pg_strcasecmp(value, "UNKNOWN") == 0)
328 * UNKNOWN is the value shown as the "default" for TimeZone in
329 * guc.c. We interpret it as being a complete no-op; we don't
330 * change the timezone setting. Note that if there is a known
331 * timezone setting, we will return that name rather than UNKNOWN
332 * as the canonical spelling.
334 * During GUC initialization, since the timezone library isn't set
335 * up yet, pg_get_timezone_name will return NULL and we will leave
336 * the setting as UNKNOWN. If this isn't overridden from the
337 * config file then pg_timezone_initialize() will eventually
338 * select a default value from the environment.
342 const char *curzone = pg_get_timezone_name(session_timezone);
351 * Otherwise assume it is a timezone name, and try to load it.
355 new_tz = pg_tzset(value);
359 ereport(GUC_complaint_elevel(source),
360 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
361 errmsg("unrecognized time zone name: \"%s\"",
366 if (!tz_acceptable(new_tz))
368 ereport(GUC_complaint_elevel(source),
369 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
370 errmsg("time zone \"%s\" appears to use leap seconds",
372 errdetail("PostgreSQL does not support leap seconds.")));
378 /* Save the changed TZ */
379 session_timezone = new_tz;
386 * If we aren't going to do the assignment, just return OK indicator.
392 * Prepare the canonical string to return. GUC wants it malloc'd.
396 result = (char *) malloc(64);
399 snprintf(result, 64, "%.5f",
400 (double) (-CTimeZone) / (double) SECS_PER_HOUR);
403 result = strdup(value);
409 * show_timezone: GUC show_hook for timezone
422 #ifdef HAVE_INT64_TIMESTAMP
423 interval.time = -(CTimeZone * USECS_PER_SEC);
425 interval.time = -CTimeZone;
428 tzn = DatumGetCString(DirectFunctionCall1(interval_out,
429 IntervalPGetDatum(&interval)));
432 tzn = pg_get_timezone_name(session_timezone);
444 * For log_timezone, we don't support the interval-based methods of setting a
445 * zone, which are only there for SQL spec compliance not because they're
450 * assign_log_timezone: GUC assign_hook for log_timezone
453 assign_log_timezone(const char *value, bool doit, GucSource source)
457 if (pg_strcasecmp(value, "UNKNOWN") == 0)
460 * UNKNOWN is the value shown as the "default" for log_timezone in
461 * guc.c. We interpret it as being a complete no-op; we don't change
462 * the timezone setting. Note that if there is a known timezone
463 * setting, we will return that name rather than UNKNOWN as the
464 * canonical spelling.
466 * During GUC initialization, since the timezone library isn't set up
467 * yet, pg_get_timezone_name will return NULL and we will leave the
468 * setting as UNKNOWN. If this isn't overridden from the config file
469 * then pg_timezone_initialize() will eventually select a default
470 * value from the environment.
474 const char *curzone = pg_get_timezone_name(log_timezone);
483 * Otherwise assume it is a timezone name, and try to load it.
487 new_tz = pg_tzset(value);
491 ereport(GUC_complaint_elevel(source),
492 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
493 errmsg("unrecognized time zone name: \"%s\"",
498 if (!tz_acceptable(new_tz))
500 ereport(GUC_complaint_elevel(source),
501 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
502 errmsg("time zone \"%s\" appears to use leap seconds",
504 errdetail("PostgreSQL does not support leap seconds.")));
510 /* Save the changed TZ */
511 log_timezone = new_tz;
516 * If we aren't going to do the assignment, just return OK indicator.
522 * Prepare the canonical string to return. GUC wants it malloc'd.
524 result = strdup(value);
530 * show_log_timezone: GUC show_hook for log_timezone
533 show_log_timezone(void)
537 tzn = pg_get_timezone_name(log_timezone);
547 * SET TRANSACTION ISOLATION LEVEL
551 assign_XactIsoLevel(const char *value, bool doit, GucSource source)
553 if (FirstSnapshotSet)
555 ereport(GUC_complaint_elevel(source),
556 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
557 errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
558 /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
559 if (source != PGC_S_OVERRIDE)
562 else if (IsSubTransaction())
564 ereport(GUC_complaint_elevel(source),
565 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
566 errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
567 /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
568 if (source != PGC_S_OVERRIDE)
572 if (strcmp(value, "serializable") == 0)
575 XactIsoLevel = XACT_SERIALIZABLE;
577 else if (strcmp(value, "repeatable read") == 0)
580 XactIsoLevel = XACT_REPEATABLE_READ;
582 else if (strcmp(value, "read committed") == 0)
585 XactIsoLevel = XACT_READ_COMMITTED;
587 else if (strcmp(value, "read uncommitted") == 0)
590 XactIsoLevel = XACT_READ_UNCOMMITTED;
592 else if (strcmp(value, "default") == 0)
595 XactIsoLevel = DefaultXactIsoLevel;
604 show_XactIsoLevel(void)
606 switch (XactIsoLevel)
608 case XACT_READ_UNCOMMITTED:
609 return "read uncommitted";
610 case XACT_READ_COMMITTED:
611 return "read committed";
612 case XACT_REPEATABLE_READ:
613 return "repeatable read";
614 case XACT_SERIALIZABLE:
615 return "serializable";
627 assign_random_seed(double value, bool doit, GucSource source)
629 /* Can't really roll back on error, so ignore non-interactive setting */
630 if (doit && source >= PGC_S_INTERACTIVE)
631 DirectFunctionCall1(setseed, Float8GetDatum(value));
636 show_random_seed(void)
638 return "unavailable";
643 * encoding handling functions
647 assign_client_encoding(const char *value, bool doit, GucSource source)
651 encoding = pg_valid_client_encoding(value);
656 * Note: if we are in startup phase then SetClientEncoding may not be able
657 * to really set the encoding. In this case we will assume that the
658 * encoding is okay, and InitializeClientEncoding() will fix things once
659 * initialization is complete.
661 if (SetClientEncoding(encoding, doit) < 0)
663 ereport(GUC_complaint_elevel(source),
664 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
665 errmsg("conversion between %s and %s is not supported",
666 value, GetDatabaseEncodingName())));
674 * SET SESSION AUTHORIZATION
676 * When resetting session auth after an error, we can't expect to do catalog
677 * lookups. Hence, the stored form of the value must provide a numeric oid
678 * that can be re-used directly. We store the string in the form of
679 * NAMEDATALEN 'x's, followed by T or F to indicate superuserness, followed
680 * by the numeric oid, followed by a comma, followed by the role name.
681 * This cannot be confused with a plain role name because of the NAMEDATALEN
682 * limit on names, so we can tell whether we're being passed an initial
683 * role name or a saved/restored value. (NOTE: we rely on guc.c to have
684 * properly truncated any incoming value, but not to truncate already-stored
685 * values. See GUC_IS_NAME processing.)
687 extern char *session_authorization_string; /* in guc.c */
690 assign_session_authorization(const char *value, bool doit, GucSource source)
692 Oid roleid = InvalidOid;
693 bool is_superuser = false;
694 const char *actual_rolename = NULL;
697 if (strspn(value, "x") == NAMEDATALEN &&
698 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
700 /* might be a saved userid string */
704 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
706 if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
708 /* syntactically valid, so break out the data */
710 is_superuser = (value[NAMEDATALEN] == 'T');
711 actual_rolename = endptr + 1;
715 if (roleid == InvalidOid)
717 /* not a saved ID, so look it up */
720 if (InSecurityDefinerContext())
723 * Disallow SET SESSION AUTHORIZATION inside a security definer
724 * context. We need to do this because when we exit the context,
725 * GUC won't be notified, leaving things out of sync. Note that
726 * this test is positioned so that restoring a previously saved
727 * setting isn't prevented.
729 ereport(GUC_complaint_elevel(source),
730 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
731 errmsg("cannot set session authorization within security-definer function")));
735 if (!IsTransactionState())
738 * Can't do catalog lookups, so fail. The upshot of this is that
739 * session_authorization cannot be set in postgresql.conf, which
740 * seems like a good thing anyway.
745 roleTup = SearchSysCache(AUTHNAME,
746 PointerGetDatum(value),
748 if (!HeapTupleIsValid(roleTup))
750 ereport(GUC_complaint_elevel(source),
751 (errcode(ERRCODE_UNDEFINED_OBJECT),
752 errmsg("role \"%s\" does not exist", value)));
756 roleid = HeapTupleGetOid(roleTup);
757 is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
758 actual_rolename = value;
760 ReleaseSysCache(roleTup);
764 SetSessionAuthorization(roleid, is_superuser);
766 result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
770 memset(result, 'x', NAMEDATALEN);
772 sprintf(result + NAMEDATALEN, "%c%u,%s",
773 is_superuser ? 'T' : 'F',
781 show_session_authorization(void)
784 * Extract the user name from the stored string; see
785 * assign_session_authorization
787 const char *value = session_authorization_string;
791 Assert(strspn(value, "x") == NAMEDATALEN &&
792 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
794 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
796 Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
805 * When resetting session auth after an error, we can't expect to do catalog
806 * lookups. Hence, the stored form of the value must provide a numeric oid
807 * that can be re-used directly. We implement this exactly like SET
808 * SESSION AUTHORIZATION.
810 * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
811 * a translation of "none" to InvalidOid.
813 extern char *role_string; /* in guc.c */
816 assign_role(const char *value, bool doit, GucSource source)
818 Oid roleid = InvalidOid;
819 bool is_superuser = false;
820 const char *actual_rolename = value;
823 if (strspn(value, "x") == NAMEDATALEN &&
824 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
826 /* might be a saved userid string */
830 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
832 if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
834 /* syntactically valid, so break out the data */
836 is_superuser = (value[NAMEDATALEN] == 'T');
837 actual_rolename = endptr + 1;
841 if (roleid == InvalidOid && InSecurityDefinerContext())
844 * Disallow SET ROLE inside a security definer context. We need to do
845 * this because when we exit the context, GUC won't be notified,
846 * leaving things out of sync. Note that this test is arranged so
847 * that restoring a previously saved setting isn't prevented.
849 * XXX it would be nice to allow this case in future, with the
850 * behavior being that the SET ROLE's effects end when the security
851 * definer context is exited.
853 ereport(GUC_complaint_elevel(source),
854 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
855 errmsg("cannot set role within security-definer function")));
859 if (roleid == InvalidOid &&
860 strcmp(actual_rolename, "none") != 0)
862 /* not a saved ID, so look it up */
865 if (!IsTransactionState())
868 * Can't do catalog lookups, so fail. The upshot of this is that
869 * role cannot be set in postgresql.conf, which seems like a good
875 roleTup = SearchSysCache(AUTHNAME,
876 PointerGetDatum(value),
878 if (!HeapTupleIsValid(roleTup))
880 ereport(GUC_complaint_elevel(source),
881 (errcode(ERRCODE_UNDEFINED_OBJECT),
882 errmsg("role \"%s\" does not exist", value)));
886 roleid = HeapTupleGetOid(roleTup);
887 is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
889 ReleaseSysCache(roleTup);
892 * Verify that session user is allowed to become this role
894 if (!is_member_of_role(GetSessionUserId(), roleid))
896 ereport(GUC_complaint_elevel(source),
897 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
898 errmsg("permission denied to set role \"%s\"",
905 SetCurrentRoleId(roleid, is_superuser);
907 result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
911 memset(result, 'x', NAMEDATALEN);
913 sprintf(result + NAMEDATALEN, "%c%u,%s",
914 is_superuser ? 'T' : 'F',
925 * Extract the role name from the stored string; see assign_role
927 const char *value = role_string;
931 /* This special case only applies if no SET ROLE has been done */
932 if (value == NULL || strcmp(value, "none") == 0)
935 Assert(strspn(value, "x") == NAMEDATALEN &&
936 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
938 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
940 Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
943 * Check that the stored string still matches the effective setting, else
944 * return "none". This is a kluge to deal with the fact that SET SESSION
945 * AUTHORIZATION logically resets SET ROLE to NONE, but we cannot set the
946 * GUC role variable from assign_session_authorization (because we haven't
947 * got enough info to call set_config_option).
949 if (savedoid != GetCurrentRoleId())