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 0 : ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
30 : {
31 : CustomScanState *css;
32 : const TupleTableSlotOps *slotOps;
33 0 : Relation scan_rel = NULL;
34 0 : Index scanrelid = cscan->scan.scanrelid;
35 : 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 0 : css = castNode(CustomScanState,
45 : cscan->methods->CreateCustomScanState(cscan));
46 :
47 : /* ensure flags is filled correctly */
48 0 : css->flags = cscan->flags;
49 :
50 : /* fill up fields of ScanState */
51 0 : css->ss.ps.plan = &cscan->scan.plan;
52 0 : css->ss.ps.state = estate;
53 0 : css->ss.ps.ExecProcNode = ExecCustomScan;
54 :
55 : /* create expression context for node */
56 0 : ExecAssignExprContext(estate, &css->ss.ps);
57 :
58 : /*
59 : * open the scan relation, if any
60 : */
61 0 : if (scanrelid > 0)
62 : {
63 0 : scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags);
64 0 : css->ss.ss_currentRelation = scan_rel;
65 : }
66 :
67 : /*
68 : * Use a custom slot if specified in CustomScanState or use virtual slot
69 : * otherwise.
70 : */
71 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 0 : if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
81 0 : {
82 : TupleDesc scan_tupdesc;
83 :
84 0 : scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist);
85 0 : ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, slotOps);
86 : /* Node's targetlist will contain Vars with varno = INDEX_VAR */
87 0 : tlistvarno = INDEX_VAR;
88 : }
89 : else
90 : {
91 0 : ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel),
92 : slotOps);
93 : /* Node's targetlist will contain Vars with varno = scanrelid */
94 0 : tlistvarno = scanrelid;
95 : }
96 :
97 : /*
98 : * Initialize result slot, type and projection.
99 : */
100 0 : ExecInitResultTupleSlotTL(&css->ss.ps, &TTSOpsVirtual);
101 0 : ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
102 :
103 : /* initialize child expressions */
104 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 : * of the custom-scan-state node according to its logic.
110 : */
111 0 : css->methods->BeginCustomScan(css, estate, eflags);
112 :
113 0 : return css;
114 : }
115 :
116 : static TupleTableSlot *
117 0 : ExecCustomScan(PlanState *pstate)
118 : {
119 0 : CustomScanState *node = castNode(CustomScanState, pstate);
120 :
121 0 : CHECK_FOR_INTERRUPTS();
122 :
123 : Assert(node->methods->ExecCustomScan != NULL);
124 0 : return node->methods->ExecCustomScan(node);
125 : }
126 :
127 : void
128 0 : ExecEndCustomScan(CustomScanState *node)
129 : {
130 : Assert(node->methods->EndCustomScan != NULL);
131 0 : node->methods->EndCustomScan(node);
132 :
133 : /* Free the exprcontext */
134 0 : ExecFreeExprContext(&node->ss.ps);
135 :
136 : /* Clean out the tuple table */
137 0 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
138 0 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
139 0 : }
140 :
141 : void
142 0 : ExecReScanCustomScan(CustomScanState *node)
143 : {
144 : Assert(node->methods->ReScanCustomScan != NULL);
145 0 : node->methods->ReScanCustomScan(node);
146 0 : }
147 :
148 : void
149 0 : ExecCustomMarkPos(CustomScanState *node)
150 : {
151 0 : if (!node->methods->MarkPosCustomScan)
152 0 : ereport(ERROR,
153 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
154 : errmsg("custom scan \"%s\" does not support MarkPos",
155 : node->methods->CustomName)));
156 0 : node->methods->MarkPosCustomScan(node);
157 0 : }
158 :
159 : void
160 0 : ExecCustomRestrPos(CustomScanState *node)
161 : {
162 0 : if (!node->methods->RestrPosCustomScan)
163 0 : ereport(ERROR,
164 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
165 : errmsg("custom scan \"%s\" does not support MarkPos",
166 : node->methods->CustomName)));
167 0 : node->methods->RestrPosCustomScan(node);
168 0 : }
169 :
170 : void
171 0 : ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt)
172 : {
173 0 : const CustomExecMethods *methods = node->methods;
174 :
175 0 : if (methods->EstimateDSMCustomScan)
176 : {
177 0 : node->pscan_len = methods->EstimateDSMCustomScan(node, pcxt);
178 0 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
179 0 : shm_toc_estimate_keys(&pcxt->estimator, 1);
180 : }
181 0 : }
182 :
183 : void
184 0 : ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
185 : {
186 0 : const CustomExecMethods *methods = node->methods;
187 :
188 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 0 : methods->InitializeDSMCustomScan(node, pcxt, coordinate);
195 0 : shm_toc_insert(pcxt->toc, plan_node_id, coordinate);
196 : }
197 0 : }
198 :
199 : void
200 0 : ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
201 : {
202 0 : const CustomExecMethods *methods = node->methods;
203 :
204 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 0 : methods->ReInitializeDSMCustomScan(node, pcxt, coordinate);
211 : }
212 0 : }
213 :
214 : void
215 0 : ExecCustomScanInitializeWorker(CustomScanState *node,
216 : ParallelWorkerContext *pwcxt)
217 : {
218 0 : const CustomExecMethods *methods = node->methods;
219 :
220 0 : if (methods->InitializeWorkerCustomScan)
221 : {
222 0 : int plan_node_id = node->ss.ps.plan->plan_node_id;
223 : void *coordinate;
224 :
225 0 : coordinate = shm_toc_lookup(pwcxt->toc, plan_node_id, false);
226 0 : methods->InitializeWorkerCustomScan(node, pwcxt->toc, coordinate);
227 : }
228 0 : }
229 :
230 : void
231 0 : ExecShutdownCustomScan(CustomScanState *node)
232 : {
233 0 : const CustomExecMethods *methods = node->methods;
234 :
235 0 : if (methods->ShutdownCustomScan)
236 0 : methods->ShutdownCustomScan(node);
237 0 : }
|