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