]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeWorktablescan.c
23b5b9498576512067bddfbfdcae0f64208f7a2b
[postgresql] / src / backend / executor / nodeWorktablescan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeWorktablescan.c
4  *        routines to handle WorkTableScan nodes.
5  *
6  * Portions Copyright (c) 1996-2017, 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 *
30 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          */
50         Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
51
52         tuplestorestate = node->rustate->working_table;
53
54         /*
55          * Get the next tuple from tuplestore. Return NULL if no more tuples.
56          */
57         slot = node->ss.ss_ScanTupleSlot;
58         (void) tuplestore_gettupleslot(tuplestorestate, true, false, slot);
59         return slot;
60 }
61
62 /*
63  * WorkTableScanRecheck -- access method routine to recheck a tuple in EvalPlanQual
64  */
65 static bool
66 WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
67 {
68         /* nothing to check */
69         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 TupleTableSlot *
81 ExecWorkTableScan(WorkTableScanState *node)
82 {
83         /*
84          * On the first call, find the ancestor RecursiveUnion's state via the
85          * Param slot reserved for it.  (We can't do this during node init because
86          * there are corner cases where we'll get the init call before the
87          * RecursiveUnion does.)
88          */
89         if (node->rustate == NULL)
90         {
91                 WorkTableScan *plan = (WorkTableScan *) node->ss.ps.plan;
92                 EState     *estate = node->ss.ps.state;
93                 ParamExecData *param;
94
95                 param = &(estate->es_param_exec_vals[plan->wtParam]);
96                 Assert(param->execPlan == NULL);
97                 Assert(!param->isnull);
98                 node->rustate = castNode(RecursiveUnionState, DatumGetPointer(param->value));
99                 Assert(node->rustate);
100
101                 /*
102                  * The scan tuple type (ie, the rowtype we expect to find in the work
103                  * table) is the same as the result rowtype of the ancestor
104                  * RecursiveUnion node.  Note this depends on the assumption that
105                  * RecursiveUnion doesn't allow projection.
106                  */
107                 ExecAssignScanType(&node->ss,
108                                                    ExecGetResultType(&node->rustate->ps));
109
110                 /*
111                  * Now we can initialize the projection info.  This must be completed
112                  * before we can call ExecScan().
113                  */
114                 ExecAssignScanProjectionInfo(&node->ss);
115         }
116
117         return ExecScan(&node->ss,
118                                         (ExecScanAccessMtd) WorkTableScanNext,
119                                         (ExecScanRecheckMtd) WorkTableScanRecheck);
120 }
121
122
123 /* ----------------------------------------------------------------
124  *              ExecInitWorkTableScan
125  * ----------------------------------------------------------------
126  */
127 WorkTableScanState *
128 ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
129 {
130         WorkTableScanState *scanstate;
131
132         /* check for unsupported flags */
133         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
134
135         /*
136          * WorkTableScan should not have any children.
137          */
138         Assert(outerPlan(node) == NULL);
139         Assert(innerPlan(node) == NULL);
140
141         /*
142          * create new WorkTableScanState for node
143          */
144         scanstate = makeNode(WorkTableScanState);
145         scanstate->ss.ps.plan = (Plan *) node;
146         scanstate->ss.ps.state = estate;
147         scanstate->rustate = NULL;      /* we'll set this later */
148
149         /*
150          * Miscellaneous initialization
151          *
152          * create expression context for node
153          */
154         ExecAssignExprContext(estate, &scanstate->ss.ps);
155
156         /*
157          * initialize child expressions
158          */
159         scanstate->ss.ps.targetlist = (List *)
160                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
161                                          (PlanState *) scanstate);
162         scanstate->ss.ps.qual = (List *)
163                 ExecInitExpr((Expr *) node->scan.plan.qual,
164                                          (PlanState *) scanstate);
165
166         /*
167          * tuple table initialization
168          */
169         ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
170         ExecInitScanTupleSlot(estate, &scanstate->ss);
171
172         /*
173          * Initialize result tuple type, but not yet projection info.
174          */
175         ExecAssignResultTypeFromTL(&scanstate->ss.ps);
176
177         return scanstate;
178 }
179
180 /* ----------------------------------------------------------------
181  *              ExecEndWorkTableScan
182  *
183  *              frees any storage allocated through C routines.
184  * ----------------------------------------------------------------
185  */
186 void
187 ExecEndWorkTableScan(WorkTableScanState *node)
188 {
189         /*
190          * Free exprcontext
191          */
192         ExecFreeExprContext(&node->ss.ps);
193
194         /*
195          * clean out the tuple table
196          */
197         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
198         ExecClearTuple(node->ss.ss_ScanTupleSlot);
199 }
200
201 /* ----------------------------------------------------------------
202  *              ExecReScanWorkTableScan
203  *
204  *              Rescans the relation.
205  * ----------------------------------------------------------------
206  */
207 void
208 ExecReScanWorkTableScan(WorkTableScanState *node)
209 {
210         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
211
212         ExecScanReScan(&node->ss);
213
214         /* No need (or way) to rescan if ExecWorkTableScan not called yet */
215         if (node->rustate)
216                 tuplestore_rescan(node->rustate->working_table);
217 }