]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeFunctionscan.c
Be more tense about not creating tuplestores with randomAccess = true unless
[postgresql] / src / backend / executor / nodeFunctionscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeFunctionscan.c
4  *        Support routines for scanning RangeFunctions (functions in rangetable).
5  *
6  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.49 2008/10/29 00:00:38 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *              ExecFunctionScan                scans a function.
18  *              ExecFunctionNext                retrieve next tuple in sequential order.
19  *              ExecInitFunctionScan    creates and initializes a functionscan node.
20  *              ExecEndFunctionScan             releases any storage allocated.
21  *              ExecFunctionReScan              rescans the function
22  */
23 #include "postgres.h"
24
25 #include "executor/nodeFunctionscan.h"
26 #include "funcapi.h"
27 #include "utils/builtins.h"
28
29
30 static TupleTableSlot *FunctionNext(FunctionScanState *node);
31
32 /* ----------------------------------------------------------------
33  *                                              Scan Support
34  * ----------------------------------------------------------------
35  */
36 /* ----------------------------------------------------------------
37  *              FunctionNext
38  *
39  *              This is a workhorse for ExecFunctionScan
40  * ----------------------------------------------------------------
41  */
42 static TupleTableSlot *
43 FunctionNext(FunctionScanState *node)
44 {
45         TupleTableSlot *slot;
46         EState     *estate;
47         ScanDirection direction;
48         Tuplestorestate *tuplestorestate;
49
50         /*
51          * get information from the estate and scan state
52          */
53         estate = node->ss.ps.state;
54         direction = estate->es_direction;
55
56         tuplestorestate = node->tuplestorestate;
57
58         /*
59          * If first time through, read all tuples from function and put them in a
60          * tuplestore. Subsequent calls just fetch tuples from tuplestore.
61          */
62         if (tuplestorestate == NULL)
63         {
64                 node->tuplestorestate = tuplestorestate =
65                         ExecMakeTableFunctionResult(node->funcexpr,
66                                                                                 node->ss.ps.ps_ExprContext,
67                                                                                 node->tupdesc,
68                                                                                 node->eflags & EXEC_FLAG_BACKWARD);
69         }
70
71         /*
72          * Get the next tuple from tuplestore. Return NULL if no more tuples.
73          */
74         slot = node->ss.ss_ScanTupleSlot;
75         (void) tuplestore_gettupleslot(tuplestorestate,
76                                                                    ScanDirectionIsForward(direction),
77                                                                    slot);
78         return slot;
79 }
80
81 /* ----------------------------------------------------------------
82  *              ExecFunctionScan(node)
83  *
84  *              Scans the function sequentially and returns the next qualifying
85  *              tuple.
86  *              It calls the ExecScan() routine and passes it the access method
87  *              which retrieves tuples sequentially.
88  *
89  */
90
91 TupleTableSlot *
92 ExecFunctionScan(FunctionScanState *node)
93 {
94         /*
95          * use FunctionNext as access method
96          */
97         return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
98 }
99
100 /* ----------------------------------------------------------------
101  *              ExecInitFunctionScan
102  * ----------------------------------------------------------------
103  */
104 FunctionScanState *
105 ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
106 {
107         FunctionScanState *scanstate;
108         Oid                     funcrettype;
109         TypeFuncClass functypclass;
110         TupleDesc       tupdesc = NULL;
111
112         /* check for unsupported flags */
113         Assert(!(eflags & EXEC_FLAG_MARK));
114
115         /*
116          * FunctionScan should not have any children.
117          */
118         Assert(outerPlan(node) == NULL);
119         Assert(innerPlan(node) == NULL);
120
121         /*
122          * create new ScanState for node
123          */
124         scanstate = makeNode(FunctionScanState);
125         scanstate->ss.ps.plan = (Plan *) node;
126         scanstate->ss.ps.state = estate;
127         scanstate->eflags = eflags;
128
129         /*
130          * Miscellaneous initialization
131          *
132          * create expression context for node
133          */
134         ExecAssignExprContext(estate, &scanstate->ss.ps);
135
136 #define FUNCTIONSCAN_NSLOTS 2
137
138         /*
139          * tuple table initialization
140          */
141         ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
142         ExecInitScanTupleSlot(estate, &scanstate->ss);
143
144         /*
145          * initialize child expressions
146          */
147         scanstate->ss.ps.targetlist = (List *)
148                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
149                                          (PlanState *) scanstate);
150         scanstate->ss.ps.qual = (List *)
151                 ExecInitExpr((Expr *) node->scan.plan.qual,
152                                          (PlanState *) scanstate);
153
154         /*
155          * Now determine if the function returns a simple or composite type, and
156          * build an appropriate tupdesc.
157          */
158         functypclass = get_expr_result_type(node->funcexpr,
159                                                                                 &funcrettype,
160                                                                                 &tupdesc);
161
162         if (functypclass == TYPEFUNC_COMPOSITE)
163         {
164                 /* Composite data type, e.g. a table's row type */
165                 Assert(tupdesc);
166                 /* Must copy it out of typcache for safety */
167                 tupdesc = CreateTupleDescCopy(tupdesc);
168         }
169         else if (functypclass == TYPEFUNC_SCALAR)
170         {
171                 /* Base data type, i.e. scalar */
172                 char       *attname = strVal(linitial(node->funccolnames));
173
174                 tupdesc = CreateTemplateTupleDesc(1, false);
175                 TupleDescInitEntry(tupdesc,
176                                                    (AttrNumber) 1,
177                                                    attname,
178                                                    funcrettype,
179                                                    -1,
180                                                    0);
181         }
182         else if (functypclass == TYPEFUNC_RECORD)
183         {
184                 tupdesc = BuildDescFromLists(node->funccolnames,
185                                                                          node->funccoltypes,
186                                                                          node->funccoltypmods);
187         }
188         else
189         {
190                 /* crummy error message, but parser should have caught this */
191                 elog(ERROR, "function in FROM has unsupported return type");
192         }
193
194         /*
195          * For RECORD results, make sure a typmod has been assigned.  (The
196          * function should do this for itself, but let's cover things in case it
197          * doesn't.)
198          */
199         BlessTupleDesc(tupdesc);
200
201         scanstate->tupdesc = tupdesc;
202         ExecAssignScanType(&scanstate->ss, tupdesc);
203
204         /*
205          * Other node-specific setup
206          */
207         scanstate->tuplestorestate = NULL;
208         scanstate->funcexpr = ExecInitExpr((Expr *) node->funcexpr,
209                                                                            (PlanState *) scanstate);
210
211         scanstate->ss.ps.ps_TupFromTlist = false;
212
213         /*
214          * Initialize result tuple type and projection info.
215          */
216         ExecAssignResultTypeFromTL(&scanstate->ss.ps);
217         ExecAssignScanProjectionInfo(&scanstate->ss);
218
219         return scanstate;
220 }
221
222 int
223 ExecCountSlotsFunctionScan(FunctionScan *node)
224 {
225         return ExecCountSlotsNode(outerPlan(node)) +
226                 ExecCountSlotsNode(innerPlan(node)) +
227                 FUNCTIONSCAN_NSLOTS;
228 }
229
230 /* ----------------------------------------------------------------
231  *              ExecEndFunctionScan
232  *
233  *              frees any storage allocated through C routines.
234  * ----------------------------------------------------------------
235  */
236 void
237 ExecEndFunctionScan(FunctionScanState *node)
238 {
239         /*
240          * Free the exprcontext
241          */
242         ExecFreeExprContext(&node->ss.ps);
243
244         /*
245          * clean out the tuple table
246          */
247         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
248         ExecClearTuple(node->ss.ss_ScanTupleSlot);
249
250         /*
251          * Release tuplestore resources
252          */
253         if (node->tuplestorestate != NULL)
254                 tuplestore_end(node->tuplestorestate);
255         node->tuplestorestate = NULL;
256 }
257
258 /* ----------------------------------------------------------------
259  *              ExecFunctionReScan
260  *
261  *              Rescans the relation.
262  * ----------------------------------------------------------------
263  */
264 void
265 ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
266 {
267         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
268         node->ss.ps.ps_TupFromTlist = false;
269
270         /*
271          * If we haven't materialized yet, just return.
272          */
273         if (!node->tuplestorestate)
274                 return;
275
276         /*
277          * Here we have a choice whether to drop the tuplestore (and recompute the
278          * function outputs) or just rescan it.  We must recompute if the
279          * expression contains parameters, else we rescan.  XXX maybe we should
280          * recompute if the function is volatile?
281          */
282         if (node->ss.ps.chgParam != NULL)
283         {
284                 tuplestore_end(node->tuplestorestate);
285                 node->tuplestorestate = NULL;
286         }
287         else
288                 tuplestore_rescan(node->tuplestorestate);
289 }