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