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