Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * nodeWorktablescan.c
4 : : * routines to handle WorkTableScan 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/nodeWorktablescan.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres.h"
17 : :
18 : : #include "executor/executor.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 *
5671 tgl@sss.pgh.pa.us 30 :CBC 25383 : 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 : : */
4407 peter_e@gmx.net 50 [ - + ]: 25383 : Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51 : :
5671 tgl@sss.pgh.pa.us 52 : 25383 : tuplestorestate = node->rustate->working_table;
53 : :
54 : : /*
55 : : * Get the next tuple from tuplestore. Return NULL if no more tuples.
56 : : */
57 : 25383 : slot = node->ss.ss_ScanTupleSlot;
5497 58 : 25383 : (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
5671 59 : 25383 : return slot;
60 : : }
61 : :
62 : : /*
63 : : * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64 : : */
65 : : static bool
5284 tgl@sss.pgh.pa.us 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 *
2463 andres@anarazel.de 81 :CBC 18372 : ExecWorkTableScan(PlanState *pstate)
82 : : {
83 : 18372 : 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 : : */
5662 tgl@sss.pgh.pa.us 91 [ + + ]: 18372 : if (node->rustate == NULL)
92 : : {
93 : 376 : WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
94 : 376 : EState *estate = node->ss.ps.state;
95 : : ParamExecData *param;
96 : :
97 : 376 : param = &(estate->es_param_exec_vals[plan->wtParam]);
98 [ - + ]: 376 : Assert(param->execPlan == NULL);
99 [ - + ]: 376 : Assert(!param->isnull);
2635 andres@anarazel.de 100 : 376 : node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
101 [ - + ]: 376 : 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 : : */
5662 tgl@sss.pgh.pa.us 109 : 376 : ExecAssignScanType(&node->ss,
110 : 376 : 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 : 376 : ExecAssignScanProjectionInfo(&node->ss);
117 : : }
118 : :
5284 119 : 18372 : return ExecScan(&node->ss,
120 : : (ExecScanAccessMtd) WorkTableScanNext,
121 : : (ExecScanRecheckMtd) WorkTableScanRecheck);
122 : : }
123 : :
124 : :
125 : : /* ----------------------------------------------------------------
126 : : * ExecInitWorkTableScan
127 : : * ----------------------------------------------------------------
128 : : */
129 : : WorkTableScanState *
5671 130 : 403 : ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
131 : : {
132 : : WorkTableScanState *scanstate;
133 : :
134 : : /* check for unsupported flags */
5647 135 [ - + ]: 403 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
136 : :
137 : : /*
138 : : * WorkTableScan should not have any children.
139 : : */
5671 140 [ - + ]: 403 : Assert(outerPlan(node) == NULL);
141 [ - + ]: 403 : Assert(innerPlan(node) == NULL);
142 : :
143 : : /*
144 : : * create new WorkTableScanState for node
145 : : */
146 : 403 : scanstate = makeNode(WorkTableScanState);
147 : 403 : scanstate->ss.ps.plan = (Plan *) node;
148 : 403 : scanstate->ss.ps.state = estate;
2463 andres@anarazel.de 149 : 403 : scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
5662 tgl@sss.pgh.pa.us 150 : 403 : scanstate->rustate = NULL; /* we'll set this later */
151 : :
152 : : /*
153 : : * Miscellaneous initialization
154 : : *
155 : : * create expression context for node
156 : : */
5671 157 : 403 : ExecAssignExprContext(estate, &scanstate->ss.ps);
158 : :
159 : : /*
160 : : * tuple table initialization
161 : : */
1983 andres@anarazel.de 162 : 403 : ExecInitResultTypeTL(&scanstate->ss.ps);
163 : :
164 : : /* signal that return type is not yet known */
1977 165 : 403 : scanstate->ss.ps.resultopsset = true;
166 : 403 : scanstate->ss.ps.resultopsfixed = false;
167 : :
168 : 403 : ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple);
169 : :
170 : : /*
171 : : * initialize child expressions
172 : : */
2249 173 : 403 : scanstate->ss.ps.qual =
174 : 403 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
175 : :
176 : : /*
177 : : * Do not yet initialize projection info, see ExecWorkTableScan() for
178 : : * details.
179 : : */
180 : :
5671 tgl@sss.pgh.pa.us 181 : 403 : return scanstate;
182 : : }
183 : :
184 : : /* ----------------------------------------------------------------
185 : : * ExecReScanWorkTableScan
186 : : *
187 : : * Rescans the relation.
188 : : * ----------------------------------------------------------------
189 : : */
190 : : void
5025 191 : 3151 : ExecReScanWorkTableScan(WorkTableScanState *node)
192 : : {
1983 andres@anarazel.de 193 [ + + ]: 3151 : if (node->ss.ps.ps_ResultTupleSlot)
194 : 2953 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
195 : :
5284 tgl@sss.pgh.pa.us 196 : 3151 : ExecScanReScan(&node->ss);
197 : :
198 : : /* No need (or way) to rescan if ExecWorkTableScan not called yet */
5662 199 [ + + ]: 3151 : if (node->rustate)
200 : 3148 : tuplestore_rescan(node->rustate->working_table);
5671 201 : 3151 : }
|