aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/variable.c
diff options
context:
space:
mode:
authorThomas G. Lockhart <lockhart@fourpalms.org>2001-10-18 17:30:21 +0000
committerThomas G. Lockhart <lockhart@fourpalms.org>2001-10-18 17:30:21 +0000
commit9310075a13c28fc77224094d2cf3cc1c03446b4a (patch)
tree64e430f8525c5782e26d3ddede403829836909c6 /src/backend/commands/variable.c
parent6254465d0621f724cdc9a1e99da24fa8a29f579d (diff)
downloadpostgresql-9310075a13c28fc77224094d2cf3cc1c03446b4a.tar.gz
postgresql-9310075a13c28fc77224094d2cf3cc1c03446b4a.zip
Accept an INTERVAL argument for SET TIME ZONE per SQL99.
Modified the parser and the SET handlers to use full Node structures rather than simply a character string argument. Implement INTERVAL() YEAR TO MONTH (etc) syntax per SQL99. Does not yet accept the goofy string format that goes along with, but this should be fairly straight forward to fix now as a bug or later as a feature. Implement precision for the INTERVAL() type. Use the typmod mechanism for both of INTERVAL features. Fix the INTERVAL syntax in the parser: opt_interval was in the wrong place. INTERVAL is now a reserved word, otherwise we get reduce/reduce errors. Implement an explicit date_part() function for TIMETZ. Should fix coersion problem with INTERVAL reported by Peter E. Fix up some error messages for date/time types. Use all caps for type names within message. Fix recently introduced side-effect bug disabling 'epoch' as a recognized field for date_part() etc. Reported by Peter E. (??) Bump catalog version number. Rename "microseconds" current transaction time field from ...Msec to ...Usec. Duh! date/time regression tests updated for reference platform, but a few changes will be necessary for others.
Diffstat (limited to 'src/backend/commands/variable.c')
-rw-r--r--src/backend/commands/variable.c293
1 files changed, 208 insertions, 85 deletions
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 029ea86a2bd..9da67760745 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.53 2001/09/19 15:19:12 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.54 2001/10/18 17:30:14 thomas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,7 @@
#include "optimizer/paths.h"
#include "parser/parse_expr.h"
#include "utils/builtins.h"
+#include "utils/date.h"
#include "utils/guc.h"
#include "utils/tqual.h"
@@ -41,24 +42,24 @@
static bool show_datestyle(void);
static bool reset_datestyle(void);
-static bool parse_datestyle(char *);
+static bool parse_datestyle(List *);
static bool show_timezone(void);
static bool reset_timezone(void);
-static bool parse_timezone(char *);
+static bool parse_timezone(List *);
static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
-static bool parse_XactIsoLevel(char *);
-static bool parse_random_seed(char *);
+static bool parse_XactIsoLevel(List *);
static bool show_random_seed(void);
static bool reset_random_seed(void);
+static bool parse_random_seed(List *);
static bool show_client_encoding(void);
static bool reset_client_encoding(void);
-static bool parse_client_encoding(char *);
+static bool parse_client_encoding(List *);
static bool show_server_encoding(void);
static bool reset_server_encoding(void);
-static bool parse_server_encoding(char *);
+static bool parse_server_encoding(List *);
/*
@@ -177,7 +178,7 @@ get_token(char **tok, char **val, char *str)
/*
- * DATE_STYLE
+ * DATESTYLE
*
* NOTE: set_default_datestyle() is called during backend startup to check
* if the PGDATESTYLE environment variable is set. We want the env var
@@ -189,17 +190,14 @@ static int DefaultDateStyle;
static bool DefaultEuroDates;
static bool
-parse_datestyle(char *value)
+parse_datestyle_internal(char *value)
{
char *tok;
int dcnt = 0,
ecnt = 0;
if (value == NULL)
- {
- reset_datestyle();
- return TRUE;
- }
+ return reset_datestyle();
while ((value = get_token(&tok, NULL, value)) != 0)
{
@@ -258,6 +256,21 @@ parse_datestyle(char *value)
}
static bool
+parse_datestyle(List *args)
+{
+ char *value;
+
+ if (args == NULL)
+ return reset_datestyle();
+
+ Assert(IsA(lfirst(args), A_Const));
+
+ value = ((A_Const *) lfirst(args))->val.val.str;
+
+ return parse_datestyle_internal(value);
+}
+
+static bool
show_datestyle(void)
{
char buf[64];
@@ -321,8 +334,11 @@ set_default_datestyle(void)
*/
DBDate = strdup(DBDate);
- /* Parse desired setting into DateStyle/EuroDates */
- parse_datestyle(DBDate);
+ /* Parse desired setting into DateStyle/EuroDates
+ * Use parse_datestyle_internal() to avoid any palloc() issues per above
+ * - thomas 2001-10-15
+ */
+ parse_datestyle_internal(DBDate);
free(DBDate);
@@ -348,39 +364,96 @@ static char tzbuf[64];
/* parse_timezone()
* Handle SET TIME ZONE...
* Try to save existing TZ environment variable for later use in RESET TIME ZONE.
- * - thomas 1997-11-10
+ * Accept an explicit interval per SQL9x, though this is less useful than a full time zone.
+ * - thomas 2001-10-11
*/
static bool
-parse_timezone(char *value)
+parse_timezone(List *args)
{
- char *tok;
+ List *arg;
+ TypeName *type;
- if (value == NULL)
- {
- reset_timezone();
- return TRUE;
- }
+ if (args == NULL)
+ return reset_timezone();
- while ((value = get_token(&tok, NULL, value)) != 0)
+ Assert(IsA(args, List));
+
+ foreach(arg, args)
{
- /* Not yet tried to save original value from environment? */
- if (defaultTZ == NULL)
- {
- /* found something? then save it for later */
- if ((defaultTZ = getenv("TZ")) != NULL)
- strcpy(TZvalue, defaultTZ);
+ A_Const *p;
- /* found nothing so mark with an invalid pointer */
- else
- defaultTZ = (char *) -1;
- }
+ Assert(IsA(arg, List));
+ p = lfirst(arg);
+ Assert(IsA(p, A_Const));
- strcpy(tzbuf, "TZ=");
- strcat(tzbuf, tok);
- if (putenv(tzbuf) != 0)
- elog(ERROR, "Unable to set TZ environment variable to %s", tok);
+ type = p->typename;
+ if (type != NULL)
+ {
+ if (strcmp(type->name, "interval") == 0)
+ {
+ Interval *interval;
+
+ interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
+ CStringGetDatum(p->val.val.str),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1)));
+ if (interval->month != 0)
+ elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
+ CTimeZone = interval->time;
+ }
+ else if (strcmp(type->name, "float8") == 0)
+ {
+ float8 time;
+
+ time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
+ CTimeZone = time * 3600;
+ }
+ /* We do not actually generate an integer constant in gram.y so this is not used... */
+ else if (strcmp(type->name, "int4") == 0)
+ {
+ int32 time;
+
+ time = p->val.val.ival;
+ CTimeZone = time * 3600;
+ }
+ else
+ {
+ elog(ERROR, "Unable to process SET TIME ZONE command; internal coding error");
+ }
- tzset();
+ HasCTZSet = true;
+ }
+ else
+ {
+ char *tok;
+ char *value;
+
+ value = p->val.val.str;
+
+ while ((value = get_token(&tok, NULL, value)) != 0)
+ {
+ /* Not yet tried to save original value from environment? */
+ if (defaultTZ == NULL)
+ {
+ /* found something? then save it for later */
+ if ((defaultTZ = getenv("TZ")) != NULL)
+ strcpy(TZvalue, defaultTZ);
+
+ /* found nothing so mark with an invalid pointer */
+ else
+ defaultTZ = (char *) -1;
+ }
+
+ strcpy(tzbuf, "TZ=");
+ strcat(tzbuf, tok);
+ if (putenv(tzbuf) != 0)
+ elog(ERROR, "Unable to set TZ environment variable to %s", tok);
+
+ tzset();
+ }
+
+ HasCTZSet = false;
+ }
}
return TRUE;
@@ -389,11 +462,26 @@ parse_timezone(char *value)
static bool
show_timezone(void)
{
- char *tz;
+ char *tzn;
+
+ if (HasCTZSet)
+ {
+ Interval interval;
- tz = getenv("TZ");
+ interval.month = 0;
+ interval.time = CTimeZone;
+
+ tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval)));
+ }
+ else
+ {
+ tzn = getenv("TZ");
+ }
- elog(NOTICE, "Time zone is %s", ((tz != NULL) ? tz : "unset"));
+ if (tzn != NULL)
+ elog(NOTICE, "Time zone is '%s'", tzn);
+ else
+ elog(NOTICE, "Time zone is unset");
return TRUE;
} /* show_timezone() */
@@ -411,8 +499,13 @@ show_timezone(void)
static bool
reset_timezone(void)
{
+ if (HasCTZSet)
+ {
+ HasCTZSet = false;
+ }
+
/* no time zone has been set in this session? */
- if (defaultTZ == NULL)
+ else if (defaultTZ == NULL)
{
}
@@ -443,17 +536,23 @@ reset_timezone(void)
-/* SET TRANSACTION */
+/*
+ *
+ * SET TRANSACTION
+ *
+ */
static bool
-parse_XactIsoLevel(char *value)
+parse_XactIsoLevel(List *args)
{
+ char *value;
- if (value == NULL)
- {
- reset_XactIsoLevel();
- return TRUE;
- }
+ if (args == NULL)
+ return reset_XactIsoLevel();
+
+ Assert(IsA(lfirst(args), A_Const));
+
+ value = ((A_Const *) lfirst(args))->val.val.str;
if (SerializableSnapshot != NULL)
{
@@ -461,7 +560,6 @@ parse_XactIsoLevel(char *value)
return TRUE;
}
-
if (strcmp(value, "serializable") == 0)
XactIsoLevel = XACT_SERIALIZABLE;
else if (strcmp(value, "read committed") == 0)
@@ -503,17 +601,21 @@ reset_XactIsoLevel(void)
* Random number seed
*/
static bool
-parse_random_seed(char *value)
+parse_random_seed(List *args)
{
- double seed = 0;
+ char *value;
+ double seed = 0;
+
+ if (args == NULL)
+ return reset_random_seed();
+
+ Assert(IsA(lfirst(args), A_Const));
+
+ value = ((A_Const *) lfirst(args))->val.val.str;
+
+ sscanf(value, "%lf", &seed);
+ DirectFunctionCall1(setseed, Float8GetDatum(seed));
- if (value == NULL)
- reset_random_seed();
- else
- {
- sscanf(value, "%lf", &seed);
- DirectFunctionCall1(setseed, Float8GetDatum(seed));
- }
return (TRUE);
}
@@ -544,16 +646,26 @@ reset_random_seed(void)
*/
static bool
-parse_client_encoding(char *value)
+parse_client_encoding(List *args)
{
+ char *value;
#ifdef MULTIBYTE
- int encoding;
+ int encoding;
+#endif
+ if (args == NULL)
+ return reset_client_encoding();
+
+ Assert(IsA(lfirst(args), A_Const));
+
+ value = ((A_Const *) lfirst(args))->val.val.str;
+
+#ifdef MULTIBYTE
encoding = pg_valid_client_encoding(value);
if (encoding < 0)
{
if (value)
- elog(ERROR, "Client encoding %s is not supported", value);
+ elog(ERROR, "Client encoding '%s' is not supported", value);
else
elog(ERROR, "No client encoding is specified");
}
@@ -576,8 +688,8 @@ parse_client_encoding(char *value)
static bool
show_client_encoding(void)
{
- elog(NOTICE, "Current client encoding is %s",
- pg_get_client_encoding_name());
+ elog(NOTICE, "Current client encoding is '%s'",
+ pg_get_client_encoding_name());
return TRUE;
}
@@ -596,6 +708,7 @@ reset_client_encoding(void)
}
else
encoding = GetDatabaseEncoding();
+
pg_set_client_encoding(encoding);
#endif
return TRUE;
@@ -610,7 +723,7 @@ set_default_client_encoding(void)
static bool
-parse_server_encoding(char *value)
+parse_server_encoding(List *args)
{
elog(NOTICE, "SET SERVER_ENCODING is not supported");
return TRUE;
@@ -619,7 +732,7 @@ parse_server_encoding(char *value)
static bool
show_server_encoding(void)
{
- elog(NOTICE, "Current server encoding is %s", GetDatabaseEncodingName());
+ elog(NOTICE, "Current server encoding is '%s'", GetDatabaseEncodingName());
return TRUE;
}
@@ -632,33 +745,42 @@ reset_server_encoding(void)
+/* SetPGVariable()
+ * Dispatcher for handling SET commands.
+ * Special cases ought to be removed and handled separately by TCOP
+ */
void
-SetPGVariable(const char *name, const char *value)
+SetPGVariable(const char *name, List *args)
{
- char *mvalue = value ? pstrdup(value) : ((char *) NULL);
-
- /*
- * Special cases ought to be removed and handled separately by TCOP
- */
if (strcasecmp(name, "datestyle") == 0)
- parse_datestyle(mvalue);
+ parse_datestyle(args);
else if (strcasecmp(name, "timezone") == 0)
- parse_timezone(mvalue);
+ parse_timezone(args);
else if (strcasecmp(name, "XactIsoLevel") == 0)
- parse_XactIsoLevel(mvalue);
+ parse_XactIsoLevel(args);
else if (strcasecmp(name, "client_encoding") == 0)
- parse_client_encoding(mvalue);
+ parse_client_encoding(args);
else if (strcasecmp(name, "server_encoding") == 0)
- parse_server_encoding(mvalue);
+ parse_server_encoding(args);
else if (strcasecmp(name, "seed") == 0)
- parse_random_seed(mvalue);
- else if (strcasecmp(name, "session_authorization") == 0)
- SetSessionAuthorization(value);
+ parse_random_seed(args);
else
- SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET, false);
+ {
+ /* For routines defined somewhere else,
+ * go ahead and extract the string argument
+ * to match the original interface definition.
+ * Later, we can change this code too...
+ */
+ char *value;
- if (mvalue)
- pfree(mvalue);
+ value = ((args != NULL)? ((A_Const *) lfirst(args))->val.val.str: NULL);
+
+ if (strcasecmp(name, "session_authorization") == 0)
+ SetSessionAuthorization(value);
+ else
+ SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET, false);
+ }
+ return;
}
void
@@ -685,7 +807,8 @@ GetPGVariable(const char *name)
show_client_encoding();
show_server_encoding();
show_random_seed();
- } else
+ }
+ else
{
const char *val = GetConfigOption(name);