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 $$