1 /* ------------------------------------------------------------------------
2  *
3  * nodeCustom.c
4  *		Routines to handle execution of custom scan node
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  */
11 #include "postgres.h"
12 
13 #include "access/parallel.h"
14 #include "executor/executor.h"
15 #include "executor/nodeCustom.h"
16 #include "nodes/execnodes.h"
17 #include "nodes/plannodes.h"
18 #include "miscadmin.h"
19 #include "parser/parsetree.h"
20 #include "utils/hsearch.h"
21 #include "utils/memutils.h"
22 #include "utils/rel.h"
23 
24 
25 static TupleTableSlot *ExecCustomScan(PlanState *pstate);
26 
27 
28 CustomScanState *
ExecInitCustomScan(CustomScan * cscan,EState * estate,int eflags)29 ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
30 {
31 	CustomScanState *css;
32 	Relation	scan_rel = NULL;
33 	Index		scanrelid = cscan->scan.scanrelid;
34 	Index		tlistvarno;
35 
36 	/*
37 	 * Allocate the CustomScanState object.  We let the custom scan provider
38 	 * do the palloc, in case it wants to make a larger object that embeds
39 	 * CustomScanState as the first field.  It must set the node tag and the
40 	 * methods field correctly at this time.  Other standard fields should be
41 	 * set to zero.
42 	 */
43 	css = castNode(CustomScanState,
44 				   cscan->methods->CreateCustomScanState(cscan));
45 
46 	/* ensure flags is filled correctly */
47 	css->flags = cscan->flags;
48 
49 	/* fill up fields of ScanState */
50 	css->ss.ps.plan = &cscan->scan.plan;
51 	css->ss.ps.state = estate;
52 	css->ss.ps.ExecProcNode = ExecCustomScan;
53 
54 	/* create expression context for node */
55 	ExecAssignExprContext(estate, &css->ss.ps);
56 
57 	/* initialize child expressions */
58 	css->ss.ps.qual =
59 		ExecInitQual(cscan->scan.plan.qual, (PlanState *) css);
60 
61 	/* tuple table initialization */
62 	ExecInitScanTupleSlot(estate, &css->ss);
63 	ExecInitResultTupleSlot(estate, &css->ss.ps);
64 
65 	/*
66 	 * open the base relation, if any, and acquire an appropriate lock on it
67 	 */
68 	if (scanrelid > 0)
69 	{
70 		scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags);
71 		css->ss.ss_currentRelation = scan_rel;
72 	}
73 
74 	/*
75 	 * Determine the scan tuple type.  If the custom scan provider provided a
76 	 * targetlist describing the scan tuples, use that; else use base
77 	 * relation's rowtype.
78 	 */
79 	if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
80 	{
81 		TupleDesc	scan_tupdesc;
82 
83 		scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false);
84 		ExecAssignScanType(&css->ss, scan_tupdesc);
85 		/* Node's targetlist will contain Vars with varno = INDEX_VAR */
86 		tlistvarno = INDEX_VAR;
87 	}
88 	else
89 	{
90 		ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
91 		/* Node's targetlist will contain Vars with varno = scanrelid */
92 		tlistvarno = scanrelid;
93 	}
94 
95 	/*
96 	 * Initialize result tuple type and projection info.
97 	 */
98 	ExecAssignResultTypeFromTL(&css->ss.ps);
99 	ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
100 
101 	/*
102 	 * The callback of custom-scan provider applies the final initialization
103 	 * of the custom-scan-state node according to its logic.
104 	 */
105 	css->methods->BeginCustomScan(css, estate, eflags);
106 
107 	return css;
108 }
109 
110 static TupleTableSlot *
ExecCustomScan(PlanState * pstate)111 ExecCustomScan(PlanState *pstate)
112 {
113 	CustomScanState *node = castNode(CustomScanState, pstate);
114 
115 	CHECK_FOR_INTERRUPTS();
116 
117 	Assert(node->methods->ExecCustomScan != NULL);
118 	return node->methods->ExecCustomScan(node);
119 }
120 
121 void
ExecEndCustomScan(CustomScanState * node)122 ExecEndCustomScan(CustomScanState *node)
123 {
124 	Assert(node->methods->EndCustomScan != NULL);
125 	node->methods->EndCustomScan(node);
126 
127 	/* Free the exprcontext */
128 	ExecFreeExprContext(&node->ss.ps);
129 
130 	/* Clean out the tuple table */
131 	ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
132 	ExecClearTuple(node->ss.ss_ScanTupleSlot);
133 
134 	/* Close the heap relation */
135 	if (node->ss.ss_currentRelation)
136 		ExecCloseScanRelation(node->ss.ss_currentRelation);
137 }
138 
139 void
ExecReScanCustomScan(CustomScanState * node)140 ExecReScanCustomScan(CustomScanState *node)
141 {
142 	Assert(node->methods->ReScanCustomScan != NULL);
143 	node->methods->ReScanCustomScan(node);
144 }
145 
146 void
ExecCustomMarkPos(CustomScanState * node)147 ExecCustomMarkPos(CustomScanState *node)
148 {
149 	if (!node->methods->MarkPosCustomScan)
150 		ereport(ERROR,
151 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
152 				 errmsg("custom scan \"%s\" does not support MarkPos",
153 						node->methods->CustomName)));
154 	node->methods->MarkPosCustomScan(node);
155 }
156 
157 void
ExecCustomRestrPos(CustomScanState * node)158 ExecCustomRestrPos(CustomScanState *node)
159 {
160 	if (!node->methods->RestrPosCustomScan)
161 		ereport(ERROR,
162 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
163 				 errmsg("custom scan \"%s\" does not support MarkPos",
164 						node->methods->CustomName)));
165 	node->methods->RestrPosCustomScan(node);
166 }
167 
168 void
ExecCustomScanEstimate(CustomScanState * node,ParallelContext * pcxt)169 ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt)
170 {
171 	const CustomExecMethods *methods = node->methods;
172 
173 	if (methods->EstimateDSMCustomScan)
174 	{
175 		node->pscan_len = methods->EstimateDSMCustomScan(node, pcxt);
176 		shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
177 		shm_toc_estimate_keys(&pcxt->estimator, 1);
178 	}
179 }
180 
181 void
ExecCustomScanInitializeDSM(CustomScanState * node,ParallelContext * pcxt)182 ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
183 {
184 	const CustomExecMethods *methods = node->methods;
185 
186 	if (methods->InitializeDSMCustomScan)
187 	{
188 		int			plan_node_id = node->ss.ps.plan->plan_node_id;
189 		void	   *coordinate;
190 
191 		coordinate = shm_toc_allocate(pcxt->toc, node->pscan_len);
192 		methods->InitializeDSMCustomScan(node, pcxt, coordinate);
193 		shm_toc_insert(pcxt->toc, plan_node_id, coordinate);
194 	}
195 }
196 
197 void
ExecCustomScanReInitializeDSM(CustomScanState * node,ParallelContext * pcxt)198 ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
199 {
200 	const CustomExecMethods *methods = node->methods;
201 
202 	if (methods->ReInitializeDSMCustomScan)
203 	{
204 		int			plan_node_id = node->ss.ps.plan->plan_node_id;
205 		void	   *coordinate;
206 
207 		coordinate = shm_toc_lookup(pcxt->toc, plan_node_id, false);
208 		methods->ReInitializeDSMCustomScan(node, pcxt, coordinate);
209 	}
210 }
211 
212 void
ExecCustomScanInitializeWorker(CustomScanState * node,shm_toc * toc)213 ExecCustomScanInitializeWorker(CustomScanState *node, shm_toc *toc)
214 {
215 	const CustomExecMethods *methods = node->methods;
216 
217 	if (methods->InitializeWorkerCustomScan)
218 	{
219 		int			plan_node_id = node->ss.ps.plan->plan_node_id;
220 		void	   *coordinate;
221 
222 		coordinate = shm_toc_lookup(toc, plan_node_id, false);
223 		methods->InitializeWorkerCustomScan(node, toc, coordinate);
224 	}
225 }
226 
227 void
ExecShutdownCustomScan(CustomScanState * node)228 ExecShutdownCustomScan(CustomScanState *node)
229 {
230 	const CustomExecMethods *methods = node->methods;
231 
232 	if (methods->ShutdownCustomScan)
233 		methods->ShutdownCustomScan(node);
234 }
235