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-2026, 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 : : #include "utils/tuplestore.h"
21 : :
22 : : static TupleTableSlot *WorkTableScanNext(WorkTableScanState *node);
23 : :
24 : : /* ----------------------------------------------------------------
25 : : * WorkTableScanNext
26 : : *
27 : : * This is a workhorse for ExecWorkTableScan
28 : : * ----------------------------------------------------------------
29 : : */
30 : : static TupleTableSlot *
6422 tgl@sss.pgh.pa.us 31 :CBC 45706 : WorkTableScanNext(WorkTableScanState *node)
32 : : {
33 : : TupleTableSlot *slot;
34 : : Tuplestorestate *tuplestorestate;
35 : :
36 : : /*
37 : : * get information from the estate and scan state
38 : : *
39 : : * Note: we intentionally do not support backward scan. Although it would
40 : : * take only a couple more lines here, it would force nodeRecursiveunion.c
41 : : * to create the tuplestore with backward scan enabled, which has a
42 : : * performance cost. In practice backward scan is never useful for a
43 : : * worktable plan node, since it cannot appear high enough in the plan
44 : : * tree of a scrollable cursor to be exposed to a backward-scan
45 : : * requirement. So it's not worth expending effort to support it.
46 : : *
47 : : * Note: we are also assuming that this node is the only reader of the
48 : : * worktable. Therefore, we don't need a private read pointer for the
49 : : * tuplestore, nor do we need to tell tuplestore_gettupleslot to copy.
50 : : */
5158 peter_e@gmx.net 51 [ - + ]: 45706 : Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
52 : :
6422 tgl@sss.pgh.pa.us 53 : 45706 : tuplestorestate = node->rustate->working_table;
54 : :
55 : : /*
56 : : * Get the next tuple from tuplestore. Return NULL if no more tuples.
57 : : */
58 : 45706 : slot = node->ss.ss_ScanTupleSlot;
6248 59 : 45706 : (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
6422 60 : 45706 : return slot;
61 : : }
62 : :
63 : : /*
64 : : * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
65 : : */
66 : : static bool
6035 tgl@sss.pgh.pa.us 67 :UBC 0 : WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
68 : : {
69 : : /* nothing to check */
70 : 0 : return true;
71 : : }
72 : :
73 : : /* ----------------------------------------------------------------
74 : : * ExecWorkTableScan(node)
75 : : *
76 : : * Scans the worktable sequentially and returns the next qualifying tuple.
77 : : * We call the ExecScan() routine and pass it the appropriate
78 : : * access method functions.
79 : : * ----------------------------------------------------------------
80 : : */
81 : : static TupleTableSlot *
3214 andres@anarazel.de 82 :CBC 38180 : ExecWorkTableScan(PlanState *pstate)
83 : : {
84 : 38180 : WorkTableScanState *node = castNode(WorkTableScanState, pstate);
85 : :
86 : : /*
87 : : * On the first call, find the ancestor RecursiveUnion's state via the
88 : : * Param slot reserved for it. (We can't do this during node init because
89 : : * there are corner cases where we'll get the init call before the
90 : : * RecursiveUnion does.)
91 : : */
6413 tgl@sss.pgh.pa.us 92 [ + + ]: 38180 : if (node->rustate == NULL)
93 : : {
94 : 581 : WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
95 : 581 : EState *estate = node->ss.ps.state;
96 : : ParamExecData *param;
97 : :
98 : 581 : param = &(estate->es_param_exec_vals[plan->wtParam]);
99 [ - + ]: 581 : Assert(param->execPlan == NULL);
100 [ - + ]: 581 : Assert(!param->isnull);
3386 andres@anarazel.de 101 : 581 : node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
102 [ - + ]: 581 : Assert(node->rustate);
103 : :
104 : : /*
105 : : * The scan tuple type (ie, the rowtype we expect to find in the work
106 : : * table) is the same as the result rowtype of the ancestor
107 : : * RecursiveUnion node. Note this depends on the assumption that
108 : : * RecursiveUnion doesn't allow projection.
109 : : */
6413 tgl@sss.pgh.pa.us 110 : 581 : ExecAssignScanType(&node->ss,
111 : 581 : ExecGetResultType(&node->rustate->ps));
112 : :
113 : : /*
114 : : * Now we can initialize the projection info. This must be completed
115 : : * before we can call ExecScan().
116 : : */
117 : 581 : ExecAssignScanProjectionInfo(&node->ss);
118 : : }
119 : :
6035 120 : 38180 : return ExecScan(&node->ss,
121 : : (ExecScanAccessMtd) WorkTableScanNext,
122 : : (ExecScanRecheckMtd) WorkTableScanRecheck);
123 : : }
124 : :
125 : :
126 : : /* ----------------------------------------------------------------
127 : : * ExecInitWorkTableScan
128 : : * ----------------------------------------------------------------
129 : : */
130 : : WorkTableScanState *
6422 131 : 617 : ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
132 : : {
133 : : WorkTableScanState *scanstate;
134 : :
135 : : /* check for unsupported flags */
6398 136 [ - + ]: 617 : Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
137 : :
138 : : /*
139 : : * WorkTableScan should not have any children.
140 : : */
6422 141 [ - + ]: 617 : Assert(outerPlan(node) == NULL);
142 [ - + ]: 617 : Assert(innerPlan(node) == NULL);
143 : :
144 : : /*
145 : : * create new WorkTableScanState for node
146 : : */
147 : 617 : scanstate = makeNode(WorkTableScanState);
148 : 617 : scanstate->ss.ps.plan = (Plan *) node;
149 : 617 : scanstate->ss.ps.state = estate;
3214 andres@anarazel.de 150 : 617 : scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
6413 tgl@sss.pgh.pa.us 151 : 617 : scanstate->rustate = NULL; /* we'll set this later */
152 : :
153 : : /*
154 : : * Miscellaneous initialization
155 : : *
156 : : * create expression context for node
157 : : */
6422 158 : 617 : ExecAssignExprContext(estate, &scanstate->ss.ps);
159 : :
160 : : /*
161 : : * tuple table initialization
162 : : */
2734 andres@anarazel.de 163 : 617 : ExecInitResultTypeTL(&scanstate->ss.ps);
164 : :
165 : : /* signal that return type is not yet known */
2728 166 : 617 : scanstate->ss.ps.resultopsset = true;
167 : 617 : scanstate->ss.ps.resultopsfixed = false;
168 : :
50 drowley@postgresql.o 169 :GNC 617 : ExecInitScanTupleSlot(estate, &scanstate->ss, NULL, &TTSOpsMinimalTuple, 0);
170 : :
171 : : /*
172 : : * initialize child expressions
173 : : */
3000 andres@anarazel.de 174 :CBC 617 : scanstate->ss.ps.qual =
175 : 617 : ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
176 : :
177 : : /*
178 : : * Do not yet initialize projection info, see ExecWorkTableScan() for
179 : : * details.
180 : : */
181 : :
6422 tgl@sss.pgh.pa.us 182 : 617 : return scanstate;
183 : : }
184 : :
185 : : /* ----------------------------------------------------------------
186 : : * ExecReScanWorkTableScan
187 : : *
188 : : * Rescans the relation.
189 : : * ----------------------------------------------------------------
190 : : */
191 : : void
5776 192 : 4280 : ExecReScanWorkTableScan(WorkTableScanState *node)
193 : : {
2734 andres@anarazel.de 194 [ + + ]: 4280 : if (node->ss.ps.ps_ResultTupleSlot)
195 : 3901 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
196 : :
6035 tgl@sss.pgh.pa.us 197 : 4280 : ExecScanReScan(&node->ss);
198 : :
199 : : /* No need (or way) to rescan if ExecWorkTableScan not called yet */
6413 200 [ + + ]: 4280 : if (node->rustate)
201 : 4276 : tuplestore_rescan(node->rustate->working_table);
6422 202 : 4280 : }
|