1 /*-------------------------------------------------------------------------
2 *
3 * nodeSeqscan.c
4 * Support routines for sequential scans of relations.
5 *
6 * Portions Copyright (c) 1996-2017, 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 "executor/execdebug.h"
32 #include "executor/nodeSeqscan.h"
33 #include "utils/rel.h"
34
35 static void InitScanRelation(SeqScanState *node, EState *estate, int eflags);
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 *
SeqNext(SeqScanState * node)50 SeqNext(SeqScanState *node)
51 {
52 HeapTuple tuple;
53 HeapScanDesc scandesc;
54 EState *estate;
55 ScanDirection direction;
56 TupleTableSlot *slot;
57
58 /*
59 * get information from the estate and scan state
60 */
61 scandesc = node->ss.ss_currentScanDesc;
62 estate = node->ss.ps.state;
63 direction = estate->es_direction;
64 slot = node->ss.ss_ScanTupleSlot;
65
66 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 scandesc = heap_beginscan(node->ss.ss_currentRelation,
73 estate->es_snapshot,
74 0, NULL);
75 node->ss.ss_currentScanDesc = scandesc;
76 }
77
78 /*
79 * get the next tuple from the table
80 */
81 tuple = heap_getnext(scandesc, direction);
82
83 /*
84 * save the tuple and the buffer returned to us by the access methods in
85 * our scan tuple slot and return the slot. Note: we pass 'false' because
86 * tuples returned by heap_getnext() are pointers onto disk pages and were
87 * not created with palloc() and so should not be pfree()'d. Note also
88 * that ExecStoreTuple will increment the refcount of the buffer; the
89 * refcount will not be dropped until the tuple table slot is cleared.
90 */
91 if (tuple)
92 ExecStoreTuple(tuple, /* tuple to store */
93 slot, /* slot to store in */
94 scandesc->rs_cbuf, /* buffer associated with this
95 * tuple */
96 false); /* don't pfree this pointer */
97 else
98 ExecClearTuple(slot);
99
100 return slot;
101 }
102
103 /*
104 * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
105 */
106 static bool
SeqRecheck(SeqScanState * node,TupleTableSlot * slot)107 SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
108 {
109 /*
110 * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan
111 * (and this is very bad) - so, here we do not check are keys ok or not.
112 */
113 return true;
114 }
115
116 /* ----------------------------------------------------------------
117 * ExecSeqScan(node)
118 *
119 * Scans the relation sequentially and returns the next qualifying
120 * tuple.
121 * We call the ExecScan() routine and pass it the appropriate
122 * access method functions.
123 * ----------------------------------------------------------------
124 */
125 static TupleTableSlot *
ExecSeqScan(PlanState * pstate)126 ExecSeqScan(PlanState *pstate)
127 {
128 SeqScanState *node = castNode(SeqScanState, pstate);
129
130 return ExecScan(&node->ss,
131 (ExecScanAccessMtd) SeqNext,
132 (ExecScanRecheckMtd) SeqRecheck);
133 }
134
135 /* ----------------------------------------------------------------
136 * InitScanRelation
137 *
138 * Set up to access the scan relation.
139 * ----------------------------------------------------------------
140 */
141 static void
InitScanRelation(SeqScanState * node,EState * estate,int eflags)142 InitScanRelation(SeqScanState *node, EState *estate, int eflags)
143 {
144 Relation currentRelation;
145
146 /*
147 * get the relation object id from the relid'th entry in the range table,
148 * open that relation and acquire appropriate lock on it.
149 */
150 currentRelation = ExecOpenScanRelation(estate,
151 ((SeqScan *) node->ss.ps.plan)->scanrelid,
152 eflags);
153
154 node->ss.ss_currentRelation = currentRelation;
155
156 /* and report the scan tuple slot's rowtype */
157 ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation));
158 }
159
160
161 /* ----------------------------------------------------------------
162 * ExecInitSeqScan
163 * ----------------------------------------------------------------
164 */
165 SeqScanState *
ExecInitSeqScan(SeqScan * node,EState * estate,int eflags)166 ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
167 {
168 SeqScanState *scanstate;
169
170 /*
171 * Once upon a time it was possible to have an outerPlan of a SeqScan, but
172 * not any more.
173 */
174 Assert(outerPlan(node) == NULL);
175 Assert(innerPlan(node) == NULL);
176
177 /*
178 * create state structure
179 */
180 scanstate = makeNode(SeqScanState);
181 scanstate->ss.ps.plan = (Plan *) node;
182 scanstate->ss.ps.state = estate;
183 scanstate->ss.ps.ExecProcNode = ExecSeqScan;
184
185 /*
186 * Miscellaneous initialization
187 *
188 * create expression context for node
189 */
190 ExecAssignExprContext(estate, &scanstate->ss.ps);
191
192 /*
193 * initialize child expressions
194 */
195 scanstate->ss.ps.qual =
196 ExecInitQual(node->plan.qual, (PlanState *) scanstate);
197
198 /*
199 * tuple table initialization
200 */
201 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
202 ExecInitScanTupleSlot(estate, &scanstate->ss);
203
204 /*
205 * initialize scan relation
206 */
207 InitScanRelation(scanstate, estate, eflags);
208
209 /*
210 * Initialize result tuple type and projection info.
211 */
212 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
213 ExecAssignScanProjectionInfo(&scanstate->ss);
214
215 return scanstate;
216 }
217
218 /* ----------------------------------------------------------------
219 * ExecEndSeqScan
220 *
221 * frees any storage allocated through C routines.
222 * ----------------------------------------------------------------
223 */
224 void
ExecEndSeqScan(SeqScanState * node)225 ExecEndSeqScan(SeqScanState *node)
226 {
227 Relation relation;
228 HeapScanDesc scanDesc;
229
230 /*
231 * get information from node
232 */
233 relation = node->ss.ss_currentRelation;
234 scanDesc = node->ss.ss_currentScanDesc;
235
236 /*
237 * Free the exprcontext
238 */
239 ExecFreeExprContext(&node->ss.ps);
240
241 /*
242 * clean out the tuple table
243 */
244 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
245 ExecClearTuple(node->ss.ss_ScanTupleSlot);
246
247 /*
248 * close heap scan
249 */
250 if (scanDesc != NULL)
251 heap_endscan(scanDesc);
252
253 /*
254 * close the heap relation.
255 */
256 ExecCloseScanRelation(relation);
257 }
258
259 /* ----------------------------------------------------------------
260 * Join Support
261 * ----------------------------------------------------------------
262 */
263
264 /* ----------------------------------------------------------------
265 * ExecReScanSeqScan
266 *
267 * Rescans the relation.
268 * ----------------------------------------------------------------
269 */
270 void
ExecReScanSeqScan(SeqScanState * node)271 ExecReScanSeqScan(SeqScanState *node)
272 {
273 HeapScanDesc scan;
274
275 scan = node->ss.ss_currentScanDesc;
276
277 if (scan != NULL)
278 heap_rescan(scan, /* scan desc */
279 NULL); /* new scan keys */
280
281 ExecScanReScan((ScanState *) node);
282 }
283
284 /* ----------------------------------------------------------------
285 * Parallel Scan Support
286 * ----------------------------------------------------------------
287 */
288
289 /* ----------------------------------------------------------------
290 * ExecSeqScanEstimate
291 *
292 * estimates the space required to serialize seqscan node.
293 * ----------------------------------------------------------------
294 */
295 void
ExecSeqScanEstimate(SeqScanState * node,ParallelContext * pcxt)296 ExecSeqScanEstimate(SeqScanState *node,
297 ParallelContext *pcxt)
298 {
299 EState *estate = node->ss.ps.state;
300
301 node->pscan_len = heap_parallelscan_estimate(estate->es_snapshot);
302 shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
303 shm_toc_estimate_keys(&pcxt->estimator, 1);
304 }
305
306 /* ----------------------------------------------------------------
307 * ExecSeqScanInitializeDSM
308 *
309 * Set up a parallel heap scan descriptor.
310 * ----------------------------------------------------------------
311 */
312 void
ExecSeqScanInitializeDSM(SeqScanState * node,ParallelContext * pcxt)313 ExecSeqScanInitializeDSM(SeqScanState *node,
314 ParallelContext *pcxt)
315 {
316 EState *estate = node->ss.ps.state;
317 ParallelHeapScanDesc pscan;
318
319 pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
320 heap_parallelscan_initialize(pscan,
321 node->ss.ss_currentRelation,
322 estate->es_snapshot);
323 shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
324 node->ss.ss_currentScanDesc =
325 heap_beginscan_parallel(node->ss.ss_currentRelation, pscan);
326 }
327
328 /* ----------------------------------------------------------------
329 * ExecSeqScanReInitializeDSM
330 *
331 * Reset shared state before beginning a fresh scan.
332 * ----------------------------------------------------------------
333 */
334 void
ExecSeqScanReInitializeDSM(SeqScanState * node,ParallelContext * pcxt)335 ExecSeqScanReInitializeDSM(SeqScanState *node,
336 ParallelContext *pcxt)
337 {
338 HeapScanDesc scan = node->ss.ss_currentScanDesc;
339
340 heap_parallelscan_reinitialize(scan->rs_parallel);
341 }
342
343 /* ----------------------------------------------------------------
344 * ExecSeqScanInitializeWorker
345 *
346 * Copy relevant information from TOC into planstate.
347 * ----------------------------------------------------------------
348 */
349 void
ExecSeqScanInitializeWorker(SeqScanState * node,shm_toc * toc)350 ExecSeqScanInitializeWorker(SeqScanState *node, shm_toc *toc)
351 {
352 ParallelHeapScanDesc pscan;
353
354 pscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id, false);
355 node->ss.ss_currentScanDesc =
356 heap_beginscan_parallel(node->ss.ss_currentRelation, pscan);
357 }
358