Fix an old corner-case bug in set_config_option: push_old_value has to be
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 26 May 2008 18:54:36 +0000 (18:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 26 May 2008 18:54:36 +0000 (18:54 +0000)
called before, not after, calling the assign_hook if any.  This is because
push_old_value might fail (due to palloc out-of-memory), and in that case
there would be no stack entry to tell transaction abort to undo the GUC
assignment.  Of course the actual assignment to the GUC variable hasn't
happened yet --- but the assign_hook might have altered subsidiary state.
Without a stack entry we won't call it again to make it undo such actions.
So this is necessary to make the world safe for assign_hooks with side
effects.  Per a discussion a couple weeks ago with Magnus.

Back-patch to 8.0.  7.x did not have the problem because it did not have
allocatable stacks of GUC values.

src/backend/utils/misc/guc.c

index 1dbffbfb4825bdb3eadc46af06c2f373728487e8..bca9e3fc384d2a2f995ca98966693d2995055025 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.432 2008/01/30 18:35:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.432.2.1 2008/05/26 18:54:36 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -4370,6 +4370,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4380,32 +4384,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
+                                               if (stack->source <= source)
                                                {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
-                                               {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.boolval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.boolval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4447,6 +4445,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4457,32 +4459,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
+                                               if (stack->source <= source)
                                                {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
-                                               {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.intval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.intval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4521,6 +4517,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook)
                                        if (!(*conf->assign_hook) (newval, changeVal, source))
                                        {
@@ -4531,32 +4531,26 @@ set_config_option(const char *name, const char *value,
                                                return false;
                                        }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       *conf->variable = newval;
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               *conf->variable = newval;
-                                               conf->gen.source = source;
+                                               conf->reset_val = newval;
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
+                                               if (stack->source <= source)
                                                {
-                                                       conf->reset_val = newval;
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
-                                               {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               stack->prior.realval = newval;
-                                                               stack->source = source;
-                                                       }
+                                                       stack->prior.realval = newval;
+                                                       stack->source = source;
                                                }
                                        }
                                }
@@ -4610,6 +4604,10 @@ set_config_option(const char *name, const char *value,
                                        source = conf->gen.reset_source;
                                }
 
+                               /* Save old value to support transaction abort */
+                               if (changeVal && !makeDefault)
+                                       push_old_value(&conf->gen, action);
+
                                if (conf->assign_hook && newval)
                                {
                                        const char *hookresult;
@@ -4647,40 +4645,32 @@ set_config_option(const char *name, const char *value,
                                        }
                                }
 
-                               if (changeVal || makeDefault)
+                               if (changeVal)
+                               {
+                                       set_string_field(conf, conf->variable, newval);
+                                       conf->gen.source = source;
+                               }
+                               if (makeDefault)
                                {
-                                       /* Save old value to support transaction abort */
-                                       if (!makeDefault)
-                                               push_old_value(&conf->gen, action);
-                                       if (changeVal)
+                                       GucStack   *stack;
+
+                                       if (conf->gen.reset_source <= source)
                                        {
-                                               set_string_field(conf, conf->variable, newval);
-                                               conf->gen.source = source;
+                                               set_string_field(conf, &conf->reset_val, newval);
+                                               conf->gen.reset_source = source;
                                        }
-                                       if (makeDefault)
+                                       for (stack = conf->gen.stack; stack; stack = stack->prev)
                                        {
-                                               GucStack   *stack;
-
-                                               if (conf->gen.reset_source <= source)
+                                               if (stack->source <= source)
                                                {
-                                                       set_string_field(conf, &conf->reset_val, newval);
-                                                       conf->gen.reset_source = source;
-                                               }
-                                               for (stack = conf->gen.stack; stack; stack = stack->prev)
-                                               {
-                                                       if (stack->source <= source)
-                                                       {
-                                                               set_string_field(conf, &stack->prior.stringval,
-                                                                                                newval);
-                                                               stack->source = source;
-                                                       }
+                                                       set_string_field(conf, &stack->prior.stringval,
+                                                                                        newval);
+                                                       stack->source = source;
                                                }
-                                               /* Perhaps we didn't install newval anywhere */
-                                               if (newval && !string_field_used(conf, newval))
-                                                       free(newval);
                                        }
                                }
-                               else if (newval)
+                               /* Perhaps we didn't install newval anywhere */
+                               if (newval && !string_field_used(conf, newval))
                                        free(newval);
                                break;
                        }