OSDN Git Service

Get rid of postgres.c's separate parsing logic for PGDATESTYLE env.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2000 22:10:47 +0000 (22:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 19 Feb 2000 22:10:47 +0000 (22:10 +0000)
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.

src/backend/commands/variable.c
src/backend/tcop/postgres.c
src/include/commands/variable.h

index 718a62a..ca3f96c 100644 (file)
@@ -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);
index 77422de..2415ef3 100644 (file)
@@ -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");
        }
 
        /*
index a5110e8..c9b39d9 100644 (file)
@@ -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 */