Make configuration parameters fall back to their default values when they
authorPeter Eisentraut <peter_e@gmx.net>
Mon, 12 Mar 2007 22:09:28 +0000 (22:09 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Mon, 12 Mar 2007 22:09:28 +0000 (22:09 +0000)
are removed from the configuration file.

Joachim Wieland

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

index ab8b5fd8b4ec8de39e977a3b5c700fb83b51016f..db81e3bd70c87cc0c90064d497852757935062ba 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.234 2007/02/09 03:35:33 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.235 2007/03/12 22:09:27 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1513,6 +1513,9 @@ CommitTransaction(void)
    /* NOTIFY commit must come before lower-level cleanup */
    AtCommit_Notify();
 
+   /* GUC processing could abort transaction */
+   AtEOXact_GUC(true, false);
+
    /*
     * Update flat files if we changed pg_database, pg_authid or
     * pg_auth_members.  This should be the last step before commit.
@@ -1623,7 +1626,6 @@ CommitTransaction(void)
    /* Check we've released all catcache entries */
    AtEOXact_CatCache(true);
 
-   AtEOXact_GUC(true, false);
    AtEOXact_SPI(true);
    AtEOXact_on_commit_actions(true);
    AtEOXact_Namespace(true);
index c9b6958cee5604afb15bc4b46b4be0e71175ca35..b9b62bcabf0be9ce9cba373b06e51ee4c4b8c0cf 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.47 2007/02/10 14:58:55 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.48 2007/03/12 22:09:27 petere Exp $
  */
 
 %{
@@ -54,6 +54,8 @@ static bool ParseConfigFile(const char *config_file, const char *calling_file,
 static void free_name_value_list(struct name_value_pair * list);
 static char *GUC_scanstr(const char *s);
 
+static char *custom_variable_classes_backup;
+
 %}
 
 %option 8bit
@@ -116,6 +118,10 @@ ProcessConfigFile(GucContext context)
 {
    int         elevel;
    struct name_value_pair *item, *head, *tail;
+   int                     i;
+   bool                   *in_conffile = NULL;
+   const char             *var;
+   bool                    success = false;
 
    Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP);
 
@@ -132,6 +138,18 @@ ProcessConfigFile(GucContext context)
 
    head = tail = NULL;
 
+   /*
+    * We do not know whether we will read the configuration file
+    * without error.  If we encounter an error we have to restore the
+    * previous value of the custom_variable_classes variable for
+    * consistency.  Therefore we have to save its value.
+    */
+   var = GetConfigOption("custom_variable_classes");
+   if (var)
+       custom_variable_classes_backup = pstrdup(var);
+   set_config_option("custom_variable_classes", NULL, context,
+                     PGC_S_DEFAULT, false, true);
+
    if (!ParseConfigFile(ConfigFileName, NULL,
                         0, context, elevel,
                         &head, &tail))
@@ -140,20 +158,198 @@ 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] && strchr(gconf->name, GUC_QUALIFIER_SEPARATOR))
+       {
+           /* handle custom variables here */
+           int j;
+
+           /*
+            * guc_delete_variable will re-sort the array of
+            * configuration options and decrease num_guc_variables by
+            * one.
+            */
+           guc_delete_custom_variable(gconf->name);
+
+           /*
+            * Since the array is always sorted we just have to shift
+            * all boolean values after position i by one position to
+            * the left.
+            */
+           for (j = i; j < num_guc_variables; j++)
+               in_conffile[j] = in_conffile[j+1];
+
+           /*
+            * Decrease the loop variable to re-test the entry at the
+            * current position that is now a different one.
+            */
+           i--;
+
+           continue;
+       }
+       else 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);
+
+   success = true;
 
  cleanup_list:
+   free(in_conffile);
    free_name_value_list(head);
+   if (!success)
+       set_config_option("custom_variable_classes",
+                         custom_variable_classes_backup,
+                         context, PGC_S_FILE, false, true);
+   if (custom_variable_classes_backup)
+   {
+       pfree(custom_variable_classes_backup);
+       custom_variable_classes_backup = NULL;
+   }
 }
 
 
@@ -312,14 +508,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 0fa3489fb62ed6cf811840f8256ba5be2d217d4e..48ac8705b1f81fda8993b94a36483ed52d85395d 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.379 2007/03/06 02:06:14 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.380 2007/03/12 22:09:28 petere Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -2439,7 +2439,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)
    {
@@ -2462,7 +2463,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)
    {
@@ -2631,6 +2633,105 @@ 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;
+}
+
+static void
+guc_delete_variable(const char *name)
+{
+   struct config_generic  *gen;
+   int                     idx;
+   GucStack               *stack, *prev;
+   struct config_string   *conf;
+
+   idx = guc_get_index(name);
+   Assert(idx >= 0);
+
+   gen = guc_variables[idx];
+
+   /*
+    * Even though this function could delete other types of variables as well,
+    * at the moment we only call it for custom variables that always have type
+    * string.
+    */
+   Assert(gen->group == CUSTOM_OPTIONS);
+   Assert(gen->vartype == PGC_STRING);
+
+   conf = (struct config_string *) gen;
+   set_string_field(conf, &conf->reset_val, NULL);
+   set_string_field(conf, &conf->tentative_val, NULL);
+   for (stack = conf->gen.stack; stack; stack = prev)
+   {
+       set_string_field(conf, &stack->tentative_val.stringval, NULL);
+       set_string_field(conf, &stack->value.stringval, NULL);
+       prev = stack->prev;
+       pfree(stack);
+   }
+
+   /* no pfree() here, gen has been allocated via guc_malloc */
+   free(gen);
+   guc_variables[idx] = guc_variables[num_guc_variables - 1];
+   num_guc_variables--;
+   qsort((void *) guc_variables, num_guc_variables,
+         sizeof(struct config_generic *), guc_var_compare);
+}
+
+static void
+guc_delete_custom_variable(const char *name)
+{
+   struct config_generic  *gen;
+   struct config_string   *conf;
+   int                     idx;
+
+   idx = guc_get_index(name);
+   Assert(idx >= 0);
+
+   gen = guc_variables[idx];
+
+   Assert(gen->group == CUSTOM_OPTIONS);
+   Assert(gen->vartype == PGC_STRING);
+
+   conf = (struct config_string *) gen;
+
+   /*
+    * Here we check whether it is safe to really delete the variable
+    * or if we have to wait for the end of the transaction.  We do
+    * not remove the physical entry of a custom variable if it has
+    * been SET to another value in the transaction but has been
+    * removed from the configuration file.
+    */
+   if (gen->stack)
+   {
+       /*
+        * Make sure this custom variable (which has a definition in
+        * the configuration file) behaves as any other custom
+        * variable from now on.  We have deleted its former
+        * definition; that's why "RESET foo.bar" should not fall back
+        * to this deleted definition from the configuration file.
+        * The analogy is that any other custom variable that gets
+        * introduced in a session has no reset value either.  And a
+        * variable that has been SET within a transaction and has
+        * then been deleted from the configuration file should behave
+        * as if it had been introduced in the session.
+        */
+       Assert(gen->vartype == PGC_STRING);
+       gen->reset_source = PGC_S_DEFAULT;
+       set_string_field(conf, &conf->reset_val, NULL);
+   }
+   else
+       guc_delete_variable(name);
+}
+
+
 /*
  * Create and add a placeholder variable. It's presumed to belong
  * to a valid custom variable class at this point.
@@ -2809,39 +2910,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:
@@ -3296,8 +3397,25 @@ push_old_value(struct config_generic * gconf)
    }
 }
 
-/*
+/*------
  * Do GUC processing at transaction or subtransaction commit or abort.
+ *
+ * GUC can abort the transaction in exactly one case, namely when you
+ * delete a custom variable class while a still-open transaction has
+ * SET a custom variable within this class.
+ *
+ * Consider the following example. In the configuration file we could
+ * have:
+ *
+ * custom_variable_classes = "foo"
+ *
+ * begin;
+ * set foo.bar to 1;
+ * <delete foo.bar from configuration file and send SIGHUP>
+ * commit;
+ *
+ * This will result in an error because foo.bar is no longer available
+ * but commit would have to guarantee that the value is preserved.
  */
 void
 AtEOXact_GUC(bool isCommit, bool isSubXact)
@@ -3335,6 +3453,33 @@ AtEOXact_GUC(bool isCommit, bool isSubXact)
            continue;
        Assert(stack->nest_level == my_level);
 
+       if (!isSubXact && gconf->group == CUSTOM_OPTIONS)
+       {
+           char *dot = strchr(gconf->name, GUC_QUALIFIER_SEPARATOR);
+           Assert(dot != NULL);
+           if (!is_custom_class(gconf->name, dot - gconf->name))
+           {
+               if (!isCommit)
+               {
+                   /* We do not commit the transaction.  Delete the variable. */
+                   guc_delete_variable(gconf->name);
+                   /* Call the loop with the same i again, which is
+                    * the next variable. */
+                   i--;
+                   continue;
+               }
+               else
+               {
+                   /* We commit the transaction.  Throw an error that
+                    * the respective custom class does not exist. */
+                   ereport(ERROR,
+                       (errcode(ERRCODE_UNDEFINED_OBJECT),
+                        errmsg("no valid custom variable class available for "
+                               "parameter \"%s\"", gconf->name)));
+               }
+           }
+       }
+
        /*
         * We will pop the stack entry.  Start by restoring outer xact status
         * (since we may want to modify it below).  Be careful to use
@@ -3998,19 +4143,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)
        {
@@ -4042,6 +4194,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;
@@ -4126,6 +4286,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;
@@ -4210,6 +4378,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;
@@ -4288,6 +4464,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)
                {
                    /*
@@ -6304,6 +6497,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)
    {
@@ -6348,7 +6548,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 1b89024eebb333c1d4f7b59eaa3a8f98dd05996a..19dd16d15e44dae030a7596f6cbe24dfef26ca66 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.30 2007/01/05 22:19:59 momjian Exp $
+ *   $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.31 2007/03/12 22:09:28 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -154,11 +154,12 @@ 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        tentative_val;
+   bool        reset_val;
 };
 
 struct config_int
@@ -167,13 +168,14 @@ 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         tentative_val;
+   int         reset_val;
 };
 
 struct config_real
@@ -182,13 +184,14 @@ 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      tentative_val;
+   double      reset_val;
 };
 
 struct config_string