1 /*-------------------------------------------------------------------------
4 * Routines for handling specialized SET variables.
7 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
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())