diff options
-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.) */ |