aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/variable.c')
-rw-r--r--src/backend/commands/variable.c281
1 files changed, 165 insertions, 116 deletions
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 718a62a118d..ca3f96c063d 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.29 2000/02/15 20:49:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.30 2000/02/19 22:10:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,157 +40,165 @@ extern bool _use_keyset_query_optimizer;
static bool show_date(void);
static bool reset_date(void);
-static bool parse_date(const char *);
+static bool parse_date(char *);
static bool show_timezone(void);
static bool reset_timezone(void);
-static bool parse_timezone(const char *);
+static bool parse_timezone(char *);
static bool show_effective_cache_size(void);
static bool reset_effective_cache_size(void);
-static bool parse_effective_cache_size(const char *);
+static bool parse_effective_cache_size(char *);
static bool show_random_page_cost(void);
static bool reset_random_page_cost(void);
-static bool parse_random_page_cost(const char *);
+static bool parse_random_page_cost(char *);
static bool show_cpu_tuple_cost(void);
static bool reset_cpu_tuple_cost(void);
-static bool parse_cpu_tuple_cost(const char *);
+static bool parse_cpu_tuple_cost(char *);
static bool show_cpu_index_tuple_cost(void);
static bool reset_cpu_index_tuple_cost(void);
-static bool parse_cpu_index_tuple_cost(const char *);
+static bool parse_cpu_index_tuple_cost(char *);
static bool show_cpu_operator_cost(void);
static bool reset_cpu_operator_cost(void);
-static bool parse_cpu_operator_cost(const char *);
+static bool parse_cpu_operator_cost(char *);
static bool reset_enable_seqscan(void);
static bool show_enable_seqscan(void);
-static bool parse_enable_seqscan(const char *);
+static bool parse_enable_seqscan(char *);
static bool reset_enable_indexscan(void);
static bool show_enable_indexscan(void);
-static bool parse_enable_indexscan(const char *);
+static bool parse_enable_indexscan(char *);
static bool reset_enable_tidscan(void);
static bool show_enable_tidscan(void);
-static bool parse_enable_tidscan(const char *);
+static bool parse_enable_tidscan(char *);
static bool reset_enable_sort(void);
static bool show_enable_sort(void);
-static bool parse_enable_sort(const char *);
+static bool parse_enable_sort(char *);
static bool reset_enable_nestloop(void);
static bool show_enable_nestloop(void);
-static bool parse_enable_nestloop(const char *);
+static bool parse_enable_nestloop(char *);
static bool reset_enable_mergejoin(void);
static bool show_enable_mergejoin(void);
-static bool parse_enable_mergejoin(const char *);
+static bool parse_enable_mergejoin(char *);
static bool reset_enable_hashjoin(void);
static bool show_enable_hashjoin(void);
-static bool parse_enable_hashjoin(const char *);
+static bool parse_enable_hashjoin(char *);
static bool reset_geqo(void);
static bool show_geqo(void);
-static bool parse_geqo(const char *);
+static bool parse_geqo(char *);
static bool show_ksqo(void);
static bool reset_ksqo(void);
-static bool parse_ksqo(const char *);
+static bool parse_ksqo(char *);
static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
-static bool parse_XactIsoLevel(const char *);
+static bool parse_XactIsoLevel(char *);
/*
+ * get_token
+ * Obtain the next item in a comma-separated list of items,
+ * where each item can be either "word" or "word=word".
+ * The "word=word" form is only accepted if 'val' is not NULL.
+ * Words are any sequences not containing whitespace, ',', or '='.
+ * Whitespace can appear between the words and punctuation.
*
- * Get_Token
+ * 'tok': receives a pointer to first word of item, or NULL if none.
+ * 'val': if not NULL, receives a pointer to second word, or NULL if none.
+ * 'str': start of input string.
*
+ * Returns NULL if input string contained no more words, else pointer
+ * to just past this item, which can be used as 'str' for next call.
+ * (If this is the last item, returned pointer will point at a null char,
+ * so caller can alternatively check for that instead of calling again.)
+ *
+ * NB: input string is destructively modified by placing null characters
+ * at ends of words!
+ *
+ * A former version of this code avoided modifying the input string by
+ * returning palloc'd copies of the words. However, we want to use this
+ * code early in backend startup to parse the PGDATESTYLE environment var,
+ * and palloc/pfree aren't initialized at that point. Cleanest answer
+ * seems to be to palloc in SetPGVariable() so that we can treat the string
+ * as modifiable here.
*/
-static const char *
-get_token(char **tok, char **val, const char *str)
+static char *
+get_token(char **tok, char **val, char *str)
{
- const char *start;
- int len = 0;
+ char ch;
*tok = NULL;
if (val != NULL)
*val = NULL;
- if (!(*str))
+ if (!str || *str == '\0')
return NULL;
- /* skip white spaces */
+ /* skip leading white space */
while (isspace(*str))
str++;
- if (*str == ',' || *str == '=')
- elog(ERROR, "Syntax error near (%s): empty setting", str);
/* end of string? then return NULL */
- if (!(*str))
+ if (*str == '\0')
return NULL;
- /* OK, at beginning of non-NULL string... */
- start = str;
+ if (*str == ',' || *str == '=')
+ elog(ERROR, "Syntax error near \"%s\": empty setting", str);
- /*
- * count chars in token until we hit white space or comma or '=' or
- * end of string
- */
- while (*str && (!isspace(*str))
- && *str != ',' && *str != '=')
- {
+ /* OK, at beginning of non-empty item */
+ *tok = str;
+
+ /* Advance to end of word */
+ while (*str && !isspace(*str) && *str != ',' && *str != '=')
str++;
- len++;
- }
- *tok = (char *) palloc(len + 1);
- StrNCpy(*tok, start, len + 1);
+ /* Terminate word string for caller */
+ ch = *str;
+ *str = '\0';
- /* skip white spaces */
- while (isspace(*str))
- str++;
+ /* Skip any whitespace */
+ while (isspace(ch))
+ ch = *(++str);
/* end of string? */
- if (!(*str))
- {
+ if (ch == '\0')
return str;
-
- /* delimiter? */
- }
- else if (*str == ',')
- {
+ /* delimiter? */
+ if (ch == ',')
return ++str;
- }
- else if ((val == NULL) || (*str != '='))
- {
- elog(ERROR, "Syntax error near (%s)", str);
- };
+ /* Had better be '=', and caller must be expecting it */
+ if (val == NULL || ch != '=')
+ elog(ERROR, "Syntax error near \"%s\"", str);
- str++; /* '=': get value */
- len = 0;
+ /* '=': get the value */
+ str++;
- /* skip white spaces */
+ /* skip whitespace after '=' */
while (isspace(*str))
str++;
- if (*str == ',' || !(*str))
- elog(ERROR, "Syntax error near (=%s)", str);
+ if (*str == ',' || *str == '\0')
+ elog(ERROR, "Syntax error near \"=%s\"", str);
- start = str;
+ /* OK, at beginning of non-empty value */
+ *val = str;
- /*
- * count chars in token's value until we hit white space or comma or
- * end of string
- */
- while (*str && (!isspace(*str)) && *str != ',')
- {
+ /* Advance to end of word */
+ while (*str && !isspace(*str) && *str != ',')
str++;
- len++;
- }
- *val = (char *) palloc(len + 1);
- StrNCpy(*val, start, len + 1);
+ /* Terminate word string for caller */
+ ch = *str;
+ *str = '\0';
- /* skip white spaces */
- while (isspace(*str))
- str++;
+ /* Skip any whitespace */
+ while (isspace(ch))
+ ch = *(++str);
- if (!(*str))
- return NULL;
- if (*str == ',')
+ /* end of string? */
+ if (ch == '\0')
+ return str;
+ /* delimiter? */
+ if (ch == ',')
return ++str;
- elog(ERROR, "Syntax error near (%s)", str);
+ elog(ERROR, "Syntax error near \"%s\"", str);
return str;
}
@@ -199,7 +207,7 @@ get_token(char **tok, char **val, const char *str)
* Generic parse routine for boolean ON/OFF variables
*/
static bool
-parse_boolean_var(const char *value,
+parse_boolean_var(char *value,
bool *variable, const char *varname, bool defaultval)
{
if (value == NULL)
@@ -222,7 +230,7 @@ parse_boolean_var(const char *value,
* ENABLE_SEQSCAN
*/
static bool
-parse_enable_seqscan(const char *value)
+parse_enable_seqscan(char *value)
{
return parse_boolean_var(value, &enable_seqscan,
"ENABLE_SEQSCAN", true);
@@ -247,7 +255,7 @@ reset_enable_seqscan()
* ENABLE_INDEXSCAN
*/
static bool
-parse_enable_indexscan(const char *value)
+parse_enable_indexscan(char *value)
{
return parse_boolean_var(value, &enable_indexscan,
"ENABLE_INDEXSCAN", true);
@@ -272,7 +280,7 @@ reset_enable_indexscan()
* ENABLE_TIDSCAN
*/
static bool
-parse_enable_tidscan(const char *value)
+parse_enable_tidscan(char *value)
{
return parse_boolean_var(value, &enable_tidscan,
"ENABLE_TIDSCAN", true);
@@ -297,7 +305,7 @@ reset_enable_tidscan()
* ENABLE_SORT
*/
static bool
-parse_enable_sort(const char *value)
+parse_enable_sort(char *value)
{
return parse_boolean_var(value, &enable_sort,
"ENABLE_SORT", true);
@@ -322,7 +330,7 @@ reset_enable_sort()
* ENABLE_NESTLOOP
*/
static bool
-parse_enable_nestloop(const char *value)
+parse_enable_nestloop(char *value)
{
return parse_boolean_var(value, &enable_nestloop,
"ENABLE_NESTLOOP", true);
@@ -347,7 +355,7 @@ reset_enable_nestloop()
* ENABLE_MERGEJOIN
*/
static bool
-parse_enable_mergejoin(const char *value)
+parse_enable_mergejoin(char *value)
{
return parse_boolean_var(value, &enable_mergejoin,
"ENABLE_MERGEJOIN", true);
@@ -372,7 +380,7 @@ reset_enable_mergejoin()
* ENABLE_HASHJOIN
*/
static bool
-parse_enable_hashjoin(const char *value)
+parse_enable_hashjoin(char *value)
{
return parse_boolean_var(value, &enable_hashjoin,
"ENABLE_HASHJOIN", true);
@@ -399,11 +407,11 @@ reset_enable_hashjoin()
*
*/
static bool
-parse_geqo(const char *value)
+parse_geqo(char *value)
{
- const char *rest;
char *tok,
- *val;
+ *val,
+ *rest;
if (value == NULL)
{
@@ -412,11 +420,12 @@ parse_geqo(const char *value)
}
rest = get_token(&tok, &val, value);
+
+ /* expect one and only one item */
if (tok == NULL)
elog(ERROR, "Value undefined");
-
- if ((rest) && (*rest != '\0'))
- elog(ERROR, "Unable to parse '%s'", value);
+ if (rest && *rest != '\0')
+ elog(ERROR, "Unable to parse '%s'", rest);
if (strcasecmp(tok, "on") == 0)
{
@@ -427,21 +436,19 @@ parse_geqo(const char *value)
new_geqo_rels = pg_atoi(val, sizeof(int), '\0');
if (new_geqo_rels <= 1)
elog(ERROR, "Bad value for # of relations (%s)", val);
- pfree(val);
}
enable_geqo = true;
geqo_rels = new_geqo_rels;
}
else if (strcasecmp(tok, "off") == 0)
{
- if ((val != NULL) && (*val != '\0'))
+ if (val != NULL)
elog(ERROR, "%s does not allow a parameter", tok);
enable_geqo = false;
}
else
elog(ERROR, "Bad value for GEQO (%s)", value);
- pfree(tok);
return TRUE;
}
@@ -471,7 +478,7 @@ reset_geqo(void)
* EFFECTIVE_CACHE_SIZE
*/
static bool
-parse_effective_cache_size(const char *value)
+parse_effective_cache_size(char *value)
{
float64 res;
@@ -506,7 +513,7 @@ reset_effective_cache_size()
* RANDOM_PAGE_COST
*/
static bool
-parse_random_page_cost(const char *value)
+parse_random_page_cost(char *value)
{
float64 res;
@@ -540,7 +547,7 @@ reset_random_page_cost()
* CPU_TUPLE_COST
*/
static bool
-parse_cpu_tuple_cost(const char *value)
+parse_cpu_tuple_cost(char *value)
{
float64 res;
@@ -574,7 +581,7 @@ reset_cpu_tuple_cost()
* CPU_INDEX_TUPLE_COST
*/
static bool
-parse_cpu_index_tuple_cost(const char *value)
+parse_cpu_index_tuple_cost(char *value)
{
float64 res;
@@ -608,7 +615,7 @@ reset_cpu_index_tuple_cost()
* CPU_OPERATOR_COST
*/
static bool
-parse_cpu_operator_cost(const char *value)
+parse_cpu_operator_cost(char *value)
{
float64 res;
@@ -639,12 +646,19 @@ reset_cpu_operator_cost()
}
/*
- *
* DATE_STYLE
*
+ * NOTE: set_default_datestyle() is called during backend startup to check
+ * if the PGDATESTYLE environment variable is set. We want the env var
+ * to determine the value that "RESET DateStyle" will reset to!
*/
+
+/* These get initialized from the "master" values in init/globals.c */
+static int DefaultDateStyle;
+static bool DefaultEuroDates;
+
static bool
-parse_date(const char *value)
+parse_date(char *value)
{
char *tok;
int dcnt = 0,
@@ -698,13 +712,12 @@ parse_date(const char *value)
}
else if (!strcasecmp(tok, "DEFAULT"))
{
- DateStyle = USE_POSTGRES_DATES;
- EuroDates = FALSE;
+ DateStyle = DefaultDateStyle;
+ EuroDates = DefaultEuroDates;
ecnt++;
}
else
elog(ERROR, "Bad value for date style (%s)", tok);
- pfree(tok);
}
if (dcnt > 1 || ecnt > 1)
@@ -746,12 +759,45 @@ show_date()
static bool
reset_date()
{
- DateStyle = USE_POSTGRES_DATES;
- EuroDates = FALSE;
+ DateStyle = DefaultDateStyle;
+ EuroDates = DefaultEuroDates;
return TRUE;
}
+void
+set_default_datestyle(void)
+{
+ char *DBDate;
+
+ /* Initialize from compile-time defaults in init/globals.c.
+ * NB: this is a necessary step; consider PGDATESTYLE="DEFAULT".
+ */
+ DefaultDateStyle = DateStyle;
+ DefaultEuroDates = EuroDates;
+
+ /* If the environment var is set, override compiled-in values */
+ DBDate = getenv("PGDATESTYLE");
+ if (DBDate == NULL)
+ return;
+
+ /* Make a modifiable copy --- overwriting the env var doesn't seem
+ * like a good idea, even though we currently won't look at it again.
+ * Note that we cannot use palloc at this early stage of initialization.
+ */
+ DBDate = strdup(DBDate);
+
+ /* Parse desired setting into DateStyle/EuroDates */
+ parse_date(DBDate);
+
+ free(DBDate);
+
+ /* And make it the default for future RESETs */
+ DefaultDateStyle = DateStyle;
+ DefaultEuroDates = EuroDates;
+}
+
+
/* Timezone support
* Working storage for strings is allocated with an arbitrary size of 64 bytes.
*/
@@ -771,7 +817,7 @@ static char tzbuf[64];
* - thomas 1997-11-10
*/
static bool
-parse_timezone(const char *value)
+parse_timezone(char *value)
{
char *tok;
@@ -801,7 +847,6 @@ parse_timezone(const char *value)
elog(ERROR, "Unable to set TZ environment variable to %s", tok);
tzset();
- pfree(tok);
}
return TRUE;
@@ -869,7 +914,7 @@ See optimizer/prep/prepkeyset.c for more on this.
daveh@insightdist.com 6/16/98
-----------------------------------------------------------------------*/
static bool
-parse_ksqo(const char *value)
+parse_ksqo(char *value)
{
return parse_boolean_var(value, &_use_keyset_query_optimizer,
"KSQO", false);
@@ -893,7 +938,7 @@ reset_ksqo()
/* SET TRANSACTION */
static bool
-parse_XactIsoLevel(const char *value)
+parse_XactIsoLevel(char *value)
{
if (value == NULL)
@@ -949,7 +994,7 @@ reset_XactIsoLevel()
* Pg_options
*/
static bool
-parse_pg_options(const char *value)
+parse_pg_options(char *value)
{
if (!superuser()) {
elog(ERROR, "Only users with superuser privilege can set pg_options");
@@ -978,10 +1023,10 @@ reset_pg_options(void)
/*-----------------------------------------------------------------------*/
-struct VariableParsers
+static struct VariableParsers
{
const char *name;
- bool (*parser) (const char *);
+ bool (*parser) (char *);
bool (*show) ();
bool (*reset) ();
} VariableParsers[] =
@@ -1071,11 +1116,15 @@ bool
SetPGVariable(const char *name, const char *value)
{
struct VariableParsers *vp;
+ char *val;
+
+ /* Make a modifiable copy for convenience of get_token */
+ val = pstrdup(value);
for (vp = VariableParsers; vp->name; vp++)
{
if (!strcasecmp(vp->name, name))
- return (vp->parser) (value);
+ return (vp->parser) (val);
}
elog(NOTICE, "Unrecognized variable %s", name);