aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/functions.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-03-18 22:04:14 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-03-18 22:04:14 +0000
commit0d49838df6f54c5b49d40a8cf396ea799bd3c4d9 (patch)
tree10bc9771479d02eb22a9a2fcec20e758ad5715bb /src/backend/executor/functions.c
parent433c5238bf1980b917b758f3003f16f134c34540 (diff)
downloadpostgresql-0d49838df6f54c5b49d40a8cf396ea799bd3c4d9.tar.gz
postgresql-0d49838df6f54c5b49d40a8cf396ea799bd3c4d9.zip
Arrange to "inline" SQL functions that appear in a query's FROM clause,
are declared to return set, and consist of just a single SELECT. We can replace the FROM-item with a sub-SELECT and then optimize much as if we were dealing with a view. Patch from Richard Rowell, cleaned up by me.
Diffstat (limited to 'src/backend/executor/functions.c')
-rw-r--r--src/backend/executor/functions.c61
1 files changed, 44 insertions, 17 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 0dec881d37e..da6976b62f7 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.120 2008/01/01 19:45:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.121 2008/03/18 22:04:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,7 @@
#include "commands/trigger.h"
#include "executor/functions.h"
#include "funcapi.h"
+#include "nodes/makefuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "tcop/tcopprot.h"
@@ -269,6 +270,7 @@ init_sql_fcache(FmgrInfo *finfo)
fcache->returnsTuple = check_sql_fn_retval(foid,
rettype,
queryTree_list,
+ false,
&fcache->junkFilter);
/* Finally, plan the queries */
@@ -856,7 +858,9 @@ ShutdownSQLFunction(Datum arg)
*
* The return value of a sql function is the value returned by
* the final query in the function. We do some ad-hoc type checking here
- * to be sure that the user is returning the type he claims.
+ * to be sure that the user is returning the type he claims. There are
+ * also a couple of strange-looking features to assist callers in dealing
+ * with allowed special cases, such as binary-compatible result types.
*
* For a polymorphic function the passed rettype must be the actual resolved
* output type of the function; we should never see a polymorphic pseudotype
@@ -868,6 +872,10 @@ ShutdownSQLFunction(Datum arg)
* allow "SELECT rowtype_expression", this may be false even when the declared
* function return type is a rowtype.
*
+ * If insertRelabels is true, then binary-compatible cases are dealt with
+ * by actually inserting RelabelType nodes into the final SELECT; obviously
+ * the caller must pass a parsetree that it's okay to modify in this case.
+ *
* If junkFilter isn't NULL, then *junkFilter is set to a JunkFilter defined
* to convert the function's tuple result to the correct output tuple type.
* Whenever the result value is false (ie, the function isn't returning a
@@ -875,6 +883,7 @@ ShutdownSQLFunction(Datum arg)
*/
bool
check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
+ bool insertRelabels,
JunkFilter **junkFilter)
{
Query *parse;
@@ -945,10 +954,12 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
rettype == VOIDOID)
{
/*
- * For scalar-type returns, the target list should have exactly one
- * entry, and its type should agree with what the user declared. (As
- * of Postgres 7.2, we accept binary-compatible types too.)
+ * For scalar-type returns, the target list must have exactly one
+ * non-junk entry, and its type must agree with what the user
+ * declared; except we allow binary-compatible types too.
*/
+ TargetEntry *tle;
+
if (tlistlen != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -956,7 +967,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
format_type_be(rettype)),
errdetail("Final SELECT must return exactly one column.")));
- restype = exprType((Node *) ((TargetEntry *) linitial(tlist))->expr);
+ /* We assume here that non-junk TLEs must come first in tlists */
+ tle = (TargetEntry *) linitial(tlist);
+ Assert(!tle->resjunk);
+
+ restype = exprType((Node *) tle->expr);
if (!IsBinaryCoercible(restype, rettype))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -964,6 +979,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
format_type_be(rettype)),
errdetail("Actual return type is %s.",
format_type_be(restype))));
+ if (insertRelabels && restype != rettype)
+ tle->expr = (Expr *) makeRelabelType(tle->expr,
+ rettype,
+ -1,
+ COERCE_DONTCARE);
}
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
{
@@ -977,14 +997,24 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
* If the target list is of length 1, and the type of the varnode in
* the target list matches the declared return type, this is okay.
* This can happen, for example, where the body of the function is
- * 'SELECT func2()', where func2 has the same return type as the
- * function that's calling it.
+ * 'SELECT func2()', where func2 has the same composite return type
+ * as the function that's calling it.
*/
if (tlistlen == 1)
{
- restype = exprType((Node *) ((TargetEntry *) linitial(tlist))->expr);
+ TargetEntry *tle = (TargetEntry *) linitial(tlist);
+
+ Assert(!tle->resjunk);
+ restype = exprType((Node *) tle->expr);
if (IsBinaryCoercible(restype, rettype))
+ {
+ if (insertRelabels && restype != rettype)
+ tle->expr = (Expr *) makeRelabelType(tle->expr,
+ rettype,
+ -1,
+ COERCE_DONTCARE);
return false; /* NOT returning whole tuple */
+ }
}
/* Is the rowtype fixed, or determined only at runtime? */
@@ -1043,6 +1073,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
format_type_be(tletype),
format_type_be(atttype),
tuplogcols)));
+ if (insertRelabels && tletype != atttype)
+ tle->expr = (Expr *) makeRelabelType(tle->expr,
+ atttype,
+ -1,
+ COERCE_DONTCARE);
}
for (;;)
@@ -1070,14 +1105,6 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
/* Report that we are returning entire tuple result */
return true;
}
- else if (IsPolymorphicType(rettype))
- {
- /* This should already have been caught ... */
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
- errmsg("cannot determine result data type"),
- errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
- }
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),