Coverage Report

Created: 2025-06-13 06:06

/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
}