diff options
-rw-r--r-- | src/backend/executor/nodeValuesscan.c | 14 | ||||
-rw-r--r-- | src/test/regress/expected/plpgsql.out | 32 | ||||
-rw-r--r-- | src/test/regress/sql/plpgsql.sql | 12 |
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 |