]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeValuesscan.c
Repair bug #2839: the various ExecReScan functions need to reset
[postgresql] / src / backend / executor / nodeValuesscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeValuesscan.c
4  *        Support routines for scanning Values lists
5  *        ("VALUES (...), (...), ..." in rangetable).
6  *
7  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.4 2006/12/26 19:26:46 tgl Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 /*
17  * INTERFACE ROUTINES
18  *              ExecValuesScan                  scans a values list.
19  *              ExecValuesNext                  retrieve next tuple in sequential order.
20  *              ExecInitValuesScan              creates and initializes a valuesscan node.
21  *              ExecEndValuesScan               releases any storage allocated.
22  *              ExecValuesReScan                rescans the values list
23  */
24 #include "postgres.h"
25
26 #include "executor/executor.h"
27 #include "executor/nodeValuesscan.h"
28 #include "parser/parsetree.h"
29 #include "utils/memutils.h"
30
31
32 static TupleTableSlot *ValuesNext(ValuesScanState *node);
33
34
35 /* ----------------------------------------------------------------
36  *                                              Scan Support
37  * ----------------------------------------------------------------
38  */
39
40 /* ----------------------------------------------------------------
41  *              ValuesNext
42  *
43  *              This is a workhorse for ExecValuesScan
44  * ----------------------------------------------------------------
45  */
46 static TupleTableSlot *
47 ValuesNext(ValuesScanState *node)
48 {
49         TupleTableSlot *slot;
50         EState     *estate;
51         ExprContext *econtext;
52         ScanDirection direction;
53         List       *exprlist;
54
55         /*
56          * get information from the estate and scan state
57          */
58         estate = node->ss.ps.state;
59         direction = estate->es_direction;
60         slot = node->ss.ss_ScanTupleSlot;
61         econtext = node->rowcontext;
62
63         /*
64          * Get the next tuple. Return NULL if no more tuples.
65          */
66         if (ScanDirectionIsForward(direction))
67         {
68                 if (node->curr_idx < node->array_len)
69                         node->curr_idx++;
70                 if (node->curr_idx < node->array_len)
71                         exprlist = node->exprlists[node->curr_idx];
72                 else
73                         exprlist = NIL;
74         }
75         else
76         {
77                 if (node->curr_idx >= 0)
78                         node->curr_idx--;
79                 if (node->curr_idx >= 0)
80                         exprlist = node->exprlists[node->curr_idx];
81                 else
82                         exprlist = NIL;
83         }
84
85         /*
86          * Always clear the result slot; this is appropriate if we are at the end
87          * of the data, and if we're not, we still need it as the first step of
88          * the store-virtual-tuple protocol.  It seems wise to clear the slot
89          * before we reset the context it might have pointers into.
90          */
91         ExecClearTuple(slot);
92
93         if (exprlist)
94         {
95                 MemoryContext oldContext;
96                 List       *exprstatelist;
97                 Datum      *values;
98                 bool       *isnull;
99                 ListCell   *lc;
100                 int                     resind;
101
102                 /*
103                  * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
104                  * not just ResetExprContext because we want any registered shutdown
105                  * callbacks to be called.
106                  */
107                 ReScanExprContext(econtext);
108
109                 /*
110                  * Build the expression eval state in the econtext's per-tuple memory.
111                  * This is a tad unusual, but we want to delete the eval state again
112                  * when we move to the next row, to avoid growth of memory
113                  * requirements over a long values list.
114                  */
115                 oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
116
117                 /*
118                  * Pass NULL, not my plan node, because we don't want anything in this
119                  * transient state linking into permanent state.  The only possibility
120                  * is a SubPlan, and there shouldn't be any (any subselects in the
121                  * VALUES list should be InitPlans).
122                  */
123                 exprstatelist = (List *) ExecInitExpr((Expr *) exprlist, NULL);
124
125                 /* parser should have checked all sublists are the same length */
126                 Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
127
128                 /*
129                  * Compute the expressions and build a virtual result tuple. We
130                  * already did ExecClearTuple(slot).
131                  */
132                 values = slot->tts_values;
133                 isnull = slot->tts_isnull;
134
135                 resind = 0;
136                 foreach(lc, exprstatelist)
137                 {
138                         ExprState  *estate = (ExprState *) lfirst(lc);
139
140                         values[resind] = ExecEvalExpr(estate,
141                                                                                   econtext,
142                                                                                   &isnull[resind],
143                                                                                   NULL);
144                         resind++;
145                 }
146
147                 MemoryContextSwitchTo(oldContext);
148
149                 /*
150                  * And return the virtual tuple.
151                  */
152                 ExecStoreVirtualTuple(slot);
153         }
154
155         return slot;
156 }
157
158
159 /* ----------------------------------------------------------------
160  *              ExecValuesScan(node)
161  *
162  *              Scans the values lists sequentially and returns the next qualifying
163  *              tuple.
164  *              It calls the ExecScan() routine and passes it the access method
165  *              which retrieves tuples sequentially.
166  * ----------------------------------------------------------------
167  */
168 TupleTableSlot *
169 ExecValuesScan(ValuesScanState *node)
170 {
171         /*
172          * use ValuesNext as access method
173          */
174         return ExecScan(&node->ss, (ExecScanAccessMtd) ValuesNext);
175 }
176
177 /* ----------------------------------------------------------------
178  *              ExecInitValuesScan
179  * ----------------------------------------------------------------
180  */
181 ValuesScanState *
182 ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
183 {
184         ValuesScanState *scanstate;
185         RangeTblEntry *rte;
186         TupleDesc       tupdesc;
187         ListCell   *vtl;
188         int                     i;
189         PlanState  *planstate;
190
191         /*
192          * ValuesScan should not have any children.
193          */
194         Assert(outerPlan(node) == NULL);
195         Assert(innerPlan(node) == NULL);
196
197         /*
198          * create new ScanState for node
199          */
200         scanstate = makeNode(ValuesScanState);
201         scanstate->ss.ps.plan = (Plan *) node;
202         scanstate->ss.ps.state = estate;
203
204         /*
205          * Miscellaneous initialization
206          */
207         planstate = &scanstate->ss.ps;
208
209         /*
210          * Create expression contexts.  We need two, one for per-sublist
211          * processing and one for execScan.c to use for quals and projections. We
212          * cheat a little by using ExecAssignExprContext() to build both.
213          */
214         ExecAssignExprContext(estate, planstate);
215         scanstate->rowcontext = planstate->ps_ExprContext;
216         ExecAssignExprContext(estate, planstate);
217
218 #define VALUESSCAN_NSLOTS 2
219
220         /*
221          * tuple table initialization
222          */
223         ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
224         ExecInitScanTupleSlot(estate, &scanstate->ss);
225
226         /*
227          * initialize child expressions
228          */
229         scanstate->ss.ps.targetlist = (List *)
230                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
231                                          (PlanState *) scanstate);
232         scanstate->ss.ps.qual = (List *)
233                 ExecInitExpr((Expr *) node->scan.plan.qual,
234                                          (PlanState *) scanstate);
235
236         /*
237          * get info about values list
238          */
239         rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
240         Assert(rte->rtekind == RTE_VALUES);
241         tupdesc = ExecTypeFromExprList((List *) linitial(rte->values_lists));
242
243         ExecAssignScanType(&scanstate->ss, tupdesc);
244
245         /*
246          * Other node-specific setup
247          */
248         scanstate->marked_idx = -1;
249         scanstate->curr_idx = -1;
250         scanstate->array_len = list_length(rte->values_lists);
251
252         /* convert list of sublists into array of sublists for easy addressing */
253         scanstate->exprlists = (List **)
254                 palloc(scanstate->array_len * sizeof(List *));
255         i = 0;
256         foreach(vtl, rte->values_lists)
257         {
258                 scanstate->exprlists[i++] = (List *) lfirst(vtl);
259         }
260
261         scanstate->ss.ps.ps_TupFromTlist = false;
262
263         /*
264          * Initialize result tuple type and projection info.
265          */
266         ExecAssignResultTypeFromTL(&scanstate->ss.ps);
267         ExecAssignScanProjectionInfo(&scanstate->ss);
268
269         return scanstate;
270 }
271
272 int
273 ExecCountSlotsValuesScan(ValuesScan *node)
274 {
275         return ExecCountSlotsNode(outerPlan(node)) +
276                 ExecCountSlotsNode(innerPlan(node)) +
277                 VALUESSCAN_NSLOTS;
278 }
279
280 /* ----------------------------------------------------------------
281  *              ExecEndValuesScan
282  *
283  *              frees any storage allocated through C routines.
284  * ----------------------------------------------------------------
285  */
286 void
287 ExecEndValuesScan(ValuesScanState *node)
288 {
289         /*
290          * Free both exprcontexts
291          */
292         ExecFreeExprContext(&node->ss.ps);
293         node->ss.ps.ps_ExprContext = node->rowcontext;
294         ExecFreeExprContext(&node->ss.ps);
295
296         /*
297          * clean out the tuple table
298          */
299         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
300         ExecClearTuple(node->ss.ss_ScanTupleSlot);
301 }
302
303 /* ----------------------------------------------------------------
304  *              ExecValuesMarkPos
305  *
306  *              Marks scan position.
307  * ----------------------------------------------------------------
308  */
309 void
310 ExecValuesMarkPos(ValuesScanState *node)
311 {
312         node->marked_idx = node->curr_idx;
313 }
314
315 /* ----------------------------------------------------------------
316  *              ExecValuesRestrPos
317  *
318  *              Restores scan position.
319  * ----------------------------------------------------------------
320  */
321 void
322 ExecValuesRestrPos(ValuesScanState *node)
323 {
324         node->curr_idx = node->marked_idx;
325 }
326
327 /* ----------------------------------------------------------------
328  *              ExecValuesReScan
329  *
330  *              Rescans the relation.
331  * ----------------------------------------------------------------
332  */
333 void
334 ExecValuesReScan(ValuesScanState *node, ExprContext *exprCtxt)
335 {
336         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
337         node->ss.ps.ps_TupFromTlist = false;
338
339         node->curr_idx = -1;
340 }