PostgreSQL Source Code git master
execScan.h
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 * execScan.h
3 * Inline-able support functions for Scan nodes
4 *
5 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * IDENTIFICATION
9 * src/include/executor/execScan.h
10 *-------------------------------------------------------------------------
11 */
12
13#ifndef EXECSCAN_H
14#define EXECSCAN_H
15
16#include "miscadmin.h"
17#include "executor/executor.h"
18#include "nodes/execnodes.h"
19
20/*
21 * ExecScanFetch -- check interrupts & fetch next potential tuple
22 *
23 * This routine substitutes a test tuple if inside an EvalPlanQual recheck.
24 * Otherwise, it simply executes the access method's next-tuple routine.
25 *
26 * The pg_attribute_always_inline attribute allows the compiler to inline
27 * this function into its caller. When EPQState is NULL, the EvalPlanQual
28 * logic is completely eliminated at compile time, avoiding unnecessary
29 * run-time checks and code for cases where EPQ is not required.
30 */
33 EPQState *epqstate,
34 ExecScanAccessMtd accessMtd,
35 ExecScanRecheckMtd recheckMtd)
36{
38
39 if (epqstate != NULL)
40 {
41 /*
42 * We are inside an EvalPlanQual recheck. Return the test tuple if
43 * one is available, after rechecking any access-method-specific
44 * conditions.
45 */
46 Index scanrelid = ((Scan *) node->ps.plan)->scanrelid;
47
48 if (scanrelid == 0)
49 {
50 /*
51 * This is a ForeignScan or CustomScan which has pushed down a
52 * join to the remote side. If it is a descendant node in the EPQ
53 * recheck plan tree, run the recheck method function. Otherwise,
54 * run the access method function below.
55 */
56 if (bms_is_member(epqstate->epqParam, node->ps.plan->extParam))
57 {
58 /*
59 * The recheck method is responsible not only for rechecking
60 * the scan/join quals but also for storing the correct tuple
61 * in the slot.
62 */
63
64 TupleTableSlot *slot = node->ss_ScanTupleSlot;
65
66 if (!(*recheckMtd) (node, slot))
67 ExecClearTuple(slot); /* would not be returned by scan */
68 return slot;
69 }
70 }
71 else if (epqstate->relsubs_done[scanrelid - 1])
72 {
73 /*
74 * Return empty slot, as either there is no EPQ tuple for this rel
75 * or we already returned it.
76 */
77
78 TupleTableSlot *slot = node->ss_ScanTupleSlot;
79
80 return ExecClearTuple(slot);
81 }
82 else if (epqstate->relsubs_slot[scanrelid - 1] != NULL)
83 {
84 /*
85 * Return replacement tuple provided by the EPQ caller.
86 */
87
88 TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1];
89
90 Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL);
91
92 /* Mark to remember that we shouldn't return it again */
93 epqstate->relsubs_done[scanrelid - 1] = true;
94
95 /* Return empty slot if we haven't got a test tuple */
96 if (TupIsNull(slot))
97 return NULL;
98
99 /* Check if it meets the access-method conditions */
100 if (!(*recheckMtd) (node, slot))
101 return ExecClearTuple(slot); /* would not be returned by
102 * scan */
103 return slot;
104 }
105 else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
106 {
107 /*
108 * Fetch and return replacement tuple using a non-locking rowmark.
109 */
110
111 TupleTableSlot *slot = node->ss_ScanTupleSlot;
112
113 /* Mark to remember that we shouldn't return more */
114 epqstate->relsubs_done[scanrelid - 1] = true;
115
116 if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot))
117 return NULL;
118
119 /* Return empty slot if we haven't got a test tuple */
120 if (TupIsNull(slot))
121 return NULL;
122
123 /* Check if it meets the access-method conditions */
124 if (!(*recheckMtd) (node, slot))
125 return ExecClearTuple(slot); /* would not be returned by
126 * scan */
127 return slot;
128 }
129 }
130
131 /*
132 * Run the node-type-specific access method function to get the next tuple
133 */
134 return (*accessMtd) (node);
135}
136
137/* ----------------------------------------------------------------
138 * ExecScanExtended
139 * Scans the relation using the specified 'access method' and returns the
140 * next tuple. Optionally checks the tuple against 'qual' and applies
141 * 'projInfo' if provided.
142 *
143 * The 'recheck method' validates an arbitrary tuple of the relation against
144 * conditions enforced by the access method.
145 *
146 * This function is an alternative to ExecScan, used when callers may omit
147 * 'qual' or 'projInfo'. The pg_attribute_always_inline attribute allows the
148 * compiler to eliminate non-relevant branches at compile time, avoiding
149 * run-time checks in those cases.
150 *
151 * Conditions:
152 * -- The AMI "cursor" is positioned at the previously returned tuple.
153 *
154 * Initial States:
155 * -- The relation is opened for scanning, with the "cursor"
156 * positioned before the first qualifying tuple.
157 * ----------------------------------------------------------------
158 */
161 ExecScanAccessMtd accessMtd, /* function returning a tuple */
162 ExecScanRecheckMtd recheckMtd,
163 EPQState *epqstate,
164 ExprState *qual,
165 ProjectionInfo *projInfo)
166{
167 ExprContext *econtext = node->ps.ps_ExprContext;
168
169 /* interrupt checks are in ExecScanFetch */
170
171 /*
172 * If we have neither a qual to check nor a projection to do, just skip
173 * all the overhead and return the raw scan tuple.
174 */
175 if (!qual && !projInfo)
176 {
177 ResetExprContext(econtext);
178 return ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
179 }
180
181 /*
182 * Reset per-tuple memory context to free any expression evaluation
183 * storage allocated in the previous tuple cycle.
184 */
185 ResetExprContext(econtext);
186
187 /*
188 * get a tuple from the access method. Loop until we obtain a tuple that
189 * passes the qualification.
190 */
191 for (;;)
192 {
193 TupleTableSlot *slot;
194
195 slot = ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
196
197 /*
198 * if the slot returned by the accessMtd contains NULL, then it means
199 * there is nothing more to scan so we just return an empty slot,
200 * being careful to use the projection result slot so it has correct
201 * tupleDesc.
202 */
203 if (TupIsNull(slot))
204 {
205 if (projInfo)
206 return ExecClearTuple(projInfo->pi_state.resultslot);
207 else
208 return slot;
209 }
210
211 /*
212 * place the current tuple into the expr context
213 */
214 econtext->ecxt_scantuple = slot;
215
216 /*
217 * check that the current tuple satisfies the qual-clause
218 *
219 * check for non-null qual here to avoid a function call to ExecQual()
220 * when the qual is null ... saves only a few cycles, but they add up
221 * ...
222 */
223 if (qual == NULL || ExecQual(qual, econtext))
224 {
225 /*
226 * Found a satisfactory scan tuple.
227 */
228 if (projInfo)
229 {
230 /*
231 * Form a projection tuple, store it in the result tuple slot
232 * and return it.
233 */
234 return ExecProject(projInfo);
235 }
236 else
237 {
238 /*
239 * Here, we aren't projecting, so just return scan tuple.
240 */
241 return slot;
242 }
243 }
244 else
245 InstrCountFiltered1(node, 1);
246
247 /*
248 * Tuple fails qual, so free per-tuple memory and try again.
249 */
250 ResetExprContext(econtext);
251 }
252}
253
254#endif /* EXECSCAN_H */
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
#define pg_attribute_always_inline
Definition: c.h:274
unsigned int Index
Definition: c.h:624
bool EvalPlanQualFetchRowMark(EPQState *epqstate, Index rti, TupleTableSlot *slot)
Definition: execMain.c:2805
static pg_attribute_always_inline TupleTableSlot * ExecScanFetch(ScanState *node, EPQState *epqstate, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.h:32
static pg_attribute_always_inline TupleTableSlot * ExecScanExtended(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd, EPQState *epqstate, ExprState *qual, ProjectionInfo *projInfo)
Definition: execScan.h:160
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1269
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:483
#define ResetExprContext(econtext)
Definition: executor.h:650
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:519
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:580
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:579
Assert(PointerIsAligned(start, uint64))
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1340
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1312
int epqParam
Definition: execnodes.h:1302
bool * relsubs_done
Definition: execnodes.h:1347
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:273
TupleTableSlot * resultslot
Definition: execnodes.h:104
Plan * plan
Definition: execnodes.h:1165
ExprContext * ps_ExprContext
Definition: execnodes.h:1204
Bitmapset * extParam
Definition: plannodes.h:249
ExprState pi_state
Definition: execnodes.h:386
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1624
PlanState ps
Definition: execnodes.h:1621
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:457
#define TupIsNull(slot)
Definition: tuptable.h:309