1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeFunctions (functions in rangetable).
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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
),
82 /* ----------------------------------------------------------------
83 * ExecFunctionScan(node)
85 * Scans the function sequentially and returns the next qualifying
87 * It calls the ExecScan() routine and passes it the access method
88 * which retrieves tuples sequentially.
93 ExecFunctionScan(FunctionScanState
*node
)
96 * use FunctionNext as access method
98 return ExecScan(&node
->ss
, (ExecScanAccessMtd
) FunctionNext
);
101 /* ----------------------------------------------------------------
102 * ExecInitFunctionScan
103 * ----------------------------------------------------------------
106 ExecInitFunctionScan(FunctionScan
*node
, EState
*estate
, int eflags
)
108 FunctionScanState
*scanstate
;
110 TypeFuncClass functypclass
;
111 TupleDesc tupdesc
= NULL
;
113 /* check for unsupported flags */
114 Assert(!(eflags
& EXEC_FLAG_MARK
));
117 * FunctionScan should not have any children.
119 Assert(outerPlan(node
) == NULL
);
120 Assert(innerPlan(node
) == NULL
);
123 * create new ScanState for node
125 scanstate
= makeNode(FunctionScanState
);
126 scanstate
->ss
.ps
.plan
= (Plan
*) node
;
127 scanstate
->ss
.ps
.state
= estate
;
128 scanstate
->eflags
= eflags
;
131 * Miscellaneous initialization
133 * create expression context for node
135 ExecAssignExprContext(estate
, &scanstate
->ss
.ps
);
137 #define FUNCTIONSCAN_NSLOTS 2
140 * tuple table initialization
142 ExecInitResultTupleSlot(estate
, &scanstate
->ss
.ps
);
143 ExecInitScanTupleSlot(estate
, &scanstate
->ss
);
146 * initialize child expressions
148 scanstate
->ss
.ps
.targetlist
= (List
*)
149 ExecInitExpr((Expr
*) node
->scan
.plan
.targetlist
,
150 (PlanState
*) scanstate
);
151 scanstate
->ss
.ps
.qual
= (List
*)
152 ExecInitExpr((Expr
*) node
->scan
.plan
.qual
,
153 (PlanState
*) scanstate
);
156 * Now determine if the function returns a simple or composite type, and
157 * build an appropriate tupdesc.
159 functypclass
= get_expr_result_type(node
->funcexpr
,
163 if (functypclass
== TYPEFUNC_COMPOSITE
)
165 /* Composite data type, e.g. a table's row type */
167 /* Must copy it out of typcache for safety */
168 tupdesc
= CreateTupleDescCopy(tupdesc
);
170 else if (functypclass
== TYPEFUNC_SCALAR
)
172 /* Base data type, i.e. scalar */
173 char *attname
= strVal(linitial(node
->funccolnames
));
175 tupdesc
= CreateTemplateTupleDesc(1, false);
176 TupleDescInitEntry(tupdesc
,
183 else if (functypclass
== TYPEFUNC_RECORD
)
185 tupdesc
= BuildDescFromLists(node
->funccolnames
,
187 node
->funccoltypmods
);
191 /* crummy error message, but parser should have caught this */
192 elog(ERROR
, "function in FROM has unsupported return type");
196 * For RECORD results, make sure a typmod has been assigned. (The
197 * function should do this for itself, but let's cover things in case it
200 BlessTupleDesc(tupdesc
);
202 scanstate
->tupdesc
= tupdesc
;
203 ExecAssignScanType(&scanstate
->ss
, tupdesc
);
206 * Other node-specific setup
208 scanstate
->tuplestorestate
= NULL
;
209 scanstate
->funcexpr
= ExecInitExpr((Expr
*) node
->funcexpr
,
210 (PlanState
*) scanstate
);
212 scanstate
->ss
.ps
.ps_TupFromTlist
= false;
215 * Initialize result tuple type and projection info.
217 ExecAssignResultTypeFromTL(&scanstate
->ss
.ps
);
218 ExecAssignScanProjectionInfo(&scanstate
->ss
);
224 ExecCountSlotsFunctionScan(FunctionScan
*node
)
226 return ExecCountSlotsNode(outerPlan(node
)) +
227 ExecCountSlotsNode(innerPlan(node
)) +
231 /* ----------------------------------------------------------------
232 * ExecEndFunctionScan
234 * frees any storage allocated through C routines.
235 * ----------------------------------------------------------------
238 ExecEndFunctionScan(FunctionScanState
*node
)
241 * Free the exprcontext
243 ExecFreeExprContext(&node
->ss
.ps
);
246 * clean out the tuple table
248 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
249 ExecClearTuple(node
->ss
.ss_ScanTupleSlot
);
252 * Release tuplestore resources
254 if (node
->tuplestorestate
!= NULL
)
255 tuplestore_end(node
->tuplestorestate
);
256 node
->tuplestorestate
= NULL
;
259 /* ----------------------------------------------------------------
262 * Rescans the relation.
263 * ----------------------------------------------------------------
266 ExecFunctionReScan(FunctionScanState
*node
, ExprContext
*exprCtxt
)
268 ExecClearTuple(node
->ss
.ps
.ps_ResultTupleSlot
);
269 node
->ss
.ps
.ps_TupFromTlist
= false;
272 * If we haven't materialized yet, just return.
274 if (!node
->tuplestorestate
)
278 * Here we have a choice whether to drop the tuplestore (and recompute the
279 * function outputs) or just rescan it. We must recompute if the
280 * expression contains parameters, else we rescan. XXX maybe we should
281 * recompute if the function is volatile?
283 if (node
->ss
.ps
.chgParam
!= NULL
)
285 tuplestore_end(node
->tuplestorestate
);
286 node
->tuplestorestate
= NULL
;
289 tuplestore_rescan(node
->tuplestorestate
);