88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.268 2008/10/04 21:56:53 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.269 2008/10/09 19:27:40 tgl Exp $
1212 *
1313 * HISTORY
1414 * AUTHORDATEMAJOR EVENT
@@ -111,6 +111,7 @@ static Query *substitute_actual_srf_parameters(Query *expr,
111111int nargs ,List * args );
112112static Node * substitute_actual_srf_parameters_mutator (Node * node ,
113113substitute_actual_srf_parameters_context * context );
114+ static bool tlist_matches_coltypelist (List * tlist ,List * coltypelist );
114115
115116
116117/*****************************************************************************
@@ -3659,17 +3660,16 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod)
36593660 * inline_set_returning_function
36603661 *Attempt to "inline" a set-returning function in the FROM clause.
36613662 *
3662- * "node" is the expression from an RTE_FUNCTION rangetable entry. If it
3663- * represents a call of a set-returning SQL function that can safely be
3664- * inlined, expand the function and return the substitute Query structure.
3665- * Otherwise, return NULL.
3663+ * "rte" is an RTE_FUNCTION rangetable entry. If it represents a call of a
3664+ * set-returning SQL function that can safely be inlined, expand the function
3665+ * and return the substitute Query structure. Otherwise, return NULL.
36663666 *
36673667 * This has a good deal of similarity to inline_function(), but that's
36683668 * for the non-set-returning case, and there are enough differences to
36693669 * justify separate functions.
36703670 */
36713671Query *
3672- inline_set_returning_function (PlannerInfo * root ,Node * node )
3672+ inline_set_returning_function (PlannerInfo * root ,RangeTblEntry * rte )
36733673{
36743674FuncExpr * fexpr ;
36753675HeapTuple func_tuple ;
@@ -3686,6 +3686,8 @@ inline_set_returning_function(PlannerInfo *root, Node *node)
36863686Query * querytree ;
36873687int i ;
36883688
3689+ Assert (rte -> rtekind == RTE_FUNCTION );
3690+
36893691/*
36903692 * It doesn't make a lot of sense for a SQL SRF to refer to itself
36913693 * in its own FROM clause, since that must cause infinite recursion
@@ -3695,9 +3697,9 @@ inline_set_returning_function(PlannerInfo *root, Node *node)
36953697check_stack_depth ();
36963698
36973699/* Fail if FROM item isn't a simple FuncExpr */
3698- if (node == NULL || !IsA (node ,FuncExpr ))
3700+ fexpr = (FuncExpr * )rte -> funcexpr ;
3701+ if (fexpr == NULL || !IsA (fexpr ,FuncExpr ))
36993702return NULL ;
3700- fexpr = (FuncExpr * )node ;
37013703
37023704/*
37033705 * The function must be declared to return a set, else inlining would
@@ -3707,10 +3709,6 @@ inline_set_returning_function(PlannerInfo *root, Node *node)
37073709if (!fexpr -> funcretset )
37083710return NULL ;
37093711
3710- /* Fail if function returns RECORD ... we don't have enough context */
3711- if (fexpr -> funcresulttype == RECORDOID )
3712- return NULL ;
3713-
37143712/*
37153713 * Refuse to inline if the arguments contain any volatile functions or
37163714 * sub-selects. Volatile functions are rejected because inlining may
@@ -3837,9 +3835,20 @@ inline_set_returning_function(PlannerInfo *root, Node *node)
38373835if (!check_sql_fn_retval (fexpr -> funcid ,fexpr -> funcresulttype ,
38383836querytree_list ,
38393837 true,NULL )&&
3840- get_typtype (fexpr -> funcresulttype )== TYPTYPE_COMPOSITE )
3838+ (get_typtype (fexpr -> funcresulttype )== TYPTYPE_COMPOSITE ||
3839+ fexpr -> funcresulttype == RECORDOID ))
38413840gotofail ;/* reject not-whole-tuple-result cases */
38423841
3842+ /*
3843+ * If it returns RECORD, we have to check against the column type list
3844+ * provided in the RTE; check_sql_fn_retval can't do that. (If no match,
3845+ * we just fail to inline, rather than complaining; see notes for
3846+ * tlist_matches_coltypelist.)
3847+ */
3848+ if (fexpr -> funcresulttype == RECORDOID &&
3849+ !tlist_matches_coltypelist (querytree -> targetList ,rte -> funccoltypes ))
3850+ gotofail ;
3851+
38433852/*
38443853 * Looks good --- substitute parameters into the query.
38453854 */
@@ -3938,3 +3947,46 @@ substitute_actual_srf_parameters_mutator(Node *node,
39383947substitute_actual_srf_parameters_mutator ,
39393948 (void * )context );
39403949}
3950+
3951+ /*
3952+ * Check whether a SELECT targetlist emits the specified column types,
3953+ * to see if it's safe to inline a function returning record.
3954+ *
3955+ * We insist on exact match here. The executor allows binary-coercible
3956+ * cases too, but we don't have a way to preserve the correct column types
3957+ * in the correct places if we inline the function in such a case.
3958+ *
3959+ * Note that we only check type OIDs not typmods; this agrees with what the
3960+ * executor would do at runtime, and attributing a specific typmod to a
3961+ * function result is largely wishful thinking anyway.
3962+ */
3963+ static bool
3964+ tlist_matches_coltypelist (List * tlist ,List * coltypelist )
3965+ {
3966+ ListCell * tlistitem ;
3967+ ListCell * clistitem ;
3968+
3969+ clistitem = list_head (coltypelist );
3970+ foreach (tlistitem ,tlist )
3971+ {
3972+ TargetEntry * tle = (TargetEntry * )lfirst (tlistitem );
3973+ Oid coltype ;
3974+
3975+ if (tle -> resjunk )
3976+ continue ;/* ignore junk columns */
3977+
3978+ if (clistitem == NULL )
3979+ return false;/* too many tlist items */
3980+
3981+ coltype = lfirst_oid (clistitem );
3982+ clistitem = lnext (clistitem );
3983+
3984+ if (exprType ((Node * )tle -> expr )!= coltype )
3985+ return false;/* column type mismatch */
3986+ }
3987+
3988+ if (clistitem != NULL )
3989+ return false;/* too few tlist items */
3990+
3991+ return true;
3992+ }