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