Commit 9d9784c8 authored by Tom Lane's avatar Tom Lane

Remove bogus assertion about polymorphic SQL function result.

It is possible to reach check_sql_fn_retval() with an unresolved
polymorphic rettype, resulting in an assertion failure as demonstrated
by one of the added test cases.  However, the code following that
throws what seems an acceptable error message, so just remove the
Assert and adjust commentary.

While here, I thought it'd be a good idea to provide some parallel
tests of SQL-function and PL/pgSQL-function polymorphism behavior.
Some of these cases are perhaps duplicative of tests elsewhere,
but we hadn't any organized coverage of the topic AFAICS.

Although that assertion's been wrong all along, it won't have any
effect in production builds, so I'm not bothering to back-patch.

Discussion: https://postgr.es/m/21569.1584314271@sss.pgh.pa.us
parent 0bc8cebd
...@@ -1567,13 +1567,16 @@ check_sql_fn_statements(List *queryTreeList) ...@@ -1567,13 +1567,16 @@ check_sql_fn_statements(List *queryTreeList)
* false even when the declared function return type is a rowtype. * false even when the declared function return type is a rowtype.
* *
* For a polymorphic function the passed rettype must be the actual resolved * For a polymorphic function the passed rettype must be the actual resolved
* output type of the function; we should never see a polymorphic pseudotype * output type of the function. (This means we can't check the type during
* such as ANYELEMENT as rettype. (This means we can't check the type during * function definition of a polymorphic function.) If we do see a polymorphic
* function definition of a polymorphic function.) If the function returns * rettype we'll throw an error, saying it is not a supported rettype.
* composite, the passed rettupdesc should describe the expected output. *
* If rettupdesc is NULL, we can't verify that the output matches; that * If the function returns composite, the passed rettupdesc should describe
* should only happen in fmgr_sql_validator(), or when the function returns * the expected output. If rettupdesc is NULL, we can't verify that the
* RECORD and the caller doesn't actually care which composite type it is. * output matches; that should only happen in fmgr_sql_validator(), or when
* the function returns RECORD and the caller doesn't actually care which
* composite type it is.
*
* (Typically, rettype and rettupdesc are computed by get_call_result_type * (Typically, rettype and rettupdesc are computed by get_call_result_type
* or a sibling function.) * or a sibling function.)
* *
...@@ -1602,9 +1605,6 @@ check_sql_fn_retval(List *queryTreeList, ...@@ -1602,9 +1605,6 @@ check_sql_fn_retval(List *queryTreeList,
bool upper_tlist_nontrivial = false; bool upper_tlist_nontrivial = false;
ListCell *lc; ListCell *lc;
/* Caller must have resolved any polymorphism */
AssertArg(!IsPolymorphicType(rettype));
if (resultTargetList) if (resultTargetList)
*resultTargetList = NIL; /* initialize in case of VOID result */ *resultTargetList = NIL; /* initialize in case of VOID result */
......
...@@ -1746,6 +1746,83 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text); ...@@ -1746,6 +1746,83 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
50 | 5 | xxx 50 | 5 | xxx
(1 row) (1 row)
--
-- Test some simple polymorphism cases.
--
create function f1(x anyelement) returns anyelement as $$
begin
return x + 1;
end$$ language plpgsql;
select f1(42) as int, f1(4.5) as num;
int | num
-----+-----
43 | 5.5
(1 row)
select f1(point(3,4)); -- fail for lack of + operator
ERROR: operator does not exist: point + integer
LINE 1: SELECT x + 1
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT x + 1
CONTEXT: PL/pgSQL function f1(anyelement) line 3 at RETURN
drop function f1(x anyelement);
create function f1(x anyelement) returns anyarray as $$
begin
return array[x + 1, x + 2];
end$$ language plpgsql;
select f1(42) as int, f1(4.5) as num;
int | num
---------+-----------
{43,44} | {5.5,6.5}
(1 row)
drop function f1(x anyelement);
create function f1(x anyarray) returns anyelement as $$
begin
return x[1];
end$$ language plpgsql;
select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
int | num
-----+-----
2 | 4.5
(1 row)
select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
ERROR: argument declared anyarray is not an array but type anyarray
drop function f1(x anyarray);
create function f1(x anyarray) returns anyarray as $$
begin
return x;
end$$ language plpgsql;
select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
int | num
-------+-----------
{2,4} | {4.5,7.7}
(1 row)
select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
ERROR: PL/pgSQL functions cannot accept type anyarray
CONTEXT: compilation of PL/pgSQL function "f1" near line 1
drop function f1(x anyarray);
-- fail, can't infer type:
create function f1(x anyelement) returns anyrange as $$
begin
return array[x + 1, x + 2];
end$$ language plpgsql;
ERROR: cannot determine result data type
DETAIL: A function returning "anyrange" must have at least one "anyrange" argument.
create function f1(x anyrange) returns anyarray as $$
begin
return array[lower(x), upper(x)];
end$$ language plpgsql;
select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num;
int | num
---------+-----------
{42,49} | {4.5,7.8}
(1 row)
drop function f1(x anyrange);
-- --
-- Test handling of OUT parameters, including polymorphic cases. -- Test handling of OUT parameters, including polymorphic cases.
-- Note that RETURN is optional with OUT params; we try both ways. -- Note that RETURN is optional with OUT params; we try both ways.
......
-- Currently this tests polymorphic aggregates and indirectly does some --
-- testing of polymorphic SQL functions. It ought to be extended. -- Tests for polymorphic SQL functions and aggregates based on them.
-- Tests for other features related to function-calling have snuck in, too. -- Tests for other features related to function-calling have snuck in, too.
--
create function polyf(x anyelement) returns anyelement as $$
select x + 1
$$ language sql;
select polyf(42) as int, polyf(4.5) as num;
int | num
-----+-----
43 | 5.5
(1 row)
select polyf(point(3,4)); -- fail for lack of + operator
ERROR: operator does not exist: point + integer
LINE 2: select x + 1
^
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
QUERY:
select x + 1
CONTEXT: SQL function "polyf" during inlining
drop function polyf(x anyelement);
create function polyf(x anyelement) returns anyarray as $$
select array[x + 1, x + 2]
$$ language sql;
select polyf(42) as int, polyf(4.5) as num;
int | num
---------+-----------
{43,44} | {5.5,6.5}
(1 row)
drop function polyf(x anyelement);
create function polyf(x anyarray) returns anyelement as $$
select x[1]
$$ language sql;
select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
int | num
-----+-----
2 | 4.5
(1 row)
select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
ERROR: argument declared anyarray is not an array but type anyarray
drop function polyf(x anyarray);
create function polyf(x anyarray) returns anyarray as $$
select x
$$ language sql;
select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
int | num
-------+-----------
{2,4} | {4.5,7.7}
(1 row)
select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
ERROR: return type anyarray is not supported for SQL functions
CONTEXT: SQL function "polyf" during inlining
drop function polyf(x anyarray);
-- fail, can't infer type:
create function polyf(x anyelement) returns anyrange as $$
select array[x + 1, x + 2]
$$ language sql;
ERROR: cannot determine result data type
DETAIL: A function returning "anyrange" must have at least one "anyrange" argument.
create function polyf(x anyrange) returns anyarray as $$
select array[lower(x), upper(x)]
$$ language sql;
select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num;
int | num
---------+-----------
{42,49} | {4.5,7.8}
(1 row)
drop function polyf(x anyrange);
--
-- Polymorphic aggregate tests
--
-- Legend: -- Legend:
----------- -----------
-- A = type is ANY -- A = type is ANY
......
...@@ -1558,6 +1558,66 @@ END;' language plpgsql; ...@@ -1558,6 +1558,66 @@ END;' language plpgsql;
SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int); SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text); SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
--
-- Test some simple polymorphism cases.
--
create function f1(x anyelement) returns anyelement as $$
begin
return x + 1;
end$$ language plpgsql;
select f1(42) as int, f1(4.5) as num;
select f1(point(3,4)); -- fail for lack of + operator
drop function f1(x anyelement);
create function f1(x anyelement) returns anyarray as $$
begin
return array[x + 1, x + 2];
end$$ language plpgsql;
select f1(42) as int, f1(4.5) as num;
drop function f1(x anyelement);
create function f1(x anyarray) returns anyelement as $$
begin
return x[1];
end$$ language plpgsql;
select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
drop function f1(x anyarray);
create function f1(x anyarray) returns anyarray as $$
begin
return x;
end$$ language plpgsql;
select f1(array[2,4]) as int, f1(array[4.5, 7.7]) as num;
select f1(stavalues1) from pg_statistic; -- fail, can't infer element type
drop function f1(x anyarray);
-- fail, can't infer type:
create function f1(x anyelement) returns anyrange as $$
begin
return array[x + 1, x + 2];
end$$ language plpgsql;
create function f1(x anyrange) returns anyarray as $$
begin
return array[lower(x), upper(x)];
end$$ language plpgsql;
select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num;
drop function f1(x anyrange);
-- --
-- Test handling of OUT parameters, including polymorphic cases. -- Test handling of OUT parameters, including polymorphic cases.
-- Note that RETURN is optional with OUT params; we try both ways. -- Note that RETURN is optional with OUT params; we try both ways.
......
-- Currently this tests polymorphic aggregates and indirectly does some --
-- testing of polymorphic SQL functions. It ought to be extended. -- Tests for polymorphic SQL functions and aggregates based on them.
-- Tests for other features related to function-calling have snuck in, too. -- Tests for other features related to function-calling have snuck in, too.
--
create function polyf(x anyelement) returns anyelement as $$
select x + 1
$$ language sql;
select polyf(42) as int, polyf(4.5) as num;
select polyf(point(3,4)); -- fail for lack of + operator
drop function polyf(x anyelement);
create function polyf(x anyelement) returns anyarray as $$
select array[x + 1, x + 2]
$$ language sql;
select polyf(42) as int, polyf(4.5) as num;
drop function polyf(x anyelement);
create function polyf(x anyarray) returns anyelement as $$
select x[1]
$$ language sql;
select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
drop function polyf(x anyarray);
create function polyf(x anyarray) returns anyarray as $$
select x
$$ language sql;
select polyf(array[2,4]) as int, polyf(array[4.5, 7.7]) as num;
select polyf(stavalues1) from pg_statistic; -- fail, can't infer element type
drop function polyf(x anyarray);
-- fail, can't infer type:
create function polyf(x anyelement) returns anyrange as $$
select array[x + 1, x + 2]
$$ language sql;
create function polyf(x anyrange) returns anyarray as $$
select array[lower(x), upper(x)]
$$ language sql;
select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num;
drop function polyf(x anyrange);
--
-- Polymorphic aggregate tests
--
-- Legend: -- Legend:
----------- -----------
-- A = type is ANY -- A = type is ANY
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment