/src/postgres/src/backend/executor/nodeCustom.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* ------------------------------------------------------------------------ |
2 | | * |
3 | | * nodeCustom.c |
4 | | * Routines to handle execution of custom scan node |
5 | | * |
6 | | * Portions Copyright (c) 1996-2025, 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 | | ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags) |
27 | 0 | { |
28 | 0 | CustomScanState *css; |
29 | 0 | const TupleTableSlotOps *slotOps; |
30 | 0 | Relation scan_rel = NULL; |
31 | 0 | Index scanrelid = cscan->scan.scanrelid; |
32 | 0 | 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 | 0 | 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 | 0 | { |
60 | 0 | scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags); |
61 | 0 | css->ss.ss_currentRelation = scan_rel; |
62 | 0 | } |
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 | 0 | 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 | 0 | } |
86 | 0 | else |
87 | 0 | { |
88 | 0 | ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel), |
89 | 0 | slotOps); |
90 | | /* Node's targetlist will contain Vars with varno = scanrelid */ |
91 | 0 | tlistvarno = scanrelid; |
92 | 0 | } |
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 | 0 | } |
112 | | |
113 | | static TupleTableSlot * |
114 | | ExecCustomScan(PlanState *pstate) |
115 | 0 | { |
116 | 0 | CustomScanState *node = castNode(CustomScanState, pstate); |
117 | |
|
118 | 0 | CHECK_FOR_INTERRUPTS(); |
119 | |
|
120 | 0 | Assert(node->methods->ExecCustomScan != NULL); |
121 | 0 | return node->methods->ExecCustomScan(node); |
122 | 0 | } |
123 | | |
124 | | void |
125 | | ExecEndCustomScan(CustomScanState *node) |
126 | 0 | { |
127 | 0 | Assert(node->methods->EndCustomScan != NULL); |
128 | 0 | node->methods->EndCustomScan(node); |
129 | 0 | } |
130 | | |
131 | | void |
132 | | ExecReScanCustomScan(CustomScanState *node) |
133 | 0 | { |
134 | 0 | Assert(node->methods->ReScanCustomScan != NULL); |
135 | 0 | node->methods->ReScanCustomScan(node); |
136 | 0 | } |
137 | | |
138 | | void |
139 | | ExecCustomMarkPos(CustomScanState *node) |
140 | 0 | { |
141 | 0 | if (!node->methods->MarkPosCustomScan) |
142 | 0 | ereport(ERROR, |
143 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
144 | 0 | errmsg("custom scan \"%s\" does not support MarkPos", |
145 | 0 | node->methods->CustomName))); |
146 | 0 | node->methods->MarkPosCustomScan(node); |
147 | 0 | } |
148 | | |
149 | | void |
150 | | ExecCustomRestrPos(CustomScanState *node) |
151 | 0 | { |
152 | 0 | if (!node->methods->RestrPosCustomScan) |
153 | 0 | ereport(ERROR, |
154 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
155 | 0 | errmsg("custom scan \"%s\" does not support MarkPos", |
156 | 0 | node->methods->CustomName))); |
157 | 0 | node->methods->RestrPosCustomScan(node); |
158 | 0 | } |
159 | | |
160 | | void |
161 | | ExecCustomScanEstimate(CustomScanState *node, ParallelContext *pcxt) |
162 | 0 | { |
163 | 0 | const CustomExecMethods *methods = node->methods; |
164 | |
|
165 | 0 | if (methods->EstimateDSMCustomScan) |
166 | 0 | { |
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 | 0 | } |
171 | 0 | } |
172 | | |
173 | | void |
174 | | ExecCustomScanInitializeDSM(CustomScanState *node, ParallelContext *pcxt) |
175 | 0 | { |
176 | 0 | const CustomExecMethods *methods = node->methods; |
177 | |
|
178 | 0 | if (methods->InitializeDSMCustomScan) |
179 | 0 | { |
180 | 0 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
181 | 0 | 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 | 0 | } |
187 | 0 | } |
188 | | |
189 | | void |
190 | | ExecCustomScanReInitializeDSM(CustomScanState *node, ParallelContext *pcxt) |
191 | 0 | { |
192 | 0 | const CustomExecMethods *methods = node->methods; |
193 | |
|
194 | 0 | if (methods->ReInitializeDSMCustomScan) |
195 | 0 | { |
196 | 0 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
197 | 0 | void *coordinate; |
198 | |
|
199 | 0 | coordinate = shm_toc_lookup(pcxt->toc, plan_node_id, false); |
200 | 0 | methods->ReInitializeDSMCustomScan(node, pcxt, coordinate); |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | void |
205 | | ExecCustomScanInitializeWorker(CustomScanState *node, |
206 | | ParallelWorkerContext *pwcxt) |
207 | 0 | { |
208 | 0 | const CustomExecMethods *methods = node->methods; |
209 | |
|
210 | 0 | if (methods->InitializeWorkerCustomScan) |
211 | 0 | { |
212 | 0 | int plan_node_id = node->ss.ps.plan->plan_node_id; |
213 | 0 | void *coordinate; |
214 | |
|
215 | 0 | coordinate = shm_toc_lookup(pwcxt->toc, plan_node_id, false); |
216 | 0 | methods->InitializeWorkerCustomScan(node, pwcxt->toc, coordinate); |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | | void |
221 | | ExecShutdownCustomScan(CustomScanState *node) |
222 | 0 | { |
223 | 0 | const CustomExecMethods *methods = node->methods; |
224 | |
|
225 | 0 | if (methods->ShutdownCustomScan) |
226 | 0 | methods->ShutdownCustomScan(node); |
227 | 0 | } |