Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeSeqscan.c
4 : * Support routines for sequential scans of relations.
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/executor/nodeSeqscan.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : /*
16 : * INTERFACE ROUTINES
17 : * ExecSeqScan sequentially scans a relation.
18 : * ExecSeqNext retrieve next tuple in sequential order.
19 : * ExecInitSeqScan creates and initializes a seqscan node.
20 : * ExecEndSeqScan releases any storage allocated.
21 : * ExecReScanSeqScan rescans the relation
22 : *
23 : * ExecSeqScanEstimate estimates DSM space needed for parallel scan
24 : * ExecSeqScanInitializeDSM initialize DSM for parallel scan
25 : * ExecSeqScanReInitializeDSM reinitialize DSM for fresh parallel scan
26 : * ExecSeqScanInitializeWorker attach to DSM info in parallel worker
27 : */
28 : #include "postgres.h"
29 :
30 : #include "access/relscan.h"
31 : #include "access/tableam.h"
32 : #include "executor/execScan.h"
33 : #include "executor/executor.h"
34 : #include "executor/nodeSeqscan.h"
35 : #include "utils/rel.h"
36 :
37 : static TupleTableSlot *SeqNext(SeqScanState *node);
38 :
39 : /* ----------------------------------------------------------------
40 : * Scan Support
41 : * ----------------------------------------------------------------
42 : */
43 :
44 : /* ----------------------------------------------------------------
45 : * SeqNext
46 : *
47 : * This is a workhorse for ExecSeqScan
48 : * ----------------------------------------------------------------
49 : */
50 : static pg_attribute_always_inline TupleTableSlot *
51 63198267 : SeqNext(SeqScanState *node)
52 : {
53 : TableScanDesc scandesc;
54 : EState *estate;
55 : ScanDirection direction;
56 : TupleTableSlot *slot;
57 :
58 : /*
59 : * get information from the estate and scan state
60 : */
61 63198267 : scandesc = node->ss.ss_currentScanDesc;
62 63198267 : estate = node->ss.ps.state;
63 63198267 : direction = estate->es_direction;
64 63198267 : slot = node->ss.ss_ScanTupleSlot;
65 :
66 63198267 : if (scandesc == NULL)
67 : {
68 : /*
69 : * We reach here if the scan is not parallel, or if we're serially
70 : * executing a scan that was planned to be parallel.
71 : */
72 429828 : scandesc = table_beginscan(node->ss.ss_currentRelation,
73 : estate->es_snapshot,
74 : 0, NULL);
75 429828 : node->ss.ss_currentScanDesc = scandesc;
76 : }
77 :
78 : /*
79 : * get the next tuple from the table
80 : */
81 63198267 : if (table_scan_getnextslot(scandesc, direction, slot))
82 62217469 : return slot;
83 980773 : return NULL;
84 : }
85 :
86 : /*
87 : * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
88 : */
89 : static pg_attribute_always_inline bool
90 129 : SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
91 : {
92 : /*
93 : * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan
94 : * (and this is very bad) - so, here we do not check are keys ok or not.
95 : */
96 129 : return true;
97 : }
98 :
99 : /* ----------------------------------------------------------------
100 : * ExecSeqScan(node)
101 : *
102 : * Scans the relation sequentially and returns the next qualifying
103 : * tuple. This variant is used when there is no es_epq_active, no qual
104 : * and no projection. Passing const-NULLs for these to ExecScanExtended
105 : * allows the compiler to eliminate the additional code that would
106 : * ordinarily be required for the evaluation of these.
107 : * ----------------------------------------------------------------
108 : */
109 : static TupleTableSlot *
110 9091573 : ExecSeqScan(PlanState *pstate)
111 : {
112 9091573 : SeqScanState *node = castNode(SeqScanState, pstate);
113 :
114 : Assert(pstate->state->es_epq_active == NULL);
115 : Assert(pstate->qual == NULL);
116 : Assert(pstate->ps_ProjInfo == NULL);
117 :
118 9091573 : return ExecScanExtended(&node->ss,
119 : (ExecScanAccessMtd) SeqNext,
120 : (ExecScanRecheckMtd) SeqRecheck,
121 : NULL,
122 : NULL,
123 : NULL);
124 : }
125 :
126 : /*
127 : * Variant of ExecSeqScan() but when qual evaluation is required.
128 : */
129 : static TupleTableSlot *
130 4460901 : ExecSeqScanWithQual(PlanState *pstate)
131 : {
132 4460901 : SeqScanState *node = castNode(SeqScanState, pstate);
133 :
134 : /*
135 : * Use pg_assume() for != NULL tests to make the compiler realize no
136 : * runtime check for the field is needed in ExecScanExtended().
137 : */
138 : Assert(pstate->state->es_epq_active == NULL);
139 4460901 : pg_assume(pstate->qual != NULL);
140 : Assert(pstate->ps_ProjInfo == NULL);
141 :
142 4460901 : return ExecScanExtended(&node->ss,
143 : (ExecScanAccessMtd) SeqNext,
144 : (ExecScanRecheckMtd) SeqRecheck,
145 : NULL,
146 : pstate->qual,
147 : NULL);
148 : }
149 :
150 : /*
151 : * Variant of ExecSeqScan() but when projection is required.
152 : */
153 : static TupleTableSlot *
154 16123756 : ExecSeqScanWithProject(PlanState *pstate)
155 : {
156 16123756 : SeqScanState *node = castNode(SeqScanState, pstate);
157 :
158 : Assert(pstate->state->es_epq_active == NULL);
159 : Assert(pstate->qual == NULL);
160 16123756 : pg_assume(pstate->ps_ProjInfo != NULL);
161 :
162 16123756 : return ExecScanExtended(&node->ss,
163 : (ExecScanAccessMtd) SeqNext,
164 : (ExecScanRecheckMtd) SeqRecheck,
165 : NULL,
166 : NULL,
167 : pstate->ps_ProjInfo);
168 : }
169 :
170 : /*
171 : * Variant of ExecSeqScan() but when qual evaluation and projection are
172 : * required.
173 : */
174 : static TupleTableSlot *
175 5536089 : ExecSeqScanWithQualProject(PlanState *pstate)
176 : {
177 5536089 : SeqScanState *node = castNode(SeqScanState, pstate);
178 :
179 : Assert(pstate->state->es_epq_active == NULL);
180 5536089 : pg_assume(pstate->qual != NULL);
181 5536089 : pg_assume(pstate->ps_ProjInfo != NULL);
182 :
183 5536089 : return ExecScanExtended(&node->ss,
184 : (ExecScanAccessMtd) SeqNext,
185 : (ExecScanRecheckMtd) SeqRecheck,
186 : NULL,
187 : pstate->qual,
188 : pstate->ps_ProjInfo);
189 : }
190 :
191 : /*
192 : * Variant of ExecSeqScan for when EPQ evaluation is required. We don't
193 : * bother adding variants of this for with/without qual and projection as
194 : * EPQ doesn't seem as exciting a case to optimize for.
195 : */
196 : static TupleTableSlot *
197 258 : ExecSeqScanEPQ(PlanState *pstate)
198 : {
199 258 : SeqScanState *node = castNode(SeqScanState, pstate);
200 :
201 258 : return ExecScan(&node->ss,
202 : (ExecScanAccessMtd) SeqNext,
203 : (ExecScanRecheckMtd) SeqRecheck);
204 : }
205 :
206 : /* ----------------------------------------------------------------
207 : * ExecInitSeqScan
208 : * ----------------------------------------------------------------
209 : */
210 : SeqScanState *
211 465742 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
212 : {
213 : SeqScanState *scanstate;
214 :
215 : /*
216 : * Once upon a time it was possible to have an outerPlan of a SeqScan, but
217 : * not any more.
218 : */
219 : Assert(outerPlan(node) == NULL);
220 : Assert(innerPlan(node) == NULL);
221 :
222 : /*
223 : * create state structure
224 : */
225 465742 : scanstate = makeNode(SeqScanState);
226 465742 : scanstate->ss.ps.plan = (Plan *) node;
227 465742 : scanstate->ss.ps.state = estate;
228 :
229 : /*
230 : * Miscellaneous initialization
231 : *
232 : * create expression context for node
233 : */
234 465742 : ExecAssignExprContext(estate, &scanstate->ss.ps);
235 :
236 : /*
237 : * open the scan relation
238 : */
239 465734 : scanstate->ss.ss_currentRelation =
240 465742 : ExecOpenScanRelation(estate,
241 : node->scan.scanrelid,
242 : eflags);
243 :
244 : /* and create slot with the appropriate rowtype */
245 465734 : ExecInitScanTupleSlot(estate, &scanstate->ss,
246 465734 : RelationGetDescr(scanstate->ss.ss_currentRelation),
247 : table_slot_callbacks(scanstate->ss.ss_currentRelation),
248 : TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS);
249 :
250 : /*
251 : * Initialize result type and projection.
252 : */
253 465734 : ExecInitResultTypeTL(&scanstate->ss.ps);
254 465734 : ExecAssignScanProjectionInfo(&scanstate->ss);
255 :
256 : /*
257 : * initialize child expressions
258 : */
259 465734 : scanstate->ss.ps.qual =
260 465734 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
261 :
262 : /*
263 : * When EvalPlanQual() is not in use, assign ExecProcNode for this node
264 : * based on the presence of qual and projection. Each ExecSeqScan*()
265 : * variant is optimized for the specific combination of these conditions.
266 : */
267 465734 : if (scanstate->ss.ps.state->es_epq_active != NULL)
268 143 : scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
269 465591 : else if (scanstate->ss.ps.qual == NULL)
270 : {
271 84055 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
272 40398 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
273 : else
274 43657 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
275 : }
276 : else
277 : {
278 381536 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
279 39178 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
280 : else
281 342358 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
282 : }
283 :
284 465734 : return scanstate;
285 : }
286 :
287 : /* ----------------------------------------------------------------
288 : * ExecEndSeqScan
289 : *
290 : * frees any storage allocated through C routines.
291 : * ----------------------------------------------------------------
292 : */
293 : void
294 463939 : ExecEndSeqScan(SeqScanState *node)
295 : {
296 : TableScanDesc scanDesc;
297 :
298 : /*
299 : * get information from node
300 : */
301 463939 : scanDesc = node->ss.ss_currentScanDesc;
302 :
303 : /*
304 : * close heap scan
305 : */
306 463939 : if (scanDesc != NULL)
307 430845 : table_endscan(scanDesc);
308 463939 : }
309 :
310 : /* ----------------------------------------------------------------
311 : * Join Support
312 : * ----------------------------------------------------------------
313 : */
314 :
315 : /* ----------------------------------------------------------------
316 : * ExecReScanSeqScan
317 : *
318 : * Rescans the relation.
319 : * ----------------------------------------------------------------
320 : */
321 : void
322 881129 : ExecReScanSeqScan(SeqScanState *node)
323 : {
324 : TableScanDesc scan;
325 :
326 881129 : scan = node->ss.ss_currentScanDesc;
327 :
328 881129 : if (scan != NULL)
329 865338 : table_rescan(scan, /* scan desc */
330 : NULL); /* new scan keys */
331 :
332 881129 : ExecScanReScan((ScanState *) node);
333 881129 : }
334 :
335 : /* ----------------------------------------------------------------
336 : * Parallel Scan Support
337 : * ----------------------------------------------------------------
338 : */
339 :
340 : /* ----------------------------------------------------------------
341 : * ExecSeqScanEstimate
342 : *
343 : * Compute the amount of space we'll need in the parallel
344 : * query DSM, and inform pcxt->estimator about our needs.
345 : * ----------------------------------------------------------------
346 : */
347 : void
348 637 : ExecSeqScanEstimate(SeqScanState *node,
349 : ParallelContext *pcxt)
350 : {
351 637 : EState *estate = node->ss.ps.state;
352 :
353 637 : node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
354 : estate->es_snapshot);
355 637 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
356 637 : shm_toc_estimate_keys(&pcxt->estimator, 1);
357 637 : }
358 :
359 : /* ----------------------------------------------------------------
360 : * ExecSeqScanInitializeDSM
361 : *
362 : * Set up a parallel heap scan descriptor.
363 : * ----------------------------------------------------------------
364 : */
365 : void
366 637 : ExecSeqScanInitializeDSM(SeqScanState *node,
367 : ParallelContext *pcxt)
368 : {
369 637 : EState *estate = node->ss.ps.state;
370 : ParallelTableScanDesc pscan;
371 :
372 637 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
373 637 : table_parallelscan_initialize(node->ss.ss_currentRelation,
374 : pscan,
375 : estate->es_snapshot);
376 637 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
377 637 : node->ss.ss_currentScanDesc =
378 637 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
379 637 : }
380 :
381 : /* ----------------------------------------------------------------
382 : * ExecSeqScanReInitializeDSM
383 : *
384 : * Reset shared state before beginning a fresh scan.
385 : * ----------------------------------------------------------------
386 : */
387 : void
388 152 : ExecSeqScanReInitializeDSM(SeqScanState *node,
389 : ParallelContext *pcxt)
390 : {
391 : ParallelTableScanDesc pscan;
392 :
393 152 : pscan = node->ss.ss_currentScanDesc->rs_parallel;
394 152 : table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
395 152 : }
396 :
397 : /* ----------------------------------------------------------------
398 : * ExecSeqScanInitializeWorker
399 : *
400 : * Copy relevant information from TOC into planstate.
401 : * ----------------------------------------------------------------
402 : */
403 : void
404 1860 : ExecSeqScanInitializeWorker(SeqScanState *node,
405 : ParallelWorkerContext *pwcxt)
406 : {
407 : ParallelTableScanDesc pscan;
408 :
409 1860 : pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
410 1860 : node->ss.ss_currentScanDesc =
411 1860 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
412 1860 : }
|