PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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. The recheck method is responsible not
53 * only for rechecking the scan/join quals but also for storing
54 * the correct tuple in the slot.
55 */
56
57 TupleTableSlot *slot = node->ss_ScanTupleSlot;
58
59 if (!(*recheckMtd) (node, slot))
60 ExecClearTuple(slot); /* would not be returned by scan */
61 return slot;
62 }
63 else if (epqstate->relsubs_done[scanrelid - 1])
64 {
65 /*
66 * Return empty slot, as either there is no EPQ tuple for this rel
67 * or we already returned it.
68 */
69
70 TupleTableSlot *slot = node->ss_ScanTupleSlot;
71
72 return ExecClearTuple(slot);
73 }
74 else if (epqstate->relsubs_slot[scanrelid - 1] != NULL)
75 {
76 /*
77 * Return replacement tuple provided by the EPQ caller.
78 */
79
80 TupleTableSlot *slot = epqstate->relsubs_slot[scanrelid - 1];
81
82 Assert(epqstate->relsubs_rowmark[scanrelid - 1] == NULL);
83
84 /* Mark to remember that we shouldn't return it again */
85 epqstate->relsubs_done[scanrelid - 1] = true;
86
87 /* Return empty slot if we haven't got a test tuple */
88 if (TupIsNull(slot))
89 return NULL;
90
91 /* Check if it meets the access-method conditions */
92 if (!(*recheckMtd) (node, slot))
93 return ExecClearTuple(slot); /* would not be returned by
94 * scan */
95 return slot;
96 }
97 else if (epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
98 {
99 /*
100 * Fetch and return replacement tuple using a non-locking rowmark.
101 */
102
103 TupleTableSlot *slot = node->ss_ScanTupleSlot;
104
105 /* Mark to remember that we shouldn't return more */
106 epqstate->relsubs_done[scanrelid - 1] = true;
107
108 if (!EvalPlanQualFetchRowMark(epqstate, scanrelid, slot))
109 return NULL;
110
111 /* Return empty slot if we haven't got a test tuple */
112 if (TupIsNull(slot))
113 return NULL;
114
115 /* Check if it meets the access-method conditions */
116 if (!(*recheckMtd) (node, slot))
117 return ExecClearTuple(slot); /* would not be returned by
118 * scan */
119 return slot;
120 }
121 }
122
123 /*
124 * Run the node-type-specific access method function to get the next tuple
125 */
126 return (*accessMtd) (node);
127}
128
129/* ----------------------------------------------------------------
130 * ExecScanExtended
131 * Scans the relation using the specified 'access method' and returns the
132 * next tuple. Optionally checks the tuple against 'qual' and applies
133 * 'projInfo' if provided.
134 *
135 * The 'recheck method' validates an arbitrary tuple of the relation against
136 * conditions enforced by the access method.
137 *
138 * This function is an alternative to ExecScan, used when callers may omit
139 * 'qual' or 'projInfo'. The pg_attribute_always_inline attribute allows the
140 * compiler to eliminate non-relevant branches at compile time, avoiding
141 * run-time checks in those cases.
142 *
143 * Conditions:
144 * -- The AMI "cursor" is positioned at the previously returned tuple.
145 *
146 * Initial States:
147 * -- The relation is opened for scanning, with the "cursor"
148 * positioned before the first qualifying tuple.
149 * ----------------------------------------------------------------
150 */
153 ExecScanAccessMtd accessMtd, /* function returning a tuple */
154 ExecScanRecheckMtd recheckMtd,
155 EPQState *epqstate,
156 ExprState *qual,
157 ProjectionInfo *projInfo)
158{
159 ExprContext *econtext = node->ps.ps_ExprContext;
160
161 /* interrupt checks are in ExecScanFetch */
162
163 /*
164 * If we have neither a qual to check nor a projection to do, just skip
165 * all the overhead and return the raw scan tuple.
166 */
167 if (!qual && !projInfo)
168 {
169 ResetExprContext(econtext);
170 return ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
171 }
172
173 /*
174 * Reset per-tuple memory context to free any expression evaluation
175 * storage allocated in the previous tuple cycle.
176 */
177 ResetExprContext(econtext);
178
179 /*
180 * get a tuple from the access method. Loop until we obtain a tuple that
181 * passes the qualification.
182 */
183 for (;;)
184 {
185 TupleTableSlot *slot;
186
187 slot = ExecScanFetch(node, epqstate, accessMtd, recheckMtd);
188
189 /*
190 * if the slot returned by the accessMtd contains NULL, then it means
191 * there is nothing more to scan so we just return an empty slot,
192 * being careful to use the projection result slot so it has correct
193 * tupleDesc.
194 */
195 if (TupIsNull(slot))
196 {
197 if (projInfo)
198 return ExecClearTuple(projInfo->pi_state.resultslot);
199 else
200 return slot;
201 }
202
203 /*
204 * place the current tuple into the expr context
205 */
206 econtext->ecxt_scantuple = slot;
207
208 /*
209 * check that the current tuple satisfies the qual-clause
210 *
211 * check for non-null qual here to avoid a function call to ExecQual()
212 * when the qual is null ... saves only a few cycles, but they add up
213 * ...
214 */
215 if (qual == NULL || ExecQual(qual, econtext))
216 {
217 /*
218 * Found a satisfactory scan tuple.
219 */
220 if (projInfo)
221 {
222 /*
223 * Form a projection tuple, store it in the result tuple slot
224 * and return it.
225 */
226 return ExecProject(projInfo);
227 }
228 else
229 {
230 /*
231 * Here, we aren't projecting, so just return scan tuple.
232 */
233 return slot;
234 }
235 }
236 else
237 InstrCountFiltered1(node, 1);
238
239 /*
240 * Tuple fails qual, so free per-tuple memory and try again.
241 */
242 ResetExprContext(econtext);
243 }
244}
245
246#endif /* EXECSCAN_H */
#define pg_attribute_always_inline
Definition: c.h:270
unsigned int Index
Definition: c.h:585
bool EvalPlanQualFetchRowMark(EPQState *epqstate, Index rti, TupleTableSlot *slot)
Definition: execMain.c:2766
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:152
#define InstrCountFiltered1(node, delta)
Definition: execnodes.h:1257
static TupleTableSlot * ExecProject(ProjectionInfo *projInfo)
Definition: executor.h:464
#define ResetExprContext(econtext)
Definition: executor.h:631
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:500
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:561
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:560
Assert(PointerIsAligned(start, uint64))
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1328
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1300
bool * relsubs_done
Definition: execnodes.h:1335
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:268
TupleTableSlot * resultslot
Definition: execnodes.h:107
Plan * plan
Definition: execnodes.h:1153
ExprContext * ps_ExprContext
Definition: execnodes.h:1192
ExprState pi_state
Definition: execnodes.h:381
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1612
PlanState ps
Definition: execnodes.h:1609
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define TupIsNull(slot)
Definition: tuptable.h:306