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 78707128 : 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 78707128 : scandesc = node->ss.ss_currentScanDesc;
62 78707128 : estate = node->ss.ps.state;
63 78707128 : direction = estate->es_direction;
64 78707128 : slot = node->ss.ss_ScanTupleSlot;
65 :
66 78707128 : 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 187774 : scandesc = table_beginscan(node->ss.ss_currentRelation,
73 : estate->es_snapshot,
74 : 0, NULL);
75 187774 : node->ss.ss_currentScanDesc = scandesc;
76 : }
77 :
78 : /*
79 : * get the next tuple from the table
80 : */
81 78707128 : if (table_scan_getnextslot(scandesc, direction, slot))
82 77501720 : return slot;
83 1205392 : 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_eqp_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 12172534 : ExecSeqScan(PlanState *pstate)
111 : {
112 12172534 : 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 12172534 : 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 5581342 : ExecSeqScanWithQual(PlanState *pstate)
131 : {
132 5581342 : SeqScanState *node = castNode(SeqScanState, pstate);
133 :
134 : Assert(pstate->state->es_epq_active == NULL);
135 : Assert(pstate->qual != NULL);
136 : Assert(pstate->ps_ProjInfo == NULL);
137 :
138 5581342 : return ExecScanExtended(&node->ss,
139 : (ExecScanAccessMtd) SeqNext,
140 : (ExecScanRecheckMtd) SeqRecheck,
141 : NULL,
142 : pstate->qual,
143 : NULL);
144 : }
145 :
146 : /*
147 : * Variant of ExecSeqScan() but when projection is required.
148 : */
149 : static TupleTableSlot *
150 21961364 : ExecSeqScanWithProject(PlanState *pstate)
151 : {
152 21961364 : SeqScanState *node = castNode(SeqScanState, pstate);
153 :
154 : Assert(pstate->state->es_epq_active == NULL);
155 : Assert(pstate->qual == NULL);
156 : Assert(pstate->ps_ProjInfo != NULL);
157 :
158 21961364 : return ExecScanExtended(&node->ss,
159 : (ExecScanAccessMtd) SeqNext,
160 : (ExecScanRecheckMtd) SeqRecheck,
161 : NULL,
162 : NULL,
163 : pstate->ps_ProjInfo);
164 : }
165 :
166 : /*
167 : * Variant of ExecSeqScan() but when qual evaluation and projection are
168 : * required.
169 : */
170 : static TupleTableSlot *
171 6663712 : ExecSeqScanWithQualProject(PlanState *pstate)
172 : {
173 6663712 : SeqScanState *node = castNode(SeqScanState, pstate);
174 :
175 : Assert(pstate->state->es_epq_active == NULL);
176 : Assert(pstate->qual != NULL);
177 : Assert(pstate->ps_ProjInfo != NULL);
178 :
179 6663712 : return ExecScanExtended(&node->ss,
180 : (ExecScanAccessMtd) SeqNext,
181 : (ExecScanRecheckMtd) SeqRecheck,
182 : NULL,
183 : pstate->qual,
184 : pstate->ps_ProjInfo);
185 : }
186 :
187 : /*
188 : * Variant of ExecSeqScan for when EPQ evaluation is required. We don't
189 : * bother adding variants of this for with/without qual and projection as
190 : * EPQ doesn't seem as exciting a case to optimize for.
191 : */
192 : static TupleTableSlot *
193 490 : ExecSeqScanEPQ(PlanState *pstate)
194 : {
195 490 : SeqScanState *node = castNode(SeqScanState, pstate);
196 :
197 490 : return ExecScan(&node->ss,
198 : (ExecScanAccessMtd) SeqNext,
199 : (ExecScanRecheckMtd) SeqRecheck);
200 : }
201 :
202 : /* ----------------------------------------------------------------
203 : * ExecInitSeqScan
204 : * ----------------------------------------------------------------
205 : */
206 : SeqScanState *
207 246870 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
208 : {
209 : SeqScanState *scanstate;
210 :
211 : /*
212 : * Once upon a time it was possible to have an outerPlan of a SeqScan, but
213 : * not any more.
214 : */
215 : Assert(outerPlan(node) == NULL);
216 : Assert(innerPlan(node) == NULL);
217 :
218 : /*
219 : * create state structure
220 : */
221 246870 : scanstate = makeNode(SeqScanState);
222 246870 : scanstate->ss.ps.plan = (Plan *) node;
223 246870 : scanstate->ss.ps.state = estate;
224 :
225 : /*
226 : * Miscellaneous initialization
227 : *
228 : * create expression context for node
229 : */
230 246870 : ExecAssignExprContext(estate, &scanstate->ss.ps);
231 :
232 : /*
233 : * open the scan relation
234 : */
235 246858 : scanstate->ss.ss_currentRelation =
236 246870 : ExecOpenScanRelation(estate,
237 : node->scan.scanrelid,
238 : eflags);
239 :
240 : /* and create slot with the appropriate rowtype */
241 246858 : ExecInitScanTupleSlot(estate, &scanstate->ss,
242 246858 : RelationGetDescr(scanstate->ss.ss_currentRelation),
243 : table_slot_callbacks(scanstate->ss.ss_currentRelation));
244 :
245 : /*
246 : * Initialize result type and projection.
247 : */
248 246858 : ExecInitResultTypeTL(&scanstate->ss.ps);
249 246858 : ExecAssignScanProjectionInfo(&scanstate->ss);
250 :
251 : /*
252 : * initialize child expressions
253 : */
254 246852 : scanstate->ss.ps.qual =
255 246852 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
256 :
257 : /*
258 : * When EvalPlanQual() is not in use, assign ExecProcNode for this node
259 : * based on the presence of qual and projection. Each ExecSeqScan*()
260 : * variant is optimized for the specific combination of these conditions.
261 : */
262 246852 : if (scanstate->ss.ps.state->es_epq_active != NULL)
263 252 : scanstate->ss.ps.ExecProcNode = ExecSeqScanEPQ;
264 246600 : else if (scanstate->ss.ps.qual == NULL)
265 : {
266 107988 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
267 51736 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
268 : else
269 56252 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithProject;
270 : }
271 : else
272 : {
273 138612 : if (scanstate->ss.ps.ps_ProjInfo == NULL)
274 83122 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQual;
275 : else
276 55490 : scanstate->ss.ps.ExecProcNode = ExecSeqScanWithQualProject;
277 : }
278 :
279 246852 : return scanstate;
280 : }
281 :
282 : /* ----------------------------------------------------------------
283 : * ExecEndSeqScan
284 : *
285 : * frees any storage allocated through C routines.
286 : * ----------------------------------------------------------------
287 : */
288 : void
289 244290 : ExecEndSeqScan(SeqScanState *node)
290 : {
291 : TableScanDesc scanDesc;
292 :
293 : /*
294 : * get information from node
295 : */
296 244290 : scanDesc = node->ss.ss_currentScanDesc;
297 :
298 : /*
299 : * close heap scan
300 : */
301 244290 : if (scanDesc != NULL)
302 189256 : table_endscan(scanDesc);
303 244290 : }
304 :
305 : /* ----------------------------------------------------------------
306 : * Join Support
307 : * ----------------------------------------------------------------
308 : */
309 :
310 : /* ----------------------------------------------------------------
311 : * ExecReScanSeqScan
312 : *
313 : * Rescans the relation.
314 : * ----------------------------------------------------------------
315 : */
316 : void
317 1095366 : ExecReScanSeqScan(SeqScanState *node)
318 : {
319 : TableScanDesc scan;
320 :
321 1095366 : scan = node->ss.ss_currentScanDesc;
322 :
323 1095366 : if (scan != NULL)
324 1054426 : table_rescan(scan, /* scan desc */
325 : NULL); /* new scan keys */
326 :
327 1095366 : ExecScanReScan((ScanState *) node);
328 1095366 : }
329 :
330 : /* ----------------------------------------------------------------
331 : * Parallel Scan Support
332 : * ----------------------------------------------------------------
333 : */
334 :
335 : /* ----------------------------------------------------------------
336 : * ExecSeqScanEstimate
337 : *
338 : * Compute the amount of space we'll need in the parallel
339 : * query DSM, and inform pcxt->estimator about our needs.
340 : * ----------------------------------------------------------------
341 : */
342 : void
343 900 : ExecSeqScanEstimate(SeqScanState *node,
344 : ParallelContext *pcxt)
345 : {
346 900 : EState *estate = node->ss.ps.state;
347 :
348 900 : node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
349 : estate->es_snapshot);
350 900 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
351 900 : shm_toc_estimate_keys(&pcxt->estimator, 1);
352 900 : }
353 :
354 : /* ----------------------------------------------------------------
355 : * ExecSeqScanInitializeDSM
356 : *
357 : * Set up a parallel heap scan descriptor.
358 : * ----------------------------------------------------------------
359 : */
360 : void
361 900 : ExecSeqScanInitializeDSM(SeqScanState *node,
362 : ParallelContext *pcxt)
363 : {
364 900 : EState *estate = node->ss.ps.state;
365 : ParallelTableScanDesc pscan;
366 :
367 900 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
368 900 : table_parallelscan_initialize(node->ss.ss_currentRelation,
369 : pscan,
370 : estate->es_snapshot);
371 900 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
372 900 : node->ss.ss_currentScanDesc =
373 900 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
374 900 : }
375 :
376 : /* ----------------------------------------------------------------
377 : * ExecSeqScanReInitializeDSM
378 : *
379 : * Reset shared state before beginning a fresh scan.
380 : * ----------------------------------------------------------------
381 : */
382 : void
383 228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
384 : ParallelContext *pcxt)
385 : {
386 : ParallelTableScanDesc pscan;
387 :
388 228 : pscan = node->ss.ss_currentScanDesc->rs_parallel;
389 228 : table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
390 228 : }
391 :
392 : /* ----------------------------------------------------------------
393 : * ExecSeqScanInitializeWorker
394 : *
395 : * Copy relevant information from TOC into planstate.
396 : * ----------------------------------------------------------------
397 : */
398 : void
399 2682 : ExecSeqScanInitializeWorker(SeqScanState *node,
400 : ParallelWorkerContext *pwcxt)
401 : {
402 : ParallelTableScanDesc pscan;
403 :
404 2682 : pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
405 2682 : node->ss.ss_currentScanDesc =
406 2682 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
407 2682 : }
|