Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeSeqscan.c
4 : * Support routines for sequential scans of relations.
5 : *
6 : * Portions Copyright (c) 1996-2025, 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 TupleTableSlot *
51 84692596 : 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 84692596 : scandesc = node->ss.ss_currentScanDesc;
62 84692596 : estate = node->ss.ps.state;
63 84692596 : direction = estate->es_direction;
64 84692596 : slot = node->ss.ss_ScanTupleSlot;
65 :
66 84692596 : 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 181324 : scandesc = table_beginscan(node->ss.ss_currentRelation,
73 : estate->es_snapshot,
74 : 0, NULL);
75 181324 : node->ss.ss_currentScanDesc = scandesc;
76 : }
77 :
78 : /*
79 : * get the next tuple from the table
80 : */
81 84692596 : if (table_scan_getnextslot(scandesc, direction, slot))
82 83338150 : return slot;
83 1354396 : return NULL;
84 : }
85 :
86 : /*
87 : * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
88 : */
89 : static bool
90 236 : 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 236 : 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 13639936 : ExecSeqScan(PlanState *pstate)
111 : {
112 13639936 : 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 13639936 : 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 6609126 : ExecSeqScanWithQual(PlanState *pstate)
131 : {
132 6609126 : 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 6609126 : pg_assume(pstate->qual != NULL);
140 : Assert(pstate->ps_ProjInfo == NULL);
141 :
142 6609126 : 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 23628042 : ExecSeqScanWithProject(PlanState *pstate)
155 : {
156 23628042 : SeqScanState *node = castNode(SeqScanState, pstate);
157 :
158 : Assert(pstate->state->es_epq_active == NULL);
159 : Assert(pstate->qual == NULL);
160 23628042 : pg_assume(pstate->ps_ProjInfo != NULL);
161 :
162 23628042 : 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 7238010 : ExecSeqScanWithQualProject(PlanState *pstate)
176 : {
177 7238010 : SeqScanState *node = castNode(SeqScanState, pstate);
178 :
179 : Assert(pstate->state->es_epq_active == NULL);
180 7238010 : pg_assume(pstate->qual != NULL);
181 7238010 : pg_assume(pstate->ps_ProjInfo != NULL);
182 :
183 7238010 : 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 490 : ExecSeqScanEPQ(PlanState *pstate)
198 : {
199 490 : SeqScanState *node = castNode(SeqScanState, pstate);
200 :
201 490 : return ExecScan(&node->ss,
202 : (ExecScanAccessMtd) SeqNext,
203 : (ExecScanRecheckMtd) SeqRecheck);
204 : }
205 :
206 : /* ----------------------------------------------------------------
207 : * ExecInitSeqScan
208 : * ----------------------------------------------------------------
209 : */
210 : SeqScanState *
211 221844 : 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 221844 : scanstate = makeNode(SeqScanState);
226 221844 : scanstate->ss.ps.plan = (Plan *) node;
227 221844 : scanstate->ss.ps.state = estate;
228 :
229 : /*
230 : * Miscellaneous initialization
231 : *
232 : * create expression context for node
233 : */
234 221844 : ExecAssignExprContext(estate, &scanstate->ss.ps);
235 :
236 : /*
237 : * open the scan relation
238 : */
239 221832 : scanstate->ss.ss_currentRelation =
240 221844 : ExecOpenScanRelation(estate,
241 : node->scan.scanrelid,
242 : eflags);
243 :
244 : /* and create slot with the appropriate rowtype */
245 221832 : ExecInitScanTupleSlot(estate, &scanstate->ss,
246 221832 : RelationGetDescr(scanstate->ss.ss_currentRelation),
247 : table_slot_callbacks(scanstate->ss.ss_currentRelation));
248 :
249 : /*
250 : * Initialize result type and projection.
251 : */
252 221832 : ExecInitResultTypeTL(&scanstate->ss.ps);
253 221832 : ExecAssignScanProjectionInfo(&scanstate->ss);
254 :
255 : /*
256 : * initialize child expressions
257 : */
258 221832 : scanstate->ss.ps.qual =
259 221832 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
260 :
261 : /*
262 : * When EvalPlanQual() is not in use, assign ExecProcNode for this node
263 : * based on the presence of qual and projection. Each ExecSeqScan*()
264 : * variant is optimized for the specific combination of these conditions.
265 : */
266 221832 : if (scanstate->ss.ps.state->es_epq_active != NULL)
267 252 : scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
268 221580 : else if (scanstate->ss.ps.qual == NULL)
269 : {
270 111224 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
271 52516 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
272 : else
273 58708 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
274 : }
275 : else
276 : {
277 110356 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
278 52274 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
279 : else
280 58082 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
281 : }
282 :
283 221832 : return scanstate;
284 : }
285 :
286 : /* ----------------------------------------------------------------
287 : * ExecEndSeqScan
288 : *
289 : * frees any storage allocated through C routines.
290 : * ----------------------------------------------------------------
291 : */
292 : void
293 219208 : ExecEndSeqScan(SeqScanState *node)
294 : {
295 : TableScanDesc scanDesc;
296 :
297 : /*
298 : * get information from node
299 : */
300 219208 : scanDesc = node->ss.ss_currentScanDesc;
301 :
302 : /*
303 : * close heap scan
304 : */
305 219208 : if (scanDesc != NULL)
306 182758 : table_endscan(scanDesc);
307 219208 : }
308 :
309 : /* ----------------------------------------------------------------
310 : * Join Support
311 : * ----------------------------------------------------------------
312 : */
313 :
314 : /* ----------------------------------------------------------------
315 : * ExecReScanSeqScan
316 : *
317 : * Rescans the relation.
318 : * ----------------------------------------------------------------
319 : */
320 : void
321 1215516 : ExecReScanSeqScan(SeqScanState *node)
322 : {
323 : TableScanDesc scan;
324 :
325 1215516 : scan = node->ss.ss_currentScanDesc;
326 :
327 1215516 : if (scan != NULL)
328 1191334 : table_rescan(scan, /* scan desc */
329 : NULL); /* new scan keys */
330 :
331 1215516 : ExecScanReScan((ScanState *) node);
332 1215516 : }
333 :
334 : /* ----------------------------------------------------------------
335 : * Parallel Scan Support
336 : * ----------------------------------------------------------------
337 : */
338 :
339 : /* ----------------------------------------------------------------
340 : * ExecSeqScanEstimate
341 : *
342 : * Compute the amount of space we'll need in the parallel
343 : * query DSM, and inform pcxt->estimator about our needs.
344 : * ----------------------------------------------------------------
345 : */
346 : void
347 906 : ExecSeqScanEstimate(SeqScanState *node,
348 : ParallelContext *pcxt)
349 : {
350 906 : EState *estate = node->ss.ps.state;
351 :
352 906 : node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
353 : estate->es_snapshot);
354 906 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
355 906 : shm_toc_estimate_keys(&pcxt->estimator, 1);
356 906 : }
357 :
358 : /* ----------------------------------------------------------------
359 : * ExecSeqScanInitializeDSM
360 : *
361 : * Set up a parallel heap scan descriptor.
362 : * ----------------------------------------------------------------
363 : */
364 : void
365 906 : ExecSeqScanInitializeDSM(SeqScanState *node,
366 : ParallelContext *pcxt)
367 : {
368 906 : EState *estate = node->ss.ps.state;
369 : ParallelTableScanDesc pscan;
370 :
371 906 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
372 906 : table_parallelscan_initialize(node->ss.ss_currentRelation,
373 : pscan,
374 : estate->es_snapshot);
375 906 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
376 906 : node->ss.ss_currentScanDesc =
377 906 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
378 906 : }
379 :
380 : /* ----------------------------------------------------------------
381 : * ExecSeqScanReInitializeDSM
382 : *
383 : * Reset shared state before beginning a fresh scan.
384 : * ----------------------------------------------------------------
385 : */
386 : void
387 228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
388 : ParallelContext *pcxt)
389 : {
390 : ParallelTableScanDesc pscan;
391 :
392 228 : pscan = node->ss.ss_currentScanDesc->rs_parallel;
393 228 : table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
394 228 : }
395 :
396 : /* ----------------------------------------------------------------
397 : * ExecSeqScanInitializeWorker
398 : *
399 : * Copy relevant information from TOC into planstate.
400 : * ----------------------------------------------------------------
401 : */
402 : void
403 2690 : ExecSeqScanInitializeWorker(SeqScanState *node,
404 : ParallelWorkerContext *pwcxt)
405 : {
406 : ParallelTableScanDesc pscan;
407 :
408 2690 : pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
409 2690 : node->ss.ss_currentScanDesc =
410 2690 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
411 2690 : }
|