1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeFunctions (functions in rangetable).
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.1 2002/05/12 20:10:02 tgl Exp $
13 *-------------------------------------------------------------------------
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
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"
41 static TupleTableSlot *FunctionNext(FunctionScan *node);
42 static TupleTableSlot *function_getonetuple(TupleTableSlot *slot,
44 ExprContext *econtext,
48 ExprDoneCond *isDone);
49 static FunctionMode get_functionmode(Node *expr);
51 /* ----------------------------------------------------------------
53 * ----------------------------------------------------------------
55 /* ----------------------------------------------------------------
58 * This is a workhorse for ExecFunctionScan
59 * ----------------------------------------------------------------
61 static TupleTableSlot *
62 FunctionNext(FunctionScan *node)
66 ExprContext *econtext;
69 ScanDirection direction;
70 Tuplestorestate *tuplestorestate;
71 FunctionScanState *scanstate;
76 * get information from the estate and scan state
78 scanstate = (FunctionScanState *) node->scan.scanstate;
79 estate = node->scan.plan.state;
80 direction = estate->es_direction;
81 econtext = scanstate->csstate.cstate.cs_ExprContext;
83 tuplestorestate = scanstate->tuplestorestate;
84 tupdesc = scanstate->tupdesc;
85 expr = scanstate->funcexpr;
88 * If first time through, read all tuples from function and pass them to
89 * tuplestore.c. Subsequent calls just fetch tuples from tuplestore.
91 if (tuplestorestate == NULL)
94 * Initialize tuplestore module.
96 tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
99 scanstate->tuplestorestate = (void *) tuplestorestate;
102 * Compute all the function tuples and pass to tuplestore.
110 isDone = ExprSingleResult;
111 slot = function_getonetuple(scanstate->csstate.css_ScanTupleSlot,
112 expr, econtext, tupdesc,
113 scanstate->returnsTuple,
118 tuplestore_puttuple(tuplestorestate, (void *) slot->val);
119 ExecClearTuple(slot);
121 if (isDone != ExprMultipleResult)
126 * Complete the store.
128 tuplestore_donestoring(tuplestorestate);
132 * Get the next tuple from tuplestore. Return NULL if no more tuples.
134 slot = scanstate->csstate.css_ScanTupleSlot;
135 heapTuple = tuplestore_getheaptuple(tuplestorestate,
136 ScanDirectionIsForward(direction),
139 return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
142 /* ----------------------------------------------------------------
143 * ExecFunctionScan(node)
145 * Scans the Function sequentially and returns the next qualifying
147 * It calls the ExecScan() routine and passes it the access method
148 * which retrieve tuples sequentially.
153 ExecFunctionScan(FunctionScan *node)
156 * use FunctionNext as access method
158 return ExecScan(&node->scan, (ExecScanAccessMtd) FunctionNext);
161 /* ----------------------------------------------------------------
162 * ExecInitFunctionScan
163 * ----------------------------------------------------------------
166 ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
168 FunctionScanState *scanstate;
175 * FunctionScan should not have any children.
177 Assert(outerPlan((Plan *) node) == NULL);
178 Assert(innerPlan((Plan *) node) == NULL);
181 * assign the node's execution state
183 node->scan.plan.state = estate;
186 * create new ScanState for node
188 scanstate = makeNode(FunctionScanState);
189 node->scan.scanstate = &scanstate->csstate;
192 * Miscellaneous initialization
194 * create expression context for node
196 ExecAssignExprContext(estate, &scanstate->csstate.cstate);
198 #define FUNCTIONSCAN_NSLOTS 2
201 * tuple table initialization
203 ExecInitResultTupleSlot(estate, &scanstate->csstate.cstate);
204 ExecInitScanTupleSlot(estate, &scanstate->csstate);
207 * get info about function
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);
215 * Build a suitable tupledesc representing the output rows
217 if (OidIsValid(funcrelid))
220 * Composite data type, i.e. a table's row type
221 * Same as ordinary relation RTE
225 rel = relation_open(funcrelid, AccessShareLock);
226 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
227 relation_close(rel, AccessShareLock);
228 scanstate->returnsTuple = true;
233 * Must be a base data type, i.e. scalar
235 char *attname = strVal(lfirst(rte->eref->colnames));
237 tupdesc = CreateTemplateTupleDesc(1);
238 TupleDescInitEntry(tupdesc,
245 scanstate->returnsTuple = false;
247 scanstate->tupdesc = tupdesc;
248 ExecSetSlotDescriptor(scanstate->csstate.css_ScanTupleSlot,
252 * Other node-specific setup
254 scanstate->tuplestorestate = NULL;
255 scanstate->funcexpr = rte->funcexpr;
257 scanstate->functionmode = get_functionmode(rte->funcexpr);
259 scanstate->csstate.cstate.cs_TupFromTlist = false;
262 * initialize tuple type
264 ExecAssignResultTypeFromTL((Plan *) node, &scanstate->csstate.cstate);
265 ExecAssignProjectionInfo((Plan *) node, &scanstate->csstate.cstate);
271 ExecCountSlotsFunctionScan(FunctionScan *node)
273 return ExecCountSlotsNode(outerPlan(node)) +
274 ExecCountSlotsNode(innerPlan(node)) +
278 /* ----------------------------------------------------------------
279 * ExecEndFunctionScan
281 * frees any storage allocated through C routines.
282 * ----------------------------------------------------------------
285 ExecEndFunctionScan(FunctionScan *node)
287 FunctionScanState *scanstate;
291 * get information from node
293 scanstate = (FunctionScanState *) node->scan.scanstate;
294 estate = node->scan.plan.state;
297 * Free the projection info and the scan attribute info
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
303 ExecFreeProjectionInfo(&scanstate->csstate.cstate);
304 ExecFreeExprContext(&scanstate->csstate.cstate);
307 * clean out the tuple table
309 ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
310 ExecClearTuple(scanstate->csstate.css_ScanTupleSlot);
313 * Release tuplestore resources
315 if (scanstate->tuplestorestate != NULL)
316 tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate);
317 scanstate->tuplestorestate = NULL;
320 /* ----------------------------------------------------------------
321 * ExecFunctionMarkPos
323 * Calls tuplestore to save the current position in the stored file.
324 * ----------------------------------------------------------------
327 ExecFunctionMarkPos(FunctionScan *node)
329 FunctionScanState *scanstate;
331 scanstate = (FunctionScanState *) node->scan.scanstate;
334 * if we haven't materialized yet, just return.
336 if (!scanstate->tuplestorestate)
339 tuplestore_markpos((Tuplestorestate *) scanstate->tuplestorestate);
342 /* ----------------------------------------------------------------
343 * ExecFunctionRestrPos
345 * Calls tuplestore to restore the last saved file position.
346 * ----------------------------------------------------------------
349 ExecFunctionRestrPos(FunctionScan *node)
351 FunctionScanState *scanstate;
353 scanstate = (FunctionScanState *) node->scan.scanstate;
356 * if we haven't materialized yet, just return.
358 if (!scanstate->tuplestorestate)
361 tuplestore_restorepos((Tuplestorestate *) scanstate->tuplestorestate);
364 /* ----------------------------------------------------------------
367 * Rescans the relation.
368 * ----------------------------------------------------------------
371 ExecFunctionReScan(FunctionScan *node, ExprContext *exprCtxt, Plan *parent)
373 FunctionScanState *scanstate;
376 * get information from node
378 scanstate = (FunctionScanState *) node->scan.scanstate;
380 ExecClearTuple(scanstate->csstate.cstate.cs_ResultTupleSlot);
383 * If we haven't materialized yet, just return.
385 if (!scanstate->tuplestorestate)
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.
394 if (node->scan.plan.chgParam != NULL)
396 tuplestore_end((Tuplestorestate *) scanstate->tuplestorestate);
397 scanstate->tuplestorestate = NULL;
400 tuplestore_rescan((Tuplestorestate *) scanstate->tuplestorestate);
404 * Run the underlying function to get the next tuple
406 static TupleTableSlot *
407 function_getonetuple(TupleTableSlot *slot,
409 ExprContext *econtext,
413 ExprDoneCond *isDone)
420 * get the next Datum from the function
422 retDatum = ExecEvalExprSwitchContext(expr, econtext, isNull, isDone);
425 * check to see if we're really done
427 if (*isDone == ExprEndResult)
434 * Composite data type, i.e. a table's row type
435 * function returns pointer to tts??
437 slot = (TupleTableSlot *) retDatum;
442 * Must be a base data type, i.e. scalar
443 * turn it into a tuple
445 nullflag = *isNull ? 'n' : ' ';
446 tuple = heap_formtuple(tupdesc, &retDatum, &nullflag);
449 * save the tuple in the scan tuple slot and return the slot.
451 slot = ExecStoreTuple(tuple, /* tuple to store */
452 slot, /* slot to store in */
453 InvalidBuffer, /* buffer associated with
455 true); /* pfree this pointer */
463 get_functionmode(Node *expr)
466 * for the moment, hardwire this
468 return PM_REPEATEDCALL;