mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Mark read/write expanded values as read-only in ExecProject().
If a plan node output expression returns an "expanded" datum, and that
output column is referenced in more than one place in upper-level plan
nodes, we need to ensure that what is returned is a read-only reference
not a read/write reference. Otherwise one of the referencing sites could
scribble on or even delete the expanded datum before we have evaluated the
others. Commit 1dc5ebc907
, which introduced this feature, supposed
that it'd be sufficient to make SubqueryScan nodes force their output
columns to read-only state. The folly of that was revealed by bug #14174
from Andrew Gierth, and really should have been immediately obvious
considering that the planner will happily optimize SubqueryScan nodes
out of the plan without any regard for this issue.
The safest fix seems to be to make ExecProject() force its results into
read-only state; that will cover every case where a plan node returns
expression results. Actually we can delegate this to ExecTargetList()
since we can recursively assume that plain Vars will not reference
read-write datums. That should keep the extra overhead down to something
minimal. We no longer need ExecMakeSlotContentsReadOnly(), which was
introduced only in support of the idea that just a few plan node types
would need to do this.
In the future it would be nice to have the planner account for this problem
and inject force-to-read-only expression evaluation nodes into only the
places where there's a risk of multiple evaluation. That's not a suitable
solution for 9.5 or even 9.6 at this point, though.
Report: <20160603124628.9932.41279@wrigleys.postgresql.org>
This commit is contained in:
@ -5368,7 +5368,45 @@ ERROR: value for domain orderedarray violates check constraint "sorted"
|
||||
CONTEXT: PL/pgSQL function testoa(integer,integer,integer) line 5 at assignment
|
||||
drop function arrayassign1();
|
||||
drop function testoa(x1 int, x2 int, x3 int);
|
||||
-- access to call stack
|
||||
--
|
||||
-- Test handling of expanded arrays
|
||||
--
|
||||
create function returns_rw_array(int) returns int[]
|
||||
language plpgsql as $$
|
||||
declare r int[];
|
||||
begin r := array[$1, $1]; return r; end;
|
||||
$$ stable;
|
||||
create function consumes_rw_array(int[]) returns int
|
||||
language plpgsql as $$
|
||||
begin return $1[1]; end;
|
||||
$$ stable;
|
||||
-- bug #14174
|
||||
explain (verbose, costs off)
|
||||
select i, a from
|
||||
(select returns_rw_array(1) as a offset 0) ss,
|
||||
lateral consumes_rw_array(a) i;
|
||||
QUERY PLAN
|
||||
-----------------------------------------------------------------
|
||||
Nested Loop
|
||||
Output: i.i, (returns_rw_array(1))
|
||||
-> Result
|
||||
Output: returns_rw_array(1)
|
||||
-> Function Scan on public.consumes_rw_array i
|
||||
Output: i.i
|
||||
Function Call: consumes_rw_array((returns_rw_array(1)))
|
||||
(7 rows)
|
||||
|
||||
select i, a from
|
||||
(select returns_rw_array(1) as a offset 0) ss,
|
||||
lateral consumes_rw_array(a) i;
|
||||
i | a
|
||||
---+-------
|
||||
1 | {1,1}
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- Test access to call stack
|
||||
--
|
||||
create function inner_func(int)
|
||||
returns int as $$
|
||||
declare _context text;
|
||||
|
@ -4237,7 +4237,37 @@ select testoa(1,2,1); -- fail at update
|
||||
drop function arrayassign1();
|
||||
drop function testoa(x1 int, x2 int, x3 int);
|
||||
|
||||
-- access to call stack
|
||||
|
||||
--
|
||||
-- Test handling of expanded arrays
|
||||
--
|
||||
|
||||
create function returns_rw_array(int) returns int[]
|
||||
language plpgsql as $$
|
||||
declare r int[];
|
||||
begin r := array[$1, $1]; return r; end;
|
||||
$$ stable;
|
||||
|
||||
create function consumes_rw_array(int[]) returns int
|
||||
language plpgsql as $$
|
||||
begin return $1[1]; end;
|
||||
$$ stable;
|
||||
|
||||
-- bug #14174
|
||||
explain (verbose, costs off)
|
||||
select i, a from
|
||||
(select returns_rw_array(1) as a offset 0) ss,
|
||||
lateral consumes_rw_array(a) i;
|
||||
|
||||
select i, a from
|
||||
(select returns_rw_array(1) as a offset 0) ss,
|
||||
lateral consumes_rw_array(a) i;
|
||||
|
||||
|
||||
--
|
||||
-- Test access to call stack
|
||||
--
|
||||
|
||||
create function inner_func(int)
|
||||
returns int as $$
|
||||
declare _context text;
|
||||
|
Reference in New Issue
Block a user