]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeFunctionscan.c
Adjust ExecMakeTableFunctionResult to produce a single all-nulls row
[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-2004, 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.27 2004/09/22 17:41:51 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 "access/heapam.h"
26 #include "catalog/pg_type.h"
27 #include "executor/execdebug.h"
28 #include "executor/execdefs.h"
29 #include "executor/execdesc.h"
30 #include "executor/nodeFunctionscan.h"
31 #include "parser/parsetree.h"
32 #include "parser/parse_expr.h"
33 #include "parser/parse_type.h"
34 #include "utils/lsyscache.h"
35 #include "utils/typcache.h"
36
37
38 static TupleTableSlot *FunctionNext(FunctionScanState *node);
39 static bool tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
40
41 /* ----------------------------------------------------------------
42  *                                              Scan Support
43  * ----------------------------------------------------------------
44  */
45 /* ----------------------------------------------------------------
46  *              FunctionNext
47  *
48  *              This is a workhorse for ExecFunctionScan
49  * ----------------------------------------------------------------
50  */
51 static TupleTableSlot *
52 FunctionNext(FunctionScanState *node)
53 {
54         TupleTableSlot *slot;
55         EState     *estate;
56         ScanDirection direction;
57         Tuplestorestate *tuplestorestate;
58         bool            should_free;
59         HeapTuple       heapTuple;
60
61         /*
62          * get information from the estate and scan state
63          */
64         estate = node->ss.ps.state;
65         direction = estate->es_direction;
66
67         tuplestorestate = node->tuplestorestate;
68
69         /*
70          * If first time through, read all tuples from function and put them
71          * in a tuplestore. Subsequent calls just fetch tuples from
72          * tuplestore.
73          */
74         if (tuplestorestate == NULL)
75         {
76                 ExprContext *econtext = node->ss.ps.ps_ExprContext;
77                 TupleDesc       funcTupdesc;
78
79                 node->tuplestorestate = tuplestorestate =
80                         ExecMakeTableFunctionResult(node->funcexpr,
81                                                                                 econtext,
82                                                                                 node->tupdesc,
83                                                                                 &funcTupdesc);
84
85                 /*
86                  * If function provided a tupdesc, cross-check it.      We only really
87                  * need to do this for functions returning RECORD, but might as
88                  * well do it always.
89                  */
90                 if (funcTupdesc && !tupledesc_match(node->tupdesc, funcTupdesc))
91                         ereport(ERROR,
92                                         (errcode(ERRCODE_DATATYPE_MISMATCH),
93                                          errmsg("query-specified return row and actual function return row do not match")));
94         }
95
96         /*
97          * Get the next tuple from tuplestore. Return NULL if no more tuples.
98          */
99         heapTuple = tuplestore_getheaptuple(tuplestorestate,
100                                                                                 ScanDirectionIsForward(direction),
101                                                                                 &should_free);
102         slot = node->ss.ss_ScanTupleSlot;
103         return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
104 }
105
106 /* ----------------------------------------------------------------
107  *              ExecFunctionScan(node)
108  *
109  *              Scans the function sequentially and returns the next qualifying
110  *              tuple.
111  *              It calls the ExecScan() routine and passes it the access method
112  *              which retrieves tuples sequentially.
113  *
114  */
115
116 TupleTableSlot *
117 ExecFunctionScan(FunctionScanState *node)
118 {
119         /*
120          * use FunctionNext as access method
121          */
122         return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
123 }
124
125 /* ----------------------------------------------------------------
126  *              ExecInitFunctionScan
127  * ----------------------------------------------------------------
128  */
129 FunctionScanState *
130 ExecInitFunctionScan(FunctionScan *node, EState *estate)
131 {
132         FunctionScanState *scanstate;
133         RangeTblEntry *rte;
134         Oid                     funcrettype;
135         char            functyptype;
136         TupleDesc       tupdesc = NULL;
137
138         /*
139          * FunctionScan should not have any children.
140          */
141         Assert(outerPlan(node) == NULL);
142         Assert(innerPlan(node) == NULL);
143
144         /*
145          * create new ScanState for node
146          */
147         scanstate = makeNode(FunctionScanState);
148         scanstate->ss.ps.plan = (Plan *) node;
149         scanstate->ss.ps.state = estate;
150
151         /*
152          * Miscellaneous initialization
153          *
154          * create expression context for node
155          */
156         ExecAssignExprContext(estate, &scanstate->ss.ps);
157
158 #define FUNCTIONSCAN_NSLOTS 2
159
160         /*
161          * tuple table initialization
162          */
163         ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
164         ExecInitScanTupleSlot(estate, &scanstate->ss);
165
166         /*
167          * initialize child expressions
168          */
169         scanstate->ss.ps.targetlist = (List *)
170                 ExecInitExpr((Expr *) node->scan.plan.targetlist,
171                                          (PlanState *) scanstate);
172         scanstate->ss.ps.qual = (List *)
173                 ExecInitExpr((Expr *) node->scan.plan.qual,
174                                          (PlanState *) scanstate);
175
176         /*
177          * get info about function
178          */
179         rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
180         Assert(rte->rtekind == RTE_FUNCTION);
181         funcrettype = exprType(rte->funcexpr);
182
183         /*
184          * Now determine if the function returns a simple or composite type,
185          * and build an appropriate tupdesc.
186          */
187         functyptype = get_typtype(funcrettype);
188
189         if (functyptype == 'c')
190         {
191                 /* Composite data type, e.g. a table's row type */
192                 tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(funcrettype, -1));
193         }
194         else if (functyptype == 'b' || functyptype == 'd')
195         {
196                 /* Must be a base data type, i.e. scalar */
197                 char       *attname = strVal(linitial(rte->eref->colnames));
198
199                 tupdesc = CreateTemplateTupleDesc(1, false);
200                 TupleDescInitEntry(tupdesc,
201                                                    (AttrNumber) 1,
202                                                    attname,
203                                                    funcrettype,
204                                                    -1,
205                                                    0);
206         }
207         else if (funcrettype == RECORDOID)
208         {
209                 /* Must be a pseudo type, i.e. record */
210                 tupdesc = BuildDescForRelation(rte->coldeflist);
211         }
212         else
213         {
214                 /* crummy error message, but parser should have caught this */
215                 elog(ERROR, "function in FROM has unsupported return type");
216         }
217
218         /*
219          * For RECORD results, make sure a typmod has been assigned.  (The
220          * function should do this for itself, but let's cover things in case
221          * it doesn't.)
222          */
223         if (tupdesc->tdtypeid == RECORDOID && tupdesc->tdtypmod < 0)
224                 assign_record_type_typmod(tupdesc);
225
226         scanstate->tupdesc = tupdesc;
227         ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
228                                                   tupdesc, false);
229
230         /*
231          * Other node-specific setup
232          */
233         scanstate->tuplestorestate = NULL;
234         scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr,
235                                                                            (PlanState *) scanstate);
236
237         scanstate->ss.ps.ps_TupFromTlist = false;
238
239         /*
240          * Initialize result tuple type and projection info.
241          */
242         ExecAssignResultTypeFromTL(&scanstate->ss.ps);
243         ExecAssignProjectionInfo(&scanstate->ss.ps);
244
245         return scanstate;
246 }
247
248 int
249 ExecCountSlotsFunctionScan(FunctionScan *node)
250 {
251         return ExecCountSlotsNode(outerPlan(node)) +
252                 ExecCountSlotsNode(innerPlan(node)) +
253                 FUNCTIONSCAN_NSLOTS;
254 }
255
256 /* ----------------------------------------------------------------
257  *              ExecEndFunctionScan
258  *
259  *              frees any storage allocated through C routines.
260  * ----------------------------------------------------------------
261  */
262 void
263 ExecEndFunctionScan(FunctionScanState *node)
264 {
265         /*
266          * Free the exprcontext
267          */
268         ExecFreeExprContext(&node->ss.ps);
269
270         /*
271          * clean out the tuple table
272          */
273         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
274         ExecClearTuple(node->ss.ss_ScanTupleSlot);
275
276         /*
277          * Release tuplestore resources
278          */
279         if (node->tuplestorestate != NULL)
280                 tuplestore_end(node->tuplestorestate);
281         node->tuplestorestate = NULL;
282 }
283
284 /* ----------------------------------------------------------------
285  *              ExecFunctionMarkPos
286  *
287  *              Calls tuplestore to save the current position in the stored file.
288  * ----------------------------------------------------------------
289  */
290 void
291 ExecFunctionMarkPos(FunctionScanState *node)
292 {
293         /*
294          * if we haven't materialized yet, just return.
295          */
296         if (!node->tuplestorestate)
297                 return;
298
299         tuplestore_markpos(node->tuplestorestate);
300 }
301
302 /* ----------------------------------------------------------------
303  *              ExecFunctionRestrPos
304  *
305  *              Calls tuplestore to restore the last saved file position.
306  * ----------------------------------------------------------------
307  */
308 void
309 ExecFunctionRestrPos(FunctionScanState *node)
310 {
311         /*
312          * if we haven't materialized yet, just return.
313          */
314         if (!node->tuplestorestate)
315                 return;
316
317         tuplestore_restorepos(node->tuplestorestate);
318 }
319
320 /* ----------------------------------------------------------------
321  *              ExecFunctionReScan
322  *
323  *              Rescans the relation.
324  * ----------------------------------------------------------------
325  */
326 void
327 ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
328 {
329         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
330
331         /*
332          * If we haven't materialized yet, just return.
333          */
334         if (!node->tuplestorestate)
335                 return;
336
337         /*
338          * Here we have a choice whether to drop the tuplestore (and recompute
339          * the function outputs) or just rescan it.  This should depend on
340          * whether the function expression contains parameters and/or is
341          * marked volatile.  FIXME soon.
342          */
343         if (node->ss.ps.chgParam != NULL)
344         {
345                 tuplestore_end(node->tuplestorestate);
346                 node->tuplestorestate = NULL;
347         }
348         else
349                 tuplestore_rescan(node->tuplestorestate);
350 }
351
352 /*
353  * Check that function result tuple type (src_tupdesc) matches or can be
354  * considered to match what the query expects (dst_tupdesc).
355  *
356  * We really only care about number of attributes and data type.
357  * Also, we can ignore type mismatch on columns that are dropped in the
358  * destination type, so long as the physical storage matches.  This is
359  * helpful in some cases involving out-of-date cached plans.
360  */
361 static bool
362 tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
363 {
364         int                     i;
365
366         if (dst_tupdesc->natts != src_tupdesc->natts)
367                 return false;
368
369         for (i = 0; i < dst_tupdesc->natts; i++)
370         {
371                 Form_pg_attribute dattr = dst_tupdesc->attrs[i];
372                 Form_pg_attribute sattr = src_tupdesc->attrs[i];
373
374                 if (dattr->atttypid == sattr->atttypid)
375                         continue;                       /* no worries */
376                 if (!dattr->attisdropped)
377                         return false;
378                 if (dattr->attlen != sattr->attlen ||
379                         dattr->attalign != sattr->attalign)
380                         return false;
381         }
382
383         return true;
384 }