Skip to content

Commit dbd437e

Browse files
committed
Fix oversight in commit 0dca5d6.
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
1 parent 46c4c7c commit dbd437e

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

src/backend/executor/functions.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,19 @@ sql_compile_callback(FunctionCallInfo fcinfo,
11161116
*/
11171117
func->num_queries = list_length(source_list);
11181118

1119+
/*
1120+
* Edge case: empty function body is OK only if it returns VOID. Normally
1121+
* we validate that the last statement returns the right thing in
1122+
* check_sql_stmt_retval, but we'll never reach that if there's no last
1123+
* statement.
1124+
*/
1125+
if (func->num_queries == 0 && rettype != VOIDOID)
1126+
ereport(ERROR,
1127+
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
1128+
errmsg("return type mismatch in function declared to return %s",
1129+
format_type_be(rettype)),
1130+
errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.")));
1131+
11191132
/* Save the source trees in pcontext for now. */
11201133
MemoryContextSwitchTo(pcontext);
11211134
func->source_list = copyObject(source_list);
@@ -2103,7 +2116,7 @@ check_sql_stmt_retval(List *queryTreeList,
21032116
}
21042117
else
21052118
{
2106-
/* Empty function body, or last statement is a utility command */
2119+
/* Last statement is a utility command, or it rewrote to nothing */
21072120
ereport(ERROR,
21082121
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
21092122
errmsg("return type mismatch in function declared to return %s",

src/test/regress/expected/create_function_sql.out

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,9 +757,23 @@ LINE 2: AS 'SELECT $2;';
757757
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
758758
AS 'a', 'b';
759759
ERROR: only one AS item needed for language "sql"
760+
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
761+
AS '';
762+
ERROR: return type mismatch in function declared to return integer
763+
DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.
764+
CONTEXT: SQL function "test1"
765+
-- make sure empty-body case is handled at execution time, too
766+
SET check_function_bodies = off;
767+
CREATE FUNCTION test1 (anyelement) RETURNS anyarray LANGUAGE SQL
768+
AS '';
769+
SELECT test1(0);
770+
ERROR: return type mismatch in function declared to return integer[]
771+
DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE/MERGE RETURNING.
772+
CONTEXT: SQL function "test1" during startup
773+
RESET check_function_bodies;
760774
-- Cleanup
761775
DROP SCHEMA temp_func_test CASCADE;
762-
NOTICE: drop cascades to 34 other objects
776+
NOTICE: drop cascades to 35 other objects
763777
DETAIL: drop cascades to function functest_a_1(text,date)
764778
drop cascades to function functest_a_2(text[])
765779
drop cascades to function functest_a_3()
@@ -794,5 +808,6 @@ drop cascades to function create_and_insert()
794808
drop cascades to table ddl_test
795809
drop cascades to function alter_and_insert()
796810
drop cascades to function double_append(anyarray,anyelement)
811+
drop cascades to function test1(anyelement)
797812
DROP USER regress_unpriv_user;
798813
RESET search_path;

src/test/regress/sql/create_function_sql.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,16 @@ CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
449449
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
450450
AS 'a', 'b';
451451

452+
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
453+
AS '';
454+
455+
-- make sure empty-body case is handled at execution time, too
456+
SET check_function_bodies = off;
457+
CREATE FUNCTION test1 (anyelement) RETURNS anyarray LANGUAGE SQL
458+
AS '';
459+
SELECT test1(0);
460+
RESET check_function_bodies;
461+
452462
-- Cleanup
453463
DROP SCHEMA temp_func_test CASCADE;
454464
DROP USER regress_unpriv_user;

0 commit comments

Comments
 (0)