Make configuration parameters fall back to their default values when they
authorPeter Eisentraut <peter_e@gmx.net>
Sat, 21 Apr 2007 20:02:41 +0000 (20:02 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Sat, 21 Apr 2007 20:02:41 +0000 (20:02 +0000)
are removed from the configuration file.

Joachim Wieland

src/backend/utils/misc/guc-file.l
src/backend/utils/misc/guc.c
src/include/utils/guc_tables.h

index d0fc263614e4f8c8b8d094fc6c6cb68e612e1764..4327601320ed02b454bfe326728bb515524b2578 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.49 2007/03/13 14:32:25 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.50 2007/04/21 20:02:40 petere Exp $
  */
 
 %{
@@ -116,6 +116,9 @@ ProcessConfigFile(GucContext context)
 {
        int                     elevel;
        struct name_value_pair *item, *head, *tail;
+       int                     i;
+       bool       *in_conffile = NULL;
+       const char *var;
 
        Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
 
@@ -140,19 +143,158 @@ ProcessConfigFile(GucContext context)
        /* Check if all options are valid */
        for (item = head; item; item = item->next)
        {
+               char *sep = strchr(item->name, GUC_QUALIFIER_SEPARATOR);
+               if (sep && !is_custom_class(item->name, sep - item->name))
+               {
+                       ereport(elevel,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("unrecognized configuration parameter \"%s\"",
+                                               item->name)));
+                       goto cleanup_list;
+               }
+
                if (!set_config_option(item->name, item->value, context,
                                                           PGC_S_FILE, false, false))
                        goto cleanup_list;
        }
 
-       /* If we got here all the options checked out okay, so apply them. */
+
+       /*
+        * Mark all variables as not showing up in the config file.  The
+        * allocation has to take place after ParseConfigFile() since this
+        * function can change num_guc_variables due to custom variables.
+        * It would be easier to add a new field or status bit to struct
+        * conf_generic, but that way we would expose internal information
+        * that is just needed here in the following few lines.  The price
+        * to pay for this separation are a few more loops over the set of
+        * configuration options, but those are expected to be rather few
+        * and we only have to pay the cost at SIGHUP.  We initialize
+        * in_conffile only here because set_config_option() makes
+        * guc_variables grow with custom variables.
+        */
+       in_conffile = guc_malloc(elevel, num_guc_variables * sizeof(bool));
+       if (!in_conffile)
+               goto cleanup_list;
+       for (i = 0; i < num_guc_variables; i++)
+               in_conffile[i] = false;
+
        for (item = head; item; item = item->next)
        {
+               /*
+                * After set_config_option() the variable name item->name is
+                * known to exist.
+                */
+               Assert(guc_get_index(item->name) >= 0);
+               in_conffile[guc_get_index(item->name)] = true;
+       }
+
+       for (i = 0; i < num_guc_variables; i++)
+       {
+               struct config_generic *gconf = guc_variables[i];
+               if (!in_conffile[i] && gconf->source == PGC_S_FILE)
+               {
+                       if (gconf->context < PGC_SIGHUP)
+                               ereport(elevel,
+                                       (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),
+                                                        errmsg("parameter \"%s\" cannot be changed after server start; configuration file change ignored",
+                                                                       gconf->name)));
+                       else
+                       {
+                                       /* prepare */
+                                       GucStack   *stack;
+                                       if (gconf->reset_source == PGC_S_FILE)
+                                               gconf->reset_source = PGC_S_DEFAULT;
+                                       for (stack = gconf->stack; stack; stack = stack->prev)
+                                               if (stack->source == PGC_S_FILE)
+                                                       stack->source = PGC_S_DEFAULT;
+                                       /* apply the default */
+                                       set_config_option(gconf->name, NULL, context,
+                                                                         PGC_S_DEFAULT, false, true);
+                       }
+               }
+               else if (!in_conffile[i] && gconf->reset_source == PGC_S_FILE)
+               {
+                       /*------
+                        * Change the reset_val to default_val.  Here's an
+                        * example: In the configuration file we have
+                        *
+                        * seq_page_cost = 3.00
+                        *
+                        * Now we execute in a session
+                        *
+                        * SET seq_page_cost TO 4.00;
+                        *
+                        * Then we remove this option from the configuration file
+                        * and send SIGHUP. Now when you execute
+                        *
+                        * RESET seq_page_cost;
+                        *
+                        * it should fall back to 1.00 (the default value for
+                        * seq_page_cost) and not to 3.00 (which is the current
+                        * reset_val).
+                        */
+
+                       switch (gconf->vartype)
+                       {
+                               case PGC_BOOL:
+                                       {
+                                               struct config_bool *conf;
+                                               conf = (struct config_bool *) gconf;
+                                               conf->reset_val = conf->boot_val;
+                                               break;
+                                       }
+                               case PGC_INT:
+                                       {
+                                               struct config_int *conf;
+                                               conf = (struct config_int *) gconf;
+                                               conf->reset_val = conf->boot_val;
+                                               break;
+                                       }
+                               case PGC_REAL:
+                                       {
+                                               struct config_real *conf;
+                                               conf = (struct config_real *) gconf;
+                                               conf->reset_val = conf->boot_val;
+                                               break;
+                                       }
+                               case PGC_STRING:
+                                       {
+                                               struct config_string   *conf;
+                                               conf = (struct config_string *) gconf;
+                                               /*
+                                                * We can cast away the const here because we
+                                                * won't free the address.  It is protected by
+                                                * set_string_field() and string_field_used().
+                                                */
+                                               conf->reset_val = (char *) conf->boot_val;
+                                               break;
+                                       }
+                       }
+               }
+       }
+
+       /* If we got here all the options checked out okay, so apply them. */
+       for (item = head; item; item = item->next)
                set_config_option(item->name, item->value, context,
                                                  PGC_S_FILE, false, true);
-       }
+
+       /*
+        * Reset variables to the value of environment variables
+        * (PGC_S_ENV_VAR overrules PGC_S_FILE).  PGPORT is ignored,
+        * because it cannot be changed without restart.
+        */
+       var = getenv("PGDATESTYLE");
+       if (var != NULL)
+               set_config_option("datestyle", var, context,
+                                                 PGC_S_ENV_VAR, false, true);
+
+       var = getenv("PGCLIENTENCODING");
+       if (var != NULL)
+               set_config_option("client_encoding", var, context,
+                                                 PGC_S_ENV_VAR, false, true);
 
  cleanup_list:
+       free(in_conffile);
        free_name_value_list(head);
 }
 
@@ -312,14 +454,14 @@ ParseConfigFile(const char *config_file, const char *calling_file,
                        {
                                pfree(opt_name);
                                pfree(opt_value);
-                               /* we assume error message was logged already */
+
+                               /* We assume the error message was logged already. */
                                OK = false;
                                goto cleanup_exit;
                        }
-                       pfree(opt_name);
-                       pfree(opt_value);
                }
-               else
+
+               if (pg_strcasecmp(opt_name, "include") != 0)
                {
                        /* append to list */
                        struct name_value_pair *item;
index b9643a734d30425d8906ed80bd6bb108c3a5d4b3..8b1122d86e2ff1c491b0dcf47493b1c79611e65d 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.386 2007/04/18 16:44:18 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.387 2007/04/21 20:02:40 petere Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2481,7 +2481,8 @@ set_string_field(struct config_string * conf, char **field, char *newval)
        if (oldval == NULL ||
                oldval == *(conf->variable) ||
                oldval == conf->reset_val ||
-               oldval == conf->tentative_val)
+               oldval == conf->tentative_val ||
+               oldval == conf->boot_val)
                return;
        for (stack = conf->gen.stack; stack; stack = stack->prev)
        {
@@ -2504,7 +2505,8 @@ string_field_used(struct config_string * conf, char *strval)
 
        if (strval == *(conf->variable) ||
                strval == conf->reset_val ||
-               strval == conf->tentative_val)
+               strval == conf->tentative_val ||
+               strval == conf->boot_val)
                return true;
        for (stack = conf->gen.stack; stack; stack = stack->prev)
        {
@@ -2673,6 +2675,18 @@ add_guc_variable(struct config_generic * var, int elevel)
        return true;
 }
 
+static int
+guc_get_index(const char *name)
+{
+       int i;
+
+       for (i = 0; i < num_guc_variables; i++)
+               if (strcasecmp(name, guc_variables[i]->name) == 0)
+                       return i;
+
+       return -1;
+}
+
 /*
  * Create and add a placeholder variable. It's presumed to belong
  * to a valid custom variable class at this point.
@@ -2851,39 +2865,39 @@ InitializeGUCOptions(void)
                                        struct config_bool *conf = (struct config_bool *) gconf;
 
                                        if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->reset_val, true,
+                                               if (!(*conf->assign_hook) (conf->boot_val, true,
                                                                                                   PGC_S_DEFAULT))
                                                        elog(FATAL, "failed to initialize %s to %d",
-                                                                conf->gen.name, (int) conf->reset_val);
-                                       *conf->variable = conf->reset_val;
+                                                                conf->gen.name, (int) conf->boot_val);
+                                       *conf->variable = conf->reset_val = conf->boot_val;
                                        break;
                                }
                        case PGC_INT:
                                {
                                        struct config_int *conf = (struct config_int *) gconf;
 
-                                       Assert(conf->reset_val >= conf->min);
-                                       Assert(conf->reset_val <= conf->max);
+                                       Assert(conf->boot_val >= conf->min);
+                                       Assert(conf->boot_val <= conf->max);
                                        if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->reset_val, true,
+                                               if (!(*conf->assign_hook) (conf->boot_val, true,
                                                                                                   PGC_S_DEFAULT))
                                                        elog(FATAL, "failed to initialize %s to %d",
-                                                                conf->gen.name, conf->reset_val);
-                                       *conf->variable = conf->reset_val;
+                                                                conf->gen.name, conf->boot_val);
+                                       *conf->variable = conf->reset_val = conf->boot_val; 
                                        break;
                                }
                        case PGC_REAL:
                                {
                                        struct config_real *conf = (struct config_real *) gconf;
 
-                                       Assert(conf->reset_val >= conf->min);
-                                       Assert(conf->reset_val <= conf->max);
+                                       Assert(conf->boot_val >= conf->min);
+                                       Assert(conf->boot_val <= conf->max);
                                        if (conf->assign_hook)
-                                               if (!(*conf->assign_hook) (conf->reset_val, true,
+                                               if (!(*conf->assign_hook) (conf->boot_val, true,
                                                                                                   PGC_S_DEFAULT))
                                                        elog(FATAL, "failed to initialize %s to %g",
-                                                                conf->gen.name, conf->reset_val);
-                                       *conf->variable = conf->reset_val;
+                                                                conf->gen.name, conf->boot_val);
+                                       *conf->variable = conf->reset_val = conf->boot_val; 
                                        break;
                                }
                        case PGC_STRING:
@@ -3945,6 +3959,13 @@ set_config_option(const char *name, const char *value,
                return false;
        }
 
+       /*
+        * Do not replace a value that has been set on the command line by a SIGHUP
+        * reload
+        */
+       if (context == PGC_SIGHUP && record->source == PGC_S_ARGV)
+               return true;
+
        /*
         * Check if the option can be set at this time. See guc.h for the precise
         * rules. Note that we don't want to throw errors if we're in the SIGHUP
@@ -4040,19 +4061,26 @@ set_config_option(const char *name, const char *value,
        }
 
        /*
-        * Should we set reset/stacked values?  (If so, the behavior is not
-        * transactional.)
+        * Should we set reset/stacked values?  (If so, the behavior is not
+        * transactional.)  This is done either when we get a default
+        * value from the database's/user's/client's default settings or
+        * when we reset a value to its default.
         */
-       makeDefault = changeVal && (source <= PGC_S_OVERRIDE) && (value != NULL);
+       makeDefault = changeVal && (source <= PGC_S_OVERRIDE)
+                                       && ((value != NULL) || source == PGC_S_DEFAULT);
 
        /*
-        * Ignore attempted set if overridden by previously processed setting.
-        * However, if changeVal is false then plow ahead anyway since we are
-        * trying to find out if the value is potentially good, not actually use
-        * it. Also keep going if makeDefault is true, since we may want to set
-        * the reset/stacked values even if we can't set the variable itself.
+        * Ignore attempted set if overridden by previously processed
+        * setting.  However, if changeVal is false then plow ahead anyway
+        * since we are trying to find out if the value is potentially
+        * good, not actually use it.  Also keep going if makeDefault is
+        * true, since we may want to set the reset/stacked values even if
+        * we can't set the variable itself.  There's one exception to
+        * this rule: if we want to apply the default value to variables
+        * that were removed from the configuration file.  This is
+        * indicated by source == PGC_S_DEFAULT.
         */
-       if (record->source > source)
+       if (record->source > source && source != PGC_S_DEFAULT)
        {
                if (changeVal && !makeDefault)
                {
@@ -4084,6 +4112,14 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
                                }
+                               /*
+                                * If value == NULL and source == PGC_S_DEFAULT then
+                                * we reset some value to its default (removed from
+                                * configuration file).
+                                */
+                               else if (source == PGC_S_DEFAULT)
+                                       newval = conf->boot_val;
+                               /* else we handle a "RESET varname" command */
                                else
                                {
                                        newval = conf->reset_val;
@@ -4168,6 +4204,14 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
                                }
+                               /*
+                                * If value == NULL and source == PGC_S_DEFAULT then
+                                * we reset some value to its default (removed from
+                                * configuration file).
+                                */
+                               else if (source == PGC_S_DEFAULT)
+                                       newval = conf->boot_val;
+                               /* else we handle a "RESET varname" command */
                                else
                                {
                                        newval = conf->reset_val;
@@ -4252,6 +4296,14 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
                                }
+                               /*
+                                * If value == NULL and source == PGC_S_DEFAULT then
+                                * we reset some value to its default (removed from
+                                * configuration file).
+                                */
+                               else if (source == PGC_S_DEFAULT)
+                                       newval = conf->boot_val;
+                               /* else we handle a "RESET varname" command */
                                else
                                {
                                        newval = conf->reset_val;
@@ -4330,6 +4382,23 @@ set_config_option(const char *name, const char *value,
                                        if (conf->gen.flags & GUC_IS_NAME)
                                                truncate_identifier(newval, strlen(newval), true);
                                }
+                               /*
+                                * If value == NULL and source == PGC_S_DEFAULT then
+                                * we reset some value to its default (removed from
+                                * configuration file).
+                                */
+                               else if (source == PGC_S_DEFAULT)
+                               {
+                                       if (conf->boot_val == NULL)
+                                               newval = NULL;
+                                       else
+                                       {
+                                               newval = guc_strdup(elevel, conf->boot_val);
+                                               if (newval == NULL)
+                                                       return false;
+                                       }
+                               }
+                               /* else we handle a "RESET varname" command */
                                else if (conf->reset_val)
                                {
                                        /*
@@ -6404,6 +6473,13 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
        int                     c;
        StringInfoData buf;
 
+       /*
+        * Resetting custom_variable_classes by removing it from the
+        * configuration file will lead to newval = NULL
+        */
+       if (newval == NULL)
+               return guc_strdup(ERROR, "");
+
        initStringInfo(&buf);
        while ((c = *cp++) != 0)
        {
@@ -6448,7 +6524,7 @@ assign_custom_variable_classes(const char *newval, bool doit, GucSource source)
        if (buf.len == 0)
                newval = NULL;
        else if (doit)
-               newval = strdup(buf.data);
+               newval = guc_strdup(ERROR, buf.data);
 
        pfree(buf.data);
        return newval;
index 611afb808373ce60b5a8dd9296235d9768bc3137..f68a814f799616f3e935c1c350800b0d141556b0 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  *
- *       $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.32 2007/03/13 14:32:25 petere Exp $
+ *       $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.33 2007/04/21 20:02:41 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,10 +154,11 @@ struct config_bool
        /* these fields must be set correctly in initial value: */
        /* (all but reset_val are constants) */
        bool       *variable;
-       bool            reset_val;
+       bool            boot_val;
        GucBoolAssignHook assign_hook;
        GucShowHook show_hook;
        /* variable fields, initialized at runtime: */
+       bool            reset_val;
        bool            tentative_val;
 };
 
@@ -167,12 +168,13 @@ struct config_int
        /* these fields must be set correctly in initial value: */
        /* (all but reset_val are constants) */
        int                *variable;
-       int                     reset_val;
+       int                     boot_val;
        int                     min;
        int                     max;
        GucIntAssignHook assign_hook;
        GucShowHook show_hook;
        /* variable fields, initialized at runtime: */
+       int                     reset_val;
        int                     tentative_val;
 };
 
@@ -182,12 +184,13 @@ struct config_real
        /* these fields must be set correctly in initial value: */
        /* (all but reset_val are constants) */
        double     *variable;
-       double          reset_val;
+       double          boot_val;
        double          min;
        double          max;
        GucRealAssignHook assign_hook;
        GucShowHook show_hook;
        /* variable fields, initialized at runtime: */
+       double          reset_val;
        double          tentative_val;
 };