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