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