Remove bogus Assert, add some regression test cases showing why.
authorTom Lane <[email protected]>
Sat, 4 Apr 2020 22:03:30 +0000 (18:03 -0400)
committerTom Lane <[email protected]>
Sat, 4 Apr 2020 22:03:30 +0000 (18:03 -0400)
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

src/backend/parser/parse_coerce.c
src/test/regress/expected/polymorphism.out
src/test/regress/sql/polymorphism.sql

index 645e4aa4ceb2be8e619a1b25df837bbd7cfd5bca..6cab20d09a10a1d23645fa5ccf20836847280c1f 100644 (file)
@@ -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)
index d86a7004a6fb5f5f156619212e3b07bfbaf74481..1ff40764d9a1744b9fdfd48e9a7921869642ad3f 100644 (file)
@@ -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)
index b57591f69f609271c9af7031b5f2ec0b117e4a61..e5222f1f81ff5bef7942232475090c8bad4aa188 100644 (file)
@@ -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 $$