summaryrefslogtreecommitdiff
path: root/src/test/regress
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-03-31 11:52:34 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-03-31 11:52:37 -0400
commit86dc90056dfdbd9d1b891718d2e5614e3e432f35 (patch)
tree8d281c58f67e90961688fd311673fbdb2f8c35c7 /src/test/regress
parent055fee7eb4dcc78e58672aef146334275e1cc40d (diff)
downloadpostgresql-86dc90056dfdbd9d1b891718d2e5614e3e432f35.tar.gz
Rework planning and execution of UPDATE and DELETE.
This patch makes two closely related sets of changes: 1. For UPDATE, the subplan of the ModifyTable node now only delivers the new values of the changed columns (i.e., the expressions computed in the query's SET clause) plus row identity information such as CTID. ModifyTable must re-fetch the original tuple to merge in the old values of any unchanged columns. The core advantage of this is that the changed columns are uniform across all tables of an inherited or partitioned target relation, whereas the other columns might not be. A secondary advantage, when the UPDATE involves joins, is that less data needs to pass through the plan tree. The disadvantage of course is an extra fetch of each tuple to be updated. However, that seems to be very nearly free in context; even worst-case tests don't show it to add more than a couple percent to the total query cost. At some point it might be interesting to combine the re-fetch with the tuple access that ModifyTable must do anyway to mark the old tuple dead; but that would require a good deal of refactoring and it seems it wouldn't buy all that much, so this patch doesn't attempt it. 2. For inherited UPDATE/DELETE, instead of generating a separate subplan for each target relation, we now generate a single subplan that is just exactly like a SELECT's plan, then stick ModifyTable on top of that. To let ModifyTable know which target relation a given incoming row refers to, a tableoid junk column is added to the row identity information. This gets rid of the horrid hack that was inheritance_planner(), eliminating O(N^2) planning cost and memory consumption in cases where there were many unprunable target relations. Point 2 of course requires point 1, so that there is a uniform definition of the non-junk columns to be returned by the subplan. We can't insist on uniform definition of the row identity junk columns however, if we want to keep the ability to have both plain and foreign tables in a partitioning hierarchy. Since it wouldn't scale very far to have every child table have its own row identity column, this patch includes provisions to merge similar row identity columns into one column of the subplan result. In particular, we can merge the whole-row Vars typically used as row identity by FDWs into one column by pretending they are type RECORD. (It's still okay for the actual composite Datums to be labeled with the table's rowtype OID, though.) There is more that can be done to file down residual inefficiencies in this patch, but it seems to be committable now. FDW authors should note several API changes: * The argument list for AddForeignUpdateTargets() has changed, and so has the method it must use for adding junk columns to the query. Call add_row_identity_var() instead of manipulating the parse tree directly. You might want to reconsider exactly what you're adding, too. * PlanDirectModify() must now work a little harder to find the ForeignScan plan node; if the foreign table is part of a partitioning hierarchy then the ForeignScan might not be the direct child of ModifyTable. See postgres_fdw for sample code. * To check whether a relation is a target relation, it's no longer sufficient to compare its relid to root->parse->resultRelation. Instead, check it against all_result_relids or leaf_result_relids, as appropriate. Amit Langote and Tom Lane Discussion: https://postgr.es/m/CA+HiwqHpHdqdDn48yCEhynnniahH78rwcrv1rEX65-fsZGBOLQ@mail.gmail.com
Diffstat (limited to 'src/test/regress')
-rw-r--r--src/test/regress/expected/inherit.out22
-rw-r--r--src/test/regress/expected/insert_conflict.out2
-rw-r--r--src/test/regress/expected/partition_join.out42
-rw-r--r--src/test/regress/expected/partition_prune.out199
-rw-r--r--src/test/regress/expected/rowsecurity.out135
-rw-r--r--src/test/regress/expected/updatable_views.out149
-rw-r--r--src/test/regress/expected/update.out43
-rw-r--r--src/test/regress/expected/with.out56
8 files changed, 283 insertions, 365 deletions
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 2b68aef654..1c703c351f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -545,27 +545,25 @@ create table some_tab_child () inherits (some_tab);
insert into some_tab_child values(1,2);
explain (verbose, costs off)
update some_tab set a = a + 1 where false;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+--------------------------------------------------------
Update on public.some_tab
- Update on public.some_tab
-> Result
- Output: (a + 1), b, ctid
+ Output: (some_tab.a + 1), NULL::oid, NULL::tid
One-Time Filter: false
-(5 rows)
+(4 rows)
update some_tab set a = a + 1 where false;
explain (verbose, costs off)
update some_tab set a = a + 1 where false returning b, a;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+--------------------------------------------------------
Update on public.some_tab
- Output: b, a
- Update on public.some_tab
+ Output: some_tab.b, some_tab.a
-> Result
- Output: (a + 1), b, ctid
+ Output: (some_tab.a + 1), NULL::oid, NULL::tid
One-Time Filter: false
-(6 rows)
+(5 rows)
update some_tab set a = a + 1 where false returning b, a;
b | a
@@ -670,7 +668,7 @@ explain update parted_tab set a = 2 where false;
QUERY PLAN
--------------------------------------------------------
Update on parted_tab (cost=0.00..0.00 rows=0 width=0)
- -> Result (cost=0.00..0.00 rows=0 width=0)
+ -> Result (cost=0.00..0.00 rows=0 width=10)
One-Time Filter: false
(3 rows)
diff --git a/src/test/regress/expected/insert_conflict.out b/src/test/regress/expected/insert_conflict.out
index 499245068a..a54a51e5c7 100644
--- a/src/test/regress/expected/insert_conflict.out
+++ b/src/test/regress/expected/insert_conflict.out
@@ -213,7 +213,7 @@ explain (costs off, format json) insert into insertconflicttest values (0, 'Bilb
"Plans": [ +
{ +
"Node Type": "Result", +
- "Parent Relationship": "Member", +
+ "Parent Relationship": "Outer", +
"Parallel Aware": false, +
"Async Capable": false +
} +
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 0057f41caa..27f7525b3e 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -1926,37 +1926,27 @@ WHERE EXISTS (
FROM int4_tbl,
LATERAL (SELECT int4_tbl.f1 FROM int8_tbl LIMIT 2) ss
WHERE prt1_l.c IS NULL);
- QUERY PLAN
----------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------
Delete on prt1_l
Delete on prt1_l_p1 prt1_l_1
Delete on prt1_l_p3_p1 prt1_l_2
Delete on prt1_l_p3_p2 prt1_l_3
-> Nested Loop Semi Join
- -> Seq Scan on prt1_l_p1 prt1_l_1
- Filter: (c IS NULL)
- -> Nested Loop
- -> Seq Scan on int4_tbl
- -> Subquery Scan on ss
- -> Limit
- -> Seq Scan on int8_tbl
- -> Nested Loop Semi Join
- -> Seq Scan on prt1_l_p3_p1 prt1_l_2
- Filter: (c IS NULL)
- -> Nested Loop
- -> Seq Scan on int4_tbl
- -> Subquery Scan on ss_1
- -> Limit
- -> Seq Scan on int8_tbl int8_tbl_1
- -> Nested Loop Semi Join
- -> Seq Scan on prt1_l_p3_p2 prt1_l_3
- Filter: (c IS NULL)
- -> Nested Loop
- -> Seq Scan on int4_tbl
- -> Subquery Scan on ss_2
- -> Limit
- -> Seq Scan on int8_tbl int8_tbl_2
-(28 rows)
+ -> Append
+ -> Seq Scan on prt1_l_p1 prt1_l_1
+ Filter: (c IS NULL)
+ -> Seq Scan on prt1_l_p3_p1 prt1_l_2
+ Filter: (c IS NULL)
+ -> Seq Scan on prt1_l_p3_p2 prt1_l_3
+ Filter: (c IS NULL)
+ -> Materialize
+ -> Nested Loop
+ -> Seq Scan on int4_tbl
+ -> Subquery Scan on ss
+ -> Limit
+ -> Seq Scan on int8_tbl
+(18 rows)
--
-- negative testcases
diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out
index bde29e38a9..c4e827caec 100644
--- a/src/test/regress/expected/partition_prune.out
+++ b/src/test/regress/expected/partition_prune.out
@@ -2463,74 +2463,43 @@ deallocate ab_q6;
insert into ab values (1,2);
explain (analyze, costs off, summary off, timing off)
update ab_a1 set b = 3 from ab where ab.a = 1 and ab.a = ab_a1.a;
- QUERY PLAN
--------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------
Update on ab_a1 (actual rows=0 loops=1)
Update on ab_a1_b1 ab_a1_1
Update on ab_a1_b2 ab_a1_2
Update on ab_a1_b3 ab_a1_3
- -> Nested Loop (actual rows=0 loops=1)
- -> Append (actual rows=1 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1)
- Recheck Cond: (a = 1)
- Heap Blocks: exact=1
- -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
- -> Materialize (actual rows=0 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
-> Nested Loop (actual rows=1 loops=1)
-> Append (actual rows=1 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)
+ -> Bitmap Heap Scan on ab_a1_b1 ab_a1_1 (actual rows=0 loops=1)
Recheck Cond: (a = 1)
-> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1)
- Recheck Cond: (a = 1)
- Heap Blocks: exact=1
- -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Materialize (actual rows=1 loops=1)
-> Bitmap Heap Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1)
Recheck Cond: (a = 1)
Heap Blocks: exact=1
-> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
Index Cond: (a = 1)
- -> Nested Loop (actual rows=0 loops=1)
- -> Append (actual rows=1 loops=1)
- -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1)
- Recheck Cond: (a = 1)
- Heap Blocks: exact=1
- -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1)
- Recheck Cond: (a = 1)
- -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
- Index Cond: (a = 1)
- -> Materialize (actual rows=0 loops=1)
-> Bitmap Heap Scan on ab_a1_b3 ab_a1_3 (actual rows=0 loops=1)
Recheck Cond: (a = 1)
-> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
Index Cond: (a = 1)
-(65 rows)
+ -> Materialize (actual rows=1 loops=1)
+ -> Append (actual rows=1 loops=1)
+ -> Bitmap Heap Scan on ab_a1_b1 ab_1 (actual rows=0 loops=1)
+ Recheck Cond: (a = 1)
+ -> Bitmap Index Scan on ab_a1_b1_a_idx (actual rows=0 loops=1)
+ Index Cond: (a = 1)
+ -> Bitmap Heap Scan on ab_a1_b2 ab_2 (actual rows=1 loops=1)
+ Recheck Cond: (a = 1)
+ Heap Blocks: exact=1
+ -> Bitmap Index Scan on ab_a1_b2_a_idx (actual rows=1 loops=1)
+ Index Cond: (a = 1)
+ -> Bitmap Heap Scan on ab_a1_b3 ab_3 (actual rows=0 loops=1)
+ Recheck Cond: (a = 1)
+ -> Bitmap Index Scan on ab_a1_b3_a_idx (actual rows=1 loops=1)
+ Index Cond: (a = 1)
+(34 rows)
table ab;
a | b
@@ -2551,29 +2520,12 @@ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1);
Update on ab_a1_b3 ab_a1_3
InitPlan 1 (returns $0)
-> Result (actual rows=1 loops=1)
- -> Nested Loop (actual rows=1 loops=1)
- -> Seq Scan on ab_a1_b1 ab_a1_1 (actual rows=1 loops=1)
- -> Materialize (actual rows=1 loops=1)
- -> Append (actual rows=1 loops=1)
- -> Seq Scan on ab_a2_b1 ab_a2_1 (actual rows=1 loops=1)
- Filter: (b = $0)
- -> Seq Scan on ab_a2_b2 ab_a2_2 (never executed)
- Filter: (b = $0)
- -> Seq Scan on ab_a2_b3 ab_a2_3 (never executed)
- Filter: (b = $0)
- -> Nested Loop (actual rows=1 loops=1)
- -> Seq Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1)
- -> Materialize (actual rows=1 loops=1)
- -> Append (actual rows=1 loops=1)
- -> Seq Scan on ab_a2_b1 ab_a2_1 (actual rows=1 loops=1)
- Filter: (b = $0)
- -> Seq Scan on ab_a2_b2 ab_a2_2 (never executed)
- Filter: (b = $0)
- -> Seq Scan on ab_a2_b3 ab_a2_3 (never executed)
- Filter: (b = $0)
- -> Nested Loop (actual rows=1 loops=1)
- -> Seq Scan on ab_a1_b3 ab_a1_3 (actual rows=1 loops=1)
- -> Materialize (actual rows=1 loops=1)
+ -> Nested Loop (actual rows=3 loops=1)
+ -> Append (actual rows=3 loops=1)
+ -> Seq Scan on ab_a1_b1 ab_a1_1 (actual rows=1 loops=1)
+ -> Seq Scan on ab_a1_b2 ab_a1_2 (actual rows=1 loops=1)
+ -> Seq Scan on ab_a1_b3 ab_a1_3 (actual rows=1 loops=1)
+ -> Materialize (actual rows=1 loops=3)
-> Append (actual rows=1 loops=1)
-> Seq Scan on ab_a2_b1 ab_a2_1 (actual rows=1 loops=1)
Filter: (b = $0)
@@ -2581,7 +2533,7 @@ update ab_a1 set b = 3 from ab_a2 where ab_a2.b = (select 1);
Filter: (b = $0)
-> Seq Scan on ab_a2_b3 ab_a2_3 (never executed)
Filter: (b = $0)
-(36 rows)
+(19 rows)
select tableoid::regclass, * from ab;
tableoid | a | b
@@ -3420,28 +3372,30 @@ explain (costs off) select * from pp_lp where a = 1;
(5 rows)
explain (costs off) update pp_lp set value = 10 where a = 1;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+----------------------------------------
Update on pp_lp
Update on pp_lp1 pp_lp_1
Update on pp_lp2 pp_lp_2
- -> Seq Scan on pp_lp1 pp_lp_1
- Filter: (a = 1)
- -> Seq Scan on pp_lp2 pp_lp_2
- Filter: (a = 1)
-(7 rows)
+ -> Append
+ -> Seq Scan on pp_lp1 pp_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on pp_lp2 pp_lp_2
+ Filter: (a = 1)
+(8 rows)
explain (costs off) delete from pp_lp where a = 1;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+----------------------------------------
Delete on pp_lp
Delete on pp_lp1 pp_lp_1
Delete on pp_lp2 pp_lp_2
- -> Seq Scan on pp_lp1 pp_lp_1
- Filter: (a = 1)
- -> Seq Scan on pp_lp2 pp_lp_2
- Filter: (a = 1)
-(7 rows)
+ -> Append
+ -> Seq Scan on pp_lp1 pp_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on pp_lp2 pp_lp_2
+ Filter: (a = 1)
+(8 rows)
set constraint_exclusion = 'off'; -- this should not affect the result.
explain (costs off) select * from pp_lp where a = 1;
@@ -3455,28 +3409,30 @@ explain (costs off) select * from pp_lp where a = 1;
(5 rows)
explain (costs off) update pp_lp set value = 10 where a = 1;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+----------------------------------------
Update on pp_lp
Update on pp_lp1 pp_lp_1
Update on pp_lp2 pp_lp_2
- -> Seq Scan on pp_lp1 pp_lp_1
- Filter: (a = 1)
- -> Seq Scan on pp_lp2 pp_lp_2
- Filter: (a = 1)
-(7 rows)
+ -> Append
+ -> Seq Scan on pp_lp1 pp_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on pp_lp2 pp_lp_2
+ Filter: (a = 1)
+(8 rows)
explain (costs off) delete from pp_lp where a = 1;
- QUERY PLAN
-----------------------------------
+ QUERY PLAN
+----------------------------------------
Delete on pp_lp
Delete on pp_lp1 pp_lp_1
Delete on pp_lp2 pp_lp_2
- -> Seq Scan on pp_lp1 pp_lp_1
- Filter: (a = 1)
- -> Seq Scan on pp_lp2 pp_lp_2
- Filter: (a = 1)
-(7 rows)
+ -> Append
+ -> Seq Scan on pp_lp1 pp_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on pp_lp2 pp_lp_2
+ Filter: (a = 1)
+(8 rows)
drop table pp_lp;
-- Ensure enable_partition_prune does not affect non-partitioned tables.
@@ -3500,28 +3456,31 @@ explain (costs off) select * from inh_lp where a = 1;
(5 rows)
explain (costs off) update inh_lp set value = 10 where a = 1;
- QUERY PLAN
-------------------------------------
+ QUERY PLAN
+------------------------------------------------
Update on inh_lp
- Update on inh_lp
- Update on inh_lp1 inh_lp_1
- -> Seq Scan on inh_lp
- Filter: (a = 1)
- -> Seq Scan on inh_lp1 inh_lp_1
- Filter: (a = 1)
-(7 rows)
+ Update on inh_lp inh_lp_1
+ Update on inh_lp1 inh_lp_2
+ -> Result
+ -> Append
+ -> Seq Scan on inh_lp inh_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on inh_lp1 inh_lp_2
+ Filter: (a = 1)
+(9 rows)
explain (costs off) delete from inh_lp where a = 1;
- QUERY PLAN
-------------------------------------
+ QUERY PLAN
+------------------------------------------
Delete on inh_lp
- Delete on inh_lp
- Delete on inh_lp1 inh_lp_1
- -> Seq Scan on inh_lp
- Filter: (a = 1)
- -> Seq Scan on inh_lp1 inh_lp_1
- Filter: (a = 1)
-(7 rows)
+ Delete on inh_lp inh_lp_1
+ Delete on inh_lp1 inh_lp_2
+ -> Append
+ -> Seq Scan on inh_lp inh_lp_1
+ Filter: (a = 1)
+ -> Seq Scan on inh_lp1 inh_lp_2
+ Filter: (a = 1)
+(8 rows)
-- Ensure we don't exclude normal relations when we only expect to exclude
-- inheritance children
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 9506aaef82..b02a682471 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1632,19 +1632,21 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2);
--
SET SESSION AUTHORIZATION regress_rls_bob;
EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b);
- QUERY PLAN
------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------
Update on t1
- Update on t1
- Update on t2 t1_1
- Update on t3 t1_2
- -> Seq Scan on t1
- Filter: (((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2 t1_1
- Filter: (((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t3 t1_2
- Filter: (((a % 2) = 0) AND f_leak(b))
-(10 rows)
+ Update on t1 t1_1
+ Update on t2 t1_2
+ Update on t3 t1_3
+ -> Result
+ -> Append
+ -> Seq Scan on t1 t1_1
+ Filter: (((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t2 t1_2
+ Filter: (((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t3 t1_3
+ Filter: (((a % 2) = 0) AND f_leak(b))
+(12 rows)
UPDATE t1 SET b = b || b WHERE f_leak(b);
NOTICE: f_leak => bbb
@@ -1722,31 +1724,27 @@ NOTICE: f_leak => cde
NOTICE: f_leak => yyyyyy
EXPLAIN (COSTS OFF) UPDATE t1 SET b=t1.b FROM t2
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
- QUERY PLAN
------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------
Update on t1
- Update on t1
- Update on t2 t1_1
- Update on t3 t1_2
- -> Nested Loop
- -> Seq Scan on t1
- Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2
- Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
- -> Nested Loop
- -> Seq Scan on t2 t1_1
- Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2
- Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
+ Update on t1 t1_1
+ Update on t2 t1_2
+ Update on t3 t1_3
-> Nested Loop
- -> Seq Scan on t3 t1_2
- Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
-> Seq Scan on t2
Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b))
-(19 rows)
+ -> Append
+ -> Seq Scan on t1 t1_1
+ Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t2 t1_2
+ Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t3 t1_3
+ Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b))
+(14 rows)
UPDATE t1 SET b=t1.b FROM t2
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
+NOTICE: f_leak => cde
EXPLAIN (COSTS OFF) UPDATE t2 SET b=t2.b FROM t1
WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b);
QUERY PLAN
@@ -1795,46 +1793,30 @@ NOTICE: f_leak => cde
EXPLAIN (COSTS OFF) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2
WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b
AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2;
- QUERY PLAN
------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------
Update on t1 t1_1
- Update on t1 t1_1
- Update on t2 t1_1_1
- Update on t3 t1_1_2
+ Update on t1 t1_1_1
+ Update on t2 t1_1_2
+ Update on t3 t1_1_3
-> Nested Loop
Join Filter: (t1_1.b = t1_2.b)
- -> Seq Scan on t1 t1_1
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Append
- -> Seq Scan on t1 t1_2_1
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2 t1_2_2
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t3 t1_2_3
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Nested Loop
- Join Filter: (t1_1_1.b = t1_2.b)
- -> Seq Scan on t2 t1_1_1
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-> Append
- -> Seq Scan on t1 t1_2_1
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2 t1_2_2
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t3 t1_2_3
+ -> Seq Scan on t1 t1_1_1
Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Nested Loop
- Join Filter: (t1_1_2.b = t1_2.b)
- -> Seq Scan on t3 t1_1_2
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Append
- -> Seq Scan on t1 t1_2_1
+ -> Seq Scan on t2 t1_1_2
Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2 t1_2_2
+ -> Seq Scan on t3 t1_1_3
Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t3 t1_2_3
- Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
-(37 rows)
+ -> Materialize
+ -> Append
+ -> Seq Scan on t1 t1_2_1
+ Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t2 t1_2_2
+ Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t3 t1_2_3
+ Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b))
+(21 rows)
UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2
WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b
@@ -1843,8 +1825,6 @@ NOTICE: f_leak => daddad_updt
NOTICE: f_leak => daddad_updt
NOTICE: f_leak => defdef
NOTICE: f_leak => defdef
-NOTICE: f_leak => daddad_updt
-NOTICE: f_leak => defdef
id | a | b | id | a | b | t1_1 | t1_2
-----+---+-------------+-----+---+-------------+---------------------+---------------------
104 | 4 | daddad_updt | 104 | 4 | daddad_updt | (104,4,daddad_updt) | (104,4,daddad_updt)
@@ -1880,19 +1860,20 @@ EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b);
(3 rows)
EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b);
- QUERY PLAN
------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------
Delete on t1
- Delete on t1
- Delete on t2 t1_1
- Delete on t3 t1_2
- -> Seq Scan on t1
- Filter: (((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t2 t1_1
- Filter: (((a % 2) = 0) AND f_leak(b))
- -> Seq Scan on t3 t1_2
- Filter: (((a % 2) = 0) AND f_leak(b))
-(10 rows)
+ Delete on t1 t1_1
+ Delete on t2 t1_2
+ Delete on t3 t1_3
+ -> Append
+ -> Seq Scan on t1 t1_1
+ Filter: (((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t2 t1_2
+ Filter: (((a % 2) = 0) AND f_leak(b))
+ -> Seq Scan on t3 t1_3
+ Filter: (((a % 2) = 0) AND f_leak(b))
+(11 rows)
DELETE FROM only t1 WHERE f_leak(b) RETURNING tableoid::regclass, *, t1;
NOTICE: f_leak => bbbbbb_updt
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 24905332b1..cdff914b93 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -1283,12 +1283,12 @@ SELECT * FROM rw_view1;
(4 rows)
EXPLAIN (verbose, costs off) UPDATE rw_view1 SET b = b + 1 RETURNING *;
- QUERY PLAN
--------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------
Update on public.base_tbl
Output: base_tbl.a, base_tbl.b
-> Seq Scan on public.base_tbl
- Output: base_tbl.a, (base_tbl.b + 1), base_tbl.ctid
+ Output: (base_tbl.b + 1), base_tbl.ctid
(4 rows)
UPDATE rw_view1 SET b = b + 1 RETURNING *;
@@ -1607,26 +1607,21 @@ UPDATE rw_view1 SET a = a + 1000 FROM other_tbl_parent WHERE a = id;
QUERY PLAN
-------------------------------------------------------------------------
Update on base_tbl_parent
- Update on base_tbl_parent
- Update on base_tbl_child base_tbl_parent_1
- -> Hash Join
- Hash Cond: (other_tbl_parent.id = base_tbl_parent.a)
- -> Append
- -> Seq Scan on other_tbl_parent other_tbl_parent_1
- -> Seq Scan on other_tbl_child other_tbl_parent_2
- -> Hash
- -> Seq Scan on base_tbl_parent
+ Update on base_tbl_parent base_tbl_parent_1
+ Update on base_tbl_child base_tbl_parent_2
-> Merge Join
- Merge Cond: (base_tbl_parent_1.a = other_tbl_parent.id)
+ Merge Cond: (base_tbl_parent.a = other_tbl_parent.id)
-> Sort
- Sort Key: base_tbl_parent_1.a
- -> Seq Scan on base_tbl_child base_tbl_parent_1
+ Sort Key: base_tbl_parent.a
+ -> Append
+ -> Seq Scan on base_tbl_parent base_tbl_parent_1
+ -> Seq Scan on base_tbl_child base_tbl_parent_2
-> Sort
Sort Key: other_tbl_parent.id
-> Append
-> Seq Scan on other_tbl_parent other_tbl_parent_1
-> Seq Scan on other_tbl_child other_tbl_parent_2
-(20 rows)
+(15 rows)
UPDATE rw_view1 SET a = a + 1000 FROM other_tbl_parent WHERE a = id;
SELECT * FROM ONLY base_tbl_parent ORDER BY a;
@@ -2332,36 +2327,39 @@ SELECT * FROM v1 WHERE a=8;
EXPLAIN (VERBOSE, COSTS OFF)
UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6;
- QUERY PLAN
------------------------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------
Update on public.t1
- Update on public.t1
- Update on public.t11 t1_1
- Update on public.t12 t1_2
- Update on public.t111 t1_3
- -> Index Scan using t1_a_idx on public.t1
- Output: 100, t1.b, t1.c, t1.ctid
- Index Cond: ((t1.a > 5) AND (t1.a < 7))
- Filter: ((t1.a <> 6) AND (SubPlan 1) AND snoop(t1.a) AND leakproof(t1.a))
- SubPlan 1
- -> Append
- -> Seq Scan on public.t12 t12_1
- Filter: (t12_1.a = t1.a)
- -> Seq Scan on public.t111 t12_2
- Filter: (t12_2.a = t1.a)
- -> Index Scan using t11_a_idx on public.t11 t1_1
- Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
- Index Cond: ((t1_1.a > 5) AND (t1_1.a < 7))
- Filter: ((t1_1.a <> 6) AND (SubPlan 1) AND snoop(t1_1.a) AND leakproof(t1_1.a))
- -> Index Scan using t12_a_idx on public.t12 t1_2
- Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
- Index Cond: ((t1_2.a > 5) AND (t1_2.a < 7))
- Filter: ((t1_2.a <> 6) AND (SubPlan 1) AND snoop(t1_2.a) AND leakproof(t1_2.a))
- -> Index Scan using t111_a_idx on public.t111 t1_3
- Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
- Index Cond: ((t1_3.a > 5) AND (t1_3.a < 7))
- Filter: ((t1_3.a <> 6) AND (SubPlan 1) AND snoop(t1_3.a) AND leakproof(t1_3.a))
-(27 rows)
+ Update on public.t1 t1_1
+ Update on public.t11 t1_2
+ Update on public.t12 t1_3
+ Update on public.t111 t1_4
+ -> Result
+ Output: 100, t1.tableoid, t1.ctid
+ -> Append
+ -> Index Scan using t1_a_idx on public.t1 t1_1
+ Output: t1_1.tableoid, t1_1.ctid
+ Index Cond: ((t1_1.a > 5) AND (t1_1.a < 7))
+ Filter: ((t1_1.a <> 6) AND (SubPlan 1) AND snoop(t1_1.a) AND leakproof(t1_1.a))
+ SubPlan 1
+ -> Append
+ -> Seq Scan on public.t12 t12_1
+ Filter: (t12_1.a = t1_1.a)
+ -> Seq Scan on public.t111 t12_2
+ Filter: (t12_2.a = t1_1.a)
+ -> Index Scan using t11_a_idx on public.t11 t1_2
+ Output: t1_2.tableoid, t1_2.ctid
+ Index Cond: ((t1_2.a > 5) AND (t1_2.a < 7))
+ Filter: ((t1_2.a <> 6) AND (SubPlan 1) AND snoop(t1_2.a) AND leakproof(t1_2.a))
+ -> Index Scan using t12_a_idx on public.t12 t1_3
+ Output: t1_3.tableoid, t1_3.ctid
+ Index Cond: ((t1_3.a > 5) AND (t1_3.a < 7))
+ Filter: ((t1_3.a <> 6) AND (SubPlan 1) AND snoop(t1_3.a) AND leakproof(t1_3.a))
+ -> Index Scan using t111_a_idx on public.t111 t1_4
+ Output: t1_4.tableoid, t1_4.ctid
+ Index Cond: ((t1_4.a > 5) AND (t1_4.a < 7))
+ Filter: ((t1_4.a <> 6) AND (SubPlan 1) AND snoop(t1_4.a) AND leakproof(t1_4.a))
+(30 rows)
UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6;
SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100
@@ -2376,36 +2374,39 @@ SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100
EXPLAIN (VERBOSE, COSTS OFF)
UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
- QUERY PLAN
--------------------------------------------------------------------------
+ QUERY PLAN
+-----------------------------------------------------------------------------------
Update on public.t1
- Update on public.t1
- Update on public.t11 t1_1
- Update on public.t12 t1_2
- Update on public.t111 t1_3
- -> Index Scan using t1_a_idx on public.t1
- Output: (t1.a + 1), t1.b, t1.c, t1.ctid
- Index Cond: ((t1.a > 5) AND (t1.a = 8))
- Filter: ((SubPlan 1) AND snoop(t1.a) AND leakproof(t1.a))
- SubPlan 1
- -> Append
- -> Seq Scan on public.t12 t12_1
- Filter: (t12_1.a = t1.a)
- -> Seq Scan on public.t111 t12_2
- Filter: (t12_2.a = t1.a)
- -> Index Scan using t11_a_idx on public.t11 t1_1
- Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
- Index Cond: ((t1_1.a > 5) AND (t1_1.a = 8))
- Filter: ((SubPlan 1) AND snoop(t1_1.a) AND leakproof(t1_1.a))
- -> Index Scan using t12_a_idx on public.t12 t1_2
- Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
- Index Cond: ((t1_2.a > 5) AND (t1_2.a = 8))
- Filter: ((SubPlan 1) AND snoop(t1_2.a) AND leakproof(t1_2.a))
- -> Index Scan using t111_a_idx on public.t111 t1_3
- Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
- Index Cond: ((t1_3.a > 5) AND (t1_3.a = 8))
- Filter: ((SubPlan 1) AND snoop(t1_3.a) AND leakproof(t1_3.a))
-(27 rows)
+ Update on public.t1 t1_1
+ Update on public.t11 t1_2
+ Update on public.t12 t1_3
+ Update on public.t111 t1_4
+ -> Result
+ Output: (t1.a + 1), t1.tableoid, t1.ctid
+ -> Append
+ -> Index Scan using t1_a_idx on public.t1 t1_1
+ Output: t1_1.a, t1_1.tableoid, t1_1.ctid
+ Index Cond: ((t1_1.a > 5) AND (t1_1.a = 8))
+ Filter: ((SubPlan 1) AND snoop(t1_1.a) AND leakproof(t1_1.a))
+ SubPlan 1
+ -> Append
+ -> Seq Scan on public.t12 t12_1
+ Filter: (t12_1.a = t1_1.a)
+ -> Seq Scan on public.t111 t12_2
+ Filter: (t12_2.a = t1_1.a)
+ -> Index Scan using t11_a_idx on public.t11 t1_2
+ Output: t1_2.a, t1_2.tableoid, t1_2.ctid
+ Index Cond: ((t1_2.a > 5) AND (t1_2.a = 8))
+ Filter: ((SubPlan 1) AND snoop(t1_2.a) AND leakproof(t1_2.a))
+ -> Index Scan using t12_a_idx on public.t12 t1_3
+ Output: t1_3.a, t1_3.tableoid, t1_3.ctid
+ Index Cond: ((t1_3.a > 5) AND (t1_3.a = 8))
+ Filter: ((SubPlan 1) AND snoop(t1_3.a) AND leakproof(t1_3.a))
+ -> Index Scan using t111_a_idx on public.t111 t1_4
+ Output: t1_4.a, t1_4.tableoid, t1_4.ctid
+ Index Cond: ((t1_4.a > 5) AND (t1_4.a = 8))
+ Filter: ((SubPlan 1) AND snoop(t1_4.a) AND leakproof(t1_4.a))
+(30 rows)
UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
NOTICE: snooped value: 8
diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out
index bf939d79f6..dc34ac67b3 100644
--- a/src/test/regress/expected/update.out
+++ b/src/test/regress/expected/update.out
@@ -172,14 +172,14 @@ EXPLAIN (VERBOSE, COSTS OFF)
UPDATE update_test t
SET (a, b) = (SELECT b, a FROM update_test s WHERE s.a = t.a)
WHERE CURRENT_USER = SESSION_USER;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------
Update on public.update_test t
-> Result
- Output: $1, $2, t.c, (SubPlan 1 (returns $1,$2)), t.ctid
+ Output: $1, $2, (SubPlan 1 (returns $1,$2)), t.ctid
One-Time Filter: (CURRENT_USER = SESSION_USER)
-> Seq Scan on public.update_test t
- Output: t.c, t.a, t.ctid
+ Output: t.a, t.ctid
SubPlan 1 (returns $1,$2)
-> Seq Scan on public.update_test s
Output: s.b, s.a
@@ -308,8 +308,8 @@ ALTER TABLE part_b_10_b_20 ATTACH PARTITION part_c_1_100 FOR VALUES FROM (1) TO
-- The order of subplans should be in bound order
EXPLAIN (costs off) UPDATE range_parted set c = c - 50 WHERE c > 97;
- QUERY PLAN
--------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------
Update on range_parted
Update on part_a_1_a_10 range_parted_1
Update on part_a_10_a_20 range_parted_2
@@ -318,21 +318,22 @@ EXPLAIN (costs off) UPDATE range_parted set c = c - 50 WHERE c > 97;
Update on part_d_1_15 range_parted_5
Update on part_d_15_20 range_parted_6
Update on part_b_20_b_30 range_parted_7
- -> Seq Scan on part_a_1_a_10 range_parted_1
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_a_10_a_20 range_parted_2
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_b_1_b_10 range_parted_3
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_c_1_100 range_parted_4
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_d_1_15 range_parted_5
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_d_15_20 range_parted_6
- Filter: (c > '97'::numeric)
- -> Seq Scan on part_b_20_b_30 range_parted_7
- Filter: (c > '97'::numeric)
-(22 rows)
+ -> Append
+ -> Seq Scan on part_a_1_a_10 range_parted_1
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_a_10_a_20 range_parted_2
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_b_1_b_10 range_parted_3
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_c_1_100 range_parted_4
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_d_1_15 range_parted_5
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_d_15_20 range_parted_6
+ Filter: (c > '97'::numeric)
+ -> Seq Scan on part_b_20_b_30 range_parted_7
+ Filter: (c > '97'::numeric)
+(23 rows)
-- fail, row movement happens only within the partition subtree.
UPDATE part_c_100_200 set c = c - 20, d = c WHERE c = 105;
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 9a6b716ddc..0affacc191 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -2906,47 +2906,35 @@ SELECT * FROM parent;
EXPLAIN (VERBOSE, COSTS OFF)
WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
DELETE FROM a USING wcte WHERE aa = q2;
- QUERY PLAN
-----------------------------------------------------
+ QUERY PLAN
+------------------------------------------------------------
Delete on public.a
- Delete on public.a
- Delete on public.b a_1
- Delete on public.c a_2
- Delete on public.d a_3
+ Delete on public.a a_1
+ Delete on public.b a_2
+ Delete on public.c a_3
+ Delete on public.d a_4
CTE wcte
-> Insert on public.int8_tbl
Output: int8_tbl.q2
-> Result
Output: '42'::bigint, '47'::bigint
- -> Nested Loop
- Output: a.ctid, wcte.*
- Join Filter: (a.aa = wcte.q2)
- -> Seq Scan on public.a
- Output: a.ctid, a.aa
- -> CTE Scan on wcte
+ -> Hash Join
+ Output: wcte.*, a.tableoid, a.ctid
+ Hash Cond: (a.aa = wcte.q2)
+ -> Append
+ -> Seq Scan on public.a a_1
+ Output: a_1.aa, a_1.tableoid, a_1.ctid
+ -> Seq Scan on public.b a_2
+ Output: a_2.aa, a_2.tableoid, a_2.ctid
+ -> Seq Scan on public.c a_3
+ Output: a_3.aa, a_3.tableoid, a_3.ctid
+ -> Seq Scan on public.d a_4
+ Output: a_4.aa, a_4.tableoid, a_4.ctid
+ -> Hash
Output: wcte.*, wcte.q2
- -> Nested Loop
- Output: a_1.ctid, wcte.*
- Join Filter: (a_1.aa = wcte.q2)
- -> Seq Scan on public.b a_1
- Output: a_1.ctid, a_1.aa
- -> CTE Scan on wcte
- Output: wcte.*, wcte.q2
- -> Nested Loop
- Output: a_2.ctid, wcte.*
- Join Filter: (a_2.aa = wcte.q2)
- -> Seq Scan on public.c a_2
- Output: a_2.ctid, a_2.aa
- -> CTE Scan on wcte
- Output: wcte.*, wcte.q2
- -> Nested Loop
- Output: a_3.ctid, wcte.*
- Join Filter: (a_3.aa = wcte.q2)
- -> Seq Scan on public.d a_3
- Output: a_3.ctid, a_3.aa
- -> CTE Scan on wcte
- Output: wcte.*, wcte.q2
-(38 rows)
+ -> CTE Scan on wcte
+ Output: wcte.*, wcte.q2
+(26 rows)
-- error cases
-- data-modifying WITH tries to use its own output