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