diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c new file mode 100644 index 797d8b1..01dffde --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -880,21 +880,25 @@ InitPlan(QueryDesc *queryDesc, int eflag foreach(l, plannedstmt->rowMarks) { PlanRowMark *rc = (PlanRowMark *) lfirst(l); + RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate); Oid relid; Relation relation; ExecRowMark *erm; + /* ignore "parent" rowmarks; they are irrelevant at runtime */ + if (rc->isParent) + continue; + /* - * Ignore "parent" rowmarks, because they are irrelevant at - * runtime. Also ignore the rowmarks belonging to child tables - * that have been pruned in ExecDoInitialPruning(). + * Also ignore rowmarks belonging to child tables that have been + * pruned in ExecDoInitialPruning(). */ - if (rc->isParent || + if (rte->rtekind == RTE_RELATION && !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; /* get relation's OID (will produce InvalidOid if subquery) */ - relid = exec_rt_fetch(rc->rti, estate)->relid; + relid = rte->relid; /* open relation, if we need to access it for this mark type */ switch (rc->markType) diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c new file mode 100644 index a8afbf9..5d38bd4 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -344,15 +344,19 @@ ExecInitLockRows(LockRows *node, EState foreach(lc, node->rowMarks) { PlanRowMark *rc = lfirst_node(PlanRowMark, lc); + RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate); ExecRowMark *erm; ExecAuxRowMark *aerm; + /* ignore "parent" rowmarks; they are irrelevant at runtime */ + if (rc->isParent) + continue; + /* - * Ignore "parent" rowmarks, because they are irrelevant at runtime. - * Also ignore the rowmarks belonging to child tables that have been + * Also ignore rowmarks belonging to child tables that have been * pruned in ExecDoInitialPruning(). */ - if (rc->isParent || + if (rte->rtekind == RTE_RELATION && !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c new file mode 100644 index 874b71e..9066a58 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -5092,15 +5092,19 @@ ExecInitModifyTable(ModifyTable *node, E foreach(l, node->rowMarks) { PlanRowMark *rc = lfirst_node(PlanRowMark, l); + RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate); ExecRowMark *erm; ExecAuxRowMark *aerm; + /* ignore "parent" rowmarks; they are irrelevant at runtime */ + if (rc->isParent) + continue; + /* - * Ignore "parent" rowmarks, because they are irrelevant at runtime. - * Also ignore the rowmarks belonging to child tables that have been + * Also ignore rowmarks belonging to child tables that have been * pruned in ExecDoInitialPruning(). */ - if (rc->isParent || + if (rte->rtekind == RTE_RELATION && !bms_is_member(rc->rti, estate->es_unpruned_relids)) continue; diff --git a/src/test/isolation/expected/eval-plan-qual.out b/src/test/isolation/expected/eval-plan-qual.out new file mode 100644 index 05fffe0..a122047 --- a/src/test/isolation/expected/eval-plan-qual.out +++ b/src/test/isolation/expected/eval-plan-qual.out @@ -1473,3 +1473,23 @@ step s2pp4: DELETE FROM another_parttbl step c1: COMMIT; step s2pp4: <... completed> step c2: COMMIT; + +starting permutation: updateformergevalues mergevalues c1 c2 read +step updateformergevalues: UPDATE accounts SET balance = balance + 100; +step mergevalues: + MERGE INTO accounts + USING (VALUES ('checking', 610), ('savings', 620)) v(accountid, balance) + ON v.accountid = accounts.accountid + WHEN MATCHED THEN UPDATE SET balance = v.balance + WHEN NOT MATCHED THEN INSERT VALUES ('unmatched', -1); + +step c1: COMMIT; +step mergevalues: <... completed> +step c2: COMMIT; +step read: SELECT * FROM accounts ORDER BY accountid; +accountid|balance|balance2 +---------+-------+-------- +checking | 610| 1220 +savings | 620| 1240 +(2 rows) + diff --git a/src/test/isolation/specs/eval-plan-qual.spec b/src/test/isolation/specs/eval-plan-qual.spec new file mode 100644 index 80e1e6b..fb57fb2 --- a/src/test/isolation/specs/eval-plan-qual.spec +++ b/src/test/isolation/specs/eval-plan-qual.spec @@ -206,6 +206,8 @@ step sys1 { step s1pp1 { UPDATE another_parttbl SET b = b + 1 WHERE a = 1; } +step updateformergevalues { UPDATE accounts SET balance = balance + 100; } + session s2 setup { BEGIN ISOLATION LEVEL READ COMMITTED; } step wx2 { UPDATE accounts SET balance = balance + 450 WHERE accountid = 'checking' RETURNING balance; } @@ -318,6 +320,14 @@ step s2pp2 { PREPARE epd AS DELETE FROM step s2pp3 { EXECUTE epd(1); } step s2pp4 { DELETE FROM another_parttbl WHERE a = (SELECT 1); } +step mergevalues { + MERGE INTO accounts + USING (VALUES ('checking', 610), ('savings', 620)) v(accountid, balance) + ON v.accountid = accounts.accountid + WHEN MATCHED THEN UPDATE SET balance = v.balance + WHEN NOT MATCHED THEN INSERT VALUES ('unmatched', -1); +} + session s3 setup { BEGIN ISOLATION LEVEL READ COMMITTED; } step read { SELECT * FROM accounts ORDER BY accountid; } @@ -425,3 +435,6 @@ permutation sys1 sysmerge2 c1 c2 # Exercise run-time partition pruning code in an EPQ recheck permutation s1pp1 s2pp1 s2pp2 s2pp3 c1 c2 permutation s1pp1 s2pp4 c1 c2 + +# test EPQ recheck in MERGE from VALUES_RTE, cf bug #19355 +permutation updateformergevalues mergevalues c1 c2 read