Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeWorktablescan.c
4 : * routines to handle WorkTableScan nodes.
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/executor/nodeWorktablescan.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include "executor/execdebug.h"
19 : #include "executor/nodeWorktablescan.h"
20 :
21 : static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
22 :
23 : /* ----------------------------------------------------------------
24 : * WorkTableScanNext
25 : *
26 : * This is a workhorse for ExecWorkTableScan
27 : * ----------------------------------------------------------------
28 : */
29 : static TupleTableSlot *
5300 tgl 30 CBC 21134 : WorkTableScanNext(WorkTableScanState *node)
31 : {
32 : TupleTableSlot *slot;
33 : Tuplestorestate *tuplestorestate;
34 :
35 : /*
36 : * get information from the estate and scan state
37 : *
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.
45 : *
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.
49 : */
4036 peter_e 50 21134 : Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51 :
5300 tgl 52 21134 : tuplestorestate = node->rustate->working_table;
53 :
54 : /*
55 : * Get the next tuple from tuplestore. Return NULL if no more tuples.
56 : */
57 21134 : slot = node->ss.ss_ScanTupleSlot;
5126 58 21134 : (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
5300 59 21134 : return slot;
60 : }
61 :
62 : /*
63 : * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64 : */
65 : static bool
4913 tgl 66 UBC 0 : WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
67 : {
68 : /* nothing to check */
69 0 : return true;
70 : }
71 :
72 : /* ----------------------------------------------------------------
73 : * ExecWorkTableScan(node)
74 : *
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 : * ----------------------------------------------------------------
79 : */
80 : static TupleTableSlot *
2092 andres 81 CBC 14127 : ExecWorkTableScan(PlanState *pstate)
82 : {
83 14127 : WorkTableScanState *node = castNode(WorkTableScanState, pstate);
84 :
85 : /*
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.)
90 : */
5291 tgl 91 14127 : if (node->rustate == NULL)
92 : {
93 327 : WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
94 327 : EState *estate = node->ss.ps.state;
95 : ParamExecData *param;
96 :
97 327 : param = &(estate->es_param_exec_vals[plan->wtParam]);
98 327 : Assert(param->execPlan == NULL);
99 327 : Assert(!param->isnull);
2264 andres 100 327 : node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
101 327 : Assert(node->rustate);
102 :
103 : /*
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.
108 : */
5291 tgl 109 327 : ExecAssignScanType(&node->ss,
110 327 : ExecGetResultType(&node->rustate->ps));
111 :
112 : /*
113 : * Now we can initialize the projection info. This must be completed
114 : * before we can call ExecScan().
115 : */
116 327 : ExecAssignScanProjectionInfo(&node->ss);
117 : }
118 :
4913 119 14127 : return ExecScan(&node->ss,
120 : (ExecScanAccessMtd) WorkTableScanNext,
121 : (ExecScanRecheckMtd) WorkTableScanRecheck);
122 : }
123 :
124 :
125 : /* ----------------------------------------------------------------
126 : * ExecInitWorkTableScan
127 : * ----------------------------------------------------------------
128 : */
129 : WorkTableScanState *
5300 130 354 : ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
131 : {
132 : WorkTableScanState *scanstate;
133 :
134 : /* check for unsupported flags */
5276 135 354 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136 :
137 : /*
138 : * WorkTableScan should not have any children.
139 : */
5300 140 354 : Assert(outerPlan(node) == NULL);
141 354 : Assert(innerPlan(node) == NULL);
142 :
143 : /*
144 : * create new WorkTableScanState for node
145 : */
146 354 : scanstate = makeNode(WorkTableScanState);
147 354 : scanstate->ss.ps.plan = (Plan *) node;
148 354 : scanstate->ss.ps.state = estate;
2092 andres 149 354 : scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
5291 tgl 150 354 : scanstate->rustate = NULL; /* we'll set this later */
151 :
152 : /*
153 : * Miscellaneous initialization
154 : *
155 : * create expression context for node
156 : */
5300 157 354 : ExecAssignExprContext(estate, &scanstate->ss.ps);
158 :
159 : /*
160 : * tuple table initialization
161 : */
1612 andres 162 354 : ExecInitResultTypeTL(&scanstate->ss.ps);
163 :
164 : /* signal that return type is not yet known */
1606 165 354 : scanstate->ss.ps.resultopsset = true;
166 354 : scanstate->ss.ps.resultopsfixed = false;
167 :
168 354 : ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
169 :
170 : /*
171 : * initialize child expressions
172 : */
1878 173 354 : scanstate->ss.ps.qual =
174 354 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
175 :
176 : /*
177 : * Do not yet initialize projection info, see ExecWorkTableScan() for
178 : * details.
179 : */
180 :
5300 tgl 181 354 : return scanstate;
182 : }
183 :
184 : /* ----------------------------------------------------------------
185 : * ExecEndWorkTableScan
186 : *
187 : * frees any storage allocated through C routines.
188 : * ----------------------------------------------------------------
189 : */
190 : void
191 354 : ExecEndWorkTableScan(WorkTableScanState *node)
192 : {
193 : /*
194 : * Free exprcontext
195 : */
196 354 : ExecFreeExprContext(&node->ss.ps);
197 :
198 : /*
199 : * clean out the tuple table
200 : */
1612 andres 201 354 : if (node->ss.ps.ps_ResultTupleSlot)
202 258 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
5300 tgl 203 354 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
204 354 : }
205 :
206 : /* ----------------------------------------------------------------
207 : * ExecReScanWorkTableScan
208 : *
209 : * Rescans the relation.
210 : * ----------------------------------------------------------------
211 : */
212 : void
4654 213 3104 : ExecReScanWorkTableScan(WorkTableScanState *node)
214 : {
1612 andres 215 3104 : if (node->ss.ps.ps_ResultTupleSlot)
216 2942 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
217 :
4913 tgl 218 3104 : ExecScanReScan(&node->ss);
219 :
220 : /* No need (or way) to rescan if ExecWorkTableScan not called yet */
5291 221 3104 : if (node->rustate)
222 3101 : tuplestore_rescan(node->rustate->working_table);
5300 223 3104 : }
|