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