1 /*-------------------------------------------------------------------------
4 * Routines for handling specialized SET variables.
7 * Portions Copyright (c) 1996-2007, 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.122 2007/11/15 21:14:34 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/tqual.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 if (source >= PGC_S_INTERACTIVE)
62 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
63 errmsg("invalid list syntax for parameter \"datestyle\"")));
69 char *tok = (char *) lfirst(l);
71 /* Ugh. Somebody ought to write a table driven version -- mjl */
73 if (pg_strcasecmp(tok, "ISO") == 0)
75 if (have_style && newDateStyle != USE_ISO_DATES)
76 ok = false; /* conflicting styles */
77 newDateStyle = USE_ISO_DATES;
80 else if (pg_strcasecmp(tok, "SQL") == 0)
82 if (have_style && newDateStyle != USE_SQL_DATES)
83 ok = false; /* conflicting styles */
84 newDateStyle = USE_SQL_DATES;
87 else if (pg_strncasecmp(tok, "POSTGRES", 8) == 0)
89 if (have_style && newDateStyle != USE_POSTGRES_DATES)
90 ok = false; /* conflicting styles */
91 newDateStyle = USE_POSTGRES_DATES;
94 else if (pg_strcasecmp(tok, "GERMAN") == 0)
96 if (have_style && newDateStyle != USE_GERMAN_DATES)
97 ok = false; /* conflicting styles */
98 newDateStyle = USE_GERMAN_DATES;
100 /* GERMAN also sets DMY, unless explicitly overridden */
102 newDateOrder = DATEORDER_DMY;
104 else if (pg_strcasecmp(tok, "YMD") == 0)
106 if (have_order && newDateOrder != DATEORDER_YMD)
107 ok = false; /* conflicting orders */
108 newDateOrder = DATEORDER_YMD;
111 else if (pg_strcasecmp(tok, "DMY") == 0 ||
112 pg_strncasecmp(tok, "EURO", 4) == 0)
114 if (have_order && newDateOrder != DATEORDER_DMY)
115 ok = false; /* conflicting orders */
116 newDateOrder = DATEORDER_DMY;
119 else if (pg_strcasecmp(tok, "MDY") == 0 ||
120 pg_strcasecmp(tok, "US") == 0 ||
121 pg_strncasecmp(tok, "NONEURO", 7) == 0)
123 if (have_order && newDateOrder != DATEORDER_MDY)
124 ok = false; /* conflicting orders */
125 newDateOrder = DATEORDER_MDY;
128 else if (pg_strcasecmp(tok, "DEFAULT") == 0)
131 * Easiest way to get the current DEFAULT state is to fetch the
132 * DEFAULT string from guc.c and recursively parse it.
134 * We can't simply "return assign_datestyle(...)" because we need
135 * to handle constructs like "DEFAULT, ISO".
137 int saveDateStyle = DateStyle;
138 int saveDateOrder = DateOrder;
141 subval = assign_datestyle(GetConfigOptionResetString("datestyle"),
144 newDateStyle = DateStyle;
146 newDateOrder = DateOrder;
147 DateStyle = saveDateStyle;
148 DateOrder = saveDateOrder;
154 /* Here we know that our own return value is always malloc'd */
155 /* when doit is true */
156 free((char *) subval);
160 if (source >= PGC_S_INTERACTIVE)
162 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
163 errmsg("unrecognized \"datestyle\" key word: \"%s\"",
175 if (source >= PGC_S_INTERACTIVE)
177 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
178 errmsg("conflicting \"datestyle\" specifications")));
183 * If we aren't going to do the assignment, just return OK indicator.
189 * Prepare the canonical string to return. GUC wants it malloc'd.
191 result = (char *) malloc(32);
195 switch (newDateStyle)
198 strcpy(result, "ISO");
201 strcpy(result, "SQL");
203 case USE_GERMAN_DATES:
204 strcpy(result, "German");
207 strcpy(result, "Postgres");
210 switch (newDateOrder)
213 strcat(result, ", YMD");
216 strcat(result, ", DMY");
219 strcat(result, ", MDY");
224 * Finally, it's safe to assign to the global variables; the assignment
227 DateStyle = newDateStyle;
228 DateOrder = newDateOrder;
239 * assign_timezone: GUC assign_hook for timezone
242 assign_timezone(const char *value, bool doit, GucSource source)
249 * Check for INTERVAL 'foo'
251 if (pg_strncasecmp(value, "interval", 8) == 0)
253 const char *valueptr = value;
258 while (isspace((unsigned char) *valueptr))
260 if (*valueptr++ != '\'')
262 val = pstrdup(valueptr);
263 /* Check and remove trailing quote */
264 endptr = strchr(val, '\'');
265 if (!endptr || endptr[1] != '\0')
273 * Try to parse it. XXX an invalid interval format will result in
274 * ereport, which is not desirable for GUC. We did what we could to
275 * guard against this in flatten_set_variable_args, but a string
276 * coming in from postgresql.conf might contain anything.
278 interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
279 CStringGetDatum(val),
280 ObjectIdGetDatum(InvalidOid),
284 if (interval->month != 0)
286 if (source >= PGC_S_INTERACTIVE)
288 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
289 errmsg("invalid interval value for time zone: month not allowed")));
293 if (interval->day != 0)
295 if (source >= PGC_S_INTERACTIVE)
297 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
298 errmsg("invalid interval value for time zone: day not allowed")));
304 /* Here we change from SQL to Unix sign convention */
305 #ifdef HAVE_INT64_TIMESTAMP
306 CTimeZone = -(interval->time / USECS_PER_SEC);
308 CTimeZone = -interval->time;
318 * Try it as a numeric number of hours (possibly fractional).
320 hours = strtod(value, &endptr);
321 if (endptr != value && *endptr == '\0')
325 /* Here we change from SQL to Unix sign convention */
326 CTimeZone = -hours * SECS_PER_HOUR;
330 else if (pg_strcasecmp(value, "UNKNOWN") == 0)
333 * UNKNOWN is the value shown as the "default" for TimeZone in
334 * guc.c. We interpret it as being a complete no-op; we don't
335 * change the timezone setting. Note that if there is a known
336 * timezone setting, we will return that name rather than UNKNOWN
337 * as the canonical spelling.
339 * During GUC initialization, since the timezone library isn't set
340 * up yet, pg_get_timezone_name will return NULL and we will leave
341 * the setting as UNKNOWN. If this isn't overridden from the
342 * config file then pg_timezone_initialize() will eventually
343 * select a default value from the environment.
347 const char *curzone = pg_get_timezone_name(session_timezone);
356 * Otherwise assume it is a timezone name, and try to load it.
360 new_tz = pg_tzset(value);
364 ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
365 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
366 errmsg("unrecognized time zone name: \"%s\"",
371 if (!tz_acceptable(new_tz))
373 ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
374 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
375 errmsg("time zone \"%s\" appears to use leap seconds",
377 errdetail("PostgreSQL does not support leap seconds.")));
383 /* Save the changed TZ */
384 session_timezone = new_tz;
391 * If we aren't going to do the assignment, just return OK indicator.
397 * Prepare the canonical string to return. GUC wants it malloc'd.
401 result = (char *) malloc(64);
404 snprintf(result, 64, "%.5f",
405 (double) (-CTimeZone) / (double) SECS_PER_HOUR);
408 result = strdup(value);
414 * show_timezone: GUC show_hook for timezone
427 #ifdef HAVE_INT64_TIMESTAMP
428 interval.time = -(CTimeZone * USECS_PER_SEC);
430 interval.time = -CTimeZone;
433 tzn = DatumGetCString(DirectFunctionCall1(interval_out,
434 IntervalPGetDatum(&interval)));
437 tzn = pg_get_timezone_name(session_timezone);
449 * For log_timezone, we don't support the interval-based methods of setting a
450 * zone, which are only there for SQL spec compliance not because they're
455 * assign_log_timezone: GUC assign_hook for log_timezone
458 assign_log_timezone(const char *value, bool doit, GucSource source)
462 if (pg_strcasecmp(value, "UNKNOWN") == 0)
465 * UNKNOWN is the value shown as the "default" for log_timezone in
466 * guc.c. We interpret it as being a complete no-op; we don't change
467 * the timezone setting. Note that if there is a known timezone
468 * setting, we will return that name rather than UNKNOWN as the
469 * canonical spelling.
471 * During GUC initialization, since the timezone library isn't set up
472 * yet, pg_get_timezone_name will return NULL and we will leave the
473 * setting as UNKNOWN. If this isn't overridden from the config file
474 * then pg_timezone_initialize() will eventually select a default
475 * value from the environment.
479 const char *curzone = pg_get_timezone_name(log_timezone);
488 * Otherwise assume it is a timezone name, and try to load it.
492 new_tz = pg_tzset(value);
496 ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
497 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
498 errmsg("unrecognized time zone name: \"%s\"",
503 if (!tz_acceptable(new_tz))
505 ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
506 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
507 errmsg("time zone \"%s\" appears to use leap seconds",
509 errdetail("PostgreSQL does not support leap seconds.")));
515 /* Save the changed TZ */
516 log_timezone = new_tz;
521 * If we aren't going to do the assignment, just return OK indicator.
527 * Prepare the canonical string to return. GUC wants it malloc'd.
529 result = strdup(value);
535 * show_log_timezone: GUC show_hook for log_timezone
538 show_log_timezone(void)
542 tzn = pg_get_timezone_name(log_timezone);
552 * SET TRANSACTION ISOLATION LEVEL
556 assign_XactIsoLevel(const char *value, bool doit, GucSource source)
558 if (SerializableSnapshot != NULL)
560 if (source >= PGC_S_INTERACTIVE)
562 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
563 errmsg("SET TRANSACTION ISOLATION LEVEL must be called before any query")));
564 /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
565 else if (source != PGC_S_OVERRIDE)
568 if (IsSubTransaction())
570 if (source >= PGC_S_INTERACTIVE)
572 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
573 errmsg("SET TRANSACTION ISOLATION LEVEL must not be called in a subtransaction")));
574 /* source == PGC_S_OVERRIDE means do it anyway, eg at xact abort */
575 else if (source != PGC_S_OVERRIDE)
579 if (strcmp(value, "serializable") == 0)
582 XactIsoLevel = XACT_SERIALIZABLE;
584 else if (strcmp(value, "repeatable read") == 0)
587 XactIsoLevel = XACT_REPEATABLE_READ;
589 else if (strcmp(value, "read committed") == 0)
592 XactIsoLevel = XACT_READ_COMMITTED;
594 else if (strcmp(value, "read uncommitted") == 0)
597 XactIsoLevel = XACT_READ_UNCOMMITTED;
599 else if (strcmp(value, "default") == 0)
602 XactIsoLevel = DefaultXactIsoLevel;
611 show_XactIsoLevel(void)
613 switch (XactIsoLevel)
615 case XACT_READ_UNCOMMITTED:
616 return "read uncommitted";
617 case XACT_READ_COMMITTED:
618 return "read committed";
619 case XACT_REPEATABLE_READ:
620 return "repeatable read";
621 case XACT_SERIALIZABLE:
622 return "serializable";
634 assign_random_seed(double value, bool doit, GucSource source)
636 /* Can't really roll back on error, so ignore non-interactive setting */
637 if (doit && source >= PGC_S_INTERACTIVE)
638 DirectFunctionCall1(setseed, Float8GetDatum(value));
643 show_random_seed(void)
645 return "unavailable";
650 * encoding handling functions
654 assign_client_encoding(const char *value, bool doit, GucSource source)
658 encoding = pg_valid_client_encoding(value);
663 * Note: if we are in startup phase then SetClientEncoding may not be able
664 * to really set the encoding. In this case we will assume that the
665 * encoding is okay, and InitializeClientEncoding() will fix things once
666 * initialization is complete.
668 if (SetClientEncoding(encoding, doit) < 0)
670 if (source >= PGC_S_INTERACTIVE)
672 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
673 errmsg("conversion between %s and %s is not supported",
674 value, GetDatabaseEncodingName())));
682 * SET SESSION AUTHORIZATION
684 * When resetting session auth after an error, we can't expect to do catalog
685 * lookups. Hence, the stored form of the value must provide a numeric oid
686 * that can be re-used directly. We store the string in the form of
687 * NAMEDATALEN 'x's, followed by T or F to indicate superuserness, followed
688 * by the numeric oid, followed by a comma, followed by the role name.
689 * This cannot be confused with a plain role name because of the NAMEDATALEN
690 * limit on names, so we can tell whether we're being passed an initial
691 * role name or a saved/restored value. (NOTE: we rely on guc.c to have
692 * properly truncated any incoming value, but not to truncate already-stored
693 * values. See GUC_IS_NAME processing.)
695 extern char *session_authorization_string; /* in guc.c */
698 assign_session_authorization(const char *value, bool doit, GucSource source)
700 Oid roleid = InvalidOid;
701 bool is_superuser = false;
702 const char *actual_rolename = NULL;
705 if (strspn(value, "x") == NAMEDATALEN &&
706 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
708 /* might be a saved userid string */
712 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
714 if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
716 /* syntactically valid, so break out the data */
718 is_superuser = (value[NAMEDATALEN] == 'T');
719 actual_rolename = endptr + 1;
723 if (roleid == InvalidOid)
725 /* not a saved ID, so look it up */
728 if (!IsTransactionState())
731 * Can't do catalog lookups, so fail. The upshot of this is that
732 * session_authorization cannot be set in postgresql.conf, which
733 * seems like a good thing anyway.
738 roleTup = SearchSysCache(AUTHNAME,
739 PointerGetDatum(value),
741 if (!HeapTupleIsValid(roleTup))
743 if (source >= PGC_S_INTERACTIVE)
745 (errcode(ERRCODE_UNDEFINED_OBJECT),
746 errmsg("role \"%s\" does not exist", value)));
750 roleid = HeapTupleGetOid(roleTup);
751 is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
752 actual_rolename = value;
754 ReleaseSysCache(roleTup);
758 SetSessionAuthorization(roleid, is_superuser);
760 result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
764 memset(result, 'x', NAMEDATALEN);
766 sprintf(result + NAMEDATALEN, "%c%u,%s",
767 is_superuser ? 'T' : 'F',
775 show_session_authorization(void)
778 * Extract the user name from the stored string; see
779 * assign_session_authorization
781 const char *value = session_authorization_string;
785 Assert(strspn(value, "x") == NAMEDATALEN &&
786 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
788 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
790 Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
799 * When resetting session auth after an error, we can't expect to do catalog
800 * lookups. Hence, the stored form of the value must provide a numeric oid
801 * that can be re-used directly. We implement this exactly like SET
802 * SESSION AUTHORIZATION.
804 * The SQL spec requires "SET ROLE NONE" to unset the role, so we hardwire
805 * a translation of "none" to InvalidOid.
807 extern char *role_string; /* in guc.c */
810 assign_role(const char *value, bool doit, GucSource source)
812 Oid roleid = InvalidOid;
813 bool is_superuser = false;
814 const char *actual_rolename = value;
817 if (strspn(value, "x") == NAMEDATALEN &&
818 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'))
820 /* might be a saved userid string */
824 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
826 if (endptr != value + NAMEDATALEN + 1 && *endptr == ',')
828 /* syntactically valid, so break out the data */
830 is_superuser = (value[NAMEDATALEN] == 'T');
831 actual_rolename = endptr + 1;
835 if (roleid == InvalidOid &&
836 strcmp(actual_rolename, "none") != 0)
838 /* not a saved ID, so look it up */
841 if (!IsTransactionState())
844 * Can't do catalog lookups, so fail. The upshot of this is that
845 * role cannot be set in postgresql.conf, which seems like a good
851 roleTup = SearchSysCache(AUTHNAME,
852 PointerGetDatum(value),
854 if (!HeapTupleIsValid(roleTup))
856 if (source >= PGC_S_INTERACTIVE)
858 (errcode(ERRCODE_UNDEFINED_OBJECT),
859 errmsg("role \"%s\" does not exist", value)));
863 roleid = HeapTupleGetOid(roleTup);
864 is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
866 ReleaseSysCache(roleTup);
869 * Verify that session user is allowed to become this role
871 if (!is_member_of_role(GetSessionUserId(), roleid))
873 if (source >= PGC_S_INTERACTIVE)
875 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
876 errmsg("permission denied to set role \"%s\"",
883 SetCurrentRoleId(roleid, is_superuser);
885 result = (char *) malloc(NAMEDATALEN + 32 + strlen(actual_rolename));
889 memset(result, 'x', NAMEDATALEN);
891 sprintf(result + NAMEDATALEN, "%c%u,%s",
892 is_superuser ? 'T' : 'F',
903 * Extract the role name from the stored string; see assign_role
905 const char *value = role_string;
909 /* This special case only applies if no SET ROLE has been done */
910 if (value == NULL || strcmp(value, "none") == 0)
913 Assert(strspn(value, "x") == NAMEDATALEN &&
914 (value[NAMEDATALEN] == 'T' || value[NAMEDATALEN] == 'F'));
916 savedoid = (Oid) strtoul(value + NAMEDATALEN + 1, &endptr, 10);
918 Assert(endptr != value + NAMEDATALEN + 1 && *endptr == ',');
921 * Check that the stored string still matches the effective setting, else
922 * return "none". This is a kluge to deal with the fact that SET SESSION
923 * AUTHORIZATION logically resets SET ROLE to NONE, but we cannot set the
924 * GUC role variable from assign_session_authorization (because we haven't
925 * got enough info to call set_config_option).
927 if (savedoid != GetCurrentRoleId())