Mark read/write expanded values as read-only in ValuesNext(), too.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 3 Jun 2016 22:07:14 +0000 (18:07 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 3 Jun 2016 22:07:14 +0000 (18:07 -0400)
Further thought about bug #14174 motivated me to try the case of a
R/W datum being returned from a VALUES list, and sure enough it was
broken.  Fix that.

Also add a regression test case exercising the same scenario for
FunctionScan.  That's not broken right now, because the function's
result will get shoved into a tuplestore between generation and use;
but it could easily become broken whenever we get around to optimizing
FunctionScan better.

There don't seem to be any other places where we put the result of
expression evaluation into a virtual tuple slot that could then be
the source for Vars of further expression evaluation, so I think
this is the end of this bug.

src/backend/executor/nodeValuesscan.c
src/test/regress/expected/plpgsql.out
src/test/regress/sql/plpgsql.sql

index a39695a0c5ff9cf4d155d298bab59282504a9999..0e9cb11cf3eab398b56aea495bb8769dfada0d53 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "executor/executor.h"
 #include "executor/nodeValuesscan.h"
+#include "utils/expandeddatum.h"
 
 
 static TupleTableSlot *ValuesNext(ValuesScanState *node);
@@ -94,6 +95,7 @@ ValuesNext(ValuesScanState *node)
        List       *exprstatelist;
        Datum      *values;
        bool       *isnull;
+       Form_pg_attribute *att;
        ListCell   *lc;
        int         resind;
 
@@ -129,6 +131,7 @@ ValuesNext(ValuesScanState *node)
         */
        values = slot->tts_values;
        isnull = slot->tts_isnull;
+       att = slot->tts_tupleDescriptor->attrs;
 
        resind = 0;
        foreach(lc, exprstatelist)
@@ -139,6 +142,17 @@ ValuesNext(ValuesScanState *node)
                                          econtext,
                                          &isnull[resind],
                                          NULL);
+
+           /*
+            * We must force any R/W expanded datums to read-only state, in
+            * case they are multiply referenced in the plan node's output
+            * expressions, or in case we skip the output projection and the
+            * output column is multiply referenced in higher plan nodes.
+            */
+           values[resind] = MakeExpandedObjectReadOnly(values[resind],
+                                                       isnull[resind],
+                                                       att[resind]->attlen);
+
            resind++;
        }
 
index d0e0556224a7198cd2822781565b4e0021aa0944..2b0454559df50caba5a9313ea64a41eb4a22e072 100644 (file)
@@ -5340,6 +5340,38 @@ select i, a from
  1 | {1,1}
 (1 row)
 
+explain (verbose, costs off)
+select consumes_rw_array(a), a from returns_rw_array(1) a;
+                 QUERY PLAN                 
+--------------------------------------------
+ Function Scan on public.returns_rw_array a
+   Output: consumes_rw_array(a), a
+   Function Call: returns_rw_array(1)
+(3 rows)
+
+select consumes_rw_array(a), a from returns_rw_array(1) a;
+ consumes_rw_array |   a   
+-------------------+-------
+                 1 | {1,1}
+(1 row)
+
+explain (verbose, costs off)
+select consumes_rw_array(a), a from
+  (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Values Scan on "*VALUES*"
+   Output: consumes_rw_array("*VALUES*".column1), "*VALUES*".column1
+(2 rows)
+
+select consumes_rw_array(a), a from
+  (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
+ consumes_rw_array |   a   
+-------------------+-------
+                 1 | {1,1}
+                 2 | {2,2}
+(2 rows)
+
 --
 -- Test access to call stack
 --
index df436ee4a28bba01765b860b51a4292d76858dd7..a375394bbc2dac6b62dce323b14ca5f9949bd25b 100644 (file)
@@ -4225,6 +4225,18 @@ select i, a from
   (select returns_rw_array(1) as a offset 0) ss,
   lateral consumes_rw_array(a) i;
 
+explain (verbose, costs off)
+select consumes_rw_array(a), a from returns_rw_array(1) a;
+
+select consumes_rw_array(a), a from returns_rw_array(1) a;
+
+explain (verbose, costs off)
+select consumes_rw_array(a), a from
+  (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
+
+select consumes_rw_array(a), a from
+  (values (returns_rw_array(1)), (returns_rw_array(2))) v(a);
+
 
 --
 -- Test access to call stack