]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeFunctionscan.c
First pass at set-returning-functions in FROM, by Joe Conway with
[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-2001, 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.1 2002/05/12 20:10:02 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 "miscadmin.h"
26 #include "access/heapam.h"
27 #include "catalog/pg_type.h"
28 #include "executor/execdebug.h"
29 #include "executor/execdefs.h"
30 #include "executor/execdesc.h"
31 #include "executor/nodeFunctionscan.h"
32 #include "parser/parsetree.h"
33 #include "parser/parse_expr.h"
34 #include "parser/parse_type.h"
35 #include "storage/lmgr.h"
36 #include "tcop/pquery.h"
37 #include "utils/lsyscache.h"
38 #include "utils/syscache.h"
39 #include "utils/tuplestore.h"
40
41 static TupleTableSlot *FunctionNext(FunctionScan *node);
42 static TupleTableSlot *function_getonetuple(TupleTableSlot *slot,
43                                                                                         Node *expr,
44                                                                                         ExprContext *econtext,
45                                                                                         TupleDesc tupdesc,
46                                                                                         bool returnsTuple,
47                                                                                         bool *isNull,
48                                                                                         ExprDoneCond *isDone);
49 static FunctionMode get_functionmode(Node *expr);
50
51 /* ----------------------------------------------------------------
52  *                                              Scan Support
53  * ----------------------------------------------------------------
54  */
55 /* ----------------------------------------------------------------
56  *              FunctionNext
57  *
58  *              This is a workhorse for ExecFunctionScan
59  * ----------------------------------------------------------------
60  */
61 static TupleTableSlot *
62 FunctionNext(FunctionScan *node)
63 {
64         TupleTableSlot     *slot;
65         Node                       *expr;
66         ExprContext                *econtext;
67         TupleDesc                       tupdesc;
68         EState                     *estate;
69         ScanDirection           direction;
70         Tuplestorestate    *tuplestorestate;
71         FunctionScanState  *scanstate;
72         bool                            should_free;
73         HeapTuple                       heapTuple;
74
75         /*
76          * get information from the estate and scan state
77          */
78         scanstate = (FunctionScanState *) node->scan.scanstate;
79         estate = node->scan.plan.state;
80         direction = estate->es_direction;
81         econtext = scanstate->csstate.cstate.cs_ExprContext;
82
83         tuplestorestate = scanstate->tuplestorestate;
84         tupdesc = scanstate->tupdesc;
85         expr = scanstate->funcexpr;
86
87         /*
88          * If first time through, read all tuples from function and pass them to
89          * tuplestore.c. Subsequent calls just fetch tuples from tuplestore.
90          */
91         if (tuplestorestate == NULL)
92         {
93                 /*
94                  * Initialize tuplestore module.
95                  */
96                 tuplestorestate = tuplestore_begin_heap(true,   /* randomAccess */
97                                                                                                 SortMem);
98
99                 scanstate->tuplestorestate = (void *) tuplestorestate;
100
101                 /*
102                  * Compute all the function tuples and pass to tuplestore.
103                  */
104                 for (;;)
105                 {
106                         bool                            isNull;
107                         ExprDoneCond            isDone;
108
109                         isNull = false;
110                         isDone = ExprSingleResult;
111                         slot = function_getonetuple(scanstate->csstate.css_ScanTupleSlot,
112                                                                                 expr, econtext, tupdesc,
113                                                                                 scanstate->returnsTuple,
114                                                                                 &isNull, &isDone);
115                         if (TupIsNull(slot))
116                                 break;
117
118                         tuplestore_puttuple(tuplestorestate, (void *) slot->val);
119                         ExecClearTuple(slot);
120
121                         if (isDone != ExprMultipleResult)
122                                 break;
123                 }
124
125                 /*
126                  * Complete the store.
127                  */
128                 tuplestore_donestoring(tuplestorestate);
129         }
130
131         /*
132          * Get the next tuple from tuplestore. Return NULL if no more tuples.
133          */
134         slot = scanstate->csstate.css_ScanTupleSlot;
135         heapTuple = tuplestore_getheaptuple(tuplestorestate,
136                                                                                 ScanDirectionIsForward(direction),
137                                                                                 &should_free);
138
139         return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
140 }
141
142 /* ----------------------------------------------------------------
143  *              ExecFunctionScan(node)
144  *
145  *              Scans the Function sequentially and returns the next qualifying
146  *              tuple.
147  *              It calls the ExecScan() routine and passes it the access method
148  *              which retrieve tuples sequentially.
149  *
150  */
151
152 TupleTableSlot *
153 ExecFunctionScan(FunctionScan *node)
154 {
155         /*
156          * use FunctionNext as access method
157          */
158         return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext);
159 }
160
161 /* ----------------------------------------------------------------
162  *              ExecInitFunctionScan
163  * ----------------------------------------------------------------
164  */
165 bool
166 ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
167 {
168         FunctionScanState  *scanstate;
169         RangeTblEntry      *rte;
170         Oid                                     funcrettype;
171         Oid                                     funcrelid;
172         TupleDesc                       tupdesc;
173
174         /*
175          * FunctionScan should not have any children.
176          */
177         Assert(outerPlan((Plan *) node) == NULL);
178         Assert(innerPlan((Plan *) node) == NULL);
179
180         /*
181          * assign the node's execution state
182          */
183         node->scan.plan.state = estate;
184
185         /*
186          * create new ScanState for node
187          */
188         scanstate = makeNode(FunctionScanState);
189         node->scan.scanstate = &scanstate->csstate;
190
191         /*
192          * Miscellaneous initialization
193          *
194          * create expression context for node
195          */
196         ExecAssignExprContext(estate, &scanstate->csstate.cstate);
197
198 #define FUNCTIONSCAN_NSLOTS 2
199
200         /*
201          * tuple table initialization
202          */
203         ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate);
204         ExecInitScanTupleSlot(estate, &scanstate->csstate);
205
206         /*
207          * get info about function
208          */
209         rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
210         Assert(rte->rtekind == RTE_FUNCTION);
211         funcrettype = exprType(rte->funcexpr);
212         funcrelid = typeidTypeRelid(funcrettype);
213
214         /*
215          * Build a suitable tupledesc representing the output rows
216          */
217         if (OidIsValid(funcrelid))
218         {
219                 /*
220                  * Composite data type, i.e. a table's row type
221                  * Same as ordinary relation RTE
222                  */
223                 Relation        rel;
224
225                 rel = relation_open(funcrelid, AccessShareLock);
226                 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
227                 relation_close(rel, AccessShareLock);
228                 scanstate->returnsTuple = true;
229         }
230         else
231         {
232                 /*
233                  * Must be a base data type, i.e. scalar
234                  */
235                 char       *attname = strVal(lfirst(rte->eref->colnames));
236
237                 tupdesc = CreateTemplateTupleDesc(1);
238                 TupleDescInitEntry(tupdesc,
239                                                    (AttrNumber) 1,
240                                                    attname,
241                                                    funcrettype,
242                                                    -1,
243                                                    0,
244                                                    false);
245                 scanstate->returnsTuple = false;
246         }
247         scanstate->tupdesc = tupdesc;
248         ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot,
249                                                   tupdesc, false);
250
251         /*
252          * Other node-specific setup
253          */
254         scanstate->tuplestorestate = NULL;
255         scanstate->funcexpr = rte->funcexpr;
256
257         scanstate->functionmode = get_functionmode(rte->funcexpr);
258
259         scanstate->csstate.cstate.cs_TupFromTlist = false;
260
261         /*
262          * initialize tuple type
263          */
264         ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate);
265         ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate);
266
267         return TRUE;
268 }
269
270 int
271 ExecCountSlotsFunctionScan(FunctionScan *node)
272 {
273         return ExecCountSlotsNode(outerPlan(node)) +
274                 ExecCountSlotsNode(innerPlan(node)) +
275                 FUNCTIONSCAN_NSLOTS;
276 }
277
278 /* ----------------------------------------------------------------
279  *              ExecEndFunctionScan
280  *
281  *              frees any storage allocated through C routines.
282  * ----------------------------------------------------------------
283  */
284 void
285 ExecEndFunctionScan(FunctionScan *node)
286 {
287         FunctionScanState  *scanstate;
288         EState                     *estate;
289
290         /*
291          * get information from node
292          */
293         scanstate = (FunctionScanState *) node->scan.scanstate;
294         estate = node->scan.plan.state;
295
296         /*
297          * Free the projection info and the scan attribute info
298          *
299          * Note: we don't ExecFreeResultType(scanstate) because the rule manager
300          * depends on the tupType returned by ExecMain().  So for now, this is
301          * freed at end-transaction time.  -cim 6/2/91
302          */
303         ExecFreeProjectionInfo(&scanstate->csstate.cstate);
304         ExecFreeExprContext(&scanstate->csstate.cstate);
305
306         /*
307          * clean out the tuple table
308          */
309         ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
310         ExecClearTuple(scanstate->csstate.css_ScanTupleSlot);
311
312         /*
313          * Release tuplestore resources
314          */
315         if (scanstate->tuplestorestate != NULL)
316                 tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate);
317         scanstate->tuplestorestate = NULL;
318 }
319
320 /* ----------------------------------------------------------------
321  *              ExecFunctionMarkPos
322  *
323  *              Calls tuplestore to save the current position in the stored file.
324  * ----------------------------------------------------------------
325  */
326 void
327 ExecFunctionMarkPos(FunctionScan *node)
328 {
329         FunctionScanState  *scanstate;
330
331         scanstate = (FunctionScanState *) node->scan.scanstate;
332
333         /*
334          * if we haven't materialized yet, just return.
335          */
336         if (!scanstate->tuplestorestate)
337                 return;
338
339         tuplestore_markpos((Tuplestorestate *) scanstate->tuplestorestate);
340 }
341
342 /* ----------------------------------------------------------------
343  *              ExecFunctionRestrPos
344  *
345  *              Calls tuplestore to restore the last saved file position.
346  * ----------------------------------------------------------------
347  */
348 void
349 ExecFunctionRestrPos(FunctionScan *node)
350 {
351         FunctionScanState  *scanstate;
352
353         scanstate = (FunctionScanState *) node->scan.scanstate;
354
355         /*
356          * if we haven't materialized yet, just return.
357          */
358         if (!scanstate->tuplestorestate)
359                 return;
360
361         tuplestore_restorepos((Tuplestorestate *) scanstate->tuplestorestate);
362 }
363
364 /* ----------------------------------------------------------------
365  *              ExecFunctionReScan
366  *
367  *              Rescans the relation.
368  * ----------------------------------------------------------------
369  */
370 void
371 ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
372 {
373         FunctionScanState  *scanstate;
374
375         /*
376          * get information from node
377          */
378         scanstate = (FunctionScanState *) node->scan.scanstate;
379
380         ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
381
382         /*
383          * If we haven't materialized yet, just return.
384          */
385         if (!scanstate->tuplestorestate)
386                 return;
387
388         /*
389          * Here we have a choice whether to drop the tuplestore (and recompute
390          * the function outputs) or just rescan it.  This should depend on
391          * whether the function expression contains parameters and/or is
392          * marked volatile.  FIXME soon.
393          */
394         if (node->scan.plan.chgParam != NULL)
395         {
396                 tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate);
397                 scanstate->tuplestorestate = NULL;
398         }
399         else
400                 tuplestore_rescan((Tuplestorestate *) scanstate->tuplestorestate);
401 }
402
403 /*
404  * Run the underlying function to get the next tuple
405  */
406 static TupleTableSlot *
407 function_getonetuple(TupleTableSlot *slot,
408                                          Node *expr,
409                                          ExprContext *econtext,
410                                          TupleDesc tupdesc,
411                                          bool returnsTuple,
412                                          bool *isNull,
413                                          ExprDoneCond *isDone)
414 {
415         HeapTuple                       tuple;
416         Datum                           retDatum;
417         char                            nullflag;
418
419         /*
420          * get the next Datum from the function
421          */
422         retDatum = ExecEvalExprSwitchContext(expr, econtext, isNull, isDone);
423
424         /*
425          * check to see if we're really done
426          */
427         if (*isDone == ExprEndResult)
428                 slot = NULL;
429         else
430         {
431                 if (returnsTuple)
432                 {
433                         /*
434                          * Composite data type, i.e. a table's row type
435                          * function returns pointer to tts??
436                          */
437                         slot = (TupleTableSlot *) retDatum;
438                 }
439                 else
440                 {
441                         /*
442                          * Must be a base data type, i.e. scalar
443                          * turn it into a tuple
444                          */
445                         nullflag = *isNull ? 'n' : ' ';
446                         tuple = heap_formtuple(tupdesc, &retDatum, &nullflag);
447
448                         /*
449                          * save the tuple in the scan tuple slot and return the slot.
450                          */
451                         slot = ExecStoreTuple(tuple,                    /* tuple to store */
452                                                                   slot,                         /* slot to store in */
453                                                                   InvalidBuffer,        /* buffer associated with
454                                                                                                          * this tuple */
455                                                                   true);                        /* pfree this pointer */
456                 }
457         }
458
459         return slot;
460 }
461
462 static FunctionMode
463 get_functionmode(Node *expr)
464 {
465         /*
466          * for the moment, hardwire this
467          */
468         return PM_REPEATEDCALL;
469 }