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
26static TupleTableSlot *ExecCustomScan(PlanState *pstate);
27
28
29CustomScanState *
30ExecInitCustomScan(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
108static TupleTableSlot *
109ExecCustomScan(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
119void
120ExecEndCustomScan(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
133void
134ExecReScanCustomScan(CustomScanState *node)
135{
136 Assert(node->methods->ReScanCustomScan != NULL);
137 node->methods->ReScanCustomScan(node);
138}
139
140void
141ExecCustomMarkPos(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
151void
152ExecCustomRestrPos(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
162void
163ExecCustomScanEstimate(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
175void
176ExecCustomScanInitializeDSM(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
191void
192ExecCustomScanReInitializeDSM(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
206void
207ExecCustomScanInitializeWorker(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
222void
223ExecShutdownCustomScan(CustomScanState *node)
224{
225 const CustomExecMethods *methods = node->methods;
226
227 if (methods->ShutdownCustomScan)
228 methods->ShutdownCustomScan(node);
229}
230