diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 9dd97b79ffa..caff8d5d14b 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.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.) */