mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Fix oversight in commit 0dca5d68d.
As coded, fmgr_sql() would get an assertion failure for a SQL function that has an empty body and is declared to return some type other than VOID. Typically you'd never get that far because fmgr_sql_validator() would reject such a definition (I suspect that's how come I managed to miss the bug). But if check_function_bodies is off or the function is polymorphic, the validation check wouldn't get made. Reported-by: Alexander Lakhin <exclusion@gmail.com> Author: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/0fde377a-3870-4d18-946a-ce008ee5bb88@gmail.com
This commit is contained in:
parent
46c4c7cbc6
commit
dbd437e670
@ -1116,6 +1116,19 @@ sql_compile_callback(FunctionCallInfo fcinfo,
|
|||||||
*/
|
*/
|
||||||
func->num_queries = list_length(source_list);
|
func->num_queries = list_length(source_list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Edge case: empty function body is OK only if it returns VOID. Normally
|
||||||
|
* we validate that the last statement returns the right thing in
|
||||||
|
* check_sql_stmt_retval, but we'll never reach that if there's no last
|
||||||
|
* statement.
|
||||||
|
*/
|
||||||
|
if (func->num_queries == 0 && 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 be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
|
||||||
|
|
||||||
/* Save the source trees in pcontext for now. */
|
/* Save the source trees in pcontext for now. */
|
||||||
MemoryContextSwitchTo(pcontext);
|
MemoryContextSwitchTo(pcontext);
|
||||||
func->source_list = copyObject(source_list);
|
func->source_list = copyObject(source_list);
|
||||||
@ -2103,7 +2116,7 @@ check_sql_stmt_retval(List *queryTreeList,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Empty function body, or last statement is a utility command */
|
/* Last statement is a utility command, or it rewrote to nothing */
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||||
errmsg("return type mismatch in function declared to return %s",
|
errmsg("return type mismatch in function declared to return %s",
|
||||||
|
@ -757,9 +757,23 @@ LINE 2: AS 'SELECT $2;';
|
|||||||
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
||||||
AS 'a', 'b';
|
AS 'a', 'b';
|
||||||
ERROR: only one AS item needed for language "sql"
|
ERROR: only one AS item needed for language "sql"
|
||||||
|
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
||||||
|
AS '';
|
||||||
|
ERROR: return type mismatch in function declared to return integer
|
||||||
|
DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.
|
||||||
|
CONTEXT: SQL function "test1"
|
||||||
|
-- make sure empty-body case is handled at execution time, too
|
||||||
|
SET check_function_bodies = off;
|
||||||
|
CREATE FUNCTION test1 (anyelement) RETURNS anyarray LANGUAGE SQL
|
||||||
|
AS '';
|
||||||
|
SELECT test1(0);
|
||||||
|
ERROR: return type mismatch in function declared to return integer[]
|
||||||
|
DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.
|
||||||
|
CONTEXT: SQL function "test1" during startup
|
||||||
|
RESET check_function_bodies;
|
||||||
-- Cleanup
|
-- Cleanup
|
||||||
DROP SCHEMA temp_func_test CASCADE;
|
DROP SCHEMA temp_func_test CASCADE;
|
||||||
NOTICE: drop cascades to 34 other objects
|
NOTICE: drop cascades to 35 other objects
|
||||||
DETAIL: drop cascades to function functest_a_1(text,date)
|
DETAIL: drop cascades to function functest_a_1(text,date)
|
||||||
drop cascades to function functest_a_2(text[])
|
drop cascades to function functest_a_2(text[])
|
||||||
drop cascades to function functest_a_3()
|
drop cascades to function functest_a_3()
|
||||||
@ -794,5 +808,6 @@ drop cascades to function create_and_insert()
|
|||||||
drop cascades to table ddl_test
|
drop cascades to table ddl_test
|
||||||
drop cascades to function alter_and_insert()
|
drop cascades to function alter_and_insert()
|
||||||
drop cascades to function double_append(anyarray,anyelement)
|
drop cascades to function double_append(anyarray,anyelement)
|
||||||
|
drop cascades to function test1(anyelement)
|
||||||
DROP USER regress_unpriv_user;
|
DROP USER regress_unpriv_user;
|
||||||
RESET search_path;
|
RESET search_path;
|
||||||
|
@ -449,6 +449,16 @@ CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
|||||||
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
||||||
AS 'a', 'b';
|
AS 'a', 'b';
|
||||||
|
|
||||||
|
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
|
||||||
|
AS '';
|
||||||
|
|
||||||
|
-- make sure empty-body case is handled at execution time, too
|
||||||
|
SET check_function_bodies = off;
|
||||||
|
CREATE FUNCTION test1 (anyelement) RETURNS anyarray LANGUAGE SQL
|
||||||
|
AS '';
|
||||||
|
SELECT test1(0);
|
||||||
|
RESET check_function_bodies;
|
||||||
|
|
||||||
-- Cleanup
|
-- Cleanup
|
||||||
DROP SCHEMA temp_func_test CASCADE;
|
DROP SCHEMA temp_func_test CASCADE;
|
||||||
DROP USER regress_unpriv_user;
|
DROP USER regress_unpriv_user;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user