aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-04-04 18:03:30 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-04-04 18:03:30 -0400
commit07871d40c72e498b6e034eb674df5d8d206976bc (patch)
tree76045cf9e82f7d28b4806e83ba6cbca6f4151119 /src
parentc6b92041d38512a4176ed76ad06f713d2e6c01a8 (diff)
downloadpostgresql-07871d40c72e498b6e034eb674df5d8d206976bc.tar.gz
postgresql-07871d40c72e498b6e034eb674df5d8d206976bc.zip
Remove bogus Assert, add some regression test cases showing why.
Commit 77ec5affb added an assertion to enforce_generic_type_consistency that boils down to "if the function result is polymorphic, there must be at least one polymorphic argument". This should be true for user-created functions, but there are built-in functions for which it's not true, as pointed out by Jaime Casanova. Hence, go back to the old behavior of leaving the return type alone. There's only a limited amount of stuff you can do with such a function result, but it does work to some extent; add some regression test cases to ensure we don't break that again. Discussion: https://postgr.es/m/CAJGNTeMbhtsCUZgJJ8h8XxAJbK7U2ipsX8wkHRtZRz-NieT8RA@mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_coerce.c21
-rw-r--r--src/test/regress/expected/polymorphism.out13
-rw-r--r--src/test/regress/sql/polymorphism.sql5
3 files changed, 30 insertions, 9 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 645e4aa4ceb..6cab20d09a1 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -1813,7 +1813,8 @@ check_generic_type_consistency(const Oid *actual_arg_types,
* arguments to the proper type.
*
* Rules are applied to the function's return type (possibly altering it)
- * if it is declared as a polymorphic type:
+ * if it is declared as a polymorphic type and there is at least one
+ * polymorphic argument type:
*
* 1) If return type is ANYELEMENT, and any argument is ANYELEMENT, use the
* argument's actual type as the function's return type.
@@ -1821,11 +1822,11 @@ check_generic_type_consistency(const Oid *actual_arg_types,
* argument's actual type as the function's return type.
* 3) Similarly, if return type is ANYRANGE, and any argument is ANYRANGE,
* use the argument's actual type as the function's return type.
- * 4) Otherwise, if return type is ANYELEMENT or ANYARRAY, there should be
- * at least one ANYELEMENT, ANYARRAY, or ANYRANGE input; deduce the
+ * 4) Otherwise, if return type is ANYELEMENT or ANYARRAY, and there is
+ * at least one ANYELEMENT, ANYARRAY, or ANYRANGE input, deduce the
* return type from those inputs, or throw error if we can't.
- * 5) Otherwise, if return type is ANYRANGE, throw error. (There should
- * be at least one ANYRANGE input, since CREATE FUNCTION enforces that.)
+ * 5) Otherwise, if return type is ANYRANGE, throw error. (We have no way to
+ * select a specific range type if the arguments don't include ANYRANGE.)
* 6) ANYENUM is treated the same as ANYELEMENT except that if it is used
* (alone or in combination with plain ANYELEMENT), we add the extra
* condition that the ANYELEMENT type must be an enum.
@@ -1869,6 +1870,11 @@ check_generic_type_consistency(const Oid *actual_arg_types,
* input to an ANYCOMPATIBLEARRAY argument, but at present that seems useless
* as well, since there's no value in using ANYCOMPATIBLEARRAY unless there's
* at least one other ANYCOMPATIBLE-family argument or result.
+ *
+ * Also, if there are no arguments declared to be of polymorphic types,
+ * we'll return the rettype unmodified even if it's polymorphic. This should
+ * never occur for user-declared functions, because CREATE FUNCTION prevents
+ * it. But it does happen for some built-in functions, such as array_in().
*/
Oid
enforce_generic_type_consistency(const Oid *actual_arg_types,
@@ -2042,13 +2048,10 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
/*
* Fast Track: if none of the arguments are polymorphic, return the
- * unmodified rettype. We assume it can't be polymorphic either.
+ * unmodified rettype. Not our job to resolve it if it's polymorphic.
*/
if (n_poly_args == 0 && !have_poly_anycompatible)
- {
- Assert(!IsPolymorphicType(rettype));
return rettype;
- }
/* Check matching of family-1 polymorphic arguments, if any */
if (n_poly_args)
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index d86a7004a6f..1ff40764d9a 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -852,6 +852,19 @@ where histogram_bounds is not null;
-- (WHERE clause here is to avoid possibly getting a collation error instead)
select max(histogram_bounds) from pg_stats where tablename = 'pg_am';
ERROR: cannot compare arrays of different element types
+-- another corner case is the input functions for polymorphic pseudotypes
+select array_in('{1,2,3}','int4'::regtype,-1); -- this has historically worked
+ array_in
+----------
+ {1,2,3}
+(1 row)
+
+select * from array_in('{1,2,3}','int4'::regtype,-1); -- this not
+ERROR: function "array_in" in FROM has unsupported return type anyarray
+LINE 1: select * from array_in('{1,2,3}','int4'::regtype,-1);
+ ^
+select anyrange_in('[10,20)','int4range'::regtype,-1);
+ERROR: cannot accept a value of type anyrange
-- test variadic polymorphic functions
create function myleast(variadic anyarray) returns anyelement as $$
select min($1[i]) from generate_subscripts($1,1) g(i)
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index b57591f69f6..e5222f1f81f 100644
--- a/src/test/regress/sql/polymorphism.sql
+++ b/src/test/regress/sql/polymorphism.sql
@@ -577,6 +577,11 @@ where histogram_bounds is not null;
-- (WHERE clause here is to avoid possibly getting a collation error instead)
select max(histogram_bounds) from pg_stats where tablename = 'pg_am';
+-- another corner case is the input functions for polymorphic pseudotypes
+select array_in('{1,2,3}','int4'::regtype,-1); -- this has historically worked
+select * from array_in('{1,2,3}','int4'::regtype,-1); -- this not
+select anyrange_in('[10,20)','int4range'::regtype,-1);
+
-- test variadic polymorphic functions
create function myleast(variadic anyarray) returns anyelement as $$