1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeFunctions (functions in rangetable).
6 * Portions Copyright (c) 1996-2002, 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.16 2002/12/15 16:17:46 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 "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"
37 static TupleTableSlot *FunctionNext(FunctionScanState *node);
38 static bool tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2);
40 /* ----------------------------------------------------------------
42 * ----------------------------------------------------------------
44 /* ----------------------------------------------------------------
47 * This is a workhorse for ExecFunctionScan
48 * ----------------------------------------------------------------
50 static TupleTableSlot *
51 FunctionNext(FunctionScanState *node)
55 ScanDirection direction;
56 Tuplestorestate *tuplestorestate;
61 * get information from the estate and scan state
63 estate = node->ss.ps.state;
64 direction = estate->es_direction;
66 tuplestorestate = node->tuplestorestate;
69 * If first time through, read all tuples from function and put them
70 * in a tuplestore. Subsequent calls just fetch tuples from
73 if (tuplestorestate == NULL)
75 ExprContext *econtext = node->ss.ps.ps_ExprContext;
76 TupleDesc funcTupdesc;
78 node->tuplestorestate = tuplestorestate =
79 ExecMakeTableFunctionResult(node->funcexpr,
85 * If function provided a tupdesc, cross-check it. We only really
86 * need to do this for functions returning RECORD, but might as
90 tupledesc_mismatch(node->tupdesc, funcTupdesc))
91 elog(ERROR, "Query-specified return tuple and actual function return tuple do not match");
95 * Get the next tuple from tuplestore. Return NULL if no more tuples.
97 slot = node->ss.ss_ScanTupleSlot;
99 heapTuple = tuplestore_getheaptuple(tuplestorestate,
100 ScanDirectionIsForward(direction),
108 return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
111 /* ----------------------------------------------------------------
112 * ExecFunctionScan(node)
114 * Scans the function sequentially and returns the next qualifying
116 * It calls the ExecScan() routine and passes it the access method
117 * which retrieves tuples sequentially.
122 ExecFunctionScan(FunctionScanState *node)
125 * use FunctionNext as access method
127 return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
130 /* ----------------------------------------------------------------
131 * ExecInitFunctionScan
132 * ----------------------------------------------------------------
135 ExecInitFunctionScan(FunctionScan *node, EState *estate)
137 FunctionScanState *scanstate;
141 TupleDesc tupdesc = NULL;
144 * FunctionScan should not have any children.
146 Assert(outerPlan(node) == NULL);
147 Assert(innerPlan(node) == NULL);
150 * create new ScanState for node
152 scanstate = makeNode(FunctionScanState);
153 scanstate->ss.ps.plan = (Plan *) node;
154 scanstate->ss.ps.state = estate;
157 * Miscellaneous initialization
159 * create expression context for node
161 ExecAssignExprContext(estate, &scanstate->ss.ps);
163 #define FUNCTIONSCAN_NSLOTS 2
166 * tuple table initialization
168 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
169 ExecInitScanTupleSlot(estate, &scanstate->ss);
172 * initialize child expressions
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);
182 * get info about function
184 rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
185 Assert(rte->rtekind == RTE_FUNCTION);
186 funcrettype = exprType(rte->funcexpr);
189 * Now determine if the function returns a simple or composite type,
190 * and build an appropriate tupdesc.
192 functyptype = get_typtype(funcrettype);
194 if (functyptype == 'c')
197 * Composite data type, i.e. a table's row type
202 funcrelid = typeidTypeRelid(funcrettype);
203 if (!OidIsValid(funcrelid))
204 elog(ERROR, "Invalid typrelid for complex type %u",
206 rel = relation_open(funcrelid, AccessShareLock);
207 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
208 relation_close(rel, AccessShareLock);
210 else if (functyptype == 'b' || functyptype == 'd')
213 * Must be a base data type, i.e. scalar
215 char *attname = strVal(lfirst(rte->eref->colnames));
217 tupdesc = CreateTemplateTupleDesc(1, false);
218 TupleDescInitEntry(tupdesc,
226 else if (functyptype == 'p' && funcrettype == RECORDOID)
229 * Must be a pseudo type, i.e. record
231 tupdesc = BuildDescForRelation(rte->coldeflist);
234 elog(ERROR, "Unknown kind of return type specified for function");
236 scanstate->tupdesc = tupdesc;
237 ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
241 * Other node-specific setup
243 scanstate->tuplestorestate = NULL;
244 scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr,
245 (PlanState *) scanstate);
247 scanstate->ss.ps.ps_TupFromTlist = false;
250 * initialize tuple type
252 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
253 ExecAssignProjectionInfo(&scanstate->ss.ps);
259 ExecCountSlotsFunctionScan(FunctionScan *node)
261 return ExecCountSlotsNode(outerPlan(node)) +
262 ExecCountSlotsNode(innerPlan(node)) +
266 /* ----------------------------------------------------------------
267 * ExecEndFunctionScan
269 * frees any storage allocated through C routines.
270 * ----------------------------------------------------------------
273 ExecEndFunctionScan(FunctionScanState *node)
276 * Free the exprcontext
278 ExecFreeExprContext(&node->ss.ps);
281 * clean out the tuple table
283 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
284 ExecClearTuple(node->ss.ss_ScanTupleSlot);
287 * Release tuplestore resources
289 if (node->tuplestorestate != NULL)
290 tuplestore_end(node->tuplestorestate);
291 node->tuplestorestate = NULL;
294 /* ----------------------------------------------------------------
295 * ExecFunctionMarkPos
297 * Calls tuplestore to save the current position in the stored file.
298 * ----------------------------------------------------------------
301 ExecFunctionMarkPos(FunctionScanState *node)
304 * if we haven't materialized yet, just return.
306 if (!node->tuplestorestate)
309 tuplestore_markpos(node->tuplestorestate);
312 /* ----------------------------------------------------------------
313 * ExecFunctionRestrPos
315 * Calls tuplestore to restore the last saved file position.
316 * ----------------------------------------------------------------
319 ExecFunctionRestrPos(FunctionScanState *node)
322 * if we haven't materialized yet, just return.
324 if (!node->tuplestorestate)
327 tuplestore_restorepos(node->tuplestorestate);
330 /* ----------------------------------------------------------------
333 * Rescans the relation.
334 * ----------------------------------------------------------------
337 ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
339 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
342 * If we haven't materialized yet, just return.
344 if (!node->tuplestorestate)
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.
353 if (node->ss.ps.chgParam != NULL)
355 tuplestore_end(node->tuplestorestate);
356 node->tuplestorestate = NULL;
359 tuplestore_rescan(node->tuplestorestate);
364 tupledesc_mismatch(TupleDesc tupdesc1, TupleDesc tupdesc2)
368 if (tupdesc1->natts != tupdesc2->natts)
371 for (i = 0; i < tupdesc1->natts; i++)
373 Form_pg_attribute attr1 = tupdesc1->attrs[i];
374 Form_pg_attribute attr2 = tupdesc2->attrs[i];
377 * We really only care about number of attributes and data type
379 if (attr1->atttypid != attr2->atttypid)