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