aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/nodeValuesscan.c14
-rw-r--r--src/test/regress/expected/plpgsql.out32
-rw-r--r--src/test/regress/sql/plpgsql.sql12
3 files changed, 58 insertions, 0 deletions
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index a39695a0c5f..0e9cb11cf3e 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -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++;
}
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index d0e0556224a..2b0454559df 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -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
--
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index df436ee4a28..a375394bbc2 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -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