1 /*-------------------------------------------------------------------------
4 * This code provides support for generalized relation scans. ExecScan
5 * is passed a node and a pointer to a function to "do the right thing"
6 * and return a tuple from the relation. ExecScan then does the tedious
7 * stuff - checking the qualification and projecting the tuple
10 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * src/backend/executor/execScan.c
17 *-------------------------------------------------------------------------
21 #include "executor/executor.h"
22 #include "miscadmin.h"
23 #include "utils/memutils.h"
26 static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
30 * ExecScanFetch -- fetch next potential tuple
32 * This routine is concerned with substituting a test tuple if we are
33 * inside an EvalPlanQual recheck. If we aren't, just execute
34 * the access method's next-tuple routine.
36 static inline TupleTableSlot *
37 ExecScanFetch(ScanState *node,
38 ExecScanAccessMtd accessMtd,
39 ExecScanRecheckMtd recheckMtd)
41 EState *estate = node->ps.state;
43 if (estate->es_epqTuple != NULL)
46 * We are inside an EvalPlanQual recheck. Return the test tuple if
47 * one is available, after rechecking any access-method-specific
50 Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
52 Assert(scanrelid > 0);
53 if (estate->es_epqTupleSet[scanrelid - 1])
55 TupleTableSlot *slot = node->ss_ScanTupleSlot;
57 /* Return empty slot if we already returned a tuple */
58 if (estate->es_epqScanDone[scanrelid - 1])
59 return ExecClearTuple(slot);
60 /* Else mark to remember that we shouldn't return more */
61 estate->es_epqScanDone[scanrelid - 1] = true;
63 /* Return empty slot if we haven't got a test tuple */
64 if (estate->es_epqTuple[scanrelid - 1] == NULL)
65 return ExecClearTuple(slot);
67 /* Store test tuple in the plan node's scan slot */
68 ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
69 slot, InvalidBuffer, false);
71 /* Check if it meets the access-method conditions */
72 if (!(*recheckMtd) (node, slot))
73 ExecClearTuple(slot); /* would not be returned by scan */
80 * Run the node-type-specific access method function to get the next tuple
82 return (*accessMtd) (node);
85 /* ----------------------------------------------------------------
88 * Scans the relation using the 'access method' indicated and
89 * returns the next qualifying tuple in the direction specified
90 * in the global variable ExecDirection.
91 * The access method returns the next tuple and ExecScan() is
92 * responsible for checking the tuple returned against the qual-clause.
94 * A 'recheck method' must also be provided that can check an
95 * arbitrary tuple of the relation against any qual conditions
96 * that are implemented internal to the access method.
99 * -- the "cursor" maintained by the AMI is positioned at the tuple
100 * returned previously.
103 * -- the relation indicated is opened for scanning so that the
104 * "cursor" is positioned before the first qualifying tuple.
105 * ----------------------------------------------------------------
108 ExecScan(ScanState *node,
109 ExecScanAccessMtd accessMtd, /* function returning a tuple */
110 ExecScanRecheckMtd recheckMtd)
112 ExprContext *econtext;
114 ProjectionInfo *projInfo;
116 TupleTableSlot *resultSlot;
119 * Fetch data from node
121 qual = node->ps.qual;
122 projInfo = node->ps.ps_ProjInfo;
123 econtext = node->ps.ps_ExprContext;
126 * If we have neither a qual to check nor a projection to do, just skip
127 * all the overhead and return the raw scan tuple.
129 if (!qual && !projInfo)
131 ResetExprContext(econtext);
132 return ExecScanFetch(node, accessMtd, recheckMtd);
136 * Check to see if we're still projecting out tuples from a previous scan
137 * tuple (because there is a function-returning-set in the projection
138 * expressions). If so, try to project another one.
140 if (node->ps.ps_TupFromTlist)
142 Assert(projInfo); /* can't get here if not projecting */
143 resultSlot = ExecProject(projInfo, &isDone);
144 if (isDone == ExprMultipleResult)
146 /* Done with that source tuple... */
147 node->ps.ps_TupFromTlist = false;
151 * Reset per-tuple memory context to free any expression evaluation
152 * storage allocated in the previous tuple cycle. Note this can't happen
153 * until we're done projecting out tuples from a scan tuple.
155 ResetExprContext(econtext);
158 * get a tuple from the access method. Loop until we obtain a tuple that
159 * passes the qualification.
163 TupleTableSlot *slot;
165 CHECK_FOR_INTERRUPTS();
167 slot = ExecScanFetch(node, accessMtd, recheckMtd);
170 * if the slot returned by the accessMtd contains NULL, then it means
171 * there is nothing more to scan so we just return an empty slot,
172 * being careful to use the projection result slot so it has correct
178 return ExecClearTuple(projInfo->pi_slot);
184 * place the current tuple into the expr context
186 econtext->ecxt_scantuple = slot;
189 * check that the current tuple satisfies the qual-clause
191 * check for non-nil qual here to avoid a function call to ExecQual()
192 * when the qual is nil ... saves only a few cycles, but they add up
195 if (!qual || ExecQual(qual, econtext, false))
198 * Found a satisfactory scan tuple.
203 * Form a projection tuple, store it in the result tuple slot
204 * and return it --- unless we find we can project no tuples
205 * from this scan tuple, in which case continue scan.
207 resultSlot = ExecProject(projInfo, &isDone);
208 if (isDone != ExprEndResult)
210 node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
217 * Here, we aren't projecting, so just return scan tuple.
223 InstrCountFiltered1(node, 1);
226 * Tuple fails qual, so free per-tuple memory and try again.
228 ResetExprContext(econtext);
233 * ExecAssignScanProjectionInfo
234 * Set up projection info for a scan node, if necessary.
236 * We can avoid a projection step if the requested tlist exactly matches
237 * the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
238 * Note that this case occurs not only for simple "SELECT * FROM ...", but
239 * also in most cases where there are joins or other processing nodes above
240 * the scan node, because the planner will preferentially generate a matching
243 * ExecAssignScanType must have been called already.
246 ExecAssignScanProjectionInfo(ScanState *node)
248 Scan *scan = (Scan *) node->ps.plan;
250 ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
254 * ExecAssignScanProjectionInfoWithVarno
255 * As above, but caller can specify varno expected in Vars in the tlist.
258 ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
260 Scan *scan = (Scan *) node->ps.plan;
262 if (tlist_matches_tupdesc(&node->ps,
263 scan->plan.targetlist,
265 node->ss_ScanTupleSlot->tts_tupleDescriptor))
266 node->ps.ps_ProjInfo = NULL;
268 ExecAssignProjectionInfo(&node->ps,
269 node->ss_ScanTupleSlot->tts_tupleDescriptor);
273 tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
275 int numattrs = tupdesc->natts;
278 ListCell *tlist_item = list_head(tlist);
280 /* Check the tlist attributes */
281 for (attrno = 1; attrno <= numattrs; attrno++)
283 Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
286 if (tlist_item == NULL)
287 return false; /* tlist too short */
288 var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
289 if (!var || !IsA(var, Var))
290 return false; /* tlist item not a Var */
291 /* if these Asserts fail, planner messed up */
292 Assert(var->varno == varno);
293 Assert(var->varlevelsup == 0);
294 if (var->varattno != attrno)
295 return false; /* out of order */
296 if (att_tup->attisdropped)
297 return false; /* table contains dropped columns */
300 * Note: usually the Var's type should match the tupdesc exactly, but
301 * in situations involving unions of columns that have different
302 * typmods, the Var may have come from above the union and hence have
303 * typmod -1. This is a legitimate situation since the Var still
304 * describes the column, just not as exactly as the tupdesc does. We
305 * could change the planner to prevent it, but it'd then insert
306 * projection steps just to convert from specific typmod to typmod -1,
307 * which is pretty silly.
309 if (var->vartype != att_tup->atttypid ||
310 (var->vartypmod != att_tup->atttypmod &&
311 var->vartypmod != -1))
312 return false; /* type mismatch */
314 tlist_item = lnext(tlist_item);
318 return false; /* tlist too long */
321 * If the plan context requires a particular hasoid setting, then that has
324 if (ExecContextForcesOids(ps, &hasoid) &&
325 hasoid != tupdesc->tdhasoid)
334 * This must be called within the ReScan function of any plan node type
335 * that uses ExecScan().
338 ExecScanReScan(ScanState *node)
340 EState *estate = node->ps.state;
342 /* Stop projecting any tuples from SRFs in the targetlist */
343 node->ps.ps_TupFromTlist = false;
345 /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
346 if (estate->es_epqScanDone != NULL)
348 Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
350 Assert(scanrelid > 0);
352 estate->es_epqScanDone[scanrelid - 1] = false;