]> granicus.if.org Git - postgresql/commitdiff
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 2c4bd9c92771e9682ad268789824963f72fc87ee..9c03f8ae16680b57fa76e46f956093b032d40295 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 9563210080a223ca88280da1a583f3587d53255b..a2c36e44ba0aee3bff52c4884d855cff15cb7c45 100644 (file)
@@ -5404,6 +5404,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 b1226ea4a0f668b536276b8e5ac7e80e06733e14..776f2292ea59a4f3b3b2a92db50d9ce96902ac1a 100644 (file)
@@ -4263,6 +4263,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