88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.120 2008/01/01 19:45:49 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.121 2008/03/18 22:04:14 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2020#include "commands/trigger.h"
2121#include "executor/functions.h"
2222#include "funcapi.h"
23+ #include "nodes/makefuncs.h"
2324#include "parser/parse_coerce.h"
2425#include "parser/parse_expr.h"
2526#include "tcop/tcopprot.h"
@@ -269,6 +270,7 @@ init_sql_fcache(FmgrInfo *finfo)
269270fcache -> returnsTuple = check_sql_fn_retval (foid ,
270271rettype ,
271272queryTree_list ,
273+ false,
272274& fcache -> junkFilter );
273275
274276/* Finally, plan the queries */
@@ -856,7 +858,9 @@ ShutdownSQLFunction(Datum arg)
856858 *
857859 * The return value of a sql function is the value returned by
858860 * the final query in the function. We do some ad-hoc type checking here
859- * to be sure that the user is returning the type he claims.
861+ * to be sure that the user is returning the type he claims. There are
862+ * also a couple of strange-looking features to assist callers in dealing
863+ * with allowed special cases, such as binary-compatible result types.
860864 *
861865 * For a polymorphic function the passed rettype must be the actual resolved
862866 * output type of the function; we should never see a polymorphic pseudotype
@@ -868,13 +872,18 @@ ShutdownSQLFunction(Datum arg)
868872 * allow "SELECT rowtype_expression", this may be false even when the declared
869873 * function return type is a rowtype.
870874 *
875+ * If insertRelabels is true, then binary-compatible cases are dealt with
876+ * by actually inserting RelabelType nodes into the final SELECT; obviously
877+ * the caller must pass a parsetree that it's okay to modify in this case.
878+ *
871879 * If junkFilter isn't NULL, then *junkFilter is set to a JunkFilter defined
872880 * to convert the function's tuple result to the correct output tuple type.
873881 * Whenever the result value is false (ie, the function isn't returning a
874882 * tuple result), *junkFilter is set to NULL.
875883 */
876884bool
877885check_sql_fn_retval (Oid func_id ,Oid rettype ,List * queryTreeList ,
886+ bool insertRelabels ,
878887JunkFilter * * junkFilter )
879888{
880889Query * parse ;
@@ -945,25 +954,36 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
945954rettype == VOIDOID )
946955{
947956/*
948- * For scalar-type returns, the target listshould have exactly one
949- * entry, and its typeshould agree with what the user declared. (As
950- *of Postgres 7.2, weaccept binary-compatible types too.)
957+ * For scalar-type returns, the target listmust have exactly one
958+ *non-junk entry, and its typemust agree with what the user
959+ *declared; except weallow binary-compatible types too.
951960 */
961+ TargetEntry * tle ;
962+
952963if (tlistlen != 1 )
953964ereport (ERROR ,
954965(errcode (ERRCODE_INVALID_FUNCTION_DEFINITION ),
955966errmsg ("return type mismatch in function declared to return %s" ,
956967format_type_be (rettype )),
957968errdetail ("Final SELECT must return exactly one column." )));
958969
959- restype = exprType ((Node * ) ((TargetEntry * )linitial (tlist ))-> expr );
970+ /* We assume here that non-junk TLEs must come first in tlists */
971+ tle = (TargetEntry * )linitial (tlist );
972+ Assert (!tle -> resjunk );
973+
974+ restype = exprType ((Node * )tle -> expr );
960975if (!IsBinaryCoercible (restype ,rettype ))
961976ereport (ERROR ,
962977(errcode (ERRCODE_INVALID_FUNCTION_DEFINITION ),
963978errmsg ("return type mismatch in function declared to return %s" ,
964979format_type_be (rettype )),
965980errdetail ("Actual return type is %s." ,
966981format_type_be (restype ))));
982+ if (insertRelabels && restype != rettype )
983+ tle -> expr = (Expr * )makeRelabelType (tle -> expr ,
984+ rettype ,
985+ -1 ,
986+ COERCE_DONTCARE );
967987}
968988else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID )
969989{
@@ -977,14 +997,24 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
977997 * If the target list is of length 1, and the type of the varnode in
978998 * the target list matches the declared return type, this is okay.
979999 * This can happen, for example, where the body of the function is
980- * 'SELECT func2()', where func2 has the same return type as the
981- * function that's calling it.
1000+ * 'SELECT func2()', where func2 has the samecomposite return type
1001+ *as the function that's calling it.
9821002 */
9831003if (tlistlen == 1 )
9841004{
985- restype = exprType ((Node * ) ((TargetEntry * )linitial (tlist ))-> expr );
1005+ TargetEntry * tle = (TargetEntry * )linitial (tlist );
1006+
1007+ Assert (!tle -> resjunk );
1008+ restype = exprType ((Node * )tle -> expr );
9861009if (IsBinaryCoercible (restype ,rettype ))
1010+ {
1011+ if (insertRelabels && restype != rettype )
1012+ tle -> expr = (Expr * )makeRelabelType (tle -> expr ,
1013+ rettype ,
1014+ -1 ,
1015+ COERCE_DONTCARE );
9871016return false;/* NOT returning whole tuple */
1017+ }
9881018}
9891019
9901020/* Is the rowtype fixed, or determined only at runtime? */
@@ -1043,6 +1073,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
10431073format_type_be (tletype ),
10441074format_type_be (atttype ),
10451075tuplogcols )));
1076+ if (insertRelabels && tletype != atttype )
1077+ tle -> expr = (Expr * )makeRelabelType (tle -> expr ,
1078+ atttype ,
1079+ -1 ,
1080+ COERCE_DONTCARE );
10461081}
10471082
10481083for (;;)
@@ -1070,14 +1105,6 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
10701105/* Report that we are returning entire tuple result */
10711106return true;
10721107}
1073- else if (IsPolymorphicType (rettype ))
1074- {
1075- /* This should already have been caught ... */
1076- ereport (ERROR ,
1077- (errcode (ERRCODE_INVALID_FUNCTION_DEFINITION ),
1078- errmsg ("cannot determine result data type" ),
1079- errdetail ("A function returning a polymorphic type must have at least one polymorphic argument." )));
1080- }
10811108else
10821109ereport (ERROR ,
10831110(errcode (ERRCODE_INVALID_FUNCTION_DEFINITION ),