]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix an ancient logic error in plpgsql's exec_stmt_block: it thought it could
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Feb 2007 18:38:08 +0000 (18:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Feb 2007 18:38:08 +0000 (18:38 +0000)
get away with not (re)initializing a local variable if the variable is marked
"isconst" and not "isnull".  Unfortunately it makes this decision after having
already freed the old value, meaning that something like

   for i in 1..10 loop
     declare c constant text := 'hi there';

leads to subsequent accesses to freed memory, and hence probably crashes.
(In particular, this is why Asif Ali Rehman's bug leads to crash and not
just an unexpectedly-NULL value for SQLERRM: SQLERRM is marked CONSTANT
and so triggers this error.)

The whole thing seems wrong on its face anyway: CONSTANT means that you can't
change the variable inside the block, not that the initializer expression is
guaranteed not to change value across successive block entries.  Hence,
remove the "optimization" instead of trying to fix it.

src/pl/plpgsql/src/pl_exec.c

index 1071521d23beb9b50313c8e555b8156f0211d4d5..147284aa1e991aac208e5c90935b414649d56de2 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.6 2007/01/30 18:02:40 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.7 2007/02/08 18:38:08 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -866,29 +866,29 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
                                {
                                        PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
 
+                                       /* free any old value, in case re-entering block */
                                        if (var->freeval)
                                        {
                                                pfree((void *) (var->value));
                                                var->freeval = false;
                                        }
 
-                                       if (!var->isconst || var->isnull)
+                                       /* Initially it contains a NULL */
+                                       var->value = (Datum) 0;
+                                       var->isnull = true;
+
+                                       if (var->default_val == NULL)
+                                       {
+                                               if (var->notnull)
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+                                                                        errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
+                                                                                       var->refname)));
+                                       }
+                                       else
                                        {
-                                               if (var->default_val == NULL)
-                                               {
-                                                       var->value = (Datum) 0;
-                                                       var->isnull = true;
-                                                       if (var->notnull)
-                                                               ereport(ERROR,
-                                                               (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
-                                                                errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
-                                                                               var->refname)));
-                                               }
-                                               else
-                                               {
-                                                       exec_assign_expr(estate, (PLpgSQL_datum *) var,
-                                                                                        var->default_val);
-                                               }
+                                               exec_assign_expr(estate, (PLpgSQL_datum *) var,
+                                                                                var->default_val);
                                        }
                                }
                                break;