1 /*-------------------------------------------------------------------------
4 * Routines for handling of 'SET var TO',
5 * 'SHOW var' and 'RESET var' statements.
7 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.42 2000/10/25 19:44:44 tgl Exp $
14 *-------------------------------------------------------------------------
22 #include "access/xact.h"
23 #include "catalog/pg_shadow.h"
24 #include "commands/variable.h"
25 #include "miscadmin.h"
26 #include "optimizer/cost.h"
27 #include "optimizer/paths.h"
28 #include "parser/parse_expr.h"
29 #include "utils/builtins.h"
30 #include "utils/guc.h"
31 #include "utils/tqual.h"
34 #include "mb/pg_wchar.h"
36 /* Grand unified hard-coded badness */
37 #define pg_encoding_to_char(x) "SQL_ASCII"
38 #define pg_get_client_encoding() 0
42 static bool show_date(void);
43 static bool reset_date(void);
44 static bool parse_date(char *);
45 static bool show_timezone(void);
46 static bool reset_timezone(void);
47 static bool parse_timezone(char *);
49 static bool show_DefaultXactIsoLevel(void);
50 static bool reset_DefaultXactIsoLevel(void);
51 static bool parse_DefaultXactIsoLevel(char *);
52 static bool show_XactIsoLevel(void);
53 static bool reset_XactIsoLevel(void);
54 static bool parse_XactIsoLevel(char *);
55 static bool parse_random_seed(char *);
56 static bool show_random_seed(void);
57 static bool reset_random_seed(void);
59 static bool show_client_encoding(void);
60 static bool reset_client_encoding(void);
61 static bool parse_client_encoding(char *);
62 static bool show_server_encoding(void);
63 static bool reset_server_encoding(void);
64 static bool parse_server_encoding(char *);
69 * Obtain the next item in a comma-separated list of items,
70 * where each item can be either "word" or "word=word".
71 * The "word=word" form is only accepted if 'val' is not NULL.
72 * Words are any sequences not containing whitespace, ',', or '='.
73 * Whitespace can appear between the words and punctuation.
75 * 'tok': receives a pointer to first word of item, or NULL if none.
76 * 'val': if not NULL, receives a pointer to second word, or NULL if none.
77 * 'str': start of input string.
79 * Returns NULL if input string contained no more words, else pointer
80 * to just past this item, which can be used as 'str' for next call.
81 * (If this is the last item, returned pointer will point at a null char,
82 * so caller can alternatively check for that instead of calling again.)
84 * NB: input string is destructively modified by placing null characters
87 * A former version of this code avoided modifying the input string by
88 * returning palloc'd copies of the words. However, we want to use this
89 * code early in backend startup to parse the PGDATESTYLE environment var,
90 * and palloc/pfree aren't initialized at that point. Cleanest answer
91 * seems to be to palloc in SetPGVariable() so that we can treat the string
95 get_token(char **tok, char **val, char *str)
103 if (!str || *str == '\0')
106 /* skip leading white space */
107 while (isspace((int) *str))
110 /* end of string? then return NULL */
114 if (*str == ',' || *str == '=')
115 elog(ERROR, "Syntax error near \"%s\": empty setting", str);
117 /* OK, at beginning of non-empty item */
120 /* Advance to end of word */
121 while (*str && !isspace((int) *str) && *str != ',' && *str != '=')
124 /* Terminate word string for caller */
128 /* Skip any whitespace */
129 while (isspace((int) 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((int) *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((int) *str) && *str != ',')
160 /* Terminate word string for caller */
164 /* Skip any whitespace */
165 while (isspace((int) 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_date(char *value)
206 while ((value = get_token(&tok, NULL, value)) != 0)
208 /* Ugh. Somebody ought to write a table driven version -- mjl */
210 if (!strcasecmp(tok, "ISO"))
212 DateStyle = USE_ISO_DATES;
215 else if (!strcasecmp(tok, "SQL"))
217 DateStyle = USE_SQL_DATES;
220 else if (!strcasecmp(tok, "POSTGRES"))
222 DateStyle = USE_POSTGRES_DATES;
225 else if (!strcasecmp(tok, "GERMAN"))
227 DateStyle = USE_GERMAN_DATES;
230 if ((ecnt > 0) && (!EuroDates))
233 else if (!strncasecmp(tok, "EURO", 4))
236 if ((dcnt <= 0) || (DateStyle != USE_GERMAN_DATES))
239 else if ((!strcasecmp(tok, "US"))
240 || (!strncasecmp(tok, "NONEURO", 7)))
243 if ((dcnt <= 0) || (DateStyle == USE_GERMAN_DATES))
246 else if (!strcasecmp(tok, "DEFAULT"))
248 DateStyle = DefaultDateStyle;
249 EuroDates = DefaultEuroDates;
253 elog(ERROR, "Bad value for date style (%s)", tok);
256 if (dcnt > 1 || ecnt > 1)
257 elog(NOTICE, "Conflicting settings for date");
267 strcpy(buf, "DateStyle is ");
276 case USE_GERMAN_DATES:
277 strcat(buf, "German");
280 strcat(buf, "Postgres");
283 strcat(buf, " with ");
284 strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
285 strcat(buf, " conventions");
287 elog(NOTICE, buf, NULL);
295 DateStyle = DefaultDateStyle;
296 EuroDates = DefaultEuroDates;
302 set_default_datestyle(void)
307 * Initialize from compile-time defaults in init/globals.c. NB: this
308 * is a necessary step; consider PGDATESTYLE="DEFAULT".
310 DefaultDateStyle = DateStyle;
311 DefaultEuroDates = EuroDates;
313 /* If the environment var is set, override compiled-in values */
314 DBDate = getenv("PGDATESTYLE");
319 * Make a modifiable copy --- overwriting the env var doesn't seem
320 * like a good idea, even though we currently won't look at it again.
321 * Note that we cannot use palloc at this early stage of
324 DBDate = strdup(DBDate);
326 /* Parse desired setting into DateStyle/EuroDates */
331 /* And make it the default for future RESETs */
332 DefaultDateStyle = DateStyle;
333 DefaultEuroDates = EuroDates;
338 * Working storage for strings is allocated with an arbitrary size of 64 bytes.
341 static char *defaultTZ = NULL;
342 static char TZvalue[64];
343 static char tzbuf[64];
351 * Handle SET TIME ZONE...
352 * Try to save existing TZ environment variable for later use in RESET TIME ZONE.
353 * - thomas 1997-11-10
356 parse_timezone(char *value)
366 while ((value = get_token(&tok, NULL, value)) != 0)
368 /* Not yet tried to save original value from environment? */
369 if (defaultTZ == NULL)
371 /* found something? then save it for later */
372 if ((defaultTZ = getenv("TZ")) != NULL)
373 strcpy(TZvalue, defaultTZ);
375 /* found nothing so mark with an invalid pointer */
377 defaultTZ = (char *) -1;
380 strcpy(tzbuf, "TZ=");
382 if (putenv(tzbuf) != 0)
383 elog(ERROR, "Unable to set TZ environment variable to %s", tok);
389 } /* parse_timezone() */
398 elog(NOTICE, "Time zone is %s", ((tz != NULL) ? tz : "unknown"));
401 } /* show_timezone() */
404 * Set TZ environment variable to original value.
405 * Note that if TZ was originally not set, TZ should be cleared.
406 * unsetenv() works fine, but is BSD, not POSIX, and is not available
407 * under Solaris, among others. Apparently putenv() called as below
408 * clears the process-specific environment variables.
409 * Other reasonable arguments to putenv() (e.g. "TZ=", "TZ", "") result
410 * in a core dump (under Linux anyway).
411 * - thomas 1998-01-26
416 /* no time zone has been set in this session? */
417 if (defaultTZ == NULL)
421 /* time zone was set and original explicit time zone available? */
422 else if (defaultTZ != (char *) -1)
424 strcpy(tzbuf, "TZ=");
425 strcat(tzbuf, TZvalue);
426 if (putenv(tzbuf) != 0)
427 elog(ERROR, "Unable to set TZ environment variable to %s", TZvalue);
432 * otherwise, time zone was set but no original explicit time zone
438 if (putenv(tzbuf) != 0)
439 elog(ERROR, "Unable to clear TZ environment variable");
444 } /* reset_timezone() */
448 /* SET TRANSACTION */
451 parse_DefaultXactIsoLevel(char *value)
454 TransactionState s = CurrentTransactionState;
459 reset_DefaultXactIsoLevel();
464 if (s->state != TRANS_DEFAULT)
466 elog(ERROR, "ALTER SESSION/SET TRANSACTION ISOLATION LEVEL"
467 " can not be called within a transaction");
472 if (strcasecmp(value, "SERIALIZABLE") == 0)
473 DefaultXactIsoLevel = XACT_SERIALIZABLE;
474 else if (strcasecmp(value, "COMMITTED") == 0)
475 DefaultXactIsoLevel = XACT_READ_COMMITTED;
477 elog(ERROR, "Bad TRANSACTION ISOLATION LEVEL (%s)", value);
483 show_DefaultXactIsoLevel(void)
486 if (DefaultXactIsoLevel == XACT_SERIALIZABLE)
487 elog(NOTICE, "Default TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
489 elog(NOTICE, "Default TRANSACTION ISOLATION LEVEL is READ COMMITTED");
494 reset_DefaultXactIsoLevel(void)
497 TransactionState s = CurrentTransactionState;
499 if (s->state != TRANS_DEFAULT)
501 elog(ERROR, "ALTER SESSION/SET TRANSACTION ISOLATION LEVEL"
502 " can not be called within a transaction");
507 DefaultXactIsoLevel = XACT_READ_COMMITTED;
513 parse_XactIsoLevel(char *value)
518 reset_XactIsoLevel();
522 if (SerializableSnapshot != NULL)
524 elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
529 if (strcasecmp(value, "SERIALIZABLE") == 0)
530 XactIsoLevel = XACT_SERIALIZABLE;
531 else if (strcasecmp(value, "COMMITTED") == 0)
532 XactIsoLevel = XACT_READ_COMMITTED;
534 elog(ERROR, "Bad TRANSACTION ISOLATION LEVEL (%s)", value);
540 show_XactIsoLevel(void)
543 if (XactIsoLevel == XACT_SERIALIZABLE)
544 elog(NOTICE, "TRANSACTION ISOLATION LEVEL is SERIALIZABLE");
546 elog(NOTICE, "TRANSACTION ISOLATION LEVEL is READ COMMITTED");
551 reset_XactIsoLevel(void)
554 if (SerializableSnapshot != NULL)
556 elog(ERROR, "SET TRANSACTION ISOLATION LEVEL must be called before any query");
560 XactIsoLevel = DefaultXactIsoLevel;
570 parse_random_seed(char *value)
578 sscanf(value, "%lf", &seed);
579 DirectFunctionCall1(setseed, Float8GetDatum(seed));
585 show_random_seed(void)
587 elog(NOTICE, "Seed for random number generator is not known");
592 reset_random_seed(void)
596 DirectFunctionCall1(setseed, Float8GetDatum(seed));
602 * MULTIBYTE-related functions
604 * If MULTIBYTE support was not compiled, we still allow these variables
605 * to exist, but you can't set them to anything but "SQL_ASCII". This
606 * minimizes interoperability problems between non-MB servers and MB-enabled
611 parse_client_encoding(char *value)
616 encoding = pg_valid_client_encoding(value);
620 elog(ERROR, "Client encoding %s is not supported", value);
622 elog(ERROR, "No client encoding is specified");
626 if (pg_set_client_encoding(encoding))
628 elog(ERROR, "Conversion between %s and %s is not supported",
629 value, pg_encoding_to_char(GetDatabaseEncoding()));
634 strcasecmp(value, pg_encoding_to_char(pg_get_client_encoding())) != 0)
635 elog(ERROR, "Client encoding %s is not supported", value);
641 show_client_encoding(void)
643 elog(NOTICE, "Current client encoding is %s",
644 pg_encoding_to_char(pg_get_client_encoding()));
649 reset_client_encoding(void)
653 char *env = getenv("PGCLIENTENCODING");
657 encoding = pg_char_to_encoding(env);
659 encoding = GetDatabaseEncoding();
662 encoding = GetDatabaseEncoding();
663 pg_set_client_encoding(encoding);
669 parse_server_encoding(char *value)
671 elog(NOTICE, "SET SERVER_ENCODING is not supported");
676 show_server_encoding(void)
678 elog(NOTICE, "Current server encoding is %s",
679 pg_encoding_to_char(GetDatabaseEncoding()));
684 reset_server_encoding(void)
686 elog(NOTICE, "RESET SERVER_ENCODING is not supported");
693 SetPGVariable(const char *name, const char *value)
695 char *mvalue = value ? pstrdup(value) : ((char*) NULL);
698 * Special cases ought to be removed and handled separately
701 if (strcasecmp(name, "datestyle")==0)
703 else if (strcasecmp(name, "timezone")==0)
704 parse_timezone(mvalue);
705 else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
706 parse_DefaultXactIsoLevel(mvalue);
707 else if (strcasecmp(name, "XactIsoLevel")==0)
708 parse_XactIsoLevel(mvalue);
709 else if (strcasecmp(name, "client_encoding")==0)
710 parse_client_encoding(mvalue);
711 else if (strcasecmp(name, "server_encoding")==0)
712 parse_server_encoding(mvalue);
713 else if (strcasecmp(name, "random_seed")==0)
714 parse_random_seed(mvalue);
716 SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET);
724 GetPGVariable(const char *name)
726 if (strcasecmp(name, "datestyle")==0)
728 else if (strcasecmp(name, "timezone")==0)
730 else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
731 show_DefaultXactIsoLevel();
732 else if (strcasecmp(name, "XactIsoLevel")==0)
734 else if (strcasecmp(name, "client_encoding")==0)
735 show_client_encoding();
736 else if (strcasecmp(name, "server_encoding")==0)
737 show_server_encoding();
738 else if (strcasecmp(name, "random_seed")==0)
742 const char * val = GetConfigOption(name);
743 elog(NOTICE, "%s is %s", name, val);
748 ResetPGVariable(const char *name)
750 if (strcasecmp(name, "datestyle")==0)
752 else if (strcasecmp(name, "timezone")==0)
754 else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
755 reset_DefaultXactIsoLevel();
756 else if (strcasecmp(name, "XactIsoLevel")==0)
757 reset_XactIsoLevel();
758 else if (strcasecmp(name, "client_encoding")==0)
759 reset_client_encoding();
760 else if (strcasecmp(name, "server_encoding")==0)
761 reset_server_encoding();
762 else if (strcasecmp(name, "random_seed")==0)
765 SetConfigOption(name, NULL, superuser() ? PGC_SUSET : PGC_USERSET);