diff options
Diffstat (limited to 'src/backend/commands/variable.c')
-rw-r--r-- | src/backend/commands/variable.c | 281 |
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); |