1 /*-------------------------------------------------------------------------
2  *
3  * nodeSeqscan.c
4  *	  Support routines for sequential scans of relations.
5  *
6  * Portions Copyright (c) 1996-2021, 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 "access/tableam.h"
32 #include "executor/execdebug.h"
33 #include "executor/nodeSeqscan.h"
34 #include "utils/rel.h"
35 
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 	TableScanDesc 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 = table_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 	if (table_scan_getnextslot(scandesc, direction, slot))
81 		return slot;
82 	return NULL;
83 }
84 
85 /*
86  * SeqRecheck -- access method routine to recheck a tuple in EvalPlanQual
87  */
88 static bool
SeqRecheck(SeqScanState * node,TupleTableSlot * slot)89 SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
90 {
91 	/*
92 	 * Note that unlike IndexScan, SeqScan never use keys in heap_beginscan
93 	 * (and this is very bad) - so, here we do not check are keys ok or not.
94 	 */
95 	return true;
96 }
97 
98 /* ----------------------------------------------------------------
99  *		ExecSeqScan(node)
100  *
101  *		Scans the relation sequentially and returns the next qualifying
102  *		tuple.
103  *		We call the ExecScan() routine and pass it the appropriate
104  *		access method functions.
105  * ----------------------------------------------------------------
106  */
107 static TupleTableSlot *
ExecSeqScan(PlanState * pstate)108 ExecSeqScan(PlanState *pstate)
109 {
110 	SeqScanState *node = castNode(SeqScanState, pstate);
111 
112 	return ExecScan(&node->ss,
113 					(ExecScanAccessMtd) SeqNext,
114 					(ExecScanRecheckMtd) SeqRecheck);
115 }
116 
117 
118 /* ----------------------------------------------------------------
119  *		ExecInitSeqScan
120  * ----------------------------------------------------------------
121  */
122 SeqScanState *
ExecInitSeqScan(SeqScan * node,EState * estate,int eflags)123 ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
124 {
125 	SeqScanState *scanstate;
126 
127 	/*
128 	 * Once upon a time it was possible to have an outerPlan of a SeqScan, but
129 	 * not any more.
130 	 */
131 	Assert(outerPlan(node) == NULL);
132 	Assert(innerPlan(node) == NULL);
133 
134 	/*
135 	 * create state structure
136 	 */
137 	scanstate = makeNode(SeqScanState);
138 	scanstate->ss.ps.plan = (Plan *) node;
139 	scanstate->ss.ps.state = estate;
140 	scanstate->ss.ps.ExecProcNode = ExecSeqScan;
141 
142 	/*
143 	 * Miscellaneous initialization
144 	 *
145 	 * create expression context for node
146 	 */
147 	ExecAssignExprContext(estate, &scanstate->ss.ps);
148 
149 	/*
150 	 * open the scan relation
151 	 */
152 	scanstate->ss.ss_currentRelation =
153 		ExecOpenScanRelation(estate,
154 							 node->scanrelid,
155 							 eflags);
156 
157 	/* and create slot with the appropriate rowtype */
158 	ExecInitScanTupleSlot(estate, &scanstate->ss,
159 						  RelationGetDescr(scanstate->ss.ss_currentRelation),
160 						  table_slot_callbacks(scanstate->ss.ss_currentRelation));
161 
162 	/*
163 	 * Initialize result type and projection.
164 	 */
165 	ExecInitResultTypeTL(&scanstate->ss.ps);
166 	ExecAssignScanProjectionInfo(&scanstate->ss);
167 
168 	/*
169 	 * initialize child expressions
170 	 */
171 	scanstate->ss.ps.qual =
172 		ExecInitQual(node->plan.qual, (PlanState *) scanstate);
173 
174 	return scanstate;
175 }
176 
177 /* ----------------------------------------------------------------
178  *		ExecEndSeqScan
179  *
180  *		frees any storage allocated through C routines.
181  * ----------------------------------------------------------------
182  */
183 void
ExecEndSeqScan(SeqScanState * node)184 ExecEndSeqScan(SeqScanState *node)
185 {
186 	TableScanDesc scanDesc;
187 
188 	/*
189 	 * get information from node
190 	 */
191 	scanDesc = node->ss.ss_currentScanDesc;
192 
193 	/*
194 	 * Free the exprcontext
195 	 */
196 	ExecFreeExprContext(&node->ss.ps);
197 
198 	/*
199 	 * clean out the tuple table
200 	 */
201 	if (node->ss.ps.ps_ResultTupleSlot)
202 		ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
203 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
204 
205 	/*
206 	 * close heap scan
207 	 */
208 	if (scanDesc != NULL)
209 		table_endscan(scanDesc);
210 }
211 
212 /* ----------------------------------------------------------------
213  *						Join Support
214  * ----------------------------------------------------------------
215  */
216 
217 /* ----------------------------------------------------------------
218  *		ExecReScanSeqScan
219  *
220  *		Rescans the relation.
221  * ----------------------------------------------------------------
222  */
223 void
ExecReScanSeqScan(SeqScanState * node)224 ExecReScanSeqScan(SeqScanState *node)
225 {
226 	TableScanDesc scan;
227 
228 	scan = node->ss.ss_currentScanDesc;
229 
230 	if (scan != NULL)
231 		table_rescan(scan,		/* scan desc */
232 					 NULL);		/* new scan keys */
233 
234 	ExecScanReScan((ScanState *) node);
235 }
236 
237 /* ----------------------------------------------------------------
238  *						Parallel Scan Support
239  * ----------------------------------------------------------------
240  */
241 
242 /* ----------------------------------------------------------------
243  *		ExecSeqScanEstimate
244  *
245  *		Compute the amount of space we'll need in the parallel
246  *		query DSM, and inform pcxt->estimator about our needs.
247  * ----------------------------------------------------------------
248  */
249 void
ExecSeqScanEstimate(SeqScanState * node,ParallelContext * pcxt)250 ExecSeqScanEstimate(SeqScanState *node,
251 					ParallelContext *pcxt)
252 {
253 	EState	   *estate = node->ss.ps.state;
254 
255 	node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation,
256 												  estate->es_snapshot);
257 	shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
258 	shm_toc_estimate_keys(&pcxt->estimator, 1);
259 }
260 
261 /* ----------------------------------------------------------------
262  *		ExecSeqScanInitializeDSM
263  *
264  *		Set up a parallel heap scan descriptor.
265  * ----------------------------------------------------------------
266  */
267 void
ExecSeqScanInitializeDSM(SeqScanState * node,ParallelContext * pcxt)268 ExecSeqScanInitializeDSM(SeqScanState *node,
269 						 ParallelContext *pcxt)
270 {
271 	EState	   *estate = node->ss.ps.state;
272 	ParallelTableScanDesc pscan;
273 
274 	pscan = shm_toc_allocate(pcxt->toc, node->pscan_len);
275 	table_parallelscan_initialize(node->ss.ss_currentRelation,
276 								  pscan,
277 								  estate->es_snapshot);
278 	shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
279 	node->ss.ss_currentScanDesc =
280 		table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
281 }
282 
283 /* ----------------------------------------------------------------
284  *		ExecSeqScanReInitializeDSM
285  *
286  *		Reset shared state before beginning a fresh scan.
287  * ----------------------------------------------------------------
288  */
289 void
ExecSeqScanReInitializeDSM(SeqScanState * node,ParallelContext * pcxt)290 ExecSeqScanReInitializeDSM(SeqScanState *node,
291 						   ParallelContext *pcxt)
292 {
293 	ParallelTableScanDesc pscan;
294 
295 	pscan = node->ss.ss_currentScanDesc->rs_parallel;
296 	table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan);
297 }
298 
299 /* ----------------------------------------------------------------
300  *		ExecSeqScanInitializeWorker
301  *
302  *		Copy relevant information from TOC into planstate.
303  * ----------------------------------------------------------------
304  */
305 void
ExecSeqScanInitializeWorker(SeqScanState * node,ParallelWorkerContext * pwcxt)306 ExecSeqScanInitializeWorker(SeqScanState *node,
307 							ParallelWorkerContext *pwcxt)
308 {
309 	ParallelTableScanDesc pscan;
310 
311 	pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
312 	node->ss.ss_currentScanDesc =
313 		table_beginscan_parallel(node->ss.ss_currentRelation, pscan);
314 }
315