aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeCtescan.c13
-rw-r--r--src/test/isolation/expected/eval-plan-qual.out15
-rw-r--r--src/test/isolation/specs/eval-plan-qual.spec9
3 files changed, 37 insertions, 0 deletions
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index 218619c760d..24700dd3965 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -108,6 +108,13 @@ CteScanNext(CteScanState *node)
}
/*
+ * There are corner cases where the subplan could change which
+ * tuplestore read pointer is active, so be sure to reselect ours
+ * before storing the tuple we got.
+ */
+ tuplestore_select_read_pointer(tuplestorestate, node->readptr);
+
+ /*
* Append a copy of the returned tuple to tuplestore. NOTE: because
* our read pointer is certainly in EOF state, its read position will
* move forward over the added tuple. This is what we want. Also,
@@ -178,6 +185,12 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
* we might be asked to rescan the CTE even though upper levels didn't
* tell us to be prepared to do it efficiently. Annoying, since this
* prevents truncation of the tuplestore. XXX FIXME
+ *
+ * Note: if we are in an EPQ recheck plan tree, it's likely that no access
+ * to the tuplestore is needed at all, making this even more annoying.
+ * It's not worth improving that as long as all the read pointers would
+ * have REWIND anyway, but if we ever improve this logic then that aspect
+ * should be considered too.
*/
eflags |= EXEC_FLAG_REWIND;
diff --git a/src/test/isolation/expected/eval-plan-qual.out b/src/test/isolation/expected/eval-plan-qual.out
index eb40717679c..fed01459cf0 100644
--- a/src/test/isolation/expected/eval-plan-qual.out
+++ b/src/test/isolation/expected/eval-plan-qual.out
@@ -217,3 +217,18 @@ id data id data
9 0 9 0
10 0 10 0
step c1: COMMIT;
+
+starting permutation: wrtwcte multireadwcte c1 c2
+step wrtwcte: UPDATE table_a SET value = 'tableAValue2' WHERE id = 1;
+step multireadwcte:
+ WITH updated AS (
+ UPDATE table_a SET value = 'tableAValue3' WHERE id = 1 RETURNING id
+ )
+ SELECT (SELECT id FROM updated) AS subid, * FROM updated;
+ <waiting ...>
+step c1: COMMIT;
+step c2: COMMIT;
+step multireadwcte: <... completed>
+subid id
+
+1 1
diff --git a/src/test/isolation/specs/eval-plan-qual.spec b/src/test/isolation/specs/eval-plan-qual.spec
index d2b34ec7cc2..51ab61dc862 100644
--- a/src/test/isolation/specs/eval-plan-qual.spec
+++ b/src/test/isolation/specs/eval-plan-qual.spec
@@ -139,6 +139,14 @@ step "readwcte" {
SELECT * FROM cte2;
}
+# this test exercises a different CTE misbehavior, cf bug #14870
+step "multireadwcte" {
+ WITH updated AS (
+ UPDATE table_a SET value = 'tableAValue3' WHERE id = 1 RETURNING id
+ )
+ SELECT (SELECT id FROM updated) AS subid, * FROM updated;
+}
+
teardown { COMMIT; }
permutation "wx1" "wx2" "c1" "c2" "read"
@@ -151,3 +159,4 @@ permutation "wx2" "lockwithvalues" "c2" "c1" "read"
permutation "updateforss" "readforss" "c1" "c2"
permutation "wrtwcte" "readwcte" "c1" "c2"
permutation "wrjt" "selectjoinforupdate" "c2" "c1"
+permutation "wrtwcte" "multireadwcte" "c1" "c2"