Introduce "anycompatible" family of polymorphic types.
authorTom Lane
Thu, 19 Mar 2020 15:43:11 +0000 (11:43 -0400)
committerTom Lane
Thu, 19 Mar 2020 15:43:11 +0000 (11:43 -0400)
This patch adds the pseudo-types anycompatible, anycompatiblearray,
anycompatiblenonarray, and anycompatiblerange.  They work much like
anyelement, anyarray, anynonarray, and anyrange respectively, except
that the actual input values need not match precisely in type.
Instead, if we can find a common supertype (using the same rules
as for UNION/CASE type resolution), then the parser automatically
promotes the input values to that type.  For example,
"myfunc(anycompatible, anycompatible)" can match a call with one
integer and one bigint argument, with the integer automatically
promoted to bigint.  With anyelement in the definition, the user
would have had to cast the integer explicitly.

The new types also provide a second, independent set of type variables
for function matching; thus with "myfunc(anyelement, anyelement,
anycompatible) returns anycompatible" the first two arguments are
constrained to be the same type, but the third can be some other
type, and the result has the type of the third argument.  The need
for more than one set of type variables was foreseen back when we
first invented the polymorphic types, but we never did anything
about it.

Pavel Stehule, revised a bit by me

Discussion: https://postgr.es/m/CAFj8pRDna7VqNi8gR+Tt2Ktmz0cq5G93guc3Sbn_NVPLdXAkqA@mail.gmail.com

33 files changed:
doc/src/sgml/datatype.sgml
doc/src/sgml/extend.sgml
doc/src/sgml/plpgsql.sgml
doc/src/sgml/xfunc.sgml
src/backend/catalog/index.c
src/backend/catalog/pg_proc.c
src/backend/commands/functioncmds.c
src/backend/parser/parse_coerce.c
src/backend/utils/adt/json.c
src/backend/utils/adt/jsonb.c
src/backend/utils/adt/pseudotypes.c
src/backend/utils/fmgr/funcapi.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/include/catalog/pg_type.dat
src/include/catalog/pg_type.h
src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/aggregates.out
src/test/regress/expected/create_aggregate.out
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/plpgsql.out
src/test/regress/expected/polymorphism.out
src/test/regress/expected/rangefuncs.out
src/test/regress/expected/rangetypes.out
src/test/regress/expected/type_sanity.out
src/test/regress/sql/aggregates.sql
src/test/regress/sql/create_aggregate.sql
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/polymorphism.sql
src/test/regress/sql/rangefuncs.sql
src/test/regress/sql/rangetypes.sql
src/test/regress/sql/type_sanity.sql

index b9c5214ab8b846e37c2121b1ee32fc4ae4f5eb0a..03971822c293bcc80f1a9764e25fc9ab815a3429 100644 (file)
@@ -4798,6 +4798,22 @@ SELECT * FROM pg_attribute
     anyrange
    
 
+   
+    anycompatible
+   
+
+   
+    anycompatiblearray
+   
+
+   
+    anycompatiblenonarray
+   
+
+   
+    anycompatiblerange
+   
+
    
     void
    
@@ -4822,6 +4838,10 @@ SELECT * FROM pg_attribute
     fdw_handler
    
 
+   
+    table_am_handler
+   
+
    
     index_am_handler
    
@@ -4903,6 +4923,35 @@ SELECT * FROM pg_attribute
         ).
        
 
+       
+        anycompatible
+        Indicates that a function accepts any data type,
+        with automatic promotion of multiple arguments to a common data type
+        (see ).
+       
+
+       
+        anycompatiblearray
+        Indicates that a function accepts any array data type,
+        with automatic promotion of multiple arguments to a common data type
+        (see ).
+       
+
+       
+        anycompatiblenonarray
+        Indicates that a function accepts any non-array data type,
+        with automatic promotion of multiple arguments to a common data type
+        (see ).
+       
+
+       
+        anycompatiblerange
+        Indicates that a function accepts any range data type,
+        with automatic promotion of multiple arguments to a common data type
+        (see  and
+        ).
+       
+
        
         cstring
         Indicates that a function accepts or returns a null-terminated C string.
@@ -4924,6 +4973,11 @@ SELECT * FROM pg_attribute
         A foreign-data wrapper handler is declared to return fdw_handler.
        
 
+       
+        table_am_handler
+        A table access method handler is declared to return table_am_handler.
+       
+
        
         index_am_handler
         An index access method handler is declared to return index_am_handler.
@@ -4970,7 +5024,7 @@ SELECT * FROM pg_attribute
 
    
     Functions coded in C (whether built-in or dynamically loaded) can be
-    declared to accept or return any of these pseudo data types.  It is up to
+    declared to accept or return any of these pseudo-types.  It is up to
     the function author to ensure that the function will behave safely
     when a pseudo-type is used as an argument type.
    
@@ -4981,10 +5035,9 @@ SELECT * FROM pg_attribute
     languages forbid use of a pseudo-type as an argument type, and allow
     only void and record as a result type (plus
     trigger or event_trigger when the function is used
-    as a trigger or event trigger).  Some also
-    support polymorphic functions using the types anyelement,
-    anyarrayanynonarrayanyenum, and
-    anyrange.
+    as a trigger or event trigger).  Some also support polymorphic functions
+    using the polymorphic pseudo-types, which are shown above and discussed
+    in detail in .
    
 
    
index 97706da8717f4e6c415e21dd59f24bebad9a2eaf..930aeb767c39a492442b879824af7ee468e16ff3 100644 (file)
    
 
     
-     Five pseudo-types of special interest are anyelement,
-     anyarrayanynonarrayanyenum,
-     and anyrange,
-     which are collectively called polymorphic types.
-     Any function declared using these types is said to be
-     a polymorphic function.  A polymorphic function can
-     operate on many different data types, with the specific data type(s)
-     being determined by the data types actually passed to it in a particular
-     call.
+     Some pseudo-types of special interest are the polymorphic
+     types, which are used to declare polymorphic
+     functions.  This powerful feature allows a single function
+     definition to operate on many different data types, with the specific
+     data type(s) being determined by the data types actually passed to it
+     in a particular call.  The polymorphic types are shown in
+     .  Some examples of
+     their use appear in .
     
 
+    
+     Polymorphic Types
+     
+      
+       
+        Name
+        Family
+        Description
+       
+      
+
+      
+       
+        anyelement
+        Simple
+        Indicates that a function accepts any data type
+       
+
+       
+        anyarray
+        Simple
+        Indicates that a function accepts any array data type
+       
+
+       
+        anynonarray
+        Simple
+        Indicates that a function accepts any non-array data type
+       
+
+       
+        anyenum
+        Simple
+        Indicates that a function accepts any enum data type
+        (see )
+        
+       
+
+       
+        anyrange
+        Simple
+        Indicates that a function accepts any range data type
+        (see )
+        
+       
+
+       
+        anycompatible
+        Common
+        Indicates that a function accepts any data type,
+        with automatic promotion of multiple arguments to a common data type
+        
+       
+
+       
+        anycompatiblearray
+        Common
+        Indicates that a function accepts any array data type,
+        with automatic promotion of multiple arguments to a common data type
+        
+       
+
+       
+        anycompatiblenonarray
+        Common
+        Indicates that a function accepts any non-array data type,
+        with automatic promotion of multiple arguments to a common data type
+        
+       
+
+       
+        anycompatiblerange
+        Common
+        Indicates that a function accepts any range data type,
+        with automatic promotion of multiple arguments to a common data type
+        
+       
+      
+     
+    
+
     
      Polymorphic arguments and results are tied to each other and are resolved
-     to a specific data type when a query calling a polymorphic function is
-     parsed.  Each position (either argument or return value) declared as
+     to specific data types when a query calling a polymorphic function is
+     parsed.  When there is more than one polymorphic argument, the actual
+     data types of the input values must match up as described below.  If the
+     function's result type is polymorphic, or it has output parameters of
+     polymorphic types, the types of those results are deduced from the
+     actual types of the polymorphic inputs as described below.
+    
+
+    
+     For the simple family of polymorphic types, the
+     matching and deduction rules work like this:
+    
+
+    
+     Each position (either argument or return value) declared as
      anyelement is allowed to have any specific actual
      data type, but in any given call they must all be the
      same actual type. Each
     
      When the return value of a function is declared as a polymorphic type,
      there must be at least one argument position that is also polymorphic,
-     and the actual data type supplied as the argument determines the actual
+     and the actual data type(s) supplied for the polymorphic arguments
+     determine the actual
      result type for that call.  For example, if there were not already
      an array subscripting mechanism, one could define a function that
      implements subscripting as subscript(anyarray, integer)
     
      In most cases, the parser can infer the actual data type for a
      polymorphic result type from arguments that are of a different
-     polymorphic type; for example anyarray can be deduced
-     from anyelement or vice versa.  The exception is that a
+     polymorphic type in the same family; for example anyarray
+     can be deduced from anyelement or vice versa.
+     An exception is that a
      polymorphic result of type anyrange requires an argument
      of type anyrange; it cannot be deduced
      from anyarray or anyelement arguments.  This
      both actual arguments have to be the same enum type.
     
 
+    
+     For the common family of polymorphic types, the
+     matching and deduction rules work approximately the same as for
+     the simple family, with one major difference: the
+     actual types of the arguments need not be identical, so long as they
+     can be implicitly cast to a single common type.  The common type is
+     selected following the same rules as for UNION and
+     related constructs (see ).
+     Selection of the common type considers the actual types
+     of anycompatible and anycompatiblenonarray
+     inputs, the array element types of anycompatiblearray
+     inputs, and the range subtypes of anycompatiblerange
+     inputs.  If anycompatiblenonarray is present then the
+     common type is required to be a non-array type.  Once a common type is
+     identified, arguments in anycompatible
+     and anycompatiblenonarray positions are automatically
+     cast to that type, and arguments in anycompatiblearray
+     positions are automatically cast to the array type for that type.
+    
+
+    
+     Since there is no way to select a range type knowing only its subtype,
+     use of anycompatiblerange requires that all arguments
+     declared with that type have the same actual range type, and that that
+     type's subtype agree with the selected common type, so that no casting
+     of the range values is required.  As with anyrange, use
+     of anycompatiblerange as a function result type requires
+     that there be an anycompatiblerange argument.
+    
+
+    
+     Notice that there is no anycompatibleenum type.  Such a
+     type would not be very useful, since there normally are not any
+     implicit casts to enum types, meaning that there would be no way to
+     resolve a common type for dissimilar enum inputs.
+    
+
+    
+     The simple and common polymorphic
+     families represent two independent sets of type variables.  Consider
+     for example
+
+CREATE FUNCTION myfunc(a anyelement, b anyelement,
+                       c anycompatible, d anycompatible)
+RETURNS anycompatible AS ...
+
+     In an actual call of this function, the first two inputs must have
+     exactly the same type.  The last two inputs must be promotable to a
+     common type, but this type need not have anything to do with the type
+     of the first two inputs.  The result will have the common type of the
+     last two inputs.
+    
+
     
      A variadic function (one taking a variable number of arguments, as in
      ) can be
      polymorphic: this is accomplished by declaring its last parameter as
-     VARIADIC anyarray.  For purposes of argument
+     VARIADIC anyarray or
+     VARIADIC anycompatiblearray.
+     For purposes of argument
      matching and determining the actual result type, such a function behaves
      the same as if you had written the appropriate number of
-     anynonarray parameters.
+     anynonarray or anycompatiblenonarray
+     parameters.
     
    
   
index 2987a555a3472b6a76c9c81cf0803e834be1c625..cc99acad31f18801d475ccefbfc19abd9968cc71 100644 (file)
     
 
     
-     PL/pgSQL functions can also be declared to accept
-     and return the polymorphic types
-     anyelementanyarrayanynonarray,
-     anyenum, and anyrange.  The actual
-     data types handled by a polymorphic function can vary from call to
-     call, as discussed in .
-     An example is shown in .
+     PL/pgSQL functions can also be declared to
+     accept and return the polymorphic types described in
+     , thus allowing the actual data
+     types handled by the function to vary from call to call.
+     Examples appear in .
     
 
     
@@ -519,13 +517,11 @@ $$ LANGUAGE plpgsql;
      
 
      
-      When the return type of a PL/pgSQL
-      function is declared as a polymorphic type (anyelement,
-      anyarrayanynonarrayanyenum,
-      or anyrange), a special parameter $0
-      is created.  Its data type is the actual return type of the function,
-      as deduced from the actual input types (see 
-      linkend="extend-types-polymorphic"/>).
+      When the return type of a PL/pgSQL function
+      is declared as a polymorphic type (see
+      ), a special
+      parameter $0 is created.  Its data type is the actual
+      return type of the function, as deduced from the actual input types.
       This allows the function to access its actual return type
       as shown in .
       $0 is initialized to null and can be modified by
@@ -563,6 +559,32 @@ END;
 $$ LANGUAGE plpgsql;
 
      
+
+     
+      In practice it might be more useful to declare a polymorphic function
+      using the anycompatible family of types, so that automatic
+      promotion of the input arguments to a common type will occur.
+      For example:
+
+
+CREATE FUNCTION add_three_values(v1 anycompatible, v2 anycompatible, v3 anycompatible)
+RETURNS anycompatible AS $$
+BEGIN
+    RETURN v1 + v2 + v3;
+END;
+$$ LANGUAGE plpgsql;
+
+
+      With this example, a call such as
+
+
+SELECT add_three_values(1, 2, 4.7);
+
+
+      will work, automatically promoting the integer inputs to numeric.
+      The function using anyelement would require you to
+      cast the three inputs to the same type manually.
+     
     
 
   
index 6350f92f8669c169512ce432a5b4121e5aeb2121..0bec854d04b99ad728da8148024a634909c5a934 100644 (file)
@@ -1226,16 +1226,13 @@ $$ LANGUAGE SQL;
     
    
 
-   
+    id="xfunc-sql-polymorphic-functions">
     Polymorphic <acronym>SQL</acronym> Functions
 
     
      SQL functions can be declared to accept and
-     return the polymorphic types anyelement,
-     anyarrayanynonarray,
-     anyenum, and anyrange.  See 
-     linkend="extend-types-polymorphic"/> for a more detailed
-     explanation of polymorphic functions. Here is a polymorphic
+     return the polymorphic types described in 
+     linkend="extend-types-polymorphic"/>.  Here is a polymorphic
      function make_array that builds up an array
      from two arbitrary data type elements:
 
@@ -1260,9 +1257,43 @@ SELECT make_array(1, 2) AS intarray, make_array('a'::text, 'b') AS textarray;
      type.
      Without the typecast, you will get errors like this:
 
-
 ERROR:  could not determine polymorphic type because input has type unknown
-
+
+    
+
+    
+     With make_array declared as above, you must
+     provide two arguments that are of exactly the same data type; the
+     system will not attempt to resolve any type differences.  Thus for
+     example this does not work:
+
+SELECT make_array(1, 2.5) AS numericarray;
+ERROR:  function make_array(integer, numeric) does not exist
+
+     An alternative approach is to use the common family of
+     polymorphic types, which allows the system to try to identify a
+     suitable common type:
+
+CREATE FUNCTION make_array2(anycompatible, anycompatible)
+RETURNS anycompatiblearray AS $$
+    SELECT ARRAY[$1, $2];
+$$ LANGUAGE SQL;
+
+SELECT make_array2(1, 2.5) AS numericarray;
+ numericarray
+--------------
+ {1,2.5}
+(1 row)
+
+     Because the rules for common type resolution default to choosing
+     type text when all inputs are of unknown types, this
+     also works:
+
+SELECT make_array2('a', 'b') AS textarray;
+ textarray 
+-----------
+ {a,b}
+(1 row)
 
     
 
@@ -1284,7 +1315,7 @@ CREATE FUNCTION invalid_func() RETURNS anyelement AS $$
     SELECT 1;
 $$ LANGUAGE SQL;
 ERROR:  cannot determine result data type
-DETAIL:  A function returning a polymorphic type must have at least one polymorphic argument.
+DETAIL:  A result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange.
 
     
 
@@ -3157,11 +3188,9 @@ CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
 
     
      C-language functions can be declared to accept and
-     return the polymorphic types
-     anyelementanyarrayanynonarray,
-     anyenum, and anyrange.
-     See  for a more detailed explanation
-     of polymorphic functions. When function arguments or return types
+     return the polymorphic types described in 
+     linkend="extend-types-polymorphic"/>.
+     When a function's arguments or return types
      are defined as polymorphic types, the function author cannot know
      in advance what data type it will be called with, or
      need to return. There are two routines provided in fmgr.h
index 023ec7e6188356d695976a96d73061d1601d038f..2d81bc3cbc94ed367e97b4225ca052ae75f4cb60 100644 (file)
@@ -404,10 +404,6 @@ ConstructTupleDescriptor(Relation heapRelation,
         */
        keyType = amroutine->amkeytype;
 
-       /*
-        * Code below is concerned to the opclasses which are not used with
-        * the included columns.
-        */
        if (i < indexInfo->ii_NumIndexKeyAttrs)
        {
            tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(classObjectId[i]));
@@ -422,6 +418,10 @@ ConstructTupleDescriptor(Relation heapRelation,
             * If keytype is specified as ANYELEMENT, and opcintype is
             * ANYARRAY, then the attribute type must be an array (else it'd
             * not have matched this opclass); use its element type.
+            *
+            * We could also allow ANYCOMPATIBLE/ANYCOMPATIBLEARRAY here, but
+            * there seems no need to do so; there's no reason to declare an
+            * opclass as taking ANYCOMPATIBLEARRAY rather than ANYARRAY.
             */
            if (keyType == ANYELEMENTOID && opclassTup->opcintype == ANYARRAYOID)
            {
index 0cac936cef8d41223cfcfeada32c26811ff16ce9..6cdda35d1c97660116258fc87c63baceb821b5a4 100644 (file)
@@ -262,6 +262,9 @@ ProcedureCreate(const char *procedureName,
                        case ANYARRAYOID:
                            variadicType = ANYELEMENTOID;
                            break;
+                       case ANYCOMPATIBLEARRAYOID:
+                           variadicType = ANYCOMPATIBLEOID;
+                           break;
                        default:
                            variadicType = get_element_type(allParams[i]);
                            if (!OidIsValid(variadicType))
index 5eac55aaca196ebefe05b24d3006bbaa8314e16d..694114adedc32261998527a91ac9423b0901f0a4 100644 (file)
@@ -320,6 +320,7 @@ interpret_function_parameter_list(ParseState *pstate,
            switch (toid)
            {
                case ANYARRAYOID:
+               case ANYCOMPATIBLEARRAYOID:
                case ANYOID:
                    /* okay */
                    break;
index c3fb51d35d9edf62604928f489ba206b57adacec..645e4aa4ceb2be8e619a1b25df837bbd7cfd5bca 100644 (file)
@@ -167,15 +167,17 @@ coerce_type(ParseState *pstate, Node *node,
    }
    if (targetTypeId == ANYOID ||
        targetTypeId == ANYELEMENTOID ||
-       targetTypeId == ANYNONARRAYOID)
+       targetTypeId == ANYNONARRAYOID ||
+       targetTypeId == ANYCOMPATIBLEOID ||
+       targetTypeId == ANYCOMPATIBLENONARRAYOID)
    {
        /*
         * Assume can_coerce_type verified that implicit coercion is okay.
         *
         * Note: by returning the unmodified node here, we are saying that
         * it's OK to treat an UNKNOWN constant as a valid input for a
-        * function accepting ANY, ANYELEMENT, or ANYNONARRAY.  This should be
-        * all right, since an UNKNOWN value is still a perfectly valid Datum.
+        * function accepting one of these pseudotypes.  This should be all
+        * right, since an UNKNOWN value is still a perfectly valid Datum.
         *
         * NB: we do NOT want a RelabelType here: the exposed type of the
         * function argument must be its actual type, not the polymorphic
@@ -185,7 +187,9 @@ coerce_type(ParseState *pstate, Node *node,
    }
    if (targetTypeId == ANYARRAYOID ||
        targetTypeId == ANYENUMOID ||
-       targetTypeId == ANYRANGEOID)
+       targetTypeId == ANYRANGEOID ||
+       targetTypeId == ANYCOMPATIBLEARRAYOID ||
+       targetTypeId == ANYCOMPATIBLERANGEOID)
    {
        /*
         * Assume can_coerce_type verified that implicit coercion is okay.
@@ -193,10 +197,10 @@ coerce_type(ParseState *pstate, Node *node,
         * These cases are unlike the ones above because the exposed type of
         * the argument must be an actual array, enum, or range type.  In
         * particular the argument must *not* be an UNKNOWN constant.  If it
-        * is, we just fall through; below, we'll call anyarray_in,
-        * anyenum_in, or anyrange_in, which will produce an error.  Also, if
-        * what we have is a domain over array, enum, or range, we have to
-        * relabel it to its base type.
+        * is, we just fall through; below, we'll call the pseudotype's input
+        * function, which will produce an error.  Also, if what we have is a
+        * domain over array, enum, or range, we have to relabel it to its
+        * base type.
         *
         * Note: currently, we can't actually see a domain-over-enum here,
         * since the other functions in this file will not match such a
@@ -1386,6 +1390,103 @@ select_common_type(ParseState *pstate, List *exprs, const char *context,
    return ptype;
 }
 
+/*
+ * select_common_type_from_oids()
+ *     Determine the common supertype of an array of type OIDs.
+ *
+ * This is the same logic as select_common_type(), but working from
+ * an array of type OIDs not a list of expressions.  As in that function,
+ * earlier entries in the array have some preference over later ones.
+ * On failure, return InvalidOid if noerror is true, else throw an error.
+ *
+ * Note: neither caller will pass any UNKNOWNOID entries, so the tests
+ * for that in this function are dead code.  However, they don't cost much,
+ * and it seems better to keep this logic as close to select_common_type()
+ * as possible.
+ */
+static Oid
+select_common_type_from_oids(int nargs, const Oid *typeids, bool noerror)
+{
+   Oid         ptype;
+   TYPCATEGORY pcategory;
+   bool        pispreferred;
+   int         i = 1;
+
+   Assert(nargs > 0);
+   ptype = typeids[0];
+
+   /* If all input types are valid and exactly the same, pick that type. */
+   if (ptype != UNKNOWNOID)
+   {
+       for (; i < nargs; i++)
+       {
+           if (typeids[i] != ptype)
+               break;
+       }
+       if (i == nargs)
+           return ptype;
+   }
+
+   /*
+    * Nope, so set up for the full algorithm.  Note that at this point, we
+    * can skip array entries before "i"; they are all equal to ptype.
+    */
+   ptype = getBaseType(ptype);
+   get_type_category_preferred(ptype, &pcategory, &pispreferred);
+
+   for (; i < nargs; i++)
+   {
+       Oid         ntype = getBaseType(typeids[i]);
+
+       /* move on to next one if no new information... */
+       if (ntype != UNKNOWNOID && ntype != ptype)
+       {
+           TYPCATEGORY ncategory;
+           bool        nispreferred;
+
+           get_type_category_preferred(ntype, &ncategory, &nispreferred);
+           if (ptype == UNKNOWNOID)
+           {
+               /* so far, only unknowns so take anything... */
+               ptype = ntype;
+               pcategory = ncategory;
+               pispreferred = nispreferred;
+           }
+           else if (ncategory != pcategory)
+           {
+               /*
+                * both types in different categories? then not much hope...
+                */
+               if (noerror)
+                   return InvalidOid;
+               ereport(ERROR,
+                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                        errmsg("argument types %s and %s cannot be matched",
+                               format_type_be(ptype),
+                               format_type_be(ntype))));
+           }
+           else if (!pispreferred &&
+                    can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
+                    !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
+           {
+               /*
+                * take new type if can coerce to it implicitly but not the
+                * other way; but if we have a preferred type, stay on it.
+                */
+               ptype = ntype;
+               pcategory = ncategory;
+               pispreferred = nispreferred;
+           }
+       }
+   }
+
+   /* Like select_common_type(), choose TEXT if all inputs were UNKNOWN */
+   if (ptype == UNKNOWNOID)
+       ptype = TEXTOID;
+
+   return ptype;
+}
+
 /*
  * coerce_to_common_type()
  *     Coerce an expression to the given type.
@@ -1442,14 +1543,28 @@ coerce_to_common_type(ParseState *pstate, Node *node,
  *   we add the extra condition that the ANYELEMENT type must not be an array.
  *   (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
  *   is an extra restriction if not.)
+ * 7) All arguments declared ANYCOMPATIBLE must be implicitly castable
+ *   to a common supertype (chosen as per select_common_type's rules).
+ *   ANYCOMPATIBLENONARRAY works like ANYCOMPATIBLE but also requires the
+ *   common supertype to not be an array.  If there are ANYCOMPATIBLEARRAY
+ *   or ANYCOMPATIBLERANGE arguments, their element types or subtypes are
+ *   included while making the choice of common supertype.
+ * 8) The resolved type of ANYCOMPATIBLEARRAY arguments will be the array
+ *   type over the common supertype (which might not be the same array type
+ *   as any of the original arrays).
+ * 9) All ANYCOMPATIBLERANGE arguments must be the exact same range type
+ *   (after domain flattening), since we have no preference rule that would
+ *   let us choose one over another.  Furthermore, that range's subtype
+ *   must exactly match the common supertype chosen by rule 7.
  *
  * Domains over arrays match ANYARRAY, and are immediately flattened to their
  * base type.  (Thus, for example, we will consider it a match if one ANYARRAY
  * argument is a domain over int4[] while another one is just int4[].) Also
- * notice that such a domain does *not* match ANYNONARRAY.
+ * notice that such a domain does *not* match ANYNONARRAY.  The same goes
+ * for ANYCOMPATIBLEARRAY and ANYCOMPATIBLENONARRAY.
  *
- * Similarly, domains over ranges match ANYRANGE, and are immediately
- * flattened to their base type.
+ * Similarly, domains over ranges match ANYRANGE or ANYCOMPATIBLERANGE,
+ * and are immediately flattened to their base type.
  *
  * Note that domains aren't currently considered to match ANYENUM,
  * even if their base type would match.
@@ -1467,13 +1582,19 @@ check_generic_type_consistency(const Oid *actual_arg_types,
    Oid         elem_typeid = InvalidOid;
    Oid         array_typeid = InvalidOid;
    Oid         range_typeid = InvalidOid;
+   Oid         anycompatible_range_typeid = InvalidOid;
+   Oid         anycompatible_range_typelem = InvalidOid;
    bool        have_anynonarray = false;
    bool        have_anyenum = false;
+   bool        have_anycompatible_nonarray = false;
+   int         n_anycompatible_args = 0;
+   Oid         anycompatible_actual_types[FUNC_MAX_ARGS];
 
    /*
     * Loop through the arguments to see if we have any that are polymorphic.
     * If so, require the actual types to be consistent.
     */
+   Assert(nargs <= FUNC_MAX_ARGS);
    for (int j = 0; j < nargs; j++)
    {
        Oid         decl_type = declared_arg_types[j];
@@ -1511,6 +1632,50 @@ check_generic_type_consistency(const Oid *actual_arg_types,
                return false;
            range_typeid = actual_type;
        }
+       else if (decl_type == ANYCOMPATIBLEOID ||
+                decl_type == ANYCOMPATIBLENONARRAYOID)
+       {
+           if (decl_type == ANYCOMPATIBLENONARRAYOID)
+               have_anycompatible_nonarray = true;
+           if (actual_type == UNKNOWNOID)
+               continue;
+           /* collect the actual types of non-unknown COMPATIBLE args */
+           anycompatible_actual_types[n_anycompatible_args++] = actual_type;
+       }
+       else if (decl_type == ANYCOMPATIBLEARRAYOID)
+       {
+           Oid         elem_type;
+
+           if (actual_type == UNKNOWNOID)
+               continue;
+           actual_type = getBaseType(actual_type); /* flatten domains */
+           elem_type = get_element_type(actual_type);
+           if (!OidIsValid(elem_type))
+               return false;   /* not an array */
+           /* collect the element type for common-supertype choice */
+           anycompatible_actual_types[n_anycompatible_args++] = elem_type;
+       }
+       else if (decl_type == ANYCOMPATIBLERANGEOID)
+       {
+           if (actual_type == UNKNOWNOID)
+               continue;
+           actual_type = getBaseType(actual_type); /* flatten domains */
+           if (OidIsValid(anycompatible_range_typeid))
+           {
+               /* All ANYCOMPATIBLERANGE arguments must be the same type */
+               if (anycompatible_range_typeid != actual_type)
+                   return false;
+           }
+           else
+           {
+               anycompatible_range_typeid = actual_type;
+               anycompatible_range_typelem = get_range_subtype(actual_type);
+               if (!OidIsValid(anycompatible_range_typelem))
+                   return false;   /* not a range type */
+               /* collect the subtype for common-supertype choice */
+               anycompatible_actual_types[n_anycompatible_args++] = anycompatible_range_typelem;
+           }
+       }
    }
 
    /* Get the element type based on the array type, if we have one */
@@ -1591,6 +1756,38 @@ check_generic_type_consistency(const Oid *actual_arg_types,
            return false;
    }
 
+   /* Check matching of ANYCOMPATIBLE-family arguments, if any */
+   if (n_anycompatible_args > 0)
+   {
+       Oid         anycompatible_typeid;
+
+       anycompatible_typeid =
+           select_common_type_from_oids(n_anycompatible_args,
+                                        anycompatible_actual_types,
+                                        true);
+
+       if (!OidIsValid(anycompatible_typeid))
+           return false;       /* there's no common supertype */
+
+       if (have_anycompatible_nonarray)
+       {
+           /*
+            * require the anycompatible type to not be an array or domain
+            * over array
+            */
+           if (type_is_array_domain(anycompatible_typeid))
+               return false;
+       }
+
+       /*
+        * the anycompatible type must exactly match the range element type,
+        * if we were able to identify one
+        */
+       if (OidIsValid(anycompatible_range_typelem) &&
+           anycompatible_range_typelem != anycompatible_typeid)
+           return false;
+   }
+
    /* Looks valid */
    return true;
 }
@@ -1610,6 +1807,11 @@ check_generic_type_consistency(const Oid *actual_arg_types,
  * successful, we alter that position of declared_arg_types[] so that
  * make_fn_arguments will coerce the literal to the right thing.
  *
+ * If we have polymorphic arguments of the ANYCOMPATIBLE family,
+ * we similarly alter declared_arg_types[] entries to show the resolved
+ * common supertype, so that make_fn_arguments will coerce the actual
+ * 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:
  *
@@ -1631,11 +1833,20 @@ check_generic_type_consistency(const Oid *actual_arg_types,
  *   we add the extra condition that the ANYELEMENT type must not be an array.
  *   (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
  *   is an extra restriction if not.)
+ * 8) ANYCOMPATIBLE, ANYCOMPATIBLEARRAY, ANYCOMPATIBLENONARRAY, and
+ *   ANYCOMPATIBLERANGE are handled by resolving the common supertype
+ *   of those arguments (or their element types/subtypes, for array and range
+ *   inputs), and then coercing all those arguments to the common supertype,
+ *   or the array type over the common supertype for ANYCOMPATIBLEARRAY.
+ *   For ANYCOMPATIBLERANGE, there must be at least one non-UNKNOWN input,
+ *   all such inputs must be the same range type, and that type's subtype
+ *   must equal the common supertype.
  *
  * Domains over arrays or ranges match ANYARRAY or ANYRANGE arguments,
  * respectively, and are immediately flattened to their base type.  (In
  * particular, if the return type is also ANYARRAY or ANYRANGE, we'll set
- * it to the base type not the domain type.)
+ * it to the base type not the domain type.)  The same is true for
+ * ANYCOMPATIBLEARRAY and ANYCOMPATIBLERANGE.
  *
  * When allow_poly is false, we are not expecting any of the actual_arg_types
  * to be polymorphic, and we should not return a polymorphic result type
@@ -1652,7 +1863,12 @@ check_generic_type_consistency(const Oid *actual_arg_types,
  * the element type to infer the result type.  Note this means that functions
  * taking ANYARRAY had better behave sanely if applied to the pg_statistic
  * columns; they can't just assume that successive inputs are of the same
- * actual element type.
+ * actual element type.  There is no similar logic for ANYCOMPATIBLEARRAY;
+ * there isn't a need for it since there are no catalog columns of that type,
+ * so we won't see it as input.  We could consider matching an actual ANYARRAY
+ * 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.
  */
 Oid
 enforce_generic_type_consistency(const Oid *actual_arg_types,
@@ -1661,18 +1877,29 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
                                 Oid rettype,
                                 bool allow_poly)
 {
+   bool        have_poly_anycompatible = false;
    bool        have_poly_unknowns = false;
    Oid         elem_typeid = InvalidOid;
    Oid         array_typeid = InvalidOid;
    Oid         range_typeid = InvalidOid;
-   int         n_poly_args = 0;
+   Oid         anycompatible_typeid = InvalidOid;
+   Oid         anycompatible_array_typeid = InvalidOid;
+   Oid         anycompatible_range_typeid = InvalidOid;
+   Oid         anycompatible_range_typelem = InvalidOid;
    bool        have_anynonarray = (rettype == ANYNONARRAYOID);
    bool        have_anyenum = (rettype == ANYENUMOID);
+   bool        have_anycompatible_nonarray = (rettype == ANYCOMPATIBLENONARRAYOID);
+   bool        have_anycompatible_array = (rettype == ANYCOMPATIBLEARRAYOID);
+   bool        have_anycompatible_range = (rettype == ANYCOMPATIBLERANGEOID);
+   int         n_poly_args = 0;    /* this counts all family-1 arguments */
+   int         n_anycompatible_args = 0;   /* this counts only non-unknowns */
+   Oid         anycompatible_actual_types[FUNC_MAX_ARGS];
 
    /*
     * Loop through the arguments to see if we have any that are polymorphic.
     * If so, require the actual types to be consistent.
     */
+   Assert(nargs <= FUNC_MAX_ARGS);
    for (int j = 0; j < nargs; j++)
    {
        Oid         decl_type = declared_arg_types[j];
@@ -1743,18 +1970,87 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
                                   format_type_be(actual_type))));
            range_typeid = actual_type;
        }
+       else if (decl_type == ANYCOMPATIBLEOID ||
+                decl_type == ANYCOMPATIBLENONARRAYOID)
+       {
+           have_poly_anycompatible = true;
+           if (decl_type == ANYCOMPATIBLENONARRAYOID)
+               have_anycompatible_nonarray = true;
+           if (actual_type == UNKNOWNOID)
+               continue;
+           if (allow_poly && decl_type == actual_type)
+               continue;       /* no new information here */
+           /* collect the actual types of non-unknown COMPATIBLE args */
+           anycompatible_actual_types[n_anycompatible_args++] = actual_type;
+       }
+       else if (decl_type == ANYCOMPATIBLEARRAYOID)
+       {
+           Oid         anycompatible_elem_type;
+
+           have_poly_anycompatible = true;
+           have_anycompatible_array = true;
+           if (actual_type == UNKNOWNOID)
+               continue;
+           if (allow_poly && decl_type == actual_type)
+               continue;       /* no new information here */
+           actual_type = getBaseType(actual_type); /* flatten domains */
+           anycompatible_elem_type = get_element_type(actual_type);
+           if (!OidIsValid(anycompatible_elem_type))
+               ereport(ERROR,
+                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                        errmsg("argument declared %s is not an array but type %s",
+                               "anycompatiblearray",
+                               format_type_be(actual_type))));
+           /* collect the element type for common-supertype choice */
+           anycompatible_actual_types[n_anycompatible_args++] = anycompatible_elem_type;
+       }
+       else if (decl_type == ANYCOMPATIBLERANGEOID)
+       {
+           have_poly_anycompatible = true;
+           have_anycompatible_range = true;
+           if (actual_type == UNKNOWNOID)
+               continue;
+           if (allow_poly && decl_type == actual_type)
+               continue;       /* no new information here */
+           actual_type = getBaseType(actual_type); /* flatten domains */
+           if (OidIsValid(anycompatible_range_typeid))
+           {
+               /* All ANYCOMPATIBLERANGE arguments must be the same type */
+               if (anycompatible_range_typeid != actual_type)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("arguments declared \"anycompatiblerange\" are not all alike"),
+                            errdetail("%s versus %s",
+                                      format_type_be(anycompatible_range_typeid),
+                                      format_type_be(actual_type))));
+           }
+           else
+           {
+               anycompatible_range_typeid = actual_type;
+               anycompatible_range_typelem = get_range_subtype(actual_type);
+               if (!OidIsValid(anycompatible_range_typelem))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("argument declared %s is not a range type but type %s",
+                                   "anycompatiblerange",
+                                   format_type_be(actual_type))));
+               /* collect the subtype for common-supertype choice */
+               anycompatible_actual_types[n_anycompatible_args++] = anycompatible_range_typelem;
+           }
+       }
    }
 
    /*
     * Fast Track: if none of the arguments are polymorphic, return the
     * unmodified rettype.  We assume it can't be polymorphic either.
     */
-   if (n_poly_args == 0)
+   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)
    {
        /* Get the element type based on the array type, if we have one */
@@ -1766,13 +2062,14 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
            {
                /*
                 * Special case for matching ANYARRAY input to an ANYARRAY
-                * argument: allow it iff no other arguments are polymorphic
-                * (otherwise we couldn't be sure whether the array element
-                * type matches up) and the result type doesn't require us to
-                * infer a specific element type.
+                * argument: allow it iff no other arguments are family-1
+                * polymorphics (otherwise we couldn't be sure whether the
+                * array element type matches up) and the result type doesn't
+                * require us to infer a specific element type.
                 */
                if (n_poly_args != 1 ||
-                   (rettype != ANYARRAYOID && IsPolymorphicType(rettype)))
+                   (rettype != ANYARRAYOID &&
+                    IsPolymorphicTypeFamily1(rettype)))
                    ereport(ERROR,
                            (errcode(ERRCODE_DATATYPE_MISMATCH),
                             errmsg("cannot determine element type of \"anyarray\" argument")));
@@ -1888,9 +2185,108 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
        }
    }
 
+   /* Check matching of family-2 polymorphic arguments, if any */
+   if (have_poly_anycompatible)
+   {
+       if (n_anycompatible_args > 0)
+       {
+           anycompatible_typeid =
+               select_common_type_from_oids(n_anycompatible_args,
+                                            anycompatible_actual_types,
+                                            false);
+
+           if (have_anycompatible_array)
+           {
+               anycompatible_array_typeid = get_array_type(anycompatible_typeid);
+               if (!OidIsValid(anycompatible_array_typeid))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_UNDEFINED_OBJECT),
+                            errmsg("could not find array type for data type %s",
+                                   format_type_be(anycompatible_typeid))));
+           }
+
+           if (have_anycompatible_range)
+           {
+               /* we can't infer a range type from the others */
+               if (!OidIsValid(anycompatible_range_typeid))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("could not determine polymorphic type %s because input has type %s",
+                                   "anycompatiblerange", "unknown")));
+
+               /*
+                * the anycompatible type must exactly match the range element
+                * type
+                */
+               if (anycompatible_range_typelem != anycompatible_typeid)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("anycompatiblerange type %s does not match anycompatible type %s",
+                                   format_type_be(anycompatible_range_typeid),
+                                   format_type_be(anycompatible_typeid))));
+           }
+
+           if (have_anycompatible_nonarray)
+           {
+               /*
+                * require the element type to not be an array or domain over
+                * array
+                */
+               if (type_is_array_domain(anycompatible_typeid))
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("type matched to anycompatiblenonarray is an array type: %s",
+                                   format_type_be(anycompatible_typeid))));
+           }
+       }
+       else
+       {
+           if (allow_poly)
+           {
+               anycompatible_typeid = ANYCOMPATIBLEOID;
+               anycompatible_array_typeid = ANYCOMPATIBLEARRAYOID;
+               anycompatible_range_typeid = ANYCOMPATIBLERANGEOID;
+           }
+           else
+           {
+               /*
+                * Only way to get here is if all the ANYCOMPATIBLE args have
+                * UNKNOWN inputs.  Resolve to TEXT as select_common_type()
+                * would do.  That doesn't license us to use TEXTRANGE,
+                * though.
+                */
+               anycompatible_typeid = TEXTOID;
+               anycompatible_array_typeid = TEXTARRAYOID;
+               if (have_anycompatible_range)
+                   ereport(ERROR,
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("could not determine polymorphic type %s because input has type %s",
+                                   "anycompatiblerange", "unknown")));
+           }
+       }
+
+       /* replace polymorphic types by selected types */
+       for (int j = 0; j < nargs; j++)
+       {
+           Oid         decl_type = declared_arg_types[j];
+
+           if (decl_type == ANYCOMPATIBLEOID ||
+               decl_type == ANYCOMPATIBLENONARRAYOID)
+               declared_arg_types[j] = anycompatible_typeid;
+           else if (decl_type == ANYCOMPATIBLEARRAYOID)
+               declared_arg_types[j] = anycompatible_array_typeid;
+           else if (decl_type == ANYCOMPATIBLERANGEOID)
+               declared_arg_types[j] = anycompatible_range_typeid;
+       }
+   }
+
    /*
     * If we had any UNKNOWN inputs for polymorphic arguments, re-scan to
     * assign correct types to them.
+    *
+    * Note: we don't have to consider unknown inputs that were matched to
+    * ANYCOMPATIBLE-family arguments, because we forcibly updated their
+    * declared_arg_types[] positions just above.
     */
    if (have_poly_unknowns)
    {
@@ -1923,10 +2319,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
            {
                if (!OidIsValid(range_typeid))
                {
+                   /* we can't infer a range type from the others */
                    ereport(ERROR,
-                           (errcode(ERRCODE_UNDEFINED_OBJECT),
-                            errmsg("could not find range type for data type %s",
-                                   format_type_be(elem_typeid))));
+                           (errcode(ERRCODE_DATATYPE_MISMATCH),
+                            errmsg("could not determine polymorphic type %s because input has type %s",
+                                   "anyrange", "unknown")));
                }
                declared_arg_types[j] = range_typeid;
            }
@@ -1957,16 +2354,49 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
    /* if we return ANYRANGE use the appropriate argument type */
    if (rettype == ANYRANGEOID)
    {
+       /* this error is unreachable if the function signature is valid: */
        if (!OidIsValid(range_typeid))
-       {
            ereport(ERROR,
-                   (errcode(ERRCODE_UNDEFINED_OBJECT),
-                    errmsg("could not find range type for data type %s",
-                           format_type_be(elem_typeid))));
-       }
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg("could not determine polymorphic type %s because input has type %s",
+                           "anyrange", "unknown")));
        return range_typeid;
    }
 
+   /* if we return ANYCOMPATIBLE use the appropriate type */
+   if (rettype == ANYCOMPATIBLEOID ||
+       rettype == ANYCOMPATIBLENONARRAYOID)
+   {
+       /* this error is unreachable if the function signature is valid: */
+       if (!OidIsValid(anycompatible_typeid))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg_internal("could not identify anycompatible type")));
+       return anycompatible_typeid;
+   }
+
+   /* if we return ANYCOMPATIBLEARRAY use the appropriate type */
+   if (rettype == ANYCOMPATIBLEARRAYOID)
+   {
+       /* this error is unreachable if the function signature is valid: */
+       if (!OidIsValid(anycompatible_array_typeid))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg_internal("could not identify anycompatiblearray type")));
+       return anycompatible_array_typeid;
+   }
+
+   /* if we return ANYCOMPATIBLERANGE use the appropriate argument type */
+   if (rettype == ANYCOMPATIBLERANGEOID)
+   {
+       /* this error is unreachable if the function signature is valid: */
+       if (!OidIsValid(anycompatible_range_typeid))
+           ereport(ERROR,
+                   (errcode(ERRCODE_DATATYPE_MISMATCH),
+                    errmsg_internal("could not identify anycompatiblerange type")));
+       return anycompatible_range_typeid;
+   }
+
    /* we don't return a generic type; send back the original return type */
    return rettype;
 }
@@ -1984,11 +2414,12 @@ check_valid_polymorphic_signature(Oid ret_type,
                                  const Oid *declared_arg_types,
                                  int nargs)
 {
-   if (ret_type == ANYRANGEOID)
+   if (ret_type == ANYRANGEOID || ret_type == ANYCOMPATIBLERANGEOID)
    {
        /*
         * ANYRANGE requires an ANYRANGE input, else we can't tell which of
-        * several range types with the same element type to use.
+        * several range types with the same element type to use.  Likewise
+        * for ANYCOMPATIBLERANGE.
         */
        for (int i = 0; i < nargs; i++)
        {
@@ -1998,17 +2429,30 @@ check_valid_polymorphic_signature(Oid ret_type,
        return psprintf(_("A result of type %s requires at least one input of type %s."),
                        format_type_be(ret_type), format_type_be(ret_type));
    }
-   else if (IsPolymorphicType(ret_type))
+   else if (IsPolymorphicTypeFamily1(ret_type))
    {
-       /* Otherwise, any polymorphic type can be deduced from any other */
+       /* Otherwise, any family-1 type can be deduced from any other */
        for (int i = 0; i < nargs; i++)
        {
-           if (IsPolymorphicType(declared_arg_types[i]))
+           if (IsPolymorphicTypeFamily1(declared_arg_types[i]))
                return NULL;    /* OK */
        }
+       /* Keep this list in sync with IsPolymorphicTypeFamily1! */
        return psprintf(_("A result of type %s requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange."),
                        format_type_be(ret_type));
    }
+   else if (IsPolymorphicTypeFamily2(ret_type))
+   {
+       /* Otherwise, any family-2 type can be deduced from any other */
+       for (int i = 0; i < nargs; i++)
+       {
+           if (IsPolymorphicTypeFamily2(declared_arg_types[i]))
+               return NULL;    /* OK */
+       }
+       /* Keep this list in sync with IsPolymorphicTypeFamily2! */
+       return psprintf(_("A result of type %s requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, or anycompatiblerange."),
+                       format_type_be(ret_type));
+   }
    else
        return NULL;            /* OK, ret_type is not polymorphic */
 }
@@ -2113,8 +2557,9 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
    if (srctype == targettype)
        return true;
 
-   /* Anything is coercible to ANY or ANYELEMENT */
-   if (targettype == ANYOID || targettype == ANYELEMENTOID)
+   /* Anything is coercible to ANY or ANYELEMENT or ANYCOMPATIBLE */
+   if (targettype == ANYOID || targettype == ANYELEMENTOID ||
+       targettype == ANYCOMPATIBLEOID)
        return true;
 
    /* If srctype is a domain, reduce to its base type */
@@ -2125,13 +2570,13 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
    if (srctype == targettype)
        return true;
 
-   /* Also accept any array type as coercible to ANYARRAY */
-   if (targettype == ANYARRAYOID)
+   /* Also accept any array type as coercible to ANY[COMPATIBLE]ARRAY */
+   if (targettype == ANYARRAYOID || targettype == ANYCOMPATIBLEARRAYOID)
        if (type_is_array(srctype))
            return true;
 
-   /* Also accept any non-array type as coercible to ANYNONARRAY */
-   if (targettype == ANYNONARRAYOID)
+   /* Also accept any non-array type as coercible to ANY[COMPATIBLE]NONARRAY */
+   if (targettype == ANYNONARRAYOID || targettype == ANYCOMPATIBLENONARRAYOID)
        if (!type_is_array(srctype))
            return true;
 
@@ -2140,8 +2585,8 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
        if (type_is_enum(srctype))
            return true;
 
-   /* Also accept any range type as coercible to ANYRANGE */
-   if (targettype == ANYRANGEOID)
+   /* Also accept any range type as coercible to ANY[COMPATIBLE]RANGE */
+   if (targettype == ANYRANGEOID || targettype == ANYCOMPATIBLERANGEOID)
        if (type_is_range(srctype))
            return true;
 
index f78420e22dc7dacbe4b003a982e1b859efff88e2..8bb00abb6b36ed253c132e2116747aad2ce383b4 100644 (file)
@@ -195,7 +195,7 @@ json_categorize_type(Oid typoid,
        default:
            /* Check for arrays and composites */
            if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
-               || typoid == RECORDARRAYOID)
+               || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
                *tcategory = JSONTYPE_ARRAY;
            else if (type_is_rowtype(typoid))   /* includes RECORDOID */
                *tcategory = JSONTYPE_COMPOSITE;
index b961d2947235e10c2470d79fecf720c6ba24912d..1e9ca046c6992015130421628409e5b34e114bf2 100644 (file)
@@ -677,7 +677,7 @@ jsonb_categorize_type(Oid typoid,
        default:
            /* Check for arrays and composites */
            if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
-               || typoid == RECORDARRAYOID)
+               || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
                *tcategory = JSONBTYPE_ARRAY;
            else if (type_is_rowtype(typoid))   /* includes RECORDOID */
                *tcategory = JSONBTYPE_COMPOSITE;
index 9eee03c143a156aacc6e5390e0b35b8979e3d505..3d6b2f909353bec4ad227e54a4cb603fdf03fd25 100644 (file)
@@ -168,6 +168,26 @@ anyarray_send(PG_FUNCTION_ARGS)
    return array_send(fcinfo);
 }
 
+/*
+ * anycompatiblearray
+ *
+ * We may as well allow output, since we do for anyarray.
+ */
+PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblearray);
+PSEUDOTYPE_DUMMY_RECEIVE_FUNC(anycompatiblearray);
+
+Datum
+anycompatiblearray_out(PG_FUNCTION_ARGS)
+{
+   return array_out(fcinfo);
+}
+
+Datum
+anycompatiblearray_send(PG_FUNCTION_ARGS)
+{
+   return array_send(fcinfo);
+}
+
 /*
  * anyenum
  *
@@ -194,6 +214,19 @@ anyrange_out(PG_FUNCTION_ARGS)
    return range_out(fcinfo);
 }
 
+/*
+ * anycompatiblerange
+ *
+ * We may as well allow output, since range_out will in fact work.
+ */
+PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblerange);
+
+Datum
+anycompatiblerange_out(PG_FUNCTION_ARGS)
+{
+   return range_out(fcinfo);
+}
+
 /*
  * void
  *
@@ -316,3 +349,5 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler);
 PSEUDOTYPE_DUMMY_IO_FUNCS(internal);
 PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement);
 PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray);
+PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatible);
+PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatiblenonarray);
index 4e9d21bd541fe450b7e52a838809acdd4c097828..78ed85720385cedcd8dc43bb5bc85e895e87c04d 100644 (file)
@@ -552,7 +552,9 @@ resolve_anyrange_from_others(polymorphic_actuals *actuals)
  * with concrete data types deduced from the input arguments.
  * declared_args is an oidvector of the function's declared input arg types
  * (showing which are polymorphic), and call_expr is the call expression.
- * Returns true if able to deduce all types, false if not.
+ *
+ * Returns true if able to deduce all types, false if necessary information
+ * is not provided (call_expr is NULL or arg types aren't identifiable).
  */
 static bool
 resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
@@ -564,8 +566,13 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
    bool        have_anyelement_result = false;
    bool        have_anyarray_result = false;
    bool        have_anyrange_result = false;
+   bool        have_anycompatible_result = false;
+   bool        have_anycompatible_array_result = false;
+   bool        have_anycompatible_range_result = false;
    polymorphic_actuals poly_actuals;
+   polymorphic_actuals anyc_actuals;
    Oid         anycollation = InvalidOid;
+   Oid         anycompatcollation = InvalidOid;
    int         i;
 
    /* See if there are any polymorphic outputs; quick out if not */
@@ -587,6 +594,19 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                have_polymorphic_result = true;
                have_anyrange_result = true;
                break;
+           case ANYCOMPATIBLEOID:
+           case ANYCOMPATIBLENONARRAYOID:
+               have_polymorphic_result = true;
+               have_anycompatible_result = true;
+               break;
+           case ANYCOMPATIBLEARRAYOID:
+               have_polymorphic_result = true;
+               have_anycompatible_array_result = true;
+               break;
+           case ANYCOMPATIBLERANGEOID:
+               have_polymorphic_result = true;
+               have_anycompatible_range_result = true;
+               break;
            default:
                break;
        }
@@ -596,12 +616,16 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 
    /*
     * Otherwise, extract actual datatype(s) from input arguments.  (We assume
-    * the parser already validated consistency of the arguments.)
+    * the parser already validated consistency of the arguments.  Also, for
+    * the ANYCOMPATIBLE pseudotype family, we expect that all matching
+    * arguments were coerced to the selected common supertype, so that it
+    * doesn't matter which one's exposed type we look at.)
     */
    if (!call_expr)
        return false;           /* no hope */
 
    memset(&poly_actuals, 0, sizeof(poly_actuals));
+   memset(&anyc_actuals, 0, sizeof(anyc_actuals));
 
    for (i = 0; i < nargs; i++)
    {
@@ -636,6 +660,34 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                        return false;
                }
                break;
+           case ANYCOMPATIBLEOID:
+           case ANYCOMPATIBLENONARRAYOID:
+               if (!OidIsValid(anyc_actuals.anyelement_type))
+               {
+                   anyc_actuals.anyelement_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(anyc_actuals.anyelement_type))
+                       return false;
+               }
+               break;
+           case ANYCOMPATIBLEARRAYOID:
+               if (!OidIsValid(anyc_actuals.anyarray_type))
+               {
+                   anyc_actuals.anyarray_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(anyc_actuals.anyarray_type))
+                       return false;
+               }
+               break;
+           case ANYCOMPATIBLERANGEOID:
+               if (!OidIsValid(anyc_actuals.anyrange_type))
+               {
+                   anyc_actuals.anyrange_type =
+                       get_call_expr_argtype(call_expr, i);
+                   if (!OidIsValid(anyc_actuals.anyrange_type))
+                       return false;
+               }
+               break;
            default:
                break;
        }
@@ -651,18 +703,33 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
    if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
        resolve_anyrange_from_others(&poly_actuals);
 
+   if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
+       resolve_anyelement_from_others(&anyc_actuals);
+
+   if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
+       resolve_anyarray_from_others(&anyc_actuals);
+
+   if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
+       resolve_anyrange_from_others(&anyc_actuals);
+
    /*
     * Identify the collation to use for polymorphic OUT parameters. (It'll
-    * necessarily be the same for both anyelement and anyarray.)  Note that
-    * range types are not collatable, so any possible internal collation of a
-    * range type is not considered here.
+    * necessarily be the same for both anyelement and anyarray, likewise for
+    * anycompatible and anycompatiblearray.)  Note that range types are not
+    * collatable, so any possible internal collation of a range type is not
+    * considered here.
     */
    if (OidIsValid(poly_actuals.anyelement_type))
        anycollation = get_typcollation(poly_actuals.anyelement_type);
    else if (OidIsValid(poly_actuals.anyarray_type))
        anycollation = get_typcollation(poly_actuals.anyarray_type);
 
-   if (OidIsValid(anycollation))
+   if (OidIsValid(anyc_actuals.anyelement_type))
+       anycompatcollation = get_typcollation(anyc_actuals.anyelement_type);
+   else if (OidIsValid(anyc_actuals.anyarray_type))
+       anycompatcollation = get_typcollation(anyc_actuals.anyarray_type);
+
+   if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
    {
        /*
         * The types are collatable, so consider whether to use a nondefault
@@ -672,7 +739,12 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
        Oid         inputcollation = exprInputCollation(call_expr);
 
        if (OidIsValid(inputcollation))
-           anycollation = inputcollation;
+       {
+           if (OidIsValid(anycollation))
+               anycollation = inputcollation;
+           if (OidIsValid(anycompatcollation))
+               anycompatcollation = inputcollation;
+       }
    }
 
    /* And finally replace the tuple column types as needed */
@@ -708,6 +780,31 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
                                   0);
                /* no collation should be attached to a range type */
                break;
+           case ANYCOMPATIBLEOID:
+           case ANYCOMPATIBLENONARRAYOID:
+               TupleDescInitEntry(tupdesc, i + 1,
+                                  NameStr(att->attname),
+                                  anyc_actuals.anyelement_type,
+                                  -1,
+                                  0);
+               TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
+               break;
+           case ANYCOMPATIBLEARRAYOID:
+               TupleDescInitEntry(tupdesc, i + 1,
+                                  NameStr(att->attname),
+                                  anyc_actuals.anyarray_type,
+                                  -1,
+                                  0);
+               TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
+               break;
+           case ANYCOMPATIBLERANGEOID:
+               TupleDescInitEntry(tupdesc, i + 1,
+                                  NameStr(att->attname),
+                                  anyc_actuals.anyrange_type,
+                                  -1,
+                                  0);
+               /* no collation should be attached to a range type */
+               break;
            default:
                break;
        }
@@ -720,7 +817,9 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
  * Given the declared argument types and modes for a function, replace any
  * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types
  * deduced from the input arguments found in call_expr.
- * Returns true if able to deduce all types, false if not.
+ *
+ * Returns true if able to deduce all types, false if necessary information
+ * is not provided (call_expr is NULL or arg types aren't identifiable).
  *
  * This is the same logic as resolve_polymorphic_tupdesc, but with a different
  * argument representation, and slightly different output responsibilities.
@@ -735,16 +834,21 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
    bool        have_anyelement_result = false;
    bool        have_anyarray_result = false;
    bool        have_anyrange_result = false;
+   bool        have_anycompatible_result = false;
+   bool        have_anycompatible_array_result = false;
+   bool        have_anycompatible_range_result = false;
    polymorphic_actuals poly_actuals;
+   polymorphic_actuals anyc_actuals;
    int         inargno;
    int         i;
 
    /*
     * First pass: resolve polymorphic inputs, check for outputs.  As in
     * resolve_polymorphic_tupdesc, we rely on the parser to have enforced
-    * type consistency.
+    * type consistency and coerced ANYCOMPATIBLE args to a common supertype.
     */
    memset(&poly_actuals, 0, sizeof(poly_actuals));
+   memset(&anyc_actuals, 0, sizeof(anyc_actuals));
    inargno = 0;
    for (i = 0; i < numargs; i++)
    {
@@ -808,6 +912,61 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
                    argtypes[i] = poly_actuals.anyrange_type;
                }
                break;
+           case ANYCOMPATIBLEOID:
+           case ANYCOMPATIBLENONARRAYOID:
+               if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
+                   have_anycompatible_result = true;
+               }
+               else
+               {
+                   if (!OidIsValid(anyc_actuals.anyelement_type))
+                   {
+                       anyc_actuals.anyelement_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(anyc_actuals.anyelement_type))
+                           return false;
+                   }
+                   argtypes[i] = anyc_actuals.anyelement_type;
+               }
+               break;
+           case ANYCOMPATIBLEARRAYOID:
+               if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
+                   have_anycompatible_array_result = true;
+               }
+               else
+               {
+                   if (!OidIsValid(anyc_actuals.anyarray_type))
+                   {
+                       anyc_actuals.anyarray_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(anyc_actuals.anyarray_type))
+                           return false;
+                   }
+                   argtypes[i] = anyc_actuals.anyarray_type;
+               }
+               break;
+           case ANYCOMPATIBLERANGEOID:
+               if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+               {
+                   have_polymorphic_result = true;
+                   have_anycompatible_range_result = true;
+               }
+               else
+               {
+                   if (!OidIsValid(anyc_actuals.anyrange_type))
+                   {
+                       anyc_actuals.anyrange_type =
+                           get_call_expr_argtype(call_expr, inargno);
+                       if (!OidIsValid(anyc_actuals.anyrange_type))
+                           return false;
+                   }
+                   argtypes[i] = anyc_actuals.anyrange_type;
+               }
+               break;
            default:
                break;
        }
@@ -829,6 +988,15 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
    if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
        resolve_anyrange_from_others(&poly_actuals);
 
+   if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
+       resolve_anyelement_from_others(&anyc_actuals);
+
+   if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
+       resolve_anyarray_from_others(&anyc_actuals);
+
+   if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
+       resolve_anyrange_from_others(&anyc_actuals);
+
    /* And finally replace the output column types as needed */
    for (i = 0; i < numargs; i++)
    {
@@ -845,6 +1013,16 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
            case ANYRANGEOID:
                argtypes[i] = poly_actuals.anyrange_type;
                break;
+           case ANYCOMPATIBLEOID:
+           case ANYCOMPATIBLENONARRAYOID:
+               argtypes[i] = anyc_actuals.anyelement_type;
+               break;
+           case ANYCOMPATIBLEARRAYOID:
+               argtypes[i] = anyc_actuals.anyarray_type;
+               break;
+           case ANYCOMPATIBLERANGEOID:
+               argtypes[i] = anyc_actuals.anyrange_type;
+               break;
            default:
                break;
        }
index 3fee9342cc12d459622772484db3ac8f96537271..50069bea0e1da21d9c58c5849b6cc012e72e8c69 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202003181
+#define CATALOG_VERSION_NO 202003191
 
 #endif
index a64378b0027c3454c684aab4b0eb85340fb34c18..87d25d4a4bdecb77d0969f2df8e6da363cc0ef49 100644 (file)
   proname => 'regcollationout', provolatile => 's', prorettype => 'cstring',
   proargtypes => 'regcollation', prosrc => 'regcollationout' },
 { oid => '4195', descr => 'convert classname to regcollation',
-  proname => 'to_regcollation', provolatile => 's', prorettype => 'regcollation',
-  proargtypes => 'text', prosrc => 'to_regcollation' },
+  proname => 'to_regcollation', provolatile => 's',
+  prorettype => 'regcollation', proargtypes => 'text',
+  prosrc => 'to_regcollation' },
 { oid => '2220', descr => 'I/O',
   proname => 'regtypein', provolatile => 's', prorettype => 'regtype',
   proargtypes => 'cstring', prosrc => 'regtypein' },
 { oid => '268', descr => 'I/O',
   proname => 'table_am_handler_out', prorettype => 'cstring',
   proargtypes => 'table_am_handler', prosrc => 'table_am_handler_out' },
+{ oid => '9559', descr => 'I/O',
+  proname => 'anycompatible_in', prorettype => 'anycompatible',
+  proargtypes => 'cstring', prosrc => 'anycompatible_in' },
+{ oid => '9560', descr => 'I/O',
+  proname => 'anycompatible_out', prorettype => 'cstring',
+  proargtypes => 'anycompatible', prosrc => 'anycompatible_out' },
+{ oid => '9561', descr => 'I/O',
+  proname => 'anycompatiblearray_in', prorettype => 'anycompatiblearray',
+  proargtypes => 'cstring', prosrc => 'anycompatiblearray_in' },
+{ oid => '9562', descr => 'I/O',
+  proname => 'anycompatiblearray_out', provolatile => 's',
+  prorettype => 'cstring', proargtypes => 'anycompatiblearray',
+  prosrc => 'anycompatiblearray_out' },
+{ oid => '9563', descr => 'I/O',
+  proname => 'anycompatiblearray_recv', provolatile => 's',
+  prorettype => 'anycompatiblearray', proargtypes => 'internal',
+  prosrc => 'anycompatiblearray_recv' },
+{ oid => '9564', descr => 'I/O',
+  proname => 'anycompatiblearray_send', provolatile => 's',
+  prorettype => 'bytea', proargtypes => 'anycompatiblearray',
+  prosrc => 'anycompatiblearray_send' },
+{ oid => '9565', descr => 'I/O',
+  proname => 'anycompatiblenonarray_in', prorettype => 'anycompatiblenonarray',
+  proargtypes => 'cstring', prosrc => 'anycompatiblenonarray_in' },
+{ oid => '9566', descr => 'I/O',
+  proname => 'anycompatiblenonarray_out', prorettype => 'cstring',
+  proargtypes => 'anycompatiblenonarray',
+  prosrc => 'anycompatiblenonarray_out' },
+{ oid => '9567', descr => 'I/O',
+  proname => 'anycompatiblerange_in', provolatile => 's',
+  prorettype => 'anycompatiblerange', proargtypes => 'cstring oid int4',
+  prosrc => 'anycompatiblerange_in' },
+{ oid => '9568', descr => 'I/O',
+  proname => 'anycompatiblerange_out', provolatile => 's',
+  prorettype => 'cstring', proargtypes => 'anycompatiblerange',
+  prosrc => 'anycompatiblerange_out' },
 
 # tablesample method handlers
 { oid => '3313', descr => 'BERNOULLI tablesample method handler',
   proname => 'regcollationrecv', prorettype => 'regcollation',
   proargtypes => 'internal', prosrc => 'regcollationrecv' },
 { oid => '4197', descr => 'I/O',
-  proname => 'regcollationsend', prorettype => 'bytea', proargtypes => 'regcollation',
-  prosrc => 'regcollationsend' },
+  proname => 'regcollationsend', prorettype => 'bytea',
+  proargtypes => 'regcollation', prosrc => 'regcollationsend' },
 { oid => '2454', descr => 'I/O',
   proname => 'regtyperecv', prorettype => 'regtype', proargtypes => 'internal',
   prosrc => 'regtyperecv' },
index bb21cf166db286d01e0e33872c65fe4c9de4d792..2e6110e3f2ca91bc5b72cc118c99a3c278fe0edc 100644 (file)
 { oid => '4191', array_type_oid => '4192', descr => 'registered collation',
   typname => 'regcollation', typlen => '4', typbyval => 't', typcategory => 'N',
   typinput => 'regcollationin', typoutput => 'regcollationout',
-  typreceive => 'regcollationrecv', typsend => 'regcollationsend', typalign => 'i' },
+  typreceive => 'regcollationrecv', typsend => 'regcollationsend',
+  typalign => 'i' },
 { oid => '2206', array_type_oid => '2211', descr => 'registered type',
   typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N',
   typinput => 'regtypein', typoutput => 'regtypeout',
   typoutput => 'table_am_handler_out', typreceive => '-', typsend => '-',
   typalign => 'i' },
 { oid => '3831',
-  descr => 'pseudo-type representing a polymorphic base type that is a range',
+  descr => 'pseudo-type representing a range over a polymorphic base type',
   typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p',
   typcategory => 'P', typinput => 'anyrange_in', typoutput => 'anyrange_out',
   typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' },
+{ oid => '9550',
+  descr => 'pseudo-type representing a polymorphic common type',
+  typname => 'anycompatible', typlen => '4', typbyval => 't', typtype => 'p',
+  typcategory => 'P', typinput => 'anycompatible_in',
+  typoutput => 'anycompatible_out', typreceive => '-', typsend => '-',
+  typalign => 'i' },
+{ oid => '9551',
+  descr => 'pseudo-type representing an array of polymorphic common type elements',
+  typname => 'anycompatiblearray', typlen => '-1', typbyval => 'f',
+  typtype => 'p', typcategory => 'P', typinput => 'anycompatiblearray_in',
+  typoutput => 'anycompatiblearray_out',
+  typreceive => 'anycompatiblearray_recv', typsend => 'anycompatiblearray_send',
+  typalign => 'd', typstorage => 'x' },
+{ oid => '9552',
+  descr => 'pseudo-type representing a polymorphic common type that is not an array',
+  typname => 'anycompatiblenonarray', typlen => '4', typbyval => 't',
+  typtype => 'p', typcategory => 'P', typinput => 'anycompatiblenonarray_in',
+  typoutput => 'anycompatiblenonarray_out', typreceive => '-', typsend => '-',
+  typalign => 'i' },
+{ oid => '9553',
+  descr => 'pseudo-type representing a range over a polymorphic common type',
+  typname => 'anycompatiblerange', typlen => '-1', typbyval => 'f',
+  typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in',
+  typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-',
+  typalign => 'd', typstorage => 'x' },
 
 ]
index 97890946c5d2dd2e4e8c6494c88f89ab199572ae..7b375626484e85dbf4c77865838e9c067973b987 100644 (file)
@@ -295,12 +295,23 @@ typedef FormData_pg_type *Form_pg_type;
 
 /* Is a type OID a polymorphic pseudotype? (Beware of multiple evaluation) */
 #define IsPolymorphicType(typid)  \
+   (IsPolymorphicTypeFamily1(typid) || \
+    IsPolymorphicTypeFamily2(typid))
+
+/* Code not part of polymorphic type resolution should not use these macros: */
+#define IsPolymorphicTypeFamily1(typid)  \
    ((typid) == ANYELEMENTOID || \
     (typid) == ANYARRAYOID || \
     (typid) == ANYNONARRAYOID || \
     (typid) == ANYENUMOID || \
     (typid) == ANYRANGEOID)
 
+#define IsPolymorphicTypeFamily2(typid)  \
+   ((typid) == ANYCOMPATIBLEOID || \
+    (typid) == ANYCOMPATIBLEARRAYOID || \
+    (typid) == ANYCOMPATIBLENONARRAYOID || \
+    (typid) == ANYCOMPATIBLERANGEOID)
+
 #endif                         /* EXPOSE_TO_CLIENT_CODE */
 
 
index c8e43e684f51f63c7039890324f49298ffcabfd9..828ff5a288fcc49e2e0ca8937007db550a8dc0c6 100644 (file)
@@ -507,11 +507,13 @@ do_compile(FunctionCallInfo fcinfo,
            {
                if (forValidator)
                {
-                   if (rettypeid == ANYARRAYOID)
+                   if (rettypeid == ANYARRAYOID ||
+                       rettypeid == ANYCOMPATIBLEARRAYOID)
                        rettypeid = INT4ARRAYOID;
-                   else if (rettypeid == ANYRANGEOID)
+                   else if (rettypeid == ANYRANGEOID ||
+                            rettypeid == ANYCOMPATIBLERANGEOID)
                        rettypeid = INT4RANGEOID;
-                   else        /* ANYELEMENT or ANYNONARRAY */
+                   else        /* ANYELEMENT or ANYNONARRAY or ANYCOMPATIBLE */
                        rettypeid = INT4OID;
                    /* XXX what could we use for ANYENUM? */
                }
@@ -2493,12 +2495,16 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
                case ANYELEMENTOID:
                case ANYNONARRAYOID:
                case ANYENUMOID:    /* XXX dubious */
+               case ANYCOMPATIBLEOID:
+               case ANYCOMPATIBLENONARRAYOID:
                    argtypes[i] = INT4OID;
                    break;
                case ANYARRAYOID:
+               case ANYCOMPATIBLEARRAYOID:
                    argtypes[i] = INT4ARRAYOID;
                    break;
                case ANYRANGEOID:
+               case ANYCOMPATIBLERANGEOID:
                    argtypes[i] = INT4RANGEOID;
                    break;
                default:
index 0073072a368bf14531ee064990e892ddfb1f08e5..3259a22516e2e1c9e61f2c1394163bf438138874 100644 (file)
@@ -1950,6 +1950,30 @@ select least_agg(variadic array[q1,q2]) from int8_tbl;
  -4567890123456789
 (1 row)
 
+select cleast_agg(q1,q2) from int8_tbl;
+    cleast_agg     
+-------------------
+ -4567890123456789
+(1 row)
+
+select cleast_agg(4.5,f1) from int4_tbl;
+ cleast_agg  
+-------------
+ -2147483647
+(1 row)
+
+select cleast_agg(variadic array[4.5,f1]) from int4_tbl;
+ cleast_agg  
+-------------
+ -2147483647
+(1 row)
+
+select pg_typeof(cleast_agg(variadic array[4.5,f1])) from int4_tbl;
+ pg_typeof 
+-----------
+ numeric
+(1 row)
+
 -- test aggregates with common transition functions share the same states
 begin work;
 create type avg_state as (total bigint, count bigint);
index a2eb9996e1579f83609b9f91078937bb8495a942..dcf690942376bcd30cca1740d2bbc23ef5203d0d 100644 (file)
@@ -59,13 +59,39 @@ create aggregate aggfns(integer,integer,text) (
    sfunc = aggfns_trans, stype = aggtype[], sspace = 10000,
    initcond = '{}'
 );
--- variadic aggregate
+-- check error cases that would require run-time type coercion
+create function least_accum(int8, int8) returns int8 language sql as
+  'select least($1, $2)';
+create aggregate least_agg(int4) (
+  stype = int8, sfunc = least_accum
+);  -- fails
+ERROR:  function least_accum(bigint, bigint) requires run-time type coercion
+drop function least_accum(int8, int8);
+create function least_accum(anycompatible, anycompatible)
+returns anycompatible language sql as
+  'select least($1, $2)';
+create aggregate least_agg(int4) (
+  stype = int8, sfunc = least_accum
+);  -- fails
+ERROR:  function least_accum(bigint, bigint) requires run-time type coercion
+create aggregate least_agg(int8) (
+  stype = int8, sfunc = least_accum
+);
+drop function least_accum(anycompatible, anycompatible) cascade;
+NOTICE:  drop cascades to function least_agg(bigint)
+-- variadic aggregates
 create function least_accum(anyelement, variadic anyarray)
 returns anyelement language sql as
   'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
 create aggregate least_agg(variadic items anyarray) (
   stype = anyelement, sfunc = least_accum
 );
+create function cleast_accum(anycompatible, variadic anycompatiblearray)
+returns anycompatible language sql as
+  'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
+create aggregate cleast_agg(variadic items anycompatiblearray) (
+  stype = anycompatible, sfunc = cleast_accum
+);
 -- test ordered-set aggs using built-in support functions
 create aggregate my_percentile_disc(float8 ORDER BY anyelement) (
   stype = internal,
index 40468e8f4972d4b0f70615af3a62d3b6a75ecaa2..3c0b21d633e45c95bf8a6902af61ca2027d10bf3 100644 (file)
@@ -329,7 +329,7 @@ SELECT p1.oid, p1.proname
 FROM pg_proc as p1
 WHERE p1.prorettype IN
     ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype,
-     'anyenum'::regtype, 'anyrange'::regtype)
+     'anyenum'::regtype)
   AND NOT
     ('anyelement'::regtype = ANY (p1.proargtypes) OR
      'anyarray'::regtype = ANY (p1.proargtypes) OR
@@ -337,22 +337,64 @@ WHERE p1.prorettype IN
      'anyenum'::regtype = ANY (p1.proargtypes) OR
      'anyrange'::regtype = ANY (p1.proargtypes))
 ORDER BY 2;
- oid  |     proname      
-------+------------------
+ oid  |    proname     
+------+----------------
  2296 | anyarray_in
  2502 | anyarray_recv
  2312 | anyelement_in
  3504 | anyenum_in
  2777 | anynonarray_in
- 3832 | anyrange_in
   750 | array_in
  2400 | array_recv
  3506 | enum_in
  3532 | enum_recv
+(9 rows)
+
+-- anyrange is tighter than the rest, can only resolve from anyrange input
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype = 'anyrange'::regtype
+  AND NOT
+     'anyrange'::regtype = ANY (p1.proargtypes)
+ORDER BY 2;
+ oid  |     proname      
+------+------------------
+ 3832 | anyrange_in
  3876 | range_gist_union
  3834 | range_in
  3836 | range_recv
-(13 rows)
+(4 rows)
+
+-- similarly for the anycompatible family
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype IN
+    ('anycompatible'::regtype, 'anycompatiblearray'::regtype,
+     'anycompatiblenonarray'::regtype)
+  AND NOT
+    ('anycompatible'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblearray'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblenonarray'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblerange'::regtype = ANY (p1.proargtypes))
+ORDER BY 2;
+ oid  |         proname          
+------+--------------------------
+ 9559 | anycompatible_in
+ 9561 | anycompatiblearray_in
+ 9563 | anycompatiblearray_recv
+ 9565 | anycompatiblenonarray_in
+(4 rows)
+
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype = 'anycompatiblerange'::regtype
+  AND NOT
+     'anycompatiblerange'::regtype = ANY (p1.proargtypes)
+ORDER BY 2;
+ oid  |        proname        
+------+-----------------------
+ 9567 | anycompatiblerange_in
+(1 row)
 
 -- Look for functions that accept cstring and are neither datatype input
 -- functions nor encoding conversion functions.  It's almost never a good
index dfc10e3242660ea945189b7ef3471fc5a5e449d2..d0a6b630b8f3e13f5a5ab746e9f6ef7822e6ec59 100644 (file)
@@ -1823,6 +1823,88 @@ select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num;
 (1 row)
 
 drop function f1(x anyrange);
+create function f1(x anycompatible, y anycompatible) returns anycompatiblearray as $$
+begin
+  return array[x, y];
+end$$ language plpgsql;
+select f1(2, 4) as int, f1(2, 4.5) as num;
+  int  |   num   
+-------+---------
+ {2,4} | {2,4.5}
+(1 row)
+
+drop function f1(x anycompatible, y anycompatible);
+create function f1(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
+begin
+  return array[lower(x), upper(x), y, z];
+end$$ language plpgsql;
+select f1(int4range(42, 49), 11, 2::smallint) as int, f1(float8range(4.5, 7.8), 7.8, 11::real) as num;
+     int      |       num        
+--------------+------------------
+ {42,49,11,2} | {4.5,7.8,7.8,11}
+(1 row)
+
+select f1(int4range(42, 49), 11, 4.5) as fail;  -- range type doesn't fit
+ERROR:  function f1(int4range, integer, numeric) does not exist
+LINE 1: select f1(int4range(42, 49), 11, 4.5) as fail;
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function f1(x anycompatiblerange, y anycompatible, z anycompatible);
+-- fail, can't infer type:
+create function f1(x anycompatible) returns anycompatiblerange as $$
+begin
+  return array[x + 1, x + 2];
+end$$ language plpgsql;
+ERROR:  cannot determine result data type
+DETAIL:  A result of type anycompatiblerange requires at least one input of type anycompatiblerange.
+create function f1(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
+begin
+  return x;
+end$$ language plpgsql;
+select f1(int4range(42, 49), array[11]) as int, f1(float8range(4.5, 7.8), array[7]) as num;
+   int   |    num    
+---------+-----------
+ [42,49) | [4.5,7.8)
+(1 row)
+
+drop function f1(x anycompatiblerange, y anycompatiblearray);
+create function f1(a anyelement, b anyarray,
+                   c anycompatible, d anycompatible,
+                   OUT x anyarray, OUT y anycompatiblearray)
+as $$
+begin
+  x := a || b;
+  y := array[c, d];
+end$$ language plpgsql;
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2], 42, 34.5);
+    x     | pg_typeof |     y     | pg_typeof 
+----------+-----------+-----------+-----------
+ {11,1,2} | integer[] | {42,34.5} | numeric[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2], point(1,2), point(3,4));
+    x     | pg_typeof |         y         | pg_typeof 
+----------+-----------+-------------------+-----------
+ {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, '{1,2}', point(1,2), '(3,4)');
+    x     | pg_typeof |         y         | pg_typeof 
+----------+-----------+-------------------+-----------
+ {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2.2], 42, 34.5);  -- fail
+ERROR:  function f1(integer, numeric[], integer, numeric) does not exist
+LINE 2:   from f1(11, array[1, 2.2], 42, 34.5);
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function f1(a anyelement, b anyarray,
+                 c anycompatible, d anycompatible);
 --
 -- Test handling of OUT parameters, including polymorphic cases.
 -- Note that RETURN is optional with OUT params; we try both ways.
@@ -1940,6 +2022,25 @@ select * from duplic('foo'::text);
 (1 row)
 
 drop function duplic(anyelement);
+create function duplic(in i anycompatiblerange, out j anycompatible, out k anycompatiblearray) as $$
+begin
+  j := lower(i);
+  k := array[lower(i),upper(i)];
+  return;
+end$$ language plpgsql;
+select * from duplic(int4range(42,49));
+ j  |    k    
+----+---------
+ 42 | {42,49}
+(1 row)
+
+select * from duplic(textrange('aaa', 'bbb'));
+  j  |     k     
+-----+-----------
+ aaa | {aaa,bbb}
+(1 row)
+
+drop function duplic(anycompatiblerange);
 --
 -- test PERFORM
 --
index 331562de19d2066f30274e56989fc75536101634..d86a7004a6fb5f5f156619212e3b07bfbaf74481 100644 (file)
@@ -72,6 +72,82 @@ select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num;
 (1 row)
 
 drop function polyf(x anyrange);
+create function polyf(x anycompatible, y anycompatible) returns anycompatiblearray as $$
+  select array[x, y]
+$$ language sql;
+select polyf(2, 4) as int, polyf(2, 4.5) as num;
+  int  |   num   
+-------+---------
+ {2,4} | {2,4.5}
+(1 row)
+
+drop function polyf(x anycompatible, y anycompatible);
+create function polyf(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
+  select array[lower(x), upper(x), y, z]
+$$ language sql;
+select polyf(int4range(42, 49), 11, 2::smallint) as int, polyf(float8range(4.5, 7.8), 7.8, 11::real) as num;
+     int      |       num        
+--------------+------------------
+ {42,49,11,2} | {4.5,7.8,7.8,11}
+(1 row)
+
+select polyf(int4range(42, 49), 11, 4.5) as fail;  -- range type doesn't fit
+ERROR:  function polyf(int4range, integer, numeric) does not exist
+LINE 1: select polyf(int4range(42, 49), 11, 4.5) as fail;
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible);
+-- fail, can't infer type:
+create function polyf(x anycompatible) returns anycompatiblerange as $$
+  select array[x + 1, x + 2]
+$$ language sql;
+ERROR:  cannot determine result data type
+DETAIL:  A result of type anycompatiblerange requires at least one input of type anycompatiblerange.
+create function polyf(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
+  select x
+$$ language sql;
+select polyf(int4range(42, 49), array[11]) as int, polyf(float8range(4.5, 7.8), array[7]) as num;
+   int   |    num    
+---------+-----------
+ [42,49) | [4.5,7.8)
+(1 row)
+
+drop function polyf(x anycompatiblerange, y anycompatiblearray);
+create function polyf(a anyelement, b anyarray,
+                      c anycompatible, d anycompatible,
+                      OUT x anyarray, OUT y anycompatiblearray)
+as $$
+  select a || b, array[c, d]
+$$ language sql;
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2], 42, 34.5);
+    x     | pg_typeof |     y     | pg_typeof 
+----------+-----------+-----------+-----------
+ {11,1,2} | integer[] | {42,34.5} | numeric[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2], point(1,2), point(3,4));
+    x     | pg_typeof |         y         | pg_typeof 
+----------+-----------+-------------------+-----------
+ {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, '{1,2}', point(1,2), '(3,4)');
+    x     | pg_typeof |         y         | pg_typeof 
+----------+-----------+-------------------+-----------
+ {11,1,2} | integer[] | {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2.2], 42, 34.5);  -- fail
+ERROR:  function polyf(integer, numeric[], integer, numeric) does not exist
+LINE 2:   from polyf(11, array[1, 2.2], 42, 34.5);
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function polyf(a anyelement, b anyarray,
+                    c anycompatible, d anycompatible);
 --
 -- Polymorphic aggregate tests
 --
@@ -1621,3 +1697,238 @@ View definition:
 
 drop view dfview;
 drop function dfunc(anyelement, anyelement, bool);
+--
+-- Tests for ANYCOMPATIBLE polymorphism family
+--
+create function anyctest(anycompatible, anycompatible)
+returns anycompatible as $$
+  select greatest($1, $2)
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, 12) x;
+ x  | pg_typeof 
+----+-----------
+ 12 | integer
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+  x   | pg_typeof 
+------+-----------
+ 12.3 | numeric
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, point(1,2)) x;  -- fail
+ERROR:  function anyctest(integer, point) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, point(1,2)) x;
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+select x, pg_typeof(x) from anyctest('11', '12.3') x;  -- defaults to text
+  x   | pg_typeof 
+------+-----------
+ 12.3 | text
+(1 row)
+
+drop function anyctest(anycompatible, anycompatible);
+create function anyctest(anycompatible, anycompatible)
+returns anycompatiblearray as $$
+  select array[$1, $2]
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, 12) x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+     x     | pg_typeof 
+-----------+-----------
+ {11,12.3} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, array[1,2]) x;  -- fail
+ERROR:  function anyctest(integer, integer[]) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, array[1,2]) x;
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anyctest(anycompatible, anycompatible);
+create function anyctest(anycompatible, anycompatiblearray)
+returns anycompatiblearray as $$
+  select array[$1] || $2
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, array[12]) x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, array[12.3]) x;
+     x     | pg_typeof 
+-----------+-----------
+ {11,12.3} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(12.3, array[13]) x;
+     x     | pg_typeof 
+-----------+-----------
+ {12.3,13} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(12.3, '{13,14.4}') x;
+       x        | pg_typeof 
+----------------+-----------
+ {12.3,13,14.4} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x;  -- fail
+ERROR:  function anyctest(integer, point[]) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) ...
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+select x, pg_typeof(x) from anyctest(11, 12) x;  -- fail
+ERROR:  function anyctest(integer, integer) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anyctest(anycompatible, anycompatiblearray);
+create function anyctest(anycompatible, anycompatiblerange)
+returns anycompatiblerange as $$
+  select $2
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, int4range(4,7)) x;
+   x   | pg_typeof 
+-------+-----------
+ [4,7) | int4range
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, numrange(4,7)) x;
+   x   | pg_typeof 
+-------+-----------
+ [4,7) | numrange
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, 12) x;  -- fail
+ERROR:  function anyctest(integer, integer) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, 12) x;
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x;  -- fail
+ERROR:  function anyctest(numeric, int4range) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x...
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x;  -- fail
+ERROR:  could not determine polymorphic type anycompatiblerange because input has type unknown
+drop function anyctest(anycompatible, anycompatiblerange);
+create function anyctest(anycompatiblerange, anycompatiblerange)
+returns anycompatible as $$
+  select lower($1) + upper($2)
+$$ language sql;
+select x, pg_typeof(x) from anyctest(int4range(11,12), int4range(4,7)) x;
+ x  | pg_typeof 
+----+-----------
+ 18 | integer
+(1 row)
+
+select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail
+ERROR:  function anyctest(int4range, numrange) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(int4range(11,12), numra...
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anyctest(anycompatiblerange, anycompatiblerange);
+-- fail, can't infer result type:
+create function anyctest(anycompatible)
+returns anycompatiblerange as $$
+  select $1
+$$ language sql;
+ERROR:  cannot determine result data type
+DETAIL:  A result of type anycompatiblerange requires at least one input of type anycompatiblerange.
+create function anyctest(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+  select array[$1, $2]
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, 12) x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+     x     | pg_typeof 
+-----------+-----------
+ {11,12.3} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x;  -- fail
+ERROR:  function anyctest(integer[], integer[]) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(array[11], array[1,2]) ...
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anyctest(anycompatiblenonarray, anycompatiblenonarray);
+create function anyctest(a anyelement, b anyarray,
+                         c anycompatible, d anycompatible)
+returns anycompatiblearray as $$
+  select array[c, d]
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, array[1, 2], 42, 34.5) x;
+     x     | pg_typeof 
+-----------+-----------
+ {42,34.5} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, array[1, 2], point(1,2), point(3,4)) x;
+         x         | pg_typeof 
+-------------------+-----------
+ {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, '{1,2}', point(1,2), '(3,4)') x;
+         x         | pg_typeof 
+-------------------+-----------
+ {"(1,2)","(3,4)"} | point[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x;  -- fail
+ERROR:  function anyctest(integer, numeric[], integer, numeric) does not exist
+LINE 1: select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, ...
+                                    ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anyctest(a anyelement, b anyarray,
+                       c anycompatible, d anycompatible);
+create function anyctest(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+  select $1
+$$ language sql;
+select x, pg_typeof(x) from anyctest(11, 12) x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, 12.2) x;
+     x     | pg_typeof 
+-----------+-----------
+ {11,12.2} | numeric[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, '12') x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(11, '12.2') x;  -- fail
+ERROR:  invalid input syntax for type integer: "12.2"
+LINE 1: select x, pg_typeof(x) from anyctest(11, '12.2') x;
+                                                 ^
+select x, pg_typeof(x) from anyctest(variadic array[11, 12]) x;
+    x    | pg_typeof 
+---------+-----------
+ {11,12} | integer[]
+(1 row)
+
+select x, pg_typeof(x) from anyctest(variadic array[11, 12.2]) x;
+     x     | pg_typeof 
+-----------+-----------
+ {11,12.2} | numeric[]
+(1 row)
+
+drop function anyctest(variadic anycompatiblearray);
index cdfc43e85496fb431f861e7aba7e7bb79ff51610..7eced2845203785a6648546a87dc531b1581d1ea 100644 (file)
@@ -1557,6 +1557,59 @@ CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
 AS 'select $1, array[$1,$1]' LANGUAGE sql;
 ERROR:  cannot determine result data type
 DETAIL:  A result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange.
+CREATE FUNCTION dup (f1 anycompatible, f2 anycompatiblearray, f3 out anycompatible, f4 out anycompatiblearray)
+AS 'select $1, $2' LANGUAGE sql;
+SELECT dup(22, array[44]);
+    dup    
+-----------
+ (22,{44})
+(1 row)
+
+SELECT dup(4.5, array[44]);
+    dup     
+------------
+ (4.5,{44})
+(1 row)
+
+SELECT dup(22, array[44::bigint]);
+    dup    
+-----------
+ (22,{44})
+(1 row)
+
+SELECT *, pg_typeof(f3), pg_typeof(f4) FROM dup(22, array[44::bigint]);
+ f3 |  f4  | pg_typeof | pg_typeof 
+----+------+-----------+-----------
+ 22 | {44} | bigint    | bigint[]
+(1 row)
+
+DROP FUNCTION dup(f1 anycompatible, f2 anycompatiblearray);
+CREATE FUNCTION dup (f1 anycompatiblerange, f2 out anycompatible, f3 out anycompatiblearray, f4 out anycompatiblerange)
+AS 'select lower($1), array[lower($1), upper($1)], $1' LANGUAGE sql;
+SELECT dup(int4range(4,7));
+         dup         
+---------------------
+ (4,"{4,7}","[4,7)")
+(1 row)
+
+SELECT dup(numrange(4,7));
+         dup         
+---------------------
+ (4,"{4,7}","[4,7)")
+(1 row)
+
+SELECT dup(textrange('aaa', 'bbb'));
+              dup              
+-------------------------------
+ (aaa,"{aaa,bbb}","[aaa,bbb)")
+(1 row)
+
+DROP FUNCTION dup(f1 anycompatiblerange);
+-- fails, no way to deduce outputs
+CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray)
+AS 'select $1, array[$1,$1]' LANGUAGE sql;
+ERROR:  cannot determine result data type
+DETAIL:  A result of type anycompatible requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, or anycompatiblerange.
 --
 -- table functions
 --
index a28741a888c238bcf8c16fea3b8b0247db5826c1..c421f5394fe3594bfcefd6cfdc8f8e47c6312932 100644 (file)
@@ -1405,6 +1405,32 @@ ERROR:  function rangetypes_sql(numrange, integer[]) does not exist
 LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]);
                ^
 HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange)
+  returns anycompatible as 'select $1[1] + lower($2);' language sql;
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20));
+ anycompatiblearray_anycompatiblerange_func 
+--------------------------------------------
+                                         11
+(1 row)
+
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], numrange(10,20));
+ anycompatiblearray_anycompatiblerange_func 
+--------------------------------------------
+                                         11
+(1 row)
+
+-- should fail
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20));
+ERROR:  function anycompatiblearray_anycompatiblerange_func(numeric[], int4range) does not exist
+LINE 1: select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,...
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange);
+-- should fail
+create function bogus_func(anycompatible)
+  returns anycompatiblerange as 'select int4range(1,10)' language sql;
+ERROR:  cannot determine result data type
+DETAIL:  A result of type anycompatiblerange requires at least one input of type anycompatiblerange.
 --
 -- Arrays of ranges
 --
index cd7fc03b04c414c1dbeae3b4b50e13e52fb7db83..274130e7062b308949e5113a9e60d22573cb2718 100644 (file)
@@ -131,14 +131,16 @@ WHERE p1.typinput = p2.oid AND NOT
 
 -- Check for type of the variadic array parameter's elements.
 -- provariadic should be ANYOID if the type of the last element is ANYOID,
--- ANYELEMENTOID if the type of the last element is ANYARRAYOID, and otherwise
--- the element type corresponding to the array type.
+-- ANYELEMENTOID if the type of the last element is ANYARRAYOID,
+-- ANYCOMPATIBLEOID if the type of the last element is ANYCOMPATIBLEARRAYOID,
+-- and otherwise the element type corresponding to the array type.
 SELECT oid::regprocedure, provariadic::regtype, proargtypes::regtype[]
 FROM pg_proc
 WHERE provariadic != 0
 AND case proargtypes[array_length(proargtypes, 1)-1]
-    WHEN 2276 THEN 2276 -- any -> any
-   WHEN 2277 THEN 2283 -- anyarray -> anyelement
+   WHEN '"any"'::regtype THEN '"any"'::regtype
+   WHEN 'anyarray'::regtype THEN 'anyelement'::regtype
+   WHEN 'anycompatiblearray'::regtype THEN 'anycompatible'::regtype
    ELSE (SELECT t.oid
          FROM pg_type t
          WHERE t.typarray = proargtypes[array_length(proargtypes, 1)-1])
index 02578330a6f01685a5fa1d8ddfd729a4e171cac5..5da6f4152bea8c5a81e4ff538fb037a91cd58a0d 100644 (file)
@@ -740,6 +740,10 @@ drop view aggordview1;
 select least_agg(q1,q2) from int8_tbl;
 select least_agg(variadic array[q1,q2]) from int8_tbl;
 
+select cleast_agg(q1,q2) from int8_tbl;
+select cleast_agg(4.5,f1) from int4_tbl;
+select cleast_agg(variadic array[4.5,f1]) from int4_tbl;
+select pg_typeof(cleast_agg(variadic array[4.5,f1])) from int4_tbl;
 
 -- test aggregates with common transition functions share the same states
 begin work;
index fd7cd400c192ba09ea481af055f144f92be0dffe..d4b4036fd7d8535f3cfe88c81afc662da737fac8 100644 (file)
@@ -72,7 +72,31 @@ create aggregate aggfns(integer,integer,text) (
    initcond = '{}'
 );
 
--- variadic aggregate
+-- check error cases that would require run-time type coercion
+create function least_accum(int8, int8) returns int8 language sql as
+  'select least($1, $2)';
+
+create aggregate least_agg(int4) (
+  stype = int8, sfunc = least_accum
+);  -- fails
+
+drop function least_accum(int8, int8);
+
+create function least_accum(anycompatible, anycompatible)
+returns anycompatible language sql as
+  'select least($1, $2)';
+
+create aggregate least_agg(int4) (
+  stype = int8, sfunc = least_accum
+);  -- fails
+
+create aggregate least_agg(int8) (
+  stype = int8, sfunc = least_accum
+);
+
+drop function least_accum(anycompatible, anycompatible) cascade;
+
+-- variadic aggregates
 create function least_accum(anyelement, variadic anyarray)
 returns anyelement language sql as
   'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
@@ -81,6 +105,14 @@ create aggregate least_agg(variadic items anyarray) (
   stype = anyelement, sfunc = least_accum
 );
 
+create function cleast_accum(anycompatible, variadic anycompatiblearray)
+returns anycompatible language sql as
+  'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
+
+create aggregate cleast_agg(variadic items anycompatiblearray) (
+  stype = anycompatible, sfunc = cleast_accum
+);
+
 -- test ordered-set aggs using built-in support functions
 create aggregate my_percentile_disc(float8 ORDER BY anyelement) (
   stype = internal,
index f06f245db3b3e2abacb8e7c76176669d96f8ad48..389d5b2464a1876cdf7e09b55cd44edd51e91258 100644 (file)
@@ -273,7 +273,7 @@ SELECT p1.oid, p1.proname
 FROM pg_proc as p1
 WHERE p1.prorettype IN
     ('anyelement'::regtype, 'anyarray'::regtype, 'anynonarray'::regtype,
-     'anyenum'::regtype, 'anyrange'::regtype)
+     'anyenum'::regtype)
   AND NOT
     ('anyelement'::regtype = ANY (p1.proargtypes) OR
      'anyarray'::regtype = ANY (p1.proargtypes) OR
@@ -282,6 +282,37 @@ WHERE p1.prorettype IN
      'anyrange'::regtype = ANY (p1.proargtypes))
 ORDER BY 2;
 
+-- anyrange is tighter than the rest, can only resolve from anyrange input
+
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype = 'anyrange'::regtype
+  AND NOT
+     'anyrange'::regtype = ANY (p1.proargtypes)
+ORDER BY 2;
+
+-- similarly for the anycompatible family
+
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype IN
+    ('anycompatible'::regtype, 'anycompatiblearray'::regtype,
+     'anycompatiblenonarray'::regtype)
+  AND NOT
+    ('anycompatible'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblearray'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblenonarray'::regtype = ANY (p1.proargtypes) OR
+     'anycompatiblerange'::regtype = ANY (p1.proargtypes))
+ORDER BY 2;
+
+SELECT p1.oid, p1.proname
+FROM pg_proc as p1
+WHERE p1.prorettype = 'anycompatiblerange'::regtype
+  AND NOT
+     'anycompatiblerange'::regtype = ANY (p1.proargtypes)
+ORDER BY 2;
+
+
 -- Look for functions that accept cstring and are neither datatype input
 -- functions nor encoding conversion functions.  It's almost never a good
 -- idea to use cstring input for a function meant to be called from SQL;
index c5e6e6e5edeb4861a4997d10460a54f4c444c7a7..07c60c80e482aa3fc2f817e5137743a3052a74ce 100644 (file)
@@ -1618,6 +1618,62 @@ select f1(int4range(42, 49)) as int, f1(float8range(4.5, 7.8)) as num;
 
 drop function f1(x anyrange);
 
+create function f1(x anycompatible, y anycompatible) returns anycompatiblearray as $$
+begin
+  return array[x, y];
+end$$ language plpgsql;
+
+select f1(2, 4) as int, f1(2, 4.5) as num;
+
+drop function f1(x anycompatible, y anycompatible);
+
+create function f1(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
+begin
+  return array[lower(x), upper(x), y, z];
+end$$ language plpgsql;
+
+select f1(int4range(42, 49), 11, 2::smallint) as int, f1(float8range(4.5, 7.8), 7.8, 11::real) as num;
+
+select f1(int4range(42, 49), 11, 4.5) as fail;  -- range type doesn't fit
+
+drop function f1(x anycompatiblerange, y anycompatible, z anycompatible);
+
+-- fail, can't infer type:
+create function f1(x anycompatible) returns anycompatiblerange as $$
+begin
+  return array[x + 1, x + 2];
+end$$ language plpgsql;
+
+create function f1(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
+begin
+  return x;
+end$$ language plpgsql;
+
+select f1(int4range(42, 49), array[11]) as int, f1(float8range(4.5, 7.8), array[7]) as num;
+
+drop function f1(x anycompatiblerange, y anycompatiblearray);
+
+create function f1(a anyelement, b anyarray,
+                   c anycompatible, d anycompatible,
+                   OUT x anyarray, OUT y anycompatiblearray)
+as $$
+begin
+  x := a || b;
+  y := array[c, d];
+end$$ language plpgsql;
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2], 42, 34.5);
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2], point(1,2), point(3,4));
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, '{1,2}', point(1,2), '(3,4)');
+select x, pg_typeof(x), y, pg_typeof(y)
+  from f1(11, array[1, 2.2], 42, 34.5);  -- fail
+
+drop function f1(a anyelement, b anyarray,
+                 c anycompatible, d anycompatible);
+
 --
 -- Test handling of OUT parameters, including polymorphic cases.
 -- Note that RETURN is optional with OUT params; we try both ways.
@@ -1699,6 +1755,18 @@ select * from duplic('foo'::text);
 
 drop function duplic(anyelement);
 
+create function duplic(in i anycompatiblerange, out j anycompatible, out k anycompatiblearray) as $$
+begin
+  j := lower(i);
+  k := array[lower(i),upper(i)];
+  return;
+end$$ language plpgsql;
+
+select * from duplic(int4range(42,49));
+select * from duplic(textrange('aaa', 'bbb'));
+
+drop function duplic(anycompatiblerange);
+
 --
 -- test PERFORM
 --
index 9c7b43efebb5b05180a2194dfaa41d41737ac659..b57591f69f609271c9af7031b5f2ec0b117e4a61 100644 (file)
@@ -53,6 +53,56 @@ select polyf(int4range(42, 49)) as int, polyf(float8range(4.5, 7.8)) as num;
 
 drop function polyf(x anyrange);
 
+create function polyf(x anycompatible, y anycompatible) returns anycompatiblearray as $$
+  select array[x, y]
+$$ language sql;
+
+select polyf(2, 4) as int, polyf(2, 4.5) as num;
+
+drop function polyf(x anycompatible, y anycompatible);
+
+create function polyf(x anycompatiblerange, y anycompatible, z anycompatible) returns anycompatiblearray as $$
+  select array[lower(x), upper(x), y, z]
+$$ language sql;
+
+select polyf(int4range(42, 49), 11, 2::smallint) as int, polyf(float8range(4.5, 7.8), 7.8, 11::real) as num;
+
+select polyf(int4range(42, 49), 11, 4.5) as fail;  -- range type doesn't fit
+
+drop function polyf(x anycompatiblerange, y anycompatible, z anycompatible);
+
+-- fail, can't infer type:
+create function polyf(x anycompatible) returns anycompatiblerange as $$
+  select array[x + 1, x + 2]
+$$ language sql;
+
+create function polyf(x anycompatiblerange, y anycompatiblearray) returns anycompatiblerange as $$
+  select x
+$$ language sql;
+
+select polyf(int4range(42, 49), array[11]) as int, polyf(float8range(4.5, 7.8), array[7]) as num;
+
+drop function polyf(x anycompatiblerange, y anycompatiblearray);
+
+create function polyf(a anyelement, b anyarray,
+                      c anycompatible, d anycompatible,
+                      OUT x anyarray, OUT y anycompatiblearray)
+as $$
+  select a || b, array[c, d]
+$$ language sql;
+
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2], 42, 34.5);
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2], point(1,2), point(3,4));
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, '{1,2}', point(1,2), '(3,4)');
+select x, pg_typeof(x), y, pg_typeof(y)
+  from polyf(11, array[1, 2.2], 42, 34.5);  -- fail
+
+drop function polyf(a anyelement, b anyarray,
+                    c anycompatible, d anycompatible);
+
 
 --
 -- Polymorphic aggregate tests
@@ -868,3 +918,112 @@ select * from dfview;
 
 drop view dfview;
 drop function dfunc(anyelement, anyelement, bool);
+
+--
+-- Tests for ANYCOMPATIBLE polymorphism family
+--
+
+create function anyctest(anycompatible, anycompatible)
+returns anycompatible as $$
+  select greatest($1, $2)
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, 12) x;
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+select x, pg_typeof(x) from anyctest(11, point(1,2)) x;  -- fail
+select x, pg_typeof(x) from anyctest('11', '12.3') x;  -- defaults to text
+
+drop function anyctest(anycompatible, anycompatible);
+
+create function anyctest(anycompatible, anycompatible)
+returns anycompatiblearray as $$
+  select array[$1, $2]
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, 12) x;
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+select x, pg_typeof(x) from anyctest(11, array[1,2]) x;  -- fail
+
+drop function anyctest(anycompatible, anycompatible);
+
+create function anyctest(anycompatible, anycompatiblearray)
+returns anycompatiblearray as $$
+  select array[$1] || $2
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, array[12]) x;
+select x, pg_typeof(x) from anyctest(11, array[12.3]) x;
+select x, pg_typeof(x) from anyctest(12.3, array[13]) x;
+select x, pg_typeof(x) from anyctest(12.3, '{13,14.4}') x;
+select x, pg_typeof(x) from anyctest(11, array[point(1,2)]) x;  -- fail
+select x, pg_typeof(x) from anyctest(11, 12) x;  -- fail
+
+drop function anyctest(anycompatible, anycompatiblearray);
+
+create function anyctest(anycompatible, anycompatiblerange)
+returns anycompatiblerange as $$
+  select $2
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, int4range(4,7)) x;
+select x, pg_typeof(x) from anyctest(11, numrange(4,7)) x;
+select x, pg_typeof(x) from anyctest(11, 12) x;  -- fail
+select x, pg_typeof(x) from anyctest(11.2, int4range(4,7)) x;  -- fail
+select x, pg_typeof(x) from anyctest(11.2, '[4,7)') x;  -- fail
+
+drop function anyctest(anycompatible, anycompatiblerange);
+
+create function anyctest(anycompatiblerange, anycompatiblerange)
+returns anycompatible as $$
+  select lower($1) + upper($2)
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(int4range(11,12), int4range(4,7)) x;
+select x, pg_typeof(x) from anyctest(int4range(11,12), numrange(4,7)) x; -- fail
+
+drop function anyctest(anycompatiblerange, anycompatiblerange);
+
+-- fail, can't infer result type:
+create function anyctest(anycompatible)
+returns anycompatiblerange as $$
+  select $1
+$$ language sql;
+
+create function anyctest(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+  select array[$1, $2]
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, 12) x;
+select x, pg_typeof(x) from anyctest(11, 12.3) x;
+select x, pg_typeof(x) from anyctest(array[11], array[1,2]) x;  -- fail
+
+drop function anyctest(anycompatiblenonarray, anycompatiblenonarray);
+
+create function anyctest(a anyelement, b anyarray,
+                         c anycompatible, d anycompatible)
+returns anycompatiblearray as $$
+  select array[c, d]
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, array[1, 2], 42, 34.5) x;
+select x, pg_typeof(x) from anyctest(11, array[1, 2], point(1,2), point(3,4)) x;
+select x, pg_typeof(x) from anyctest(11, '{1,2}', point(1,2), '(3,4)') x;
+select x, pg_typeof(x) from anyctest(11, array[1, 2.2], 42, 34.5) x;  -- fail
+
+drop function anyctest(a anyelement, b anyarray,
+                       c anycompatible, d anycompatible);
+
+create function anyctest(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+  select $1
+$$ language sql;
+
+select x, pg_typeof(x) from anyctest(11, 12) x;
+select x, pg_typeof(x) from anyctest(11, 12.2) x;
+select x, pg_typeof(x) from anyctest(11, '12') x;
+select x, pg_typeof(x) from anyctest(11, '12.2') x;  -- fail
+select x, pg_typeof(x) from anyctest(variadic array[11, 12]) x;
+select x, pg_typeof(x) from anyctest(variadic array[11, 12.2]) x;
+
+drop function anyctest(variadic anycompatiblearray);
index 476b4f27e250db81b34b3a4a8cae6eb14e9fdac2..ae3119a959eb87321e8484f1915cef1016162dce 100644 (file)
@@ -407,6 +407,27 @@ DROP FUNCTION dup(anyelement);
 CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
 AS 'select $1, array[$1,$1]' LANGUAGE sql;
 
+CREATE FUNCTION dup (f1 anycompatible, f2 anycompatiblearray, f3 out anycompatible, f4 out anycompatiblearray)
+AS 'select $1, $2' LANGUAGE sql;
+SELECT dup(22, array[44]);
+SELECT dup(4.5, array[44]);
+SELECT dup(22, array[44::bigint]);
+SELECT *, pg_typeof(f3), pg_typeof(f4) FROM dup(22, array[44::bigint]);
+
+DROP FUNCTION dup(f1 anycompatible, f2 anycompatiblearray);
+
+CREATE FUNCTION dup (f1 anycompatiblerange, f2 out anycompatible, f3 out anycompatiblearray, f4 out anycompatiblerange)
+AS 'select lower($1), array[lower($1), upper($1)], $1' LANGUAGE sql;
+SELECT dup(int4range(4,7));
+SELECT dup(numrange(4,7));
+SELECT dup(textrange('aaa', 'bbb'));
+
+DROP FUNCTION dup(f1 anycompatiblerange);
+
+-- fails, no way to deduce outputs
+CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray)
+AS 'select $1, array[$1,$1]' LANGUAGE sql;
+
 --
 -- table functions
 --
index 85eaa9b34c67aba0af4a89fd39e653d630bc1218..4048b1d185445abcdc0e2aab74702898f5c6043b 100644 (file)
@@ -456,6 +456,22 @@ create function rangetypes_sql(q anyrange, b anyarray, out c anyelement)
 select rangetypes_sql(int4range(1,10), ARRAY[2,20]);
 select rangetypes_sql(numrange(1,10), ARRAY[2,20]);  -- match failure
 
+create function anycompatiblearray_anycompatiblerange_func(a anycompatiblearray, r anycompatiblerange)
+  returns anycompatible as 'select $1[1] + lower($2);' language sql;
+
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], int4range(10,20));
+
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1,2], numrange(10,20));
+
+-- should fail
+select anycompatiblearray_anycompatiblerange_func(ARRAY[1.1,2], int4range(10,20));
+
+drop function anycompatiblearray_anycompatiblerange_func(anycompatiblearray, anycompatiblerange);
+
+-- should fail
+create function bogus_func(anycompatible)
+  returns anycompatiblerange as 'select int4range(1,10)' language sql;
+
 --
 -- Arrays of ranges
 --
index fed413bf98a5cb6a874453c83b8f28564ff71c46..4b492ce06250684eb17e97b20fdf3e2f66a28fd7 100644 (file)
@@ -106,15 +106,17 @@ WHERE p1.typinput = p2.oid AND NOT
 
 -- Check for type of the variadic array parameter's elements.
 -- provariadic should be ANYOID if the type of the last element is ANYOID,
--- ANYELEMENTOID if the type of the last element is ANYARRAYOID, and otherwise
--- the element type corresponding to the array type.
+-- ANYELEMENTOID if the type of the last element is ANYARRAYOID,
+-- ANYCOMPATIBLEOID if the type of the last element is ANYCOMPATIBLEARRAYOID,
+-- and otherwise the element type corresponding to the array type.
 
 SELECT oid::regprocedure, provariadic::regtype, proargtypes::regtype[]
 FROM pg_proc
 WHERE provariadic != 0
 AND case proargtypes[array_length(proargtypes, 1)-1]
-    WHEN 2276 THEN 2276 -- any -> any
-   WHEN 2277 THEN 2283 -- anyarray -> anyelement
+   WHEN '"any"'::regtype THEN '"any"'::regtype
+   WHEN 'anyarray'::regtype THEN 'anyelement'::regtype
+   WHEN 'anycompatiblearray'::regtype THEN 'anycompatible'::regtype
    ELSE (SELECT t.oid
          FROM pg_type t
          WHERE t.typarray = proargtypes[array_length(proargtypes, 1)-1])