Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execScan.c
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
8 : * appropriately.
9 : *
10 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
11 : * Portions Copyright (c) 1994, Regents of the University of California
12 : *
13 : *
14 : * IDENTIFICATION
15 : * src/backend/executor/execScan.c
16 : *
17 : *-------------------------------------------------------------------------
18 : */
19 : #include "postgres.h"
20 :
21 : #include "executor/executor.h"
22 : #include "miscadmin.h"
23 : #include "utils/memutils.h"
24 :
25 :
26 : static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
27 :
28 :
29 : /*
30 : * ExecScanFetch -- fetch next potential tuple
31 : *
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.
35 : */
36 : static inline TupleTableSlot *
37 4253392 : ExecScanFetch(ScanState *node,
38 : ExecScanAccessMtd accessMtd,
39 : ExecScanRecheckMtd recheckMtd)
40 : {
41 4253392 : EState *estate = node->ps.state;
42 :
43 4253392 : if (estate->es_epqTuple != NULL)
44 : {
45 : /*
46 : * We are inside an EvalPlanQual recheck. Return the test tuple if
47 : * one is available, after rechecking any access-method-specific
48 : * conditions.
49 : */
50 0 : Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
51 :
52 0 : if (scanrelid == 0)
53 : {
54 0 : TupleTableSlot *slot = node->ss_ScanTupleSlot;
55 :
56 : /*
57 : * This is a ForeignScan or CustomScan which has pushed down a
58 : * join to the remote side. The recheck method is responsible not
59 : * only for rechecking the scan/join quals but also for storing
60 : * the correct tuple in the slot.
61 : */
62 0 : if (!(*recheckMtd) (node, slot))
63 0 : ExecClearTuple(slot); /* would not be returned by scan */
64 0 : return slot;
65 : }
66 0 : else if (estate->es_epqTupleSet[scanrelid - 1])
67 : {
68 0 : TupleTableSlot *slot = node->ss_ScanTupleSlot;
69 :
70 : /* Return empty slot if we already returned a tuple */
71 0 : if (estate->es_epqScanDone[scanrelid - 1])
72 0 : return ExecClearTuple(slot);
73 : /* Else mark to remember that we shouldn't return more */
74 0 : estate->es_epqScanDone[scanrelid - 1] = true;
75 :
76 : /* Return empty slot if we haven't got a test tuple */
77 0 : if (estate->es_epqTuple[scanrelid - 1] == NULL)
78 0 : return ExecClearTuple(slot);
79 :
80 : /* Store test tuple in the plan node's scan slot */
81 0 : ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
82 : slot, InvalidBuffer, false);
83 :
84 : /* Check if it meets the access-method conditions */
85 0 : if (!(*recheckMtd) (node, slot))
86 0 : ExecClearTuple(slot); /* would not be returned by scan */
87 :
88 0 : return slot;
89 : }
90 : }
91 :
92 : /*
93 : * Run the node-type-specific access method function to get the next tuple
94 : */
95 4253392 : return (*accessMtd) (node);
96 : }
97 :
98 : /* ----------------------------------------------------------------
99 : * ExecScan
100 : *
101 : * Scans the relation using the 'access method' indicated and
102 : * returns the next qualifying tuple in the direction specified
103 : * in the global variable ExecDirection.
104 : * The access method returns the next tuple and ExecScan() is
105 : * responsible for checking the tuple returned against the qual-clause.
106 : *
107 : * A 'recheck method' must also be provided that can check an
108 : * arbitrary tuple of the relation against any qual conditions
109 : * that are implemented internal to the access method.
110 : *
111 : * Conditions:
112 : * -- the "cursor" maintained by the AMI is positioned at the tuple
113 : * returned previously.
114 : *
115 : * Initial States:
116 : * -- the relation indicated is opened for scanning so that the
117 : * "cursor" is positioned before the first qualifying tuple.
118 : * ----------------------------------------------------------------
119 : */
120 : TupleTableSlot *
121 3359598 : ExecScan(ScanState *node,
122 : ExecScanAccessMtd accessMtd, /* function returning a tuple */
123 : ExecScanRecheckMtd recheckMtd)
124 : {
125 : ExprContext *econtext;
126 : ExprState *qual;
127 : ProjectionInfo *projInfo;
128 :
129 : /*
130 : * Fetch data from node
131 : */
132 3359598 : qual = node->ps.qual;
133 3359598 : projInfo = node->ps.ps_ProjInfo;
134 3359598 : econtext = node->ps.ps_ExprContext;
135 :
136 : /*
137 : * If we have neither a qual to check nor a projection to do, just skip
138 : * all the overhead and return the raw scan tuple.
139 : */
140 3359598 : if (!qual && !projInfo)
141 : {
142 1321977 : ResetExprContext(econtext);
143 1321977 : return ExecScanFetch(node, accessMtd, recheckMtd);
144 : }
145 :
146 : /*
147 : * Reset per-tuple memory context to free any expression evaluation
148 : * storage allocated in the previous tuple cycle.
149 : */
150 2037621 : ResetExprContext(econtext);
151 :
152 : /*
153 : * get a tuple from the access method. Loop until we obtain a tuple that
154 : * passes the qualification.
155 : */
156 : for (;;)
157 : {
158 : TupleTableSlot *slot;
159 :
160 2931415 : CHECK_FOR_INTERRUPTS();
161 :
162 2931415 : slot = ExecScanFetch(node, accessMtd, recheckMtd);
163 :
164 : /*
165 : * if the slot returned by the accessMtd contains NULL, then it means
166 : * there is nothing more to scan so we just return an empty slot,
167 : * being careful to use the projection result slot so it has correct
168 : * tupleDesc.
169 : */
170 2931352 : if (TupIsNull(slot))
171 : {
172 36106 : if (projInfo)
173 32319 : return ExecClearTuple(projInfo->pi_state.resultslot);
174 : else
175 3787 : return slot;
176 : }
177 :
178 : /*
179 : * place the current tuple into the expr context
180 : */
181 2895246 : econtext->ecxt_scantuple = slot;
182 :
183 : /*
184 : * check that the current tuple satisfies the qual-clause
185 : *
186 : * check for non-null qual here to avoid a function call to ExecQual()
187 : * when the qual is null ... saves only a few cycles, but they add up
188 : * ...
189 : */
190 2895246 : if (qual == NULL || ExecQual(qual, econtext))
191 : {
192 : /*
193 : * Found a satisfactory scan tuple.
194 : */
195 2001451 : if (projInfo)
196 : {
197 : /*
198 : * Form a projection tuple, store it in the result tuple slot
199 : * and return it.
200 : */
201 1801550 : return ExecProject(projInfo);
202 : }
203 : else
204 : {
205 : /*
206 : * Here, we aren't projecting, so just return scan tuple.
207 : */
208 199901 : return slot;
209 : }
210 : }
211 : else
212 893794 : InstrCountFiltered1(node, 1);
213 :
214 : /*
215 : * Tuple fails qual, so free per-tuple memory and try again.
216 : */
217 893794 : ResetExprContext(econtext);
218 893794 : }
219 : }
220 :
221 : /*
222 : * ExecAssignScanProjectionInfo
223 : * Set up projection info for a scan node, if necessary.
224 : *
225 : * We can avoid a projection step if the requested tlist exactly matches
226 : * the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
227 : * Note that this case occurs not only for simple "SELECT * FROM ...", but
228 : * also in most cases where there are joins or other processing nodes above
229 : * the scan node, because the planner will preferentially generate a matching
230 : * tlist.
231 : *
232 : * ExecAssignScanType must have been called already.
233 : */
234 : void
235 20896 : ExecAssignScanProjectionInfo(ScanState *node)
236 : {
237 20896 : Scan *scan = (Scan *) node->ps.plan;
238 :
239 20896 : ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
240 20896 : }
241 :
242 : /*
243 : * ExecAssignScanProjectionInfoWithVarno
244 : * As above, but caller can specify varno expected in Vars in the tlist.
245 : */
246 : void
247 21681 : ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
248 : {
249 21681 : Scan *scan = (Scan *) node->ps.plan;
250 :
251 21681 : if (tlist_matches_tupdesc(&node->ps,
252 : scan->plan.targetlist,
253 : varno,
254 21681 : node->ss_ScanTupleSlot->tts_tupleDescriptor))
255 8412 : node->ps.ps_ProjInfo = NULL;
256 : else
257 13269 : ExecAssignProjectionInfo(&node->ps,
258 13269 : node->ss_ScanTupleSlot->tts_tupleDescriptor);
259 21681 : }
260 :
261 : static bool
262 21681 : tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
263 : {
264 21681 : int numattrs = tupdesc->natts;
265 : int attrno;
266 : bool hasoid;
267 21681 : ListCell *tlist_item = list_head(tlist);
268 :
269 : /* Check the tlist attributes */
270 70329 : for (attrno = 1; attrno <= numattrs; attrno++)
271 : {
272 61447 : Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
273 : Var *var;
274 :
275 61447 : if (tlist_item == NULL)
276 1639 : return false; /* tlist too short */
277 59808 : var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
278 59808 : if (!var || !IsA(var, Var))
279 2816 : return false; /* tlist item not a Var */
280 : /* if these Asserts fail, planner messed up */
281 56992 : Assert(var->varno == varno);
282 56992 : Assert(var->varlevelsup == 0);
283 56992 : if (var->varattno != attrno)
284 8343 : return false; /* out of order */
285 48649 : if (att_tup->attisdropped)
286 0 : return false; /* table contains dropped columns */
287 :
288 : /*
289 : * Note: usually the Var's type should match the tupdesc exactly, but
290 : * in situations involving unions of columns that have different
291 : * typmods, the Var may have come from above the union and hence have
292 : * typmod -1. This is a legitimate situation since the Var still
293 : * describes the column, just not as exactly as the tupdesc does. We
294 : * could change the planner to prevent it, but it'd then insert
295 : * projection steps just to convert from specific typmod to typmod -1,
296 : * which is pretty silly.
297 : */
298 97297 : if (var->vartype != att_tup->atttypid ||
299 48649 : (var->vartypmod != att_tup->atttypmod &&
300 1 : var->vartypmod != -1))
301 1 : return false; /* type mismatch */
302 :
303 48648 : tlist_item = lnext(tlist_item);
304 : }
305 :
306 8882 : if (tlist_item)
307 461 : return false; /* tlist too long */
308 :
309 : /*
310 : * If the plan context requires a particular hasoid setting, then that has
311 : * to match, too.
312 : */
313 8794 : if (ExecContextForcesOids(ps, &hasoid) &&
314 373 : hasoid != tupdesc->tdhasoid)
315 9 : return false;
316 :
317 8412 : return true;
318 : }
319 :
320 : /*
321 : * ExecScanReScan
322 : *
323 : * This must be called within the ReScan function of any plan node type
324 : * that uses ExecScan().
325 : */
326 : void
327 54488 : ExecScanReScan(ScanState *node)
328 : {
329 54488 : EState *estate = node->ps.state;
330 :
331 : /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
332 54488 : if (estate->es_epqScanDone != NULL)
333 : {
334 0 : Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
335 :
336 0 : if (scanrelid > 0)
337 0 : estate->es_epqScanDone[scanrelid - 1] = false;
338 : else
339 : {
340 : Bitmapset *relids;
341 0 : int rtindex = -1;
342 :
343 : /*
344 : * If an FDW or custom scan provider has replaced the join with a
345 : * scan, there are multiple RTIs; reset the epqScanDone flag for
346 : * all of them.
347 : */
348 0 : if (IsA(node->ps.plan, ForeignScan))
349 0 : relids = ((ForeignScan *) node->ps.plan)->fs_relids;
350 0 : else if (IsA(node->ps.plan, CustomScan))
351 0 : relids = ((CustomScan *) node->ps.plan)->custom_relids;
352 : else
353 0 : elog(ERROR, "unexpected scan node: %d",
354 : (int) nodeTag(node->ps.plan));
355 :
356 0 : while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
357 : {
358 0 : Assert(rtindex > 0);
359 0 : estate->es_epqScanDone[rtindex - 1] = false;
360 : }
361 : }
362 : }
363 54488 : }
|