1 /*-------------------------------------------------------------------------
4 * Routines for handling of 'SET var TO',
5 * 'SHOW var' and 'RESET var' statements.
7 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.61 2002/03/29 19:06:07 tgl Exp $
14 *-------------------------------------------------------------------------
22 #include "access/xact.h"
23 #include "catalog/pg_shadow.h"
24 #include "catalog/pg_type.h"
25 #include "commands/variable.h"
26 #include "miscadmin.h"
27 #include "optimizer/cost.h"
28 #include "optimizer/paths.h"
29 #include "parser/parse_type.h"
30 #include "utils/builtins.h"
31 #include "utils/date.h"
32 #include "utils/guc.h"
33 #include "utils/tqual.h"
36 #include "mb/pg_wchar.h"
38 /* Grand unified hard-coded badness */
39 #define pg_get_client_encoding_name() "SQL_ASCII"
40 #define GetDatabaseEncodingName() "SQL_ASCII"
44 static bool show_datestyle(void);
45 static bool reset_datestyle(void);
46 static bool parse_datestyle(List *);
47 static bool show_timezone(void);
48 static bool reset_timezone(void);
49 static bool parse_timezone(List *);
51 static bool show_XactIsoLevel(void);
52 static bool reset_XactIsoLevel(void);
53 static bool parse_XactIsoLevel(List *);
54 static bool show_random_seed(void);
55 static bool reset_random_seed(void);
56 static bool parse_random_seed(List *);
58 static bool show_client_encoding(void);
59 static bool reset_client_encoding(void);
60 static bool parse_client_encoding(List *);
61 static bool show_server_encoding(void);
62 static bool reset_server_encoding(void);
63 static bool parse_server_encoding(List *);
68 * Obtain the next item in a comma-separated list of items,
69 * where each item can be either "word" or "word=word".
70 * The "word=word" form is only accepted if 'val' is not NULL.
71 * Words are any sequences not containing whitespace, ',', or '='.
72 * Whitespace can appear between the words and punctuation.
74 * 'tok': receives a pointer to first word of item, or NULL if none.
75 * 'val': if not NULL, receives a pointer to second word, or NULL if none.
76 * 'str': start of input string.
78 * Returns NULL if input string contained no more words, else pointer
79 * to just past this item, which can be used as 'str' for next call.
80 * (If this is the last item, returned pointer will point at a null char,
81 * so caller can alternatively check for that instead of calling again.)
83 * NB: input string is destructively modified by placing null characters
86 * A former version of this code avoided modifying the input string by
87 * returning palloc'd copies of the words. However, we want to use this
88 * code early in backend startup to parse the PGDATESTYLE environment var,
89 * and palloc/pfree aren't initialized at that point. Cleanest answer
90 * seems to be to palloc in SetPGVariable() so that we can treat the string
94 get_token(char **tok, char **val, char *str)
102 if (!str || *str == '\0')
105 /* skip leading white space */
106 while (isspace((unsigned char) *str))
109 /* end of string? then return NULL */
113 if (*str == ',' || *str == '=')
114 elog(ERROR, "Syntax error near \"%s\": empty setting", str);
116 /* OK, at beginning of non-empty item */
119 /* Advance to end of word */
120 while (*str && !isspace((unsigned char) *str) &&
121 *str != ',' && *str != '=')
124 /* Terminate word string for caller */
128 /* Skip any whitespace */
129 while (isspace((unsigned char) ch))
139 /* Had better be '=', and caller must be expecting it */
140 if (val == NULL || ch != '=')
141 elog(ERROR, "Syntax error near \"%s\"", str);
143 /* '=': get the value */
146 /* skip whitespace after '=' */
147 while (isspace((unsigned char) *str))
150 if (*str == ',' || *str == '\0')
151 elog(ERROR, "Syntax error near \"=%s\"", str);
153 /* OK, at beginning of non-empty value */
156 /* Advance to end of word */
157 while (*str && !isspace((unsigned char) *str) && *str != ',')
160 /* Terminate word string for caller */
164 /* Skip any whitespace */
165 while (isspace((unsigned char) ch))
175 elog(ERROR, "Syntax error near \"%s\"", str);
184 * NOTE: set_default_datestyle() is called during backend startup to check
185 * if the PGDATESTYLE environment variable is set. We want the env var
186 * to determine the value that "RESET DateStyle" will reset to!
189 /* These get initialized from the "master" values in init/globals.c */
190 static int DefaultDateStyle;
191 static bool DefaultEuroDates;
194 parse_datestyle_internal(char *value)
201 return reset_datestyle();
203 while ((value = get_token(&tok, NULL, value)) != 0)
205 /* Ugh. Somebody ought to write a table driven version -- mjl */
207 if (!strcasecmp(tok, "ISO"))
209 DateStyle = USE_ISO_DATES;
212 else if (!strcasecmp(tok, "SQL"))
214 DateStyle = USE_SQL_DATES;
217 else if (!strncasecmp(tok, "POSTGRESQL", 8))
219 DateStyle = USE_POSTGRES_DATES;
222 else if (!strcasecmp(tok, "GERMAN"))
224 DateStyle = USE_GERMAN_DATES;
227 if ((ecnt > 0) && (!EuroDates))
230 else if (!strncasecmp(tok, "EURO", 4))
233 if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES))
236 else if ((!strcasecmp(tok, "US"))
237 || (!strncasecmp(tok, "NONEURO", 7)))
240 if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES))
243 else if (!strcasecmp(tok, "DEFAULT"))
245 DateStyle = DefaultDateStyle;
246 EuroDates = DefaultEuroDates;
250 elog(ERROR, "Bad value for date style (%s)", tok);
253 if (dcnt > 1 || ecnt > 1)
254 elog(WARNING, "Conflicting settings for date");
260 parse_datestyle(List *args)
265 return reset_datestyle();
267 Assert(IsA(lfirst(args), A_Const));
269 value = ((A_Const *) lfirst(args))->val.val.str;
271 return parse_datestyle_internal(value);
279 strcpy(buf, "DateStyle is ");
288 case USE_GERMAN_DATES:
289 strcat(buf, "German");
292 strcat(buf, "Postgres");
295 strcat(buf, " with ");
296 strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
297 strcat(buf, " conventions");
299 elog(INFO, buf, NULL);
305 reset_datestyle(void)
307 DateStyle = DefaultDateStyle;
308 EuroDates = DefaultEuroDates;
314 set_default_datestyle(void)
319 * Initialize from compile-time defaults in init/globals.c. NB: this
320 * is a necessary step; consider PGDATESTYLE="DEFAULT".
322 DefaultDateStyle = DateStyle;
323 DefaultEuroDates = EuroDates;
325 /* If the environment var is set, override compiled-in values */
326 DBDate = getenv("PGDATESTYLE");
331 * Make a modifiable copy --- overwriting the env var doesn't seem
332 * like a good idea, even though we currently won't look at it again.
333 * Note that we cannot use palloc at this early stage of
336 DBDate = strdup(DBDate);
339 * Parse desired setting into DateStyle/EuroDates Use
340 * parse_datestyle_internal() to avoid any palloc() issues per above -
343 parse_datestyle_internal(DBDate);
347 /* And make it the default for future RESETs */
348 DefaultDateStyle = DateStyle;
349 DefaultEuroDates = EuroDates;
354 * Working storage for strings is allocated with an arbitrary size of 64 bytes.
357 static char *defaultTZ = NULL;
358 static char TZvalue[64];
359 static char tzbuf[64];
367 * Handle SET TIME ZONE...
368 * Try to save existing TZ environment variable for later use in RESET TIME ZONE.
369 * Accept an explicit interval per SQL9x, though this is less useful than a full time zone.
370 * - thomas 2001-10-11
373 parse_timezone(List *args)
379 return reset_timezone();
381 Assert(IsA(args, List));
387 Assert(IsA(arg, List));
389 Assert(IsA(p, A_Const));
394 Oid typeOid = typenameTypeId(type);
396 if (typeOid == INTERVALOID)
400 interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
401 CStringGetDatum(p->val.val.str),
402 ObjectIdGetDatum(InvalidOid),
403 Int32GetDatum(type->typmod)));
404 if (interval->month != 0)
405 elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
406 CTimeZone = interval->time;
408 else if (typeOid == FLOAT8OID)
412 time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
413 CTimeZone = time * 3600;
417 * We do not actually generate an integer constant in gram.y
418 * so this is not used...
420 else if (typeOid == INT4OID)
424 time = p->val.val.ival;
425 CTimeZone = time * 3600;
429 elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error");
439 value = p->val.val.str;
441 while ((value = get_token(&tok, NULL, value)) != 0)
443 /* Not yet tried to save original value from environment? */
444 if (defaultTZ == NULL)
446 /* found something? then save it for later */
447 if ((defaultTZ = getenv("TZ")) != NULL)
448 strcpy(TZvalue, defaultTZ);
450 /* found nothing so mark with an invalid pointer */
452 defaultTZ = (char *) -1;
455 strcpy(tzbuf, "TZ=");
457 if (putenv(tzbuf) != 0)
458 elog(ERROR, "Unable to set TZ environment variable to %s", tok);
468 } /* parse_timezone() */
480 interval.time = CTimeZone;
482 tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval)));
488 elog(INFO, "Time zone is '%s'", tzn);
490 elog(INFO, "Time zone is unset");
493 } /* show_timezone() */
496 * Set TZ environment variable to original value.
497 * Note that if TZ was originally not set, TZ should be cleared.
498 * unsetenv() works fine, but is BSD, not POSIX, and is not available
499 * under Solaris, among others. Apparently putenv() called as below
500 * clears the process-specific environment variables.
501 * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
502 * in a core dump (under Linux anyway).
503 * - thomas 1998-01-26
511 /* no time zone has been set in this session? */
512 else if (defaultTZ == NULL)
516 /* time zone was set and original explicit time zone available? */
517 else if (defaultTZ != (char *) -1)
519 strcpy(tzbuf, "TZ=");
520 strcat(tzbuf, TZvalue);
521 if (putenv(tzbuf) != 0)
522 elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
527 * otherwise, time zone was set but no original explicit time zone
533 if (putenv(tzbuf) != 0)
534 elog(ERROR, "Unable to clear TZ environment variable");
539 } /* reset_timezone() */
550 parse_XactIsoLevel(List *args)
555 return reset_XactIsoLevel();
557 Assert(IsA(lfirst(args), A_Const));
559 value = ((A_Const *) lfirst(args))->val.val.str;
561 if (SerializableSnapshot != NULL)
563 elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
567 if (strcmp(value, "serializable") == 0)
568 XactIsoLevel = XACT_SERIALIZABLE;
569 else if (strcmp(value, "read committed") == 0)
570 XactIsoLevel = XACT_READ_COMMITTED;
572 elog(ERROR, "invalid transaction isolation level: %s", value);
578 show_XactIsoLevel(void)
581 if (XactIsoLevel == XACT_SERIALIZABLE)
582 elog(INFO, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
584 elog(INFO, "TRANSACTION ISOLATION LEVEL is READ COMMITTED");
589 reset_XactIsoLevel(void)
592 if (SerializableSnapshot != NULL)
594 elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
598 XactIsoLevel = DefaultXactIsoLevel;
608 parse_random_seed(List *args)
614 return reset_random_seed();
616 Assert(IsA(lfirst(args), A_Const));
618 value = ((A_Const *) lfirst(args))->val.val.str;
620 sscanf(value, "%lf", &seed);
621 DirectFunctionCall1(setseed, Float8GetDatum(seed));
627 show_random_seed(void)
629 elog(INFO, "Seed for random number generator is unavailable");
634 reset_random_seed(void)
638 DirectFunctionCall1(setseed, Float8GetDatum(seed));
644 * MULTIBYTE-related functions
646 * If MULTIBYTE support was not compiled, we still allow these variables
647 * to exist, but you can't set them to anything but "SQL_ASCII". This
648 * minimizes interoperability problems between non-MB servers and MB-enabled
653 parse_client_encoding(List *args)
662 return reset_client_encoding();
664 Assert(IsA(lfirst(args), A_Const));
666 value = ((A_Const *) lfirst(args))->val.val.str;
669 encoding = pg_valid_client_encoding(value);
673 elog(ERROR, "Client encoding '%s' is not supported", value);
675 elog(ERROR, "No client encoding is specified");
679 if (pg_set_client_encoding(encoding) < 0)
681 elog(ERROR, "Conversion between %s and %s is not supported",
682 value, GetDatabaseEncodingName());
687 strcasecmp(value, pg_get_client_encoding_name()) != 0)
688 elog(ERROR, "Client encoding %s is not supported", value);
694 show_client_encoding(void)
696 elog(INFO, "Current client encoding is '%s'",
697 pg_get_client_encoding_name());
702 reset_client_encoding(void)
706 char *env = getenv("PGCLIENTENCODING");
710 encoding = pg_char_to_encoding(env);
712 encoding = GetDatabaseEncoding();
715 encoding = GetDatabaseEncoding();
717 pg_set_client_encoding(encoding);
722 /* Called during MULTIBYTE backend startup ... */
724 set_default_client_encoding(void)
726 reset_client_encoding();
731 parse_server_encoding(List *args)
733 elog(INFO, "SET SERVER_ENCODING is not supported");
738 show_server_encoding(void)
740 elog(INFO, "Current server encoding is '%s'", GetDatabaseEncodingName());
745 reset_server_encoding(void)
747 elog(INFO, "RESET SERVER_ENCODING is not supported");
754 * Dispatcher for handling SET commands.
755 * Special cases ought to be removed and handled separately by TCOP
758 SetPGVariable(const char *name, List *args)
760 if (strcasecmp(name, "datestyle") == 0)
761 parse_datestyle(args);
762 else if (strcasecmp(name, "timezone") == 0)
763 parse_timezone(args);
764 else if (strcasecmp(name, "XactIsoLevel") == 0)
765 parse_XactIsoLevel(args);
766 else if (strcasecmp(name, "client_encoding") == 0)
767 parse_client_encoding(args);
768 else if (strcasecmp(name, "server_encoding") == 0)
769 parse_server_encoding(args);
770 else if (strcasecmp(name, "seed") == 0)
771 parse_random_seed(args);
775 * For routines defined somewhere else, go ahead and extract the
776 * string argument to match the original interface definition.
777 * Later, we can change this code too...
781 value = ((args != NULL) ? ((A_Const *) lfirst(args))->val.val.str : NULL);
783 if (strcasecmp(name, "session_authorization") == 0)
784 SetSessionAuthorization(value);
786 SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET, PGC_S_SESSION);
792 GetPGVariable(const char *name)
794 if (strcasecmp(name, "datestyle") == 0)
796 else if (strcasecmp(name, "timezone") == 0)
798 else if (strcasecmp(name, "XactIsoLevel") == 0)
800 else if (strcasecmp(name, "client_encoding") == 0)
801 show_client_encoding();
802 else if (strcasecmp(name, "server_encoding") == 0)
803 show_server_encoding();
804 else if (strcasecmp(name, "seed") == 0)
806 else if (strcasecmp(name, "all") == 0)
812 show_client_encoding();
813 show_server_encoding();
818 const char *val = GetConfigOption(name);
820 elog(INFO, "%s is %s", name, val);
825 ResetPGVariable(const char *name)
827 if (strcasecmp(name, "datestyle") == 0)
829 else if (strcasecmp(name, "timezone") == 0)
831 else if (strcasecmp(name, "XactIsoLevel") == 0)
832 reset_XactIsoLevel();
833 else if (strcasecmp(name, "client_encoding") == 0)
834 reset_client_encoding();
835 else if (strcasecmp(name, "server_encoding") == 0)
836 reset_server_encoding();
837 else if (strcasecmp(name, "seed") == 0)
839 else if (strcasecmp(name, "all") == 0)
842 /* reset_server_encoding(); */
843 reset_client_encoding();
847 ResetAllOptions(false);
850 SetConfigOption(name, NULL,
851 superuser() ? PGC_SUSET : PGC_USERSET,