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
36static 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 */
49static TupleTableSlot *
50SeqNext(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 */
88static bool
89SeqRecheck(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 */
107static TupleTableSlot *
108ExecSeqScan(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 */
122SeqScanState *
123ExecInitSeqScan(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 */
183void
184ExecEndSeqScan(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 */
223void
224ExecReScanSeqScan(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 */
249void
250ExecSeqScanEstimate(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 */
267void
268ExecSeqScanInitializeDSM(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 */
289void
290ExecSeqScanReInitializeDSM(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 */
305void
306ExecSeqScanInitializeWorker(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