Line data Source code
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 *
50 2255918 : 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 2255918 : scandesc = node->ss.ss_currentScanDesc;
62 2255918 : estate = node->ss.ps.state;
63 2255918 : direction = estate->es_direction;
64 2255918 : slot = node->ss.ss_ScanTupleSlot;
65 :
66 2255918 : if (scandesc == NULL)
67 : {
68 : /*
69 : * We reach here if the scan is not parallel, or if we're executing a
70 : * scan that was intended to be parallel serially.
71 : */
72 8481 : scandesc = heap_beginscan(node->ss.ss_currentRelation,
73 : estate->es_snapshot,
74 : 0, NULL);
75 8481 : node->ss.ss_currentScanDesc = scandesc;
76 : }
77 :
78 : /*
79 : * get the next tuple from the table
80 : */
81 2255918 : 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 2255918 : if (tuple)
92 2247095 : 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 8823 : ExecClearTuple(slot);
99 :
100 2255918 : return slot;
101 : }
102 :
103 : /*
104 : * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
105 : */
106 : static bool
107 0 : 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 0 : 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 *
126 1401269 : ExecSeqScan(PlanState *pstate)
127 : {
128 1401269 : SeqScanState *node = castNode(SeqScanState, pstate);
129 :
130 1401269 : 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
142 10146 : 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 10146 : currentRelation = ExecOpenScanRelation(estate,
151 10146 : ((SeqScan *) node->ss.ps.plan)->scanrelid,
152 : eflags);
153 :
154 10144 : node->ss.ss_currentRelation = currentRelation;
155 :
156 : /* and report the scan tuple slot's rowtype */
157 10144 : ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation));
158 10144 : }
159 :
160 :
161 : /* ----------------------------------------------------------------
162 : * ExecInitSeqScan
163 : * ----------------------------------------------------------------
164 : */
165 : SeqScanState *
166 10146 : 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 10146 : Assert(outerPlan(node) == NULL);
175 10146 : Assert(innerPlan(node) == NULL);
176 :
177 : /*
178 : * create state structure
179 : */
180 10146 : scanstate = makeNode(SeqScanState);
181 10146 : scanstate->ss.ps.plan = (Plan *) node;
182 10146 : scanstate->ss.ps.state = estate;
183 10146 : scanstate->ss.ps.ExecProcNode = ExecSeqScan;
184 :
185 : /*
186 : * Miscellaneous initialization
187 : *
188 : * create expression context for node
189 : */
190 10146 : ExecAssignExprContext(estate, &scanstate->ss.ps);
191 :
192 : /*
193 : * initialize child expressions
194 : */
195 10146 : scanstate->ss.ps.qual =
196 10146 : ExecInitQual(node->plan.qual, (PlanState *) scanstate);
197 :
198 : /*
199 : * tuple table initialization
200 : */
201 10146 : ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
202 10146 : ExecInitScanTupleSlot(estate, &scanstate->ss);
203 :
204 : /*
205 : * initialize scan relation
206 : */
207 10146 : InitScanRelation(scanstate, estate, eflags);
208 :
209 : /*
210 : * Initialize result tuple type and projection info.
211 : */
212 10144 : ExecAssignResultTypeFromTL(&scanstate->ss.ps);
213 10144 : ExecAssignScanProjectionInfo(&scanstate->ss);
214 :
215 10144 : return scanstate;
216 : }
217 :
218 : /* ----------------------------------------------------------------
219 : * ExecEndSeqScan
220 : *
221 : * frees any storage allocated through C routines.
222 : * ----------------------------------------------------------------
223 : */
224 : void
225 9965 : ExecEndSeqScan(SeqScanState *node)
226 : {
227 : Relation relation;
228 : HeapScanDesc scanDesc;
229 :
230 : /*
231 : * get information from node
232 : */
233 9965 : relation = node->ss.ss_currentRelation;
234 9965 : scanDesc = node->ss.ss_currentScanDesc;
235 :
236 : /*
237 : * Free the exprcontext
238 : */
239 9965 : ExecFreeExprContext(&node->ss.ps);
240 :
241 : /*
242 : * clean out the tuple table
243 : */
244 9965 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
245 9965 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
246 :
247 : /*
248 : * close heap scan
249 : */
250 9965 : if (scanDesc != NULL)
251 8393 : heap_endscan(scanDesc);
252 :
253 : /*
254 : * close the heap relation.
255 : */
256 9965 : ExecCloseScanRelation(relation);
257 9965 : }
258 :
259 : /* ----------------------------------------------------------------
260 : * Join Support
261 : * ----------------------------------------------------------------
262 : */
263 :
264 : /* ----------------------------------------------------------------
265 : * ExecReScanSeqScan
266 : *
267 : * Rescans the relation.
268 : * ----------------------------------------------------------------
269 : */
270 : void
271 1863 : ExecReScanSeqScan(SeqScanState *node)
272 : {
273 : HeapScanDesc scan;
274 :
275 1863 : scan = node->ss.ss_currentScanDesc;
276 :
277 1863 : if (scan != NULL)
278 1206 : heap_rescan(scan, /* scan desc */
279 : NULL); /* new scan keys */
280 :
281 1863 : ExecScanReScan((ScanState *) node);
282 1863 : }
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
296 13 : ExecSeqScanEstimate(SeqScanState *node,
297 : ParallelContext *pcxt)
298 : {
299 13 : EState *estate = node->ss.ps.state;
300 :
301 13 : node->pscan_len = heap_parallelscan_estimate(estate->es_snapshot);
302 13 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
303 13 : shm_toc_estimate_keys(&pcxt->estimator, 1);
304 13 : }
305 :
306 : /* ----------------------------------------------------------------
307 : * ExecSeqScanInitializeDSM
308 : *
309 : * Set up a parallel heap scan descriptor.
310 : * ----------------------------------------------------------------
311 : */
312 : void
313 13 : ExecSeqScanInitializeDSM(SeqScanState *node,
314 : ParallelContext *pcxt)
315 : {
316 13 : EState *estate = node->ss.ps.state;
317 : ParallelHeapScanDesc pscan;
318 :
319 13 : pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
320 13 : heap_parallelscan_initialize(pscan,
321 : node->ss.ss_currentRelation,
322 : estate->es_snapshot);
323 13 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
324 13 : node->ss.ss_currentScanDesc =
325 13 : heap_beginscan_parallel(node->ss.ss_currentRelation, pscan);
326 13 : }
327 :
328 : /* ----------------------------------------------------------------
329 : * ExecSeqScanReInitializeDSM
330 : *
331 : * Reset shared state before beginning a fresh scan.
332 : * ----------------------------------------------------------------
333 : */
334 : void
335 2 : ExecSeqScanReInitializeDSM(SeqScanState *node,
336 : ParallelContext *pcxt)
337 : {
338 2 : HeapScanDesc scan = node->ss.ss_currentScanDesc;
339 :
340 2 : heap_parallelscan_reinitialize(scan->rs_parallel);
341 2 : }
342 :
343 : /* ----------------------------------------------------------------
344 : * ExecSeqScanInitializeWorker
345 : *
346 : * Copy relevant information from TOC into planstate.
347 : * ----------------------------------------------------------------
348 : */
349 : void
350 38 : ExecSeqScanInitializeWorker(SeqScanState *node, shm_toc *toc)
351 : {
352 : ParallelHeapScanDesc pscan;
353 :
354 38 : pscan = shm_toc_lookup(toc, node->ss.ps.plan->plan_node_id, false);
355 38 : node->ss.ss_currentScanDesc =
356 38 : heap_beginscan_parallel(node->ss.ss_currentRelation, pscan);
357 38 : }
|