1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeFunctions (functions in rangetable).
6 * Portions Copyright (c) 1996-2003, 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.22 2003/09/25 23:02:12 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_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc);
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
89 if (funcTupdesc && !tupledesc_match(node->tupdesc, funcTupdesc))
91 (errcode(ERRCODE_DATATYPE_MISMATCH),
92 errmsg("query-specified return row and actual function return row do not match")));
96 * Get the next tuple from tuplestore. Return NULL if no more tuples.
98 slot = node->ss.ss_ScanTupleSlot;
100 heapTuple = tuplestore_getheaptuple(tuplestorestate,
101 ScanDirectionIsForward(direction),
109 return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
112 /* ----------------------------------------------------------------
113 * ExecFunctionScan(node)
115 * Scans the function sequentially and returns the next qualifying
117 * It calls the ExecScan() routine and passes it the access method
118 * which retrieves tuples sequentially.
123 ExecFunctionScan(FunctionScanState *node)
126 * use FunctionNext as access method
128 return ExecScan(&node->ss, (ExecScanAccessMtd) FunctionNext);
131 /* ----------------------------------------------------------------
132 * ExecInitFunctionScan
133 * ----------------------------------------------------------------
136 ExecInitFunctionScan(FunctionScan *node, EState *estate)
138 FunctionScanState *scanstate;
142 TupleDesc tupdesc = NULL;
145 * FunctionScan should not have any children.
147 Assert(outerPlan(node) == NULL);
148 Assert(innerPlan(node) == NULL);
151 * create new ScanState for node
153 scanstate = makeNode(FunctionScanState);
154 scanstate->ss.ps.plan = (Plan *) node;
155 scanstate->ss.ps.state = estate;
158 * Miscellaneous initialization
160 * create expression context for node
162 ExecAssignExprContext(estate, &scanstate->ss.ps);
164 #define FUNCTIONSCAN_NSLOTS 2
167 * tuple table initialization
169 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
170 ExecInitScanTupleSlot(estate, &scanstate->ss);
173 * initialize child expressions
175 scanstate->ss.ps.targetlist = (List *)
176 ExecInitExpr((Expr *) node->scan.plan.targetlist,
177 (PlanState *) scanstate);
178 scanstate->ss.ps.qual = (List *)
179 ExecInitExpr((Expr *) node->scan.plan.qual,
180 (PlanState *) scanstate);
183 * get info about function
185 rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
186 Assert(rte->rtekind == RTE_FUNCTION);
187 funcrettype = exprType(rte->funcexpr);
190 * Now determine if the function returns a simple or composite type,
191 * and build an appropriate tupdesc.
193 functyptype = get_typtype(funcrettype);
195 if (functyptype == 'c')
198 * Composite data type, i.e. a table's row type
203 funcrelid = typeidTypeRelid(funcrettype);
204 if (!OidIsValid(funcrelid))
205 elog(ERROR, "invalid typrelid for complex type %u",
207 rel = relation_open(funcrelid, AccessShareLock);
208 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
209 relation_close(rel, AccessShareLock);
211 else if (functyptype == 'b' || functyptype == 'd')
214 * Must be a base data type, i.e. scalar
216 char *attname = strVal(lfirst(rte->eref->colnames));
218 tupdesc = CreateTemplateTupleDesc(1, false);
219 TupleDescInitEntry(tupdesc,
227 else if (functyptype == 'p' && funcrettype == RECORDOID)
230 * Must be a pseudo type, i.e. record
232 tupdesc = BuildDescForRelation(rte->coldeflist);
236 /* crummy error message, but parser should have caught this */
237 elog(ERROR, "function in FROM has unsupported return type");
240 scanstate->tupdesc = tupdesc;
241 ExecSetSlotDescriptor(scanstate->ss.ss_ScanTupleSlot,
245 * Other node-specific setup
247 scanstate->tuplestorestate = NULL;
248 scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr,
249 (PlanState *) scanstate);
251 scanstate->ss.ps.ps_TupFromTlist = false;
254 * Initialize result tuple type and projection info.
256 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
257 ExecAssignProjectionInfo(&scanstate->ss.ps);
263 ExecCountSlotsFunctionScan(FunctionScan *node)
265 return ExecCountSlotsNode(outerPlan(node)) +
266 ExecCountSlotsNode(innerPlan(node)) +
270 /* ----------------------------------------------------------------
271 * ExecEndFunctionScan
273 * frees any storage allocated through C routines.
274 * ----------------------------------------------------------------
277 ExecEndFunctionScan(FunctionScanState *node)
280 * Free the exprcontext
282 ExecFreeExprContext(&node->ss.ps);
285 * clean out the tuple table
287 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
288 ExecClearTuple(node->ss.ss_ScanTupleSlot);
291 * Release tuplestore resources
293 if (node->tuplestorestate != NULL)
294 tuplestore_end(node->tuplestorestate);
295 node->tuplestorestate = NULL;
298 /* ----------------------------------------------------------------
299 * ExecFunctionMarkPos
301 * Calls tuplestore to save the current position in the stored file.
302 * ----------------------------------------------------------------
305 ExecFunctionMarkPos(FunctionScanState *node)
308 * if we haven't materialized yet, just return.
310 if (!node->tuplestorestate)
313 tuplestore_markpos(node->tuplestorestate);
316 /* ----------------------------------------------------------------
317 * ExecFunctionRestrPos
319 * Calls tuplestore to restore the last saved file position.
320 * ----------------------------------------------------------------
323 ExecFunctionRestrPos(FunctionScanState *node)
326 * if we haven't materialized yet, just return.
328 if (!node->tuplestorestate)
331 tuplestore_restorepos(node->tuplestorestate);
334 /* ----------------------------------------------------------------
337 * Rescans the relation.
338 * ----------------------------------------------------------------
341 ExecFunctionReScan(FunctionScanState *node, ExprContext *exprCtxt)
343 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
346 * If we haven't materialized yet, just return.
348 if (!node->tuplestorestate)
352 * Here we have a choice whether to drop the tuplestore (and recompute
353 * the function outputs) or just rescan it. This should depend on
354 * whether the function expression contains parameters and/or is
355 * marked volatile. FIXME soon.
357 if (node->ss.ps.chgParam != NULL)
359 tuplestore_end(node->tuplestorestate);
360 node->tuplestorestate = NULL;
363 tuplestore_rescan(node->tuplestorestate);
367 * Check that function result tuple type (src_tupdesc) matches or can be
368 * considered to match what the query expects (dst_tupdesc).
370 * We really only care about number of attributes and data type.
371 * Also, we can ignore type mismatch on columns that are dropped in the
372 * destination type, so long as the physical storage matches. This is
373 * helpful in some cases involving out-of-date cached plans.
376 tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
380 if (dst_tupdesc->natts != src_tupdesc->natts)
383 for (i = 0; i < dst_tupdesc->natts; i++)
385 Form_pg_attribute dattr = dst_tupdesc->attrs[i];
386 Form_pg_attribute sattr = src_tupdesc->attrs[i];
388 if (dattr->atttypid == sattr->atttypid)
389 continue; /* no worries */
390 if (!dattr->attisdropped)
392 if (dattr->attlen != sattr->attlen ||
393 dattr->attalign != sattr->attalign)