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