1 /*-------------------------------------------------------------------------
4 * routines to handle WorkTableScan nodes.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeWorktablescan.c
13 *-------------------------------------------------------------------------
18 #include "executor/executor.h"
19 #include "executor/nodeWorktablescan.h"
21 static TupleTableSlot
*WorkTableScanNext(WorkTableScanState
*node
);
23 /* ----------------------------------------------------------------
26 * This is a workhorse for ExecWorkTableScan
27 * ----------------------------------------------------------------
29 static TupleTableSlot
*
30 WorkTableScanNext(WorkTableScanState
*node
)
33 Tuplestorestate
*tuplestorestate
;
36 * get information from the estate and scan state
38 * Note: we intentionally do not support backward scan. Although it would
39 * take only a couple more lines here, it would force nodeRecursiveunion.c
40 * to create the tuplestore with backward scan enabled, which has a
41 * performance cost. In practice backward scan is never useful for a
42 * worktable plan node, since it cannot appear high enough in the plan
43 * tree of a scrollable cursor to be exposed to a backward-scan
44 * requirement. So it's not worth expending effort to support it.
46 * Note: we are also assuming that this node is the only reader of the
47 * worktable. Therefore, we don't need a private read pointer for the
48 * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
50 Assert(ScanDirectionIsForward(node
->ss
.ps
.state
->es_direction
));
52 tuplestorestate
= node
->rustate
->working_table
;
55 * Get the next tuple from tuplestore. Return NULL if no more tuples.
57 slot
= node
->ss
.ss_ScanTupleSlot
;
58 (void) tuplestore_gettupleslot(tuplestorestate
, true, false, slot
);
63 * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
66 WorkTableScanRecheck(WorkTableScanState
*node
, TupleTableSlot
*slot
)
68 /* nothing to check */
72 /* ----------------------------------------------------------------
73 * ExecWorkTableScan(node)
75 * Scans the worktable sequentially and returns the next qualifying tuple.
76 * We call the ExecScan() routine and pass it the appropriate
77 * access method functions.
78 * ----------------------------------------------------------------
80 static TupleTableSlot
*
81 ExecWorkTableScan(PlanState
*pstate
)
83 WorkTableScanState
*node
= castNode(WorkTableScanState
, pstate
);
86 * On the first call, find the ancestor RecursiveUnion's state via the
87 * Param slot reserved for it. (We can't do this during node init because
88 * there are corner cases where we'll get the init call before the
89 * RecursiveUnion does.)
91 if (node
->rustate
== NULL
)
93 WorkTableScan
*plan
= (WorkTableScan
*) node
->ss
.ps
.plan
;
94 EState
*estate
= node
->ss
.ps
.state
;
97 param
= &(estate
->es_param_exec_vals
[plan
->wtParam
]);
98 Assert(param
->execPlan
== NULL
);
99 Assert(!param
->isnull
);
100 node
->rustate
= castNode(RecursiveUnionState
, DatumGetPointer(param
->value
));
101 Assert(node
->rustate
);
104 * The scan tuple type (ie, the rowtype we expect to find in the work
105 * table) is the same as the result rowtype of the ancestor
106 * RecursiveUnion node. Note this depends on the assumption that
107 * RecursiveUnion doesn't allow projection.
109 ExecAssignScanType(&node
->ss
,
110 ExecGetResultType(&node
->rustate
->ps
));
113 * Now we can initialize the projection info. This must be completed
114 * before we can call ExecScan().
116 ExecAssignScanProjectionInfo(&node
->ss
);
119 return ExecScan(&node
->ss
,
120 (ExecScanAccessMtd
) WorkTableScanNext
,
121 (ExecScanRecheckMtd
) WorkTableScanRecheck
);
125 /* ----------------------------------------------------------------
126 * ExecInitWorkTableScan
127 * ----------------------------------------------------------------
130 ExecInitWorkTableScan(WorkTableScan
*node
, EState
*estate
, int eflags
)
132 WorkTableScanState
*scanstate
;
134 /* check for unsupported flags */
135 Assert(!(eflags
& (EXEC_FLAG_BACKWARD
| EXEC_FLAG_MARK
)));
138 * WorkTableScan should not have any children.
140 Assert(outerPlan(node
) == NULL
);
141 Assert(innerPlan(node
) == NULL
);
144 * create new WorkTableScanState for node
146 scanstate
= makeNode(WorkTableScanState
);
147 scanstate
->ss
.ps
.plan
= (Plan
*) node
;
148 scanstate
->ss
.ps
.state
= estate
;
149 scanstate
->ss
.ps
.ExecProcNode
= ExecWorkTableScan
;
150 scanstate
->rustate
= NULL
; /* we'll set this later */
153 * Miscellaneous initialization
155 * create expression context for node
157 ExecAssignExprContext(estate
, &scanstate
->ss
.ps
);
160 * tuple table initialization
162 ExecInitResultTypeTL(&scanstate
->ss
.ps
);
164 /* signal that return type is not yet known */
165 scanstate
->ss
.ps
.resultopsset
= true;
166 scanstate
->ss
.ps
.resultopsfixed
= false;
168 ExecInitScanTupleSlot(estate
, &scanstate
->ss
, NULL
, &TTSOpsMinimalTuple
);
171 * initialize child expressions
173 scanstate
->ss
.ps
.qual
=
174 ExecInitQual(node
->scan
.plan
.qual
, (PlanState
*) scanstate
);
177 * Do not yet initialize projection info, see ExecWorkTableScan() for
184 /* ----------------------------------------------------------------
185 * ExecReScanWorkTableScan
187 * Rescans the relation.
188 * ----------------------------------------------------------------
191 ExecReScanWorkTableScan(WorkTableScanState
*node
)
193 if (node
->ss
.ps
.ps_ResultTupleSlot
)
194 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
196 ExecScanReScan(&node
->ss
);
198 /* No need (or way) to rescan if ExecWorkTableScan not called yet */
200 tuplestore_rescan(node
->rustate
->working_table
);