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-2019, 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 | |
27 | /* |
28 | * ExecScanFetch -- check interrupts & fetch next potential tuple |
29 | * |
30 | * This routine is concerned with substituting a test tuple if we are |
31 | * inside an EvalPlanQual recheck. If we aren't, just execute |
32 | * the access method's next-tuple routine. |
33 | */ |
34 | static inline TupleTableSlot * |
35 | ExecScanFetch(ScanState *node, |
36 | ExecScanAccessMtd accessMtd, |
37 | ExecScanRecheckMtd recheckMtd) |
38 | { |
39 | EState *estate = node->ps.state; |
40 | |
41 | CHECK_FOR_INTERRUPTS(); |
42 | |
43 | if (estate->es_epq_active != NULL) |
44 | { |
45 | EPQState *epqstate = estate->es_epq_active; |
46 | |
47 | /* |
48 | * We are inside an EvalPlanQual recheck. Return the test tuple if |
49 | * one is available, after rechecking any access-method-specific |
50 | * conditions. |
51 | */ |
52 | Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; |
53 | |
54 | if (scanrelid == 0) |
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 | |
63 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
64 | |
65 | if (!(*recheckMtd) (node, slot)) |
66 | ExecClearTuple(slot); /* would not be returned by scan */ |
67 | return slot; |
68 | } |
69 | else if (epqstate->relsubs_done[scanrelid - 1]) |
70 | { |
71 | /* |
72 | * Return empty slot, as we already performed an EPQ substitution |
73 | * for this relation. |
74 | */ |
75 | |
76 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
77 | |
78 | /* Return empty slot, as we already returned a tuple */ |
79 | return ExecClearTuple(slot); |
80 | } |
81 | else if (epqstate->relsubs_slot[scanrelid - 1] != NULL) |
82 | { |
83 | /* |
84 | * Return replacement tuple provided by the EPQ caller. |
85 | */ |
86 | |
87 | TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1]; |
88 | |
89 | Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL); |
90 | |
91 | /* Mark to remember that we shouldn't return more */ |
92 | epqstate->relsubs_done[scanrelid - 1] = true; |
93 | |
94 | /* Return empty slot if we haven't got a test tuple */ |
95 | if (TupIsNull(slot)) |
96 | return NULL; |
97 | |
98 | /* Check if it meets the access-method conditions */ |
99 | if (!(*recheckMtd) (node, slot)) |
100 | return ExecClearTuple(slot); /* would not be returned by |
101 | * scan */ |
102 | return slot; |
103 | } |
104 | else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL) |
105 | { |
106 | /* |
107 | * Fetch and return replacement tuple using a non-locking rowmark. |
108 | */ |
109 | |
110 | TupleTableSlot *slot = node->ss_ScanTupleSlot; |
111 | |
112 | /* Mark to remember that we shouldn't return more */ |
113 | epqstate->relsubs_done[scanrelid - 1] = true; |
114 | |
115 | if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot)) |
116 | return NULL; |
117 | |
118 | /* Return empty slot if we haven't got a test tuple */ |
119 | if (TupIsNull(slot)) |
120 | return NULL; |
121 | |
122 | /* Check if it meets the access-method conditions */ |
123 | if (!(*recheckMtd) (node, slot)) |
124 | return ExecClearTuple(slot); /* would not be returned by |
125 | * scan */ |
126 | return slot; |
127 | } |
128 | } |
129 | |
130 | /* |
131 | * Run the node-type-specific access method function to get the next tuple |
132 | */ |
133 | return (*accessMtd) (node); |
134 | } |
135 | |
136 | /* ---------------------------------------------------------------- |
137 | * ExecScan |
138 | * |
139 | * Scans the relation using the 'access method' indicated and |
140 | * returns the next qualifying tuple in the direction specified |
141 | * in the global variable ExecDirection. |
142 | * The access method returns the next tuple and ExecScan() is |
143 | * responsible for checking the tuple returned against the qual-clause. |
144 | * |
145 | * A 'recheck method' must also be provided that can check an |
146 | * arbitrary tuple of the relation against any qual conditions |
147 | * that are implemented internal to the access method. |
148 | * |
149 | * Conditions: |
150 | * -- the "cursor" maintained by the AMI is positioned at the tuple |
151 | * returned previously. |
152 | * |
153 | * Initial States: |
154 | * -- the relation indicated is opened for scanning so that the |
155 | * "cursor" is positioned before the first qualifying tuple. |
156 | * ---------------------------------------------------------------- |
157 | */ |
158 | TupleTableSlot * |
159 | ExecScan(ScanState *node, |
160 | ExecScanAccessMtd accessMtd, /* function returning a tuple */ |
161 | ExecScanRecheckMtd recheckMtd) |
162 | { |
163 | ExprContext *econtext; |
164 | ExprState *qual; |
165 | ProjectionInfo *projInfo; |
166 | |
167 | /* |
168 | * Fetch data from node |
169 | */ |
170 | qual = node->ps.qual; |
171 | projInfo = node->ps.ps_ProjInfo; |
172 | econtext = node->ps.ps_ExprContext; |
173 | |
174 | /* interrupt checks are in ExecScanFetch */ |
175 | |
176 | /* |
177 | * If we have neither a qual to check nor a projection to do, just skip |
178 | * all the overhead and return the raw scan tuple. |
179 | */ |
180 | if (!qual && !projInfo) |
181 | { |
182 | ResetExprContext(econtext); |
183 | return ExecScanFetch(node, accessMtd, recheckMtd); |
184 | } |
185 | |
186 | /* |
187 | * Reset per-tuple memory context to free any expression evaluation |
188 | * storage allocated in the previous tuple cycle. |
189 | */ |
190 | ResetExprContext(econtext); |
191 | |
192 | /* |
193 | * get a tuple from the access method. Loop until we obtain a tuple that |
194 | * passes the qualification. |
195 | */ |
196 | for (;;) |
197 | { |
198 | TupleTableSlot *slot; |
199 | |
200 | slot = ExecScanFetch(node, accessMtd, recheckMtd); |
201 | |
202 | /* |
203 | * if the slot returned by the accessMtd contains NULL, then it means |
204 | * there is nothing more to scan so we just return an empty slot, |
205 | * being careful to use the projection result slot so it has correct |
206 | * tupleDesc. |
207 | */ |
208 | if (TupIsNull(slot)) |
209 | { |
210 | if (projInfo) |
211 | return ExecClearTuple(projInfo->pi_state.resultslot); |
212 | else |
213 | return slot; |
214 | } |
215 | |
216 | /* |
217 | * place the current tuple into the expr context |
218 | */ |
219 | econtext->ecxt_scantuple = slot; |
220 | |
221 | /* |
222 | * check that the current tuple satisfies the qual-clause |
223 | * |
224 | * check for non-null qual here to avoid a function call to ExecQual() |
225 | * when the qual is null ... saves only a few cycles, but they add up |
226 | * ... |
227 | */ |
228 | if (qual == NULL || ExecQual(qual, econtext)) |
229 | { |
230 | /* |
231 | * Found a satisfactory scan tuple. |
232 | */ |
233 | if (projInfo) |
234 | { |
235 | /* |
236 | * Form a projection tuple, store it in the result tuple slot |
237 | * and return it. |
238 | */ |
239 | return ExecProject(projInfo); |
240 | } |
241 | else |
242 | { |
243 | /* |
244 | * Here, we aren't projecting, so just return scan tuple. |
245 | */ |
246 | return slot; |
247 | } |
248 | } |
249 | else |
250 | InstrCountFiltered1(node, 1); |
251 | |
252 | /* |
253 | * Tuple fails qual, so free per-tuple memory and try again. |
254 | */ |
255 | ResetExprContext(econtext); |
256 | } |
257 | } |
258 | |
259 | /* |
260 | * ExecAssignScanProjectionInfo |
261 | * Set up projection info for a scan node, if necessary. |
262 | * |
263 | * We can avoid a projection step if the requested tlist exactly matches |
264 | * the underlying tuple type. If so, we just set ps_ProjInfo to NULL. |
265 | * Note that this case occurs not only for simple "SELECT * FROM ...", but |
266 | * also in most cases where there are joins or other processing nodes above |
267 | * the scan node, because the planner will preferentially generate a matching |
268 | * tlist. |
269 | * |
270 | * The scan slot's descriptor must have been set already. |
271 | */ |
272 | void |
273 | ExecAssignScanProjectionInfo(ScanState *node) |
274 | { |
275 | Scan *scan = (Scan *) node->ps.plan; |
276 | TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; |
277 | |
278 | ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid); |
279 | } |
280 | |
281 | /* |
282 | * ExecAssignScanProjectionInfoWithVarno |
283 | * As above, but caller can specify varno expected in Vars in the tlist. |
284 | */ |
285 | void |
286 | ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno) |
287 | { |
288 | TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; |
289 | |
290 | ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno); |
291 | } |
292 | |
293 | /* |
294 | * ExecScanReScan |
295 | * |
296 | * This must be called within the ReScan function of any plan node type |
297 | * that uses ExecScan(). |
298 | */ |
299 | void |
300 | ExecScanReScan(ScanState *node) |
301 | { |
302 | EState *estate = node->ps.state; |
303 | |
304 | /* |
305 | * We must clear the scan tuple so that observers (e.g., execCurrent.c) |
306 | * can tell that this plan node is not positioned on a tuple. |
307 | */ |
308 | ExecClearTuple(node->ss_ScanTupleSlot); |
309 | |
310 | /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */ |
311 | if (estate->es_epq_active != NULL) |
312 | { |
313 | EPQState *epqstate = estate->es_epq_active; |
314 | Index scanrelid = ((Scan *) node->ps.plan)->scanrelid; |
315 | |
316 | if (scanrelid > 0) |
317 | epqstate->relsubs_done[scanrelid - 1] = false; |
318 | else |
319 | { |
320 | Bitmapset *relids; |
321 | int rtindex = -1; |
322 | |
323 | /* |
324 | * If an FDW or custom scan provider has replaced the join with a |
325 | * scan, there are multiple RTIs; reset the epqScanDone flag for |
326 | * all of them. |
327 | */ |
328 | if (IsA(node->ps.plan, ForeignScan)) |
329 | relids = ((ForeignScan *) node->ps.plan)->fs_relids; |
330 | else if (IsA(node->ps.plan, CustomScan)) |
331 | relids = ((CustomScan *) node->ps.plan)->custom_relids; |
332 | else |
333 | elog(ERROR, "unexpected scan node: %d" , |
334 | (int) nodeTag(node->ps.plan)); |
335 | |
336 | while ((rtindex = bms_next_member(relids, rtindex)) >= 0) |
337 | { |
338 | Assert(rtindex > 0); |
339 | epqstate->relsubs_done[rtindex - 1] = false; |
340 | } |
341 | } |
342 | } |
343 | } |
344 | |