PostgreSQL Source Code git master
Loading...
Searching...
No Matches
nodeCtescan.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * nodeCtescan.c
4 * routines to handle CteScan nodes.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/executor/nodeCtescan.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "executor/executor.h"
20#include "miscadmin.h"
21#include "utils/tuplestore.h"
22
24
25/* ----------------------------------------------------------------
26 * CteScanNext
27 *
28 * This is a workhorse for ExecCteScan
29 * ----------------------------------------------------------------
30 */
31static TupleTableSlot *
33{
34 EState *estate;
35 ScanDirection dir;
36 bool forward;
37 Tuplestorestate *tuplestorestate;
38 bool eof_tuplestore;
39 TupleTableSlot *slot;
40
41 /*
42 * get state info from node
43 */
44 estate = node->ss.ps.state;
45 dir = estate->es_direction;
47 tuplestorestate = node->leader->cte_table;
48 tuplestore_select_read_pointer(tuplestorestate, node->readptr);
49 slot = node->ss.ss_ScanTupleSlot;
50
51 /*
52 * If we are not at the end of the tuplestore, or are going backwards, try
53 * to fetch a tuple from tuplestore.
54 */
55 eof_tuplestore = tuplestore_ateof(tuplestorestate);
56
57 if (!forward && eof_tuplestore)
58 {
59 if (!node->leader->eof_cte)
60 {
61 /*
62 * When reversing direction at tuplestore EOF, the first
63 * gettupleslot call will fetch the last-added tuple; but we want
64 * to return the one before that, if possible. So do an extra
65 * fetch.
66 */
67 if (!tuplestore_advance(tuplestorestate, forward))
68 return NULL; /* the tuplestore must be empty */
69 }
70 eof_tuplestore = false;
71 }
72
73 /*
74 * If we can fetch another tuple from the tuplestore, return it.
75 *
76 * Note: we have to use copy=true in the tuplestore_gettupleslot call,
77 * because we are sharing the tuplestore with other nodes that might write
78 * into the tuplestore before we get called again.
79 */
80 if (!eof_tuplestore)
81 {
82 if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot))
83 return slot;
84 if (forward)
85 eof_tuplestore = true;
86 }
87
88 /*
89 * If necessary, try to fetch another row from the CTE query.
90 *
91 * Note: the eof_cte state variable exists to short-circuit further calls
92 * of the CTE plan. It's not optional, unfortunately, because some plan
93 * node types are not robust about being called again when they've already
94 * returned NULL.
95 */
96 if (eof_tuplestore && !node->leader->eof_cte)
97 {
99
100 /*
101 * We can only get here with forward==true, so no need to worry about
102 * which direction the subplan will go.
103 */
105 if (TupIsNull(cteslot))
106 {
107 node->leader->eof_cte = true;
108 return NULL;
109 }
110
111 /*
112 * There are corner cases where the subplan could change which
113 * tuplestore read pointer is active, so be sure to reselect ours
114 * before storing the tuple we got.
115 */
116 tuplestore_select_read_pointer(tuplestorestate, node->readptr);
117
118 /*
119 * Append a copy of the returned tuple to tuplestore. NOTE: because
120 * our read pointer is certainly in EOF state, its read position will
121 * move forward over the added tuple. This is what we want. Also,
122 * any other readers will *not* move past the new tuple, which is what
123 * they want.
124 */
125 tuplestore_puttupleslot(tuplestorestate, cteslot);
126
127 /*
128 * We MUST copy the CTE query's output tuple into our own slot. This
129 * is because other CteScan nodes might advance the CTE query before
130 * we are called again, and our output tuple must stay stable over
131 * that.
132 */
133 return ExecCopySlot(slot, cteslot);
134 }
135
136 /*
137 * Nothing left ...
138 */
139 return ExecClearTuple(slot);
140}
141
142/*
143 * CteScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
144 */
145static bool
147{
148 /* nothing to check */
149 return true;
150}
151
152/* ----------------------------------------------------------------
153 * ExecCteScan(node)
154 *
155 * Scans the CTE sequentially and returns the next qualifying tuple.
156 * We call the ExecScan() routine and pass it the appropriate
157 * access method functions.
158 * ----------------------------------------------------------------
159 */
160static TupleTableSlot *
162{
163 CteScanState *node = castNode(CteScanState, pstate);
164
165 return ExecScan(&node->ss,
168}
169
170
171/* ----------------------------------------------------------------
172 * ExecInitCteScan
173 * ----------------------------------------------------------------
174 */
176ExecInitCteScan(CteScan *node, EState *estate, int eflags)
177{
180
181 /* check for unsupported flags */
182 Assert(!(eflags & EXEC_FLAG_MARK));
183
184 /*
185 * For the moment we have to force the tuplestore to allow REWIND, because
186 * we might be asked to rescan the CTE even though upper levels didn't
187 * tell us to be prepared to do it efficiently. Annoying, since this
188 * prevents truncation of the tuplestore. XXX FIXME
189 *
190 * Note: if we are in an EPQ recheck plan tree, it's likely that no access
191 * to the tuplestore is needed at all, making this even more annoying.
192 * It's not worth improving that as long as all the read pointers would
193 * have REWIND anyway, but if we ever improve this logic then that aspect
194 * should be considered too.
195 */
196 eflags |= EXEC_FLAG_REWIND;
197
198 /*
199 * CteScan should not have any children.
200 */
201 Assert(outerPlan(node) == NULL);
202 Assert(innerPlan(node) == NULL);
203
204 /*
205 * create new CteScanState for node
206 */
208 scanstate->ss.ps.plan = (Plan *) node;
209 scanstate->ss.ps.state = estate;
210 scanstate->ss.ps.ExecProcNode = ExecCteScan;
211 scanstate->eflags = eflags;
212 scanstate->cte_table = NULL;
213 scanstate->eof_cte = false;
214
215 /*
216 * Find the already-initialized plan for the CTE query.
217 */
218 scanstate->cteplanstate = (PlanState *) list_nth(estate->es_subplanstates,
219 node->ctePlanId - 1);
220
221 /*
222 * The Param slot associated with the CTE query is used to hold a pointer
223 * to the CteState of the first CteScan node that initializes for this
224 * CTE. This node will be the one that holds the shared state for all the
225 * CTEs, particularly the shared tuplestore.
226 */
227 prmdata = &(estate->es_param_exec_vals[node->cteParam]);
228 Assert(prmdata->execPlan == NULL);
229 Assert(!prmdata->isnull);
231 if (scanstate->leader == NULL)
232 {
233 /* I am the leader */
235 scanstate->leader = scanstate;
236 scanstate->cte_table = tuplestore_begin_heap(true, false, work_mem);
237 tuplestore_set_eflags(scanstate->cte_table, scanstate->eflags);
238 scanstate->readptr = 0;
239 }
240 else
241 {
242 /* Not the leader */
243 /* Create my own read pointer, and ensure it is at start */
244 scanstate->readptr =
245 tuplestore_alloc_read_pointer(scanstate->leader->cte_table,
246 scanstate->eflags);
247 tuplestore_select_read_pointer(scanstate->leader->cte_table,
248 scanstate->readptr);
249 tuplestore_rescan(scanstate->leader->cte_table);
250 }
251
252 /*
253 * Miscellaneous initialization
254 *
255 * create expression context for node
256 */
257 ExecAssignExprContext(estate, &scanstate->ss.ps);
258
259 /*
260 * The scan tuple type (ie, the rowtype we expect to find in the work
261 * table) is the same as the result rowtype of the CTE query.
262 */
263 ExecInitScanTupleSlot(estate, &scanstate->ss,
264 ExecGetResultType(scanstate->cteplanstate),
266
267 /*
268 * Initialize result type and projection.
269 */
272
273 /*
274 * initialize child expressions
275 */
276 scanstate->ss.ps.qual =
277 ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
278
279 return scanstate;
280}
281
282/* ----------------------------------------------------------------
283 * ExecEndCteScan
284 *
285 * frees any storage allocated through C routines.
286 * ----------------------------------------------------------------
287 */
288void
290{
291 /*
292 * If I am the leader, free the tuplestore.
293 */
294 if (node->leader == node)
295 {
297 node->cte_table = NULL;
298 }
299}
300
301/* ----------------------------------------------------------------
302 * ExecReScanCteScan
303 *
304 * Rescans the relation.
305 * ----------------------------------------------------------------
306 */
307void
309{
310 Tuplestorestate *tuplestorestate = node->leader->cte_table;
311
312 if (node->ss.ps.ps_ResultTupleSlot)
314
315 ExecScanReScan(&node->ss);
316
317 /*
318 * Clear the tuplestore if a new scan of the underlying CTE is required.
319 * This implicitly resets all the tuplestore's read pointers. Note that
320 * multiple CTE nodes might redundantly clear the tuplestore; that's OK,
321 * and not unduly expensive. We'll stop taking this path as soon as
322 * somebody has attempted to read something from the underlying CTE
323 * (thereby causing its chgParam to be cleared).
324 */
325 if (node->leader->cteplanstate->chgParam != NULL)
326 {
327 tuplestore_clear(tuplestorestate);
328 node->leader->eof_cte = false;
329 }
330 else
331 {
332 /*
333 * Else, just rewind my own pointer. Either the underlying CTE
334 * doesn't need a rescan (and we can re-read what's in the tuplestore
335 * now), or somebody else already took care of it.
336 */
337 tuplestore_select_read_pointer(tuplestorestate, node->readptr);
338 tuplestore_rescan(tuplestorestate);
339 }
340}
#define Assert(condition)
Definition c.h:945
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition execScan.c:47
void ExecAssignScanProjectionInfo(ScanState *node)
Definition execScan.c:81
void ExecScanReScan(ScanState *node)
Definition execScan.c:108
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops, uint16 flags)
void ExecInitResultTypeTL(PlanState *planstate)
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition execUtils.c:490
#define EXEC_FLAG_REWIND
Definition executor.h:69
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition executor.h:583
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:315
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition executor.h:582
#define EXEC_FLAG_MARK
Definition executor.h:71
int work_mem
Definition globals.c:131
static TupleTableSlot * ExecCteScan(PlanState *pstate)
CteScanState * ExecInitCteScan(CteScan *node, EState *estate, int eflags)
void ExecReScanCteScan(CteScanState *node)
static bool CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
void ExecEndCteScan(CteScanState *node)
static TupleTableSlot * CteScanNext(CteScanState *node)
Definition nodeCtescan.c:32
#define makeNode(_type_)
Definition nodes.h:161
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define innerPlan(node)
Definition plannodes.h:264
#define outerPlan(node)
Definition plannodes.h:265
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static int fb(int x)
#define ScanDirectionIsForward(direction)
Definition sdir.h:64
ScanDirection
Definition sdir.h:25
Tuplestorestate * cte_table
Definition execnodes.h:2023
ScanState ss
Definition execnodes.h:2016
PlanState * cteplanstate
Definition execnodes.h:2019
struct CteScanState * leader
Definition execnodes.h:2021
int ctePlanId
Definition plannodes.h:819
int cteParam
Definition plannodes.h:821
Scan scan
Definition plannodes.h:817
ParamExecData * es_param_exec_vals
Definition execnodes.h:717
ScanDirection es_direction
Definition execnodes.h:671
List * es_subplanstates
Definition execnodes.h:737
EState * state
Definition execnodes.h:1179
Bitmapset * chgParam
Definition execnodes.h:1209
TupleTableSlot * ps_ResultTupleSlot
Definition execnodes.h:1215
TupleTableSlot * ss_ScanTupleSlot
Definition execnodes.h:1636
PlanState ps
Definition execnodes.h:1633
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition tuplestore.c:743
void tuplestore_select_read_pointer(Tuplestorestate *state, int ptr)
Definition tuplestore.c:508
void tuplestore_clear(Tuplestorestate *state)
Definition tuplestore.c:431
void tuplestore_rescan(Tuplestorestate *state)
int tuplestore_alloc_read_pointer(Tuplestorestate *state, int eflags)
Definition tuplestore.c:396
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition tuplestore.c:331
bool tuplestore_advance(Tuplestorestate *state, bool forward)
void tuplestore_end(Tuplestorestate *state)
Definition tuplestore.c:493
bool tuplestore_ateof(Tuplestorestate *state)
Definition tuplestore.c:592
void tuplestore_set_eflags(Tuplestorestate *state, int eflags)
Definition tuplestore.c:372
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
#define TupIsNull(slot)
Definition tuptable.h:325
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition tuptable.h:543