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