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 0 : }
133 :
134 : void
135 0 : ExecReScanCustomScan(CustomScanState *node)
136 : {
137 : Assert(node->methods->ReScanCustomScan != NULL);
138 0 : node->methods->ReScanCustomScan(node);
139 0 : }
140 :
141 : void
142 0 : ExecCustomMarkPos(CustomScanState *node)
143 : {
144 0 : if (!node->methods->MarkPosCustomScan)
145 0 : ereport(ERROR,
146 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
147 : errmsg("custom scan \"%s\" does not support MarkPos",
148 : node->methods->CustomName)));
149 0 : node->methods->MarkPosCustomScan(node);
150 0 : }
151 :
152 : void
153 0 : ExecCustomRestrPos(CustomScanState *node)
154 : {
155 0 : if (!node->methods->RestrPosCustomScan)
156 0 : ereport(ERROR,
157 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
158 : errmsg("custom scan \"%s\" does not support MarkPos",
159 : node->methods->CustomName)));
160 0 : node->methods->RestrPosCustomScan(node);
161 0 : }
162 :
163 : void
164 0 : ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt)
165 : {
166 0 : const CustomExecMethods *methods = node->methods;
167 :
168 0 : if (methods->EstimateDSMCustomScan)
169 : {
170 0 : node->pscan_len = methods->EstimateDSMCustomScan(node, pcxt);
171 0 : shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len);
172 0 : shm_toc_estimate_keys(&pcxt->estimator, 1);
173 : }
174 0 : }
175 :
176 : void
177 0 : ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
178 : {
179 0 : const CustomExecMethods *methods = node->methods;
180 :
181 0 : if (methods->InitializeDSMCustomScan)
182 : {
183 0 : int plan_node_id = node->ss.ps.plan->plan_node_id;
184 : void *coordinate;
185 :
186 0 : coordinate = shm_toc_allocate(pcxt->toc, node->pscan_len);
187 0 : methods->InitializeDSMCustomScan(node, pcxt, coordinate);
188 0 : shm_toc_insert(pcxt->toc, plan_node_id, coordinate);
189 : }
190 0 : }
191 :
192 : void
193 0 : ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt)
194 : {
195 0 : const CustomExecMethods *methods = node->methods;
196 :
197 0 : if (methods->ReInitializeDSMCustomScan)
198 : {
199 0 : int plan_node_id = node->ss.ps.plan->plan_node_id;
200 : void *coordinate;
201 :
202 0 : coordinate = shm_toc_lookup(pcxt->toc, plan_node_id, false);
203 0 : methods->ReInitializeDSMCustomScan(node, pcxt, coordinate);
204 : }
205 0 : }
206 :
207 : void
208 0 : ExecCustomScanInitializeWorker(CustomScanState *node,
209 : ParallelWorkerContext *pwcxt)
210 : {
211 0 : const CustomExecMethods *methods = node->methods;
212 :
213 0 : if (methods->InitializeWorkerCustomScan)
214 : {
215 0 : int plan_node_id = node->ss.ps.plan->plan_node_id;
216 : void *coordinate;
217 :
218 0 : coordinate = shm_toc_lookup(pwcxt->toc, plan_node_id, false);
219 0 : methods->InitializeWorkerCustomScan(node, pwcxt->toc, coordinate);
220 : }
221 0 : }
222 :
223 : void
224 0 : ExecShutdownCustomScan(CustomScanState *node)
225 : {
226 0 : const CustomExecMethods *methods = node->methods;
227 :
228 0 : if (methods->ShutdownCustomScan)
229 0 : methods->ShutdownCustomScan(node);
230 0 : }
|