Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeSeqscan.c
4 : * Support routines for sequential scans of relations.
5 : *
6 : * Portions Copyright (c) 1996-2024, 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/executor.h"
33 : #include "executor/nodeSeqscan.h"
34 : #include "utils/rel.h"
35 :
36 : static TupleTableSlot *SeqNext(SeqScanState *node);
37 :
38 : /* ----------------------------------------------------------------
39 : * Scan Support
40 : * ----------------------------------------------------------------
41 : */
42 :
43 : /* ----------------------------------------------------------------
44 : * SeqNext
45 : *
46 : * This is a workhorse for ExecSeqScan
47 : * ----------------------------------------------------------------
48 : */
49 : static TupleTableSlot *
50 70889670 : SeqNext(SeqScanState *node)
51 : {
52 : TableScanDesc scandesc;
53 : EState *estate;
54 : ScanDirection direction;
55 : TupleTableSlot *slot;
56 :
57 : /*
58 : * get information from the estate and scan state
59 : */
60 70889670 : scandesc = node->ss.ss_currentScanDesc;
61 70889670 : estate = node->ss.ps.state;
62 70889670 : direction = estate->es_direction;
63 70889670 : slot = node->ss.ss_ScanTupleSlot;
64 :
65 70889670 : if (scandesc == NULL)
66 : {
67 : /*
68 : * We reach here if the scan is not parallel, or if we're serially
69 : * executing a scan that was planned to be parallel.
70 : */
71 165156 : scandesc = table_beginscan(node->ss.ss_currentRelation,
72 : estate->es_snapshot,
73 : 0, NULL);
74 165156 : node->ss.ss_currentScanDesc = scandesc;
75 : }
76 :
77 : /*
78 : * get the next tuple from the table
79 : */
80 70889670 : if (table_scan_getnextslot(scandesc, direction, slot))
81 69738812 : return slot;
82 1150842 : return NULL;
83 : }
84 :
85 : /*
86 : * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
87 : */
88 : static bool
89 238 : SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
90 : {
91 : /*
92 : * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan
93 : * (and this is very bad) - so, here we do not check are keys ok or not.
94 : */
95 238 : return true;
96 : }
97 :
98 : /* ----------------------------------------------------------------
99 : * ExecSeqScan(node)
100 : *
101 : * Scans the relation sequentially and returns the next qualifying
102 : * tuple.
103 : * We call the ExecScan() routine and pass it the appropriate
104 : * access method functions.
105 : * ----------------------------------------------------------------
106 : */
107 : static TupleTableSlot *
108 45330770 : ExecSeqScan(PlanState *pstate)
109 : {
110 45330770 : SeqScanState *node = castNode(SeqScanState, pstate);
111 :
112 45330770 : return ExecScan(&node->ss,
113 : (ExecScanAccessMtd) SeqNext,
114 : (ExecScanRecheckMtd) SeqRecheck);
115 : }
116 :
117 :
118 : /* ----------------------------------------------------------------
119 : * ExecInitSeqScan
120 : * ----------------------------------------------------------------
121 : */
122 : SeqScanState *
123 204180 : ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
124 : {
125 : SeqScanState *scanstate;
126 :
127 : /*
128 : * Once upon a time it was possible to have an outerPlan of a SeqScan, but
129 : * not any more.
130 : */
131 : Assert(outerPlan(node) == NULL);
132 : Assert(innerPlan(node) == NULL);
133 :
134 : /*
135 : * create state structure
136 : */
137 204180 : scanstate = makeNode(SeqScanState);
138 204180 : scanstate->ss.ps.plan = (Plan *) node;
139 204180 : scanstate->ss.ps.state = estate;
140 204180 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
141 :
142 : /*
143 : * Miscellaneous initialization
144 : *
145 : * create expression context for node
146 : */
147 204180 : ExecAssignExprContext(estate, &scanstate->ss.ps);
148 :
149 : /*
150 : * open the scan relation
151 : */
152 204168 : scanstate->ss.ss_currentRelation =
153 204180 : ExecOpenScanRelation(estate,
154 : node->scan.scanrelid,
155 : eflags);
156 :
157 : /* and create slot with the appropriate rowtype */
158 204168 : ExecInitScanTupleSlot(estate, &scanstate->ss,
159 204168 : RelationGetDescr(scanstate->ss.ss_currentRelation),
160 : table_slot_callbacks(scanstate->ss.ss_currentRelation));
161 :
162 : /*
163 : * Initialize result type and projection.
164 : */
165 204168 : ExecInitResultTypeTL(&scanstate->ss.ps);
166 204168 : ExecAssignScanProjectionInfo(&scanstate->ss);
167 :
168 : /*
169 : * initialize child expressions
170 : */
171 204168 : scanstate->ss.ps.qual =
172 204168 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
173 :
174 204168 : return scanstate;
175 : }
176 :
177 : /* ----------------------------------------------------------------
178 : * ExecEndSeqScan
179 : *
180 : * frees any storage allocated through C routines.
181 : * ----------------------------------------------------------------
182 : */
183 : void
184 201650 : ExecEndSeqScan(SeqScanState *node)
185 : {
186 : TableScanDesc scanDesc;
187 :
188 : /*
189 : * get information from node
190 : */
191 201650 : scanDesc = node->ss.ss_currentScanDesc;
192 :
193 : /*
194 : * close heap scan
195 : */
196 201650 : if (scanDesc != NULL)
197 166674 : table_endscan(scanDesc);
198 201650 : }
199 :
200 : /* ----------------------------------------------------------------
201 : * Join Support
202 : * ----------------------------------------------------------------
203 : */
204 :
205 : /* ----------------------------------------------------------------
206 : * ExecReScanSeqScan
207 : *
208 : * Rescans the relation.
209 : * ----------------------------------------------------------------
210 : */
211 : void
212 1022518 : ExecReScanSeqScan(SeqScanState *node)
213 : {
214 : TableScanDesc scan;
215 :
216 1022518 : scan = node->ss.ss_currentScanDesc;
217 :
218 1022518 : if (scan != NULL)
219 1000642 : table_rescan(scan, /* scan desc */
220 : NULL); /* new scan keys */
221 :
222 1022518 : ExecScanReScan((ScanState *) node);
223 1022518 : }
224 :
225 : /* ----------------------------------------------------------------
226 : * Parallel Scan Support
227 : * ----------------------------------------------------------------
228 : */
229 :
230 : /* ----------------------------------------------------------------
231 : * ExecSeqScanEstimate
232 : *
233 : * Compute the amount of space we'll need in the parallel
234 : * query DSM, and inform pcxt->estimator about our needs.
235 : * ----------------------------------------------------------------
236 : */
237 : void
238 900 : ExecSeqScanEstimate(SeqScanState *node,
239 : ParallelContext *pcxt)
240 : {
241 900 : EState *estate = node->ss.ps.state;
242 :
243 900 : node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
244 : estate->es_snapshot);
245 900 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
246 900 : shm_toc_estimate_keys(&pcxt->estimator, 1);
247 900 : }
248 :
249 : /* ----------------------------------------------------------------
250 : * ExecSeqScanInitializeDSM
251 : *
252 : * Set up a parallel heap scan descriptor.
253 : * ----------------------------------------------------------------
254 : */
255 : void
256 900 : ExecSeqScanInitializeDSM(SeqScanState *node,
257 : ParallelContext *pcxt)
258 : {
259 900 : EState *estate = node->ss.ps.state;
260 : ParallelTableScanDesc pscan;
261 :
262 900 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
263 900 : table_parallelscan_initialize(node->ss.ss_currentRelation,
264 : pscan,
265 : estate->es_snapshot);
266 900 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
267 900 : node->ss.ss_currentScanDesc =
268 900 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
269 900 : }
270 :
271 : /* ----------------------------------------------------------------
272 : * ExecSeqScanReInitializeDSM
273 : *
274 : * Reset shared state before beginning a fresh scan.
275 : * ----------------------------------------------------------------
276 : */
277 : void
278 228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
279 : ParallelContext *pcxt)
280 : {
281 : ParallelTableScanDesc pscan;
282 :
283 228 : pscan = node->ss.ss_currentScanDesc->rs_parallel;
284 228 : table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
285 228 : }
286 :
287 : /* ----------------------------------------------------------------
288 : * ExecSeqScanInitializeWorker
289 : *
290 : * Copy relevant information from TOC into planstate.
291 : * ----------------------------------------------------------------
292 : */
293 : void
294 2678 : ExecSeqScanInitializeWorker(SeqScanState *node,
295 : ParallelWorkerContext *pwcxt)
296 : {
297 : ParallelTableScanDesc pscan;
298 :
299 2678 : pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
300 2678 : node->ss.ss_currentScanDesc =
301 2678 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
302 2678 : }
|