fix-rowmark-skipping-for-pruned-relations.patch
text/x-patch
Filename: fix-rowmark-skipping-for-pruned-relations.patch
Type: text/x-patch
Part: 0
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);
+ <waiting ...>
+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