aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/execMain.c34
-rw-r--r--src/test/isolation/expected/eval-plan-qual.out7
-rw-r--r--src/test/isolation/specs/eval-plan-qual.spec4
3 files changed, 22 insertions, 23 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index ac92340af56..2275a2988f6 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2892,32 +2892,12 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
}
/*
- * These arrays are reused across different plans set with
- * EvalPlanQualSetPlan(), which is safe because they all use the same
- * parent EState. Therefore we can reuse if already allocated.
- */
- if (epqstate->relsubs_rowmark == NULL)
- {
- Assert(epqstate->relsubs_done == NULL);
- epqstate->relsubs_rowmark = (ExecAuxRowMark **)
- palloc0(rtsize * sizeof(ExecAuxRowMark *));
- epqstate->relsubs_done = (bool *)
- palloc0(rtsize * sizeof(bool));
- }
- else
- {
- Assert(epqstate->relsubs_done != NULL);
- memset(epqstate->relsubs_rowmark, 0,
- rtsize * sizeof(ExecAuxRowMark *));
- memset(epqstate->relsubs_done, 0,
- rtsize * sizeof(bool));
- }
-
- /*
* Build an RTI indexed array of rowmarks, so that
* EvalPlanQualFetchRowMark() can efficiently access the to be fetched
* rowmark.
*/
+ epqstate->relsubs_rowmark = (ExecAuxRowMark **)
+ palloc0(rtsize * sizeof(ExecAuxRowMark *));
foreach(l, epqstate->arowMarks)
{
ExecAuxRowMark *earm = (ExecAuxRowMark *) lfirst(l);
@@ -2926,6 +2906,12 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
}
/*
+ * Initialize per-relation EPQ tuple states to not-fetched.
+ */
+ epqstate->relsubs_done = (bool *)
+ palloc0(rtsize * sizeof(bool));
+
+ /*
* Initialize the private state information for all the nodes in the part
* of the plan tree we need to run. This opens files, allocates storage
* and leaves us ready to start processing tuples.
@@ -2993,7 +2979,9 @@ EvalPlanQualEnd(EPQState *epqstate)
FreeExecutorState(estate);
/* Mark EPQState idle */
+ epqstate->origslot = NULL;
epqstate->recheckestate = NULL;
epqstate->recheckplanstate = NULL;
- epqstate->origslot = NULL;
+ epqstate->relsubs_rowmark = NULL;
+ epqstate->relsubs_done = NULL;
}
diff --git a/src/test/isolation/expected/eval-plan-qual.out b/src/test/isolation/expected/eval-plan-qual.out
index 71393d4e7ed..755c4bd1c74 100644
--- a/src/test/isolation/expected/eval-plan-qual.out
+++ b/src/test/isolation/expected/eval-plan-qual.out
@@ -673,6 +673,13 @@ a b c
2 3 0
step c2: COMMIT;
+starting permutation: writep3a writep3b c1 c2
+step writep3a: UPDATE p SET b = -b WHERE c = 0;
+step writep3b: UPDATE p SET b = -b WHERE c = 0; <waiting ...>
+step c1: COMMIT;
+step writep3b: <... completed>
+step c2: COMMIT;
+
starting permutation: wx2 partiallock c2 c1 read
step wx2: UPDATE accounts SET balance = balance + 450 WHERE accountid = 'checking' RETURNING balance;
balance
diff --git a/src/test/isolation/specs/eval-plan-qual.spec b/src/test/isolation/specs/eval-plan-qual.spec
index b4a8b0a4c87..3ecf9f5ba14 100644
--- a/src/test/isolation/specs/eval-plan-qual.spec
+++ b/src/test/isolation/specs/eval-plan-qual.spec
@@ -97,10 +97,12 @@ step "upsert1" {
# readp1/writep1/readp2 tests a bug where nodeLockRows did the wrong thing
# when the first updated tuple was in a non-first child table.
# writep2/returningp1 tests a memory allocation issue
+# writep3a/writep3b tests updates touching more than one table
step "readp1" { SELECT tableoid::regclass, ctid, * FROM p WHERE b IN (0, 1) AND c = 0 FOR UPDATE; }
step "writep1" { UPDATE p SET b = -1 WHERE a = 1 AND b = 1 AND c = 0; }
step "writep2" { UPDATE p SET b = -b WHERE a = 1 AND c = 0; }
+step "writep3a" { UPDATE p SET b = -b WHERE c = 0; }
step "c1" { COMMIT; }
step "r1" { ROLLBACK; }
@@ -203,6 +205,7 @@ step "returningp1" {
WITH u AS ( UPDATE p SET b = b WHERE a > 0 RETURNING * )
SELECT * FROM u;
}
+step "writep3b" { UPDATE p SET b = -b WHERE c = 0; }
step "readforss" {
SELECT ta.id AS ta_id, ta.value AS ta_value,
(SELECT ROW(tb.id, tb.value)
@@ -338,6 +341,7 @@ permutation "wx1" "delwctefail" "c1" "c2" "read"
permutation "upsert1" "upsert2" "c1" "c2" "read"
permutation "readp1" "writep1" "readp2" "c1" "c2"
permutation "writep2" "returningp1" "c1" "c2"
+permutation "writep3a" "writep3b" "c1" "c2"
permutation "wx2" "partiallock" "c2" "c1" "read"
permutation "wx2" "lockwithvalues" "c2" "c1" "read"
permutation "wx2_ext" "partiallock_ext" "c2" "c1" "read_ext"