1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-22 12:22:45 +03:00

check_sql_fn_retval has always thought that we supported doing

'SELECT foo()' in a SQL function returning a rowtype, to simply pass
back the results of another function returning the same rowtype.
However, that hasn't actually worked in many years.  Now it works again.
This commit is contained in:
Tom Lane
2004-04-02 23:14:08 +00:00
parent 3dd1ca035d
commit 8efbe30df5
4 changed files with 68 additions and 41 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.114 2004/04/01 21:28:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.115 2004/04/02 23:14:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -362,8 +362,13 @@ create_parameternames_array(int parameterCount, const char *parameterNames[])
* function execution startup. The rettype is then the actual resolved
* output type of the function, rather than the declared type. (Therefore,
* we should never see ANYARRAY or ANYELEMENT as rettype.)
*
* The return value is true if the function returns the entire tuple result
* of its final SELECT, and false otherwise. Note that because we allow
* "SELECT rowtype_expression", this may be false even when the declared
* function return type is a rowtype.
*/
void
bool
check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
{
Query *parse;
@@ -387,7 +392,7 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
errmsg("return type mismatch in function declared to return %s",
format_type_be(rettype)),
errdetail("Function's final statement must be a SELECT.")));
return;
return false;
}
/* find the final query */
@@ -408,7 +413,7 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
errmsg("return type mismatch in function declared to return %s",
format_type_be(rettype)),
errdetail("Function's final statement must not be a SELECT.")));
return;
return false;
}
/* by here, the function is declared to return some type */
@@ -468,7 +473,7 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
{
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
if (IsBinaryCoercible(restype, rettype))
return;
return false; /* NOT returning whole tuple */
}
/*
@@ -536,16 +541,31 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
errdetail("Final SELECT returns too few columns.")));
relation_close(reln, AccessShareLock);
/* Report that we are returning entire tuple result */
return true;
}
else if (rettype == RECORDOID)
{
/* Shouldn't have a typerelid */
Assert(typerelid == InvalidOid);
/*
* 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.
*/
if (tlistlen == 1)
{
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
if (IsBinaryCoercible(restype, rettype))
return false; /* NOT returning whole tuple */
}
/*
* For RECORD return type, defer this check until we get the first
* tuple.
* Otherwise assume we are returning the whole tuple. Crosschecking
* against what the caller expects will happen at runtime.
*/
return true;
}
else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
{
@@ -560,6 +580,8 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("return type %s is not supported for SQL functions",
format_type_be(rettype))));
return false;
}
@@ -751,7 +773,8 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
querytree_list = pg_parse_and_rewrite(prosrc,
proc->proargtypes,
proc->pronargs);
check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
(void) check_sql_fn_retval(proc->prorettype, functyptype,
querytree_list);
}
else
querytree_list = pg_parse_query(prosrc);