mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Fix check_sql_fn_retval to allow the case where a SQL function declared to
return void ends with a SELECT, if that SELECT has a single result that is also of type void. Without this, it's hard to write a void function that calls another void function. Per gripe from Peter. Back-patch as far as 8.0.
This commit is contained in:
parent
100beb0dea
commit
3ac7d76096
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.108.2.1 2007/02/02 00:03:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.108.2.2 2007/04/02 18:49:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -844,9 +844,9 @@ ShutdownSQLFunction(Datum arg)
|
||||
* as rettype. (This means we can't check the type during function definition
|
||||
* of a polymorphic function.)
|
||||
*
|
||||
* 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
|
||||
* This function returns true if the sql 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.
|
||||
*
|
||||
* If junkFilter isn't NULL, then *junkFilter is set to a JunkFilter defined
|
||||
@ -859,7 +859,6 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
JunkFilter **junkFilter)
|
||||
{
|
||||
Query *parse;
|
||||
bool isSelect;
|
||||
List *tlist;
|
||||
ListCell *tlistitem;
|
||||
int tlistlen;
|
||||
@ -885,32 +884,30 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
parse = (Query *) lfirst(list_tail(queryTreeList));
|
||||
|
||||
/*
|
||||
* Note: eventually replace this with QueryReturnsTuples? We'd need a
|
||||
* more general method of determining the output type, though.
|
||||
* If the last query isn't a SELECT, the return type must be VOID.
|
||||
*
|
||||
* Note: eventually replace this test with QueryReturnsTuples? We'd need
|
||||
* a more general method of determining the output type, though.
|
||||
*/
|
||||
isSelect = (parse->commandType == CMD_SELECT && parse->into == NULL);
|
||||
|
||||
/*
|
||||
* The last query must be a SELECT if and only if return type isn't VOID.
|
||||
*/
|
||||
if (rettype == VOIDOID)
|
||||
if (!(parse->commandType == CMD_SELECT && parse->into == NULL))
|
||||
{
|
||||
if (isSelect)
|
||||
if (rettype != VOIDOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("return type mismatch in function declared to return %s",
|
||||
format_type_be(rettype)),
|
||||
errdetail("Function's final statement must not be a SELECT.")));
|
||||
errdetail("Function's final statement must be a SELECT.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* by here, the function is declared to return some type */
|
||||
if (!isSelect)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("return type mismatch in function declared to return %s",
|
||||
format_type_be(rettype)),
|
||||
errdetail("Function's final statement must be a SELECT.")));
|
||||
/*
|
||||
* OK, it's a SELECT, so it must return something matching the declared
|
||||
* type. (We used to insist that the declared type not be VOID in this
|
||||
* case, but that makes it hard to write a void function that exits
|
||||
* after calling another void function. Instead, we insist that the
|
||||
* SELECT return void ... so void is treated as if it were a scalar type
|
||||
* below.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Count the non-junk entries in the result targetlist.
|
||||
@ -920,10 +917,11 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
|
||||
fn_typtype = get_typtype(rettype);
|
||||
|
||||
if (fn_typtype == 'b' || fn_typtype == 'd')
|
||||
if (fn_typtype == 'b' || fn_typtype == 'd' ||
|
||||
rettype == VOIDOID)
|
||||
{
|
||||
/*
|
||||
* For base-type returns, the target list should have exactly one
|
||||
* 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.)
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user