Commit f4657116 authored by Tom Lane's avatar Tom Lane

Get rid of postgres.c's separate parsing logic for PGDATESTYLE env.

variable, instead calling same code in variable.c that is used to parse
SET DATESTYLE.  Fix bug: although backend's startup datestyle had been
changed to ISO, 'RESET DATESTYLE' and 'SET DATESTYLE TO DEFAULT' didn't
know about it.  For consistency I have made the latter two reset to the
PGDATESTYLE-defined initial value, which may not be the same as the
compiled-in default of ISO.
parent bd43ae0e
......@@ -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 == ',')
{
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);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.142 2000/02/18 09:29:27 inoue Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.143 2000/02/19 22:10:47 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -40,6 +40,7 @@
#include "commands/async.h"
#include "commands/trigger.h"
#include "commands/variable.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
......@@ -891,7 +892,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
char *remote_host = "";
unsigned short remote_port = 0;
char *DBDate = NULL;
extern int optind;
extern char *optarg;
extern int DebugLvl;
......@@ -912,30 +912,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
SetProcessingMode(InitProcessing);
/*
* Try to get initial values for date styles and formats. Does not do
* a complete job, but should be good enough for backend. Cannot call
* parse_date() since palloc/pfree memory is not set up yet.
*/
DBDate = getenv("PGDATESTYLE");
if (DBDate != NULL)
{
if (strcasecmp(DBDate, "ISO") == 0)
DateStyle = USE_ISO_DATES;
else if (strcasecmp(DBDate, "SQL") == 0)
DateStyle = USE_SQL_DATES;
else if (strcasecmp(DBDate, "POSTGRES") == 0)
DateStyle = USE_POSTGRES_DATES;
else if (strcasecmp(DBDate, "GERMAN") == 0)
{
DateStyle = USE_GERMAN_DATES;
EuroDates = TRUE;
}
else if (strcasecmp(DBDate, "NONEURO") == 0)
EuroDates = FALSE;
else if (strcasecmp(DBDate, "EURO") == 0)
EuroDates = TRUE;
}
/* Check for PGDATESTYLE environment variable */
set_default_datestyle();
/*
* Read default pg_options from file $DATADIR/pg_options.
......@@ -1525,7 +1503,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.142 $ $Date: 2000/02/18 09:29:27 $\n");
puts("$Revision: 1.143 $ $Date: 2000/02/19 22:10:47 $\n");
}
/*
......
......@@ -2,32 +2,16 @@
* Headers for handling of 'SET var TO', 'SHOW var' and 'RESET var'
* statements
*
* $Id: variable.h,v 1.8 1998/10/08 18:30:27 momjian Exp $
* $Id: variable.h,v 1.9 2000/02/19 22:10:43 tgl Exp $
*
*/
#ifndef VARIABLE_H
#define VARIABLE_H 1
enum DateFormat
{
Date_Postgres, Date_SQL, Date_ISO
};
extern bool SetPGVariable(const char *name, const char *value);
extern bool GetPGVariable(const char *name);
extern bool ResetPGVariable(const char *name);
/*-----------------------------------------------------------------------*/
struct PGVariables
{
struct
{
bool euro;
enum DateFormat format;
} date;
};
extern struct PGVariables PGVariables;
/*-----------------------------------------------------------------------*/
bool SetPGVariable(const char *, const char *);
bool GetPGVariable(const char *);
bool ResetPGVariable(const char *);
extern void set_default_datestyle(void);
#endif /* VARIABLE_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment