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