1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeFunctions (functions in rangetable).
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.49 2008/10/29 00:00:38 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 "executor/nodeFunctionscan.h"
27 #include "utils/builtins.h"
30 static TupleTableSlot *FunctionNext(FunctionScanState *node);
32 /* ----------------------------------------------------------------
34 * ----------------------------------------------------------------
36 /* ----------------------------------------------------------------
39 * This is a workhorse for ExecFunctionScan
40 * ----------------------------------------------------------------
42 static TupleTableSlot *
43 FunctionNext(FunctionScanState *node)
47 ScanDirection direction;
48 Tuplestorestate *tuplestorestate;
51 * get information from the estate and scan state
53 estate = node->ss.ps.state;
54 direction = estate->es_direction;
56 tuplestorestate = node->tuplestorestate;
59 * If first time through, read all tuples from function and put them in a
60 * tuplestore. Subsequent calls just fetch tuples from tuplestore.
62 if (tuplestorestate == NULL)
64 node->tuplestorestate = tuplestorestate =
65 ExecMakeTableFunctionResult(node->funcexpr,
66 node->ss.ps.ps_ExprContext,
68 node->eflags & EXEC_FLAG_BACKWARD);
72 * Get the next tuple from tuplestore. Return NULL if no more tuples.
74 slot = node->ss.ss_ScanTupleSlot;
75 (void) tuplestore_gettupleslot(tuplestorestate,
76 ScanDirectionIsForward(direction),
81 /* ----------------------------------------------------------------
82 * ExecFunctionScan(node)
84 * Scans the function sequentially and returns the next qualifying
86 * It calls the ExecScan() routine and passes it the access method
87 * which retrieves tuples sequentially.
92 ExecFunctionScan(FunctionScanState *node)
95 * use FunctionNext as access method
97 return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
100 /* ----------------------------------------------------------------
101 * ExecInitFunctionScan
102 * ----------------------------------------------------------------
105 ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
107 FunctionScanState *scanstate;
109 TypeFuncClass functypclass;
110 TupleDesc tupdesc = NULL;
112 /* check for unsupported flags */
113 Assert(!(eflags & EXEC_FLAG_MARK));
116 * FunctionScan should not have any children.
118 Assert(outerPlan(node) == NULL);
119 Assert(innerPlan(node) == NULL);
122 * create new ScanState for node
124 scanstate = makeNode(FunctionScanState);
125 scanstate->ss.ps.plan = (Plan *) node;
126 scanstate->ss.ps.state = estate;
127 scanstate->eflags = eflags;
130 * Miscellaneous initialization
132 * create expression context for node
134 ExecAssignExprContext(estate, &scanstate->ss.ps);
136 #define FUNCTIONSCAN_NSLOTS 2
139 * tuple table initialization
141 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
142 ExecInitScanTupleSlot(estate, &scanstate->ss);
145 * initialize child expressions
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);
155 * Now determine if the function returns a simple or composite type, and
156 * build an appropriate tupdesc.
158 functypclass = get_expr_result_type(node->funcexpr,
162 if (functypclass == TYPEFUNC_COMPOSITE)
164 /* Composite data type, e.g. a table's row type */
166 /* Must copy it out of typcache for safety */
167 tupdesc = CreateTupleDescCopy(tupdesc);
169 else if (functypclass == TYPEFUNC_SCALAR)
171 /* Base data type, i.e. scalar */
172 char *attname = strVal(linitial(node->funccolnames));
174 tupdesc = CreateTemplateTupleDesc(1, false);
175 TupleDescInitEntry(tupdesc,
182 else if (functypclass == TYPEFUNC_RECORD)
184 tupdesc = BuildDescFromLists(node->funccolnames,
186 node->funccoltypmods);
190 /* crummy error message, but parser should have caught this */
191 elog(ERROR, "function in FROM has unsupported return type");
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
199 BlessTupleDesc(tupdesc);
201 scanstate->tupdesc = tupdesc;
202 ExecAssignScanType(&scanstate->ss, tupdesc);
205 * Other node-specific setup
207 scanstate->tuplestorestate = NULL;
208 scanstate->funcexpr = ExecInitExpr((Expr *) node->funcexpr,
209 (PlanState *) scanstate);
211 scanstate->ss.ps.ps_TupFromTlist = false;
214 * Initialize result tuple type and projection info.
216 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
217 ExecAssignScanProjectionInfo(&scanstate->ss);
223 ExecCountSlotsFunctionScan(FunctionScan *node)
225 return ExecCountSlotsNode(outerPlan(node)) +
226 ExecCountSlotsNode(innerPlan(node)) +
230 /* ----------------------------------------------------------------
231 * ExecEndFunctionScan
233 * frees any storage allocated through C routines.
234 * ----------------------------------------------------------------
237 ExecEndFunctionScan(FunctionScanState *node)
240 * Free the exprcontext
242 ExecFreeExprContext(&node->ss.ps);
245 * clean out the tuple table
247 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
248 ExecClearTuple(node->ss.ss_ScanTupleSlot);
251 * Release tuplestore resources
253 if (node->tuplestorestate != NULL)
254 tuplestore_end(node->tuplestorestate);
255 node->tuplestorestate = NULL;
258 /* ----------------------------------------------------------------
261 * Rescans the relation.
262 * ----------------------------------------------------------------
265 ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
267 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
268 node->ss.ps.ps_TupFromTlist = false;
271 * If we haven't materialized yet, just return.
273 if (!node->tuplestorestate)
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?
282 if (node->ss.ps.chgParam != NULL)
284 tuplestore_end(node->tuplestorestate);
285 node->tuplestorestate = NULL;
288 tuplestore_rescan(node->tuplestorestate);