aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/nodeIndexonlyscan.c45
-rw-r--r--src/backend/executor/nodeIndexscan.c45
-rw-r--r--src/backend/executor/nodeMergejoin.c4
3 files changed, 94 insertions, 0 deletions
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 9b7f470ee28..f61b3abf326 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -421,11 +421,39 @@ ExecEndIndexOnlyScan(IndexOnlyScanState *node)
/* ----------------------------------------------------------------
* ExecIndexOnlyMarkPos
+ *
+ * Note: we assume that no caller attempts to set a mark before having read
+ * at least one tuple. Otherwise, ioss_ScanDesc might still be NULL.
* ----------------------------------------------------------------
*/
void
ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
{
+ EState *estate = node->ss.ps.state;
+
+ if (estate->es_epqTuple != NULL)
+ {
+ /*
+ * We are inside an EvalPlanQual recheck. If a test tuple exists for
+ * this relation, then we shouldn't access the index at all. We would
+ * instead need to save, and later restore, the state of the
+ * es_epqScanDone flag, so that re-fetching the test tuple is
+ * possible. However, given the assumption that no caller sets a mark
+ * at the start of the scan, we can only get here with es_epqScanDone
+ * already set, and so no state need be saved.
+ */
+ Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+ if (estate->es_epqTupleSet[scanrelid - 1])
+ {
+ /* Verify the claim above */
+ if (!estate->es_epqScanDone[scanrelid - 1])
+ elog(ERROR, "unexpected ExecIndexOnlyMarkPos call in EPQ recheck");
+ return;
+ }
+ }
+
index_markpos(node->ioss_ScanDesc);
}
@@ -436,6 +464,23 @@ ExecIndexOnlyMarkPos(IndexOnlyScanState *node)
void
ExecIndexOnlyRestrPos(IndexOnlyScanState *node)
{
+ EState *estate = node->ss.ps.state;
+
+ if (estate->es_epqTuple != NULL)
+ {
+ /* See comments in ExecIndexOnlyMarkPos */
+ Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+ if (estate->es_epqTupleSet[scanrelid - 1])
+ {
+ /* Verify the claim above */
+ if (!estate->es_epqScanDone[scanrelid - 1])
+ elog(ERROR, "unexpected ExecIndexOnlyRestrPos call in EPQ recheck");
+ return;
+ }
+ }
+
index_restrpos(node->ioss_ScanDesc);
}
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 54fafa5033f..eed69a0c665 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -849,11 +849,39 @@ ExecEndIndexScan(IndexScanState *node)
/* ----------------------------------------------------------------
* ExecIndexMarkPos
+ *
+ * Note: we assume that no caller attempts to set a mark before having read
+ * at least one tuple. Otherwise, iss_ScanDesc might still be NULL.
* ----------------------------------------------------------------
*/
void
ExecIndexMarkPos(IndexScanState *node)
{
+ EState *estate = node->ss.ps.state;
+
+ if (estate->es_epqTuple != NULL)
+ {
+ /*
+ * We are inside an EvalPlanQual recheck. If a test tuple exists for
+ * this relation, then we shouldn't access the index at all. We would
+ * instead need to save, and later restore, the state of the
+ * es_epqScanDone flag, so that re-fetching the test tuple is
+ * possible. However, given the assumption that no caller sets a mark
+ * at the start of the scan, we can only get here with es_epqScanDone
+ * already set, and so no state need be saved.
+ */
+ Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+ if (estate->es_epqTupleSet[scanrelid - 1])
+ {
+ /* Verify the claim above */
+ if (!estate->es_epqScanDone[scanrelid - 1])
+ elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
+ return;
+ }
+ }
+
index_markpos(node->iss_ScanDesc);
}
@@ -864,6 +892,23 @@ ExecIndexMarkPos(IndexScanState *node)
void
ExecIndexRestrPos(IndexScanState *node)
{
+ EState *estate = node->ss.ps.state;
+
+ if (estate->es_epqTuple != NULL)
+ {
+ /* See comments in ExecIndexMarkPos */
+ Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+ if (estate->es_epqTupleSet[scanrelid - 1])
+ {
+ /* Verify the claim above */
+ if (!estate->es_epqScanDone[scanrelid - 1])
+ elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
+ return;
+ }
+ }
+
index_restrpos(node->iss_ScanDesc);
}
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index b52946f180a..ec5f82f6a92 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -1502,6 +1502,10 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
*
* Currently, only Material wants the extra MARKs, and it will be helpful
* only if eflags doesn't specify REWIND.
+ *
+ * Note that for IndexScan and IndexOnlyScan, it is *necessary* that we
+ * not set mj_ExtraMarks; otherwise we might attempt to set a mark before
+ * the first inner tuple, which they do not support.
*/
if (IsA(innerPlan(node), Material) &&
(eflags & EXEC_FLAG_REWIND) == 0 &&