aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execScan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execScan.c')
-rw-r--r--src/backend/executor/execScan.c96
1 files changed, 91 insertions, 5 deletions
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index 32386accbbd..f7733569ef9 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.46 2009/04/02 20:59:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execScan.c,v 1.47 2009/10/26 02:26:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,6 +26,62 @@
static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
+/*
+ * ExecScanFetch -- fetch next potential tuple
+ *
+ * This routine is concerned with substituting a test tuple if we are
+ * inside an EvalPlanQual recheck. If we aren't, just execute
+ * the access method's next-tuple routine.
+ */
+static inline TupleTableSlot *
+ExecScanFetch(ScanState *node,
+ ExecScanAccessMtd accessMtd,
+ ExecScanRecheckMtd recheckMtd)
+{
+ EState *estate = node->ps.state;
+
+ if (estate->es_epqTuple != NULL)
+ {
+ /*
+ * We are inside an EvalPlanQual recheck. Return the test tuple if
+ * one is available, after rechecking any access-method-specific
+ * conditions.
+ */
+ Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+ if (estate->es_epqTupleSet[scanrelid - 1])
+ {
+ TupleTableSlot *slot = node->ss_ScanTupleSlot;
+
+ /* Return empty slot if we already returned a tuple */
+ if (estate->es_epqScanDone[scanrelid - 1])
+ return ExecClearTuple(slot);
+ /* Else mark to remember that we shouldn't return more */
+ estate->es_epqScanDone[scanrelid - 1] = true;
+
+ /* Return empty slot if we haven't got a test tuple */
+ if (estate->es_epqTuple[scanrelid - 1] == NULL)
+ return ExecClearTuple(slot);
+
+ /* Store test tuple in the plan node's scan slot */
+ ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
+ slot, InvalidBuffer, false);
+
+ /* Check if it meets the access-method conditions */
+ if (!(*recheckMtd) (node, slot))
+ ExecClearTuple(slot); /* would not be returned by scan */
+
+ return slot;
+ }
+ }
+
+ /*
+ * Run the node-type-specific access method function to get the next tuple
+ */
+ return (*accessMtd) (node);
+}
+
/* ----------------------------------------------------------------
* ExecScan
*
@@ -35,6 +91,10 @@ static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, Tuple
* The access method returns the next tuple and execScan() is
* responsible for checking the tuple returned against the qual-clause.
*
+ * A 'recheck method' must also be provided that can check an
+ * arbitrary tuple of the relation against any qual conditions
+ * that are implemented internal to the access method.
+ *
* Conditions:
* -- the "cursor" maintained by the AMI is positioned at the tuple
* returned previously.
@@ -46,7 +106,8 @@ static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, Tuple
*/
TupleTableSlot *
ExecScan(ScanState *node,
- ExecScanAccessMtd accessMtd) /* function returning a tuple */
+ ExecScanAccessMtd accessMtd, /* function returning a tuple */
+ ExecScanRecheckMtd recheckMtd)
{
ExprContext *econtext;
List *qual;
@@ -65,7 +126,7 @@ ExecScan(ScanState *node,
* all the overhead and return the raw scan tuple.
*/
if (!qual && !projInfo)
- return (*accessMtd) (node);
+ return ExecScanFetch(node, accessMtd, recheckMtd);
/*
* Check to see if we're still projecting out tuples from a previous scan
@@ -91,7 +152,7 @@ ExecScan(ScanState *node,
ResetExprContext(econtext);
/*
- * get a tuple from the access method loop until we obtain a tuple which
+ * get a tuple from the access method. Loop until we obtain a tuple that
* passes the qualification.
*/
for (;;)
@@ -100,7 +161,7 @@ ExecScan(ScanState *node,
CHECK_FOR_INTERRUPTS();
- slot = (*accessMtd) (node);
+ slot = ExecScanFetch(node, accessMtd, recheckMtd);
/*
* if the slot returned by the accessMtd contains NULL, then it means
@@ -249,3 +310,28 @@ tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc
return true;
}
+
+/*
+ * ExecScanReScan
+ *
+ * This must be called within the ReScan function of any plan node type
+ * that uses ExecScan().
+ */
+void
+ExecScanReScan(ScanState *node)
+{
+ EState *estate = node->ps.state;
+
+ /* Stop projecting any tuples from SRFs in the targetlist */
+ node->ps.ps_TupFromTlist = false;
+
+ /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
+ if (estate->es_epqScanDone != NULL)
+ {
+ Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
+
+ Assert(scanrelid > 0);
+
+ estate->es_epqScanDone[scanrelid - 1] = false;
+ }
+}