diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-04-02 18:49:49 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-04-02 18:49:49 +0000 |
commit | 47d61a572ff1c03241776b99d979e28affe7aa2a (patch) | |
tree | 26fecf45e315c5acf7e2be54ff6a27bf2d35ce91 /src | |
parent | 51fb9106e05e083f013ac4688e5ceb59ff9c000c (diff) | |
download | postgresql-47d61a572ff1c03241776b99d979e28affe7aa2a.tar.gz postgresql-47d61a572ff1c03241776b99d979e28affe7aa2a.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/executor/functions.c | 42 |
1 files changed, 20 insertions, 22 deletions
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 9f3a85dbf85..ec6ede2a544 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.91.4.3 2007/02/02 00:03:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.91.4.4 2007/04/02 18:49:49 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -848,9 +848,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 @@ -863,7 +863,6 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, JunkFilter **junkFilter) { Query *parse; - int cmd; List *tlist; ListCell *tlistitem; int tlistlen; @@ -892,46 +891,45 @@ check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList, /* find the final query */ parse = (Query *) lfirst(list_tail(queryTreeList)); - cmd = parse->commandType; - tlist = parse->targetList; - /* - * The last query must be a SELECT if and only if return type isn't - * VOID. + * If the last query isn't a SELECT, the return type must be VOID. */ - if (rettype == VOIDOID) + if (!(parse->commandType == CMD_SELECT && parse->into == NULL)) { - if (cmd == CMD_SELECT) + 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 (cmd != CMD_SELECT) - 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. */ + tlist = parse->targetList; tlistlen = ExecCleanTargetListLength(tlist); typerelid = typeidTypeRelid(rettype); - if (fn_typtype == 'b' || fn_typtype == 'd') + if (fn_typtype == 'b' || fn_typtype == 'd' || + rettype == VOIDOID) { /* Shouldn't have a typerelid */ Assert(typerelid == InvalidOid); /* - * 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.) */ |