Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeSeqscan.c
4 : * Support routines for sequential scans of relations.
5 : *
6 : * Portions Copyright (c) 1996-2023, 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/execdebug.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 72438398 : 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 72438398 : scandesc = node->ss.ss_currentScanDesc;
61 72438398 : estate = node->ss.ps.state;
62 72438398 : direction = estate->es_direction;
63 72438398 : slot = node->ss.ss_ScanTupleSlot;
64 :
65 72438398 : 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 152710 : scandesc = table_beginscan(node->ss.ss_currentRelation,
72 : estate->es_snapshot,
73 : 0, NULL);
74 152710 : node->ss.ss_currentScanDesc = scandesc;
75 : }
76 :
77 : /*
78 : * get the next tuple from the table
79 : */
80 72438398 : if (table_scan_getnextslot(scandesc, direction, slot))
81 71561276 : return slot;
82 877102 : return NULL;
83 : }
84 :
85 : /*
86 : * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
87 : */
88 : static bool
89 212 : 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 212 : 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 46321360 : ExecSeqScan(PlanState *pstate)
109 : {
110 46321360 : SeqScanState *node = castNode(SeqScanState, pstate);
111 :
112 46321360 : return ExecScan(&node->ss,
113 : (ExecScanAccessMtd) SeqNext,
114 : (ExecScanRecheckMtd) SeqRecheck);
115 : }
116 :
117 :
118 : /* ----------------------------------------------------------------
119 : * ExecInitSeqScan
120 : * ----------------------------------------------------------------
121 : */
122 : SeqScanState *
123 186820 : 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 186820 : scanstate = makeNode(SeqScanState);
138 186820 : scanstate->ss.ps.plan = (Plan *) node;
139 186820 : scanstate->ss.ps.state = estate;
140 186820 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
141 :
142 : /*
143 : * Miscellaneous initialization
144 : *
145 : * create expression context for node
146 : */
147 186820 : ExecAssignExprContext(estate, &scanstate->ss.ps);
148 :
149 : /*
150 : * open the scan relation
151 : */
152 186808 : scanstate->ss.ss_currentRelation =
153 186820 : ExecOpenScanRelation(estate,
154 : node->scan.scanrelid,
155 : eflags);
156 :
157 : /* and create slot with the appropriate rowtype */
158 186808 : ExecInitScanTupleSlot(estate, &scanstate->ss,
159 186808 : RelationGetDescr(scanstate->ss.ss_currentRelation),
160 : table_slot_callbacks(scanstate->ss.ss_currentRelation));
161 :
162 : /*
163 : * Initialize result type and projection.
164 : */
165 186808 : ExecInitResultTypeTL(&scanstate->ss.ps);
166 186808 : ExecAssignScanProjectionInfo(&scanstate->ss);
167 :
168 : /*
169 : * initialize child expressions
170 : */
171 186808 : scanstate->ss.ps.qual =
172 186808 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
173 :
174 186808 : return scanstate;
175 : }
176 :
177 : /* ----------------------------------------------------------------
178 : * ExecEndSeqScan
179 : *
180 : * frees any storage allocated through C routines.
181 : * ----------------------------------------------------------------
182 : */
183 : void
184 184634 : ExecEndSeqScan(SeqScanState *node)
185 : {
186 : TableScanDesc scanDesc;
187 :
188 : /*
189 : * get information from node
190 : */
191 184634 : scanDesc = node->ss.ss_currentScanDesc;
192 :
193 : /*
194 : * Free the exprcontext
195 : */
196 184634 : ExecFreeExprContext(&node->ss.ps);
197 :
198 : /*
199 : * clean out the tuple table
200 : */
201 184634 : if (node->ss.ps.ps_ResultTupleSlot)
202 101234 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
203 184634 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
204 :
205 : /*
206 : * close heap scan
207 : */
208 184634 : if (scanDesc != NULL)
209 154478 : table_endscan(scanDesc);
210 184634 : }
211 :
212 : /* ----------------------------------------------------------------
213 : * Join Support
214 : * ----------------------------------------------------------------
215 : */
216 :
217 : /* ----------------------------------------------------------------
218 : * ExecReScanSeqScan
219 : *
220 : * Rescans the relation.
221 : * ----------------------------------------------------------------
222 : */
223 : void
224 755246 : ExecReScanSeqScan(SeqScanState *node)
225 : {
226 : TableScanDesc scan;
227 :
228 755246 : scan = node->ss.ss_currentScanDesc;
229 :
230 755246 : if (scan != NULL)
231 737626 : table_rescan(scan, /* scan desc */
232 : NULL); /* new scan keys */
233 :
234 755246 : ExecScanReScan((ScanState *) node);
235 755246 : }
236 :
237 : /* ----------------------------------------------------------------
238 : * Parallel Scan Support
239 : * ----------------------------------------------------------------
240 : */
241 :
242 : /* ----------------------------------------------------------------
243 : * ExecSeqScanEstimate
244 : *
245 : * Compute the amount of space we'll need in the parallel
246 : * query DSM, and inform pcxt->estimator about our needs.
247 : * ----------------------------------------------------------------
248 : */
249 : void
250 892 : ExecSeqScanEstimate(SeqScanState *node,
251 : ParallelContext *pcxt)
252 : {
253 892 : EState *estate = node->ss.ps.state;
254 :
255 892 : node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
256 : estate->es_snapshot);
257 892 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
258 892 : shm_toc_estimate_keys(&pcxt->estimator, 1);
259 892 : }
260 :
261 : /* ----------------------------------------------------------------
262 : * ExecSeqScanInitializeDSM
263 : *
264 : * Set up a parallel heap scan descriptor.
265 : * ----------------------------------------------------------------
266 : */
267 : void
268 892 : ExecSeqScanInitializeDSM(SeqScanState *node,
269 : ParallelContext *pcxt)
270 : {
271 892 : EState *estate = node->ss.ps.state;
272 : ParallelTableScanDesc pscan;
273 :
274 892 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
275 892 : table_parallelscan_initialize(node->ss.ss_currentRelation,
276 : pscan,
277 : estate->es_snapshot);
278 892 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
279 892 : node->ss.ss_currentScanDesc =
280 892 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
281 892 : }
282 :
283 : /* ----------------------------------------------------------------
284 : * ExecSeqScanReInitializeDSM
285 : *
286 : * Reset shared state before beginning a fresh scan.
287 : * ----------------------------------------------------------------
288 : */
289 : void
290 228 : ExecSeqScanReInitializeDSM(SeqScanState *node,
291 : ParallelContext *pcxt)
292 : {
293 : ParallelTableScanDesc pscan;
294 :
295 228 : pscan = node->ss.ss_currentScanDesc->rs_parallel;
296 228 : table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
297 228 : }
298 :
299 : /* ----------------------------------------------------------------
300 : * ExecSeqScanInitializeWorker
301 : *
302 : * Copy relevant information from TOC into planstate.
303 : * ----------------------------------------------------------------
304 : */
305 : void
306 2654 : ExecSeqScanInitializeWorker(SeqScanState *node,
307 : ParallelWorkerContext *pwcxt)
308 : {
309 : ParallelTableScanDesc pscan;
310 :
311 2654 : pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
312 2654 : node->ss.ss_currentScanDesc =
313 2654 : table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
314 2654 : }
|