diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 410eaed..6407d3d 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4784,6 +4784,14 @@ SELECT * FROM pg_attribute
    </indexterm>
 
    <indexterm zone="datatype-pseudo">
+    <primary>anycompatible</primary>
+   </indexterm>
+
+   <indexterm zone="datatype-pseudo">
+    <primary>anycompatiblearray</primary>
+   </indexterm>
+
+   <indexterm zone="datatype-pseudo">
     <primary>void</primary>
    </indexterm>
 
@@ -4889,6 +4897,34 @@ SELECT * FROM pg_attribute
        </row>
 
        <row>
+        <entry><type>anycompatible</type></entry>
+        <entry>Indicates that a function accepts any data type. Values
+        are converted to real common type.
+        (see <xref linkend="extend-types-polymorphic"/>).</entry>
+       </row>
+
+       <row>
+        <entry><type>anycompatiblearray</type></entry>
+        <entry>Indicates that a function accepts any array data type. The
+        elements of array are converted to common type of these values.
+        (see <xref linkend="extend-types-polymorphic"/>).</entry>
+       </row>
+
+       <row>
+        <entry><type>anycompatiblenonarray</type></entry>
+        <entry>Indicates that a function accepts any non-array data type
+        (see <xref linkend="extend-types-polymorphic"/>).</entry>
+       </row>
+
+       <row>
+        <entry><type>anycompatiblerange</type></entry>
+        <entry>Indicates that a function accepts any range data type
+        (see <xref linkend="extend-types-polymorphic"/> and
+        <xref linkend="rangetypes"/>). The subtype can be used for
+        deduction of common type.</entry>
+       </row>
+
+       <row>
         <entry><type>cstring</type></entry>
         <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
        </row>
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index 9ec1af7..05c0919 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -231,7 +231,7 @@
     <para>
      Five pseudo-types of special interest are <type>anyelement</type>,
      <type>anyarray</type>, <type>anynonarray</type>, <type>anyenum</type>,
-     and <type>anyrange</type>,
+     <type>anyrange</type>, <type>anycompatible</type> and <type>anycompatiblearray</type>.
      which are collectively called <firstterm>polymorphic types</firstterm>.
      Any function declared using these types is said to be
      a <firstterm>polymorphic function</firstterm>.  A polymorphic function can
@@ -268,6 +268,15 @@
     </para>
 
     <para>
+     Second family of polymorphic types are types <type>anycompatible</type> and
+     <type>anycompatiblearray</type>. These types are similar to types
+     <type>anyelement</type> and <type>anyarray</type>. The arguments declared
+     as <type>anyelement</type> requires same real type of passed values. For
+     <type>anycompatible</type>'s arguments is selected common type, and later
+     all these arguments are casted to this common type.
+    </para>
+
+    <para>
      Thus, when more than one argument position is declared with a polymorphic
      type, the net effect is that only certain combinations of actual argument
      types are allowed.  For example, a function declared as
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 76fd938..22540bb 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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)
 			{
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index c96a055..704668e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -257,6 +257,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))
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 5eac55a..694114a 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -320,6 +320,7 @@ interpret_function_parameter_list(ParseState *pstate,
 			switch (toid)
 			{
 				case ANYARRAYOID:
+				case ANYCOMPATIBLEARRAYOID:
 				case ANYOID:
 					/* okay */
 					break;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 7318b72..e5ea051 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -169,15 +169,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
@@ -187,7 +189,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.
@@ -195,10 +199,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
@@ -1389,6 +1393,99 @@ select_common_type(ParseState *pstate, List *exprs, const char *context,
 }
 
 /*
+ * select_common_type_from_vector()
+ *		Determine the common supertype of vector of Oids.
+ *
+ * Similar to select_common_type() but simplified for polymorphics
+ * type processing. When there are no supertype, then returns InvalidOid,
+ * when noerror is true, or raise exception when noerror is false.
+ */
+static Oid
+select_common_type_from_vector(int nargs, Oid *typeids, bool noerror)
+{
+	int			i = 0;
+	Oid			ptype;
+	TYPCATEGORY pcategory;
+	bool		pispreferred;
+
+	Assert(nargs > 0);
+	ptype = typeids[0];
+
+	/* fast leave when all types are same */
+	if (ptype != UNKNOWNOID)
+	{
+		for (i = 1; i < nargs; i++)
+		{
+			if (ptype != typeids[i])
+				break;
+		}
+
+		if (i == nargs)
+			return ptype;
+	}
+
+	/*
+	 * Nope, so set up for the full algorithm. Note that at this point, we can
+	 * skip first i elements, because was checked in previous loop.
+	 */
+	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)
+			{
+				if (noerror)
+					return InvalidOid;
+
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("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;
+			}
+		}
+	}
+
+	/*
+	 * Be consistent with select_common_type()
+	 */
+	if (ptype == UNKNOWNOID)
+		ptype = TEXTOID;
+
+	return ptype;
+}
+
+/*
  * coerce_to_common_type()
  *		Coerce an expression to the given type.
  *
@@ -1447,6 +1544,13 @@ 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.)
+ * 8) Previous rules are valid too for ANYCOMPATIBLE, ANYCOMPATIBLEARRAY,
+ *	  ANYCOMPATIBLENONARRAY and ANYCOMPATIBLERANGE with following exception.
+ *	  The used datatypes should not be strictly same. These types should be
+ *	  from same type category, and for any used type there should be implicit
+ *	  cast to selected one of these types.
+ * 9) There is not any relation between ANY types and ANYCOMPATIBLE types.
+ *	  Isn't possible derive ANY type from ANYCOMPATIBLE type and vice versa.
  *
  * 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
@@ -1484,6 +1588,12 @@ check_generic_type_consistency(const Oid *actual_arg_types,
 	bool		have_anyelement = false;
 	bool		have_anynonarray = false;
 	bool		have_anyenum = false;
+	bool		have_anycompatible_nonarray = false;
+	bool		have_anycompatible_range = false;
+	bool		have_generic_anycompatible = false;
+	Oid			anycompatible_range_typeid = InvalidOid;
+	Oid			anycompatible_actual_types[FUNC_MAX_ARGS];
+	int			n_anycompatible_args = 0;
 
 	/*
 	 * Loop through the arguments to see if we have any that are polymorphic.
@@ -1527,6 +1637,74 @@ check_generic_type_consistency(const Oid *actual_arg_types,
 				return false;
 			range_typeid = actual_type;
 		}
+		else if (decl_type == ANYCOMPATIBLEOID ||
+				 decl_type == ANYCOMPATIBLENONARRAYOID)
+		{
+			have_generic_anycompatible = true;
+			if (decl_type == ANYCOMPATIBLENONARRAYOID)
+				have_anycompatible_nonarray = true;
+
+			/* An unknown literal is no help for resolving actual types */
+			if (actual_type == UNKNOWNOID)
+				continue;
+
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != actual_type)
+				anycompatible_actual_types[n_anycompatible_args++] = actual_type;
+		}
+		else if (decl_type == ANYCOMPATIBLEARRAYOID)
+		{
+			Oid			anycompatible_elem_type;
+
+			have_generic_anycompatible = true;
+
+			if (actual_type == UNKNOWNOID)
+				continue;
+
+			actual_type = getBaseType(actual_type); /* flatten domains */
+			anycompatible_elem_type = get_element_type(actual_type);
+
+			if (!OidIsValid(anycompatible_elem_type))
+				return false;
+
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != anycompatible_elem_type)
+				anycompatible_actual_types[n_anycompatible_args++] = anycompatible_elem_type;
+		}
+		else if (decl_type == ANYCOMPATIBLERANGEOID)
+		{
+			Oid			anycompatible_range_typelem;
+
+			have_generic_anycompatible = true;
+			have_anycompatible_range = true;
+
+			if (actual_type == UNKNOWNOID)
+				continue;
+			actual_type = getBaseType(actual_type); /* flatten domains */
+
+			/*
+			 * range type is used just for derivation of common type, but
+			 * range types should be same. Same behave like anyrange - cast
+			 * between ranges are not supported.
+			 */
+			if (OidIsValid(anycompatible_range_typeid) &&
+				anycompatible_range_typeid != actual_type)
+				return false;
+
+			anycompatible_range_typelem = get_range_subtype(actual_type);
+			if (!OidIsValid(anycompatible_range_typelem))
+				return false;
+
+			if (!OidIsValid(anycompatible_range_typeid))
+				anycompatible_range_typeid = actual_type;
+
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != anycompatible_range_typelem)
+				anycompatible_actual_types[n_anycompatible_args++] = anycompatible_range_typelem;
+		}
 	}
 
 	/* Get the element type based on the array type, if we have one */
@@ -1593,6 +1771,36 @@ check_generic_type_consistency(const Oid *actual_arg_types,
 			return false;
 	}
 
+	/* check anycompatible collected data */
+	if (have_generic_anycompatible)
+	{
+		/* we can check type consisteny when we have some not unknown types */
+		if (n_anycompatible_args > 0)
+		{
+			Oid			anycompatible_typeid;
+
+			anycompatible_typeid = select_common_type_from_vector(n_anycompatible_args,
+																  anycompatible_actual_types,
+																  true);
+
+			if (!OidIsValid(anycompatible_typeid))
+				return false;
+
+			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;
+			}
+
+			if (have_anycompatible_range && !OidIsValid(anycompatible_range_typeid))
+				return false;
+		}
+	}
+
 	/* Looks valid */
 	return true;
 }
@@ -1645,6 +1853,16 @@ 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.)
+ * 10) The relation between types from ANY family type are same like
+ *	  relations between types from ANYCOMPATIBLE family type, with one
+ *	  difference. The parameters with type from ANY family type requires
+ *	  exactly one actual type. The arguments with ANYCOMPATIBLE family type
+ *	  allows types that shares type category. Later polymorphic type is
+ *	  replaced by real type. This real type is one from actual types
+ *	  (polymorphic argument actual types) for that is available implicit
+ *	  cast from type of any related polymorphic arguments.
+ * 11) The arguments with ANY family type and ANYCOMPATIBLE family type
+ *	  are independent.
  *
  * Domains over arrays or ranges match ANYARRAY or ANYRANGE arguments,
  * respectively, and are immediately flattened to their base type. (In
@@ -1675,11 +1893,15 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 								 bool allow_poly)
 {
 	int			j;
-	bool		have_generics = false;
+	bool		have_generics_any = false;
+	bool		have_generics_anycompatible = false;
 	bool		have_unknowns = false;
 	Oid			elem_typeid = InvalidOid;
 	Oid			array_typeid = InvalidOid;
 	Oid			range_typeid = InvalidOid;
+	Oid			anycompatible_typeid = InvalidOid;
+	Oid			anycompatible_array_typeid = InvalidOid;
+	Oid			anycompatible_range_typeid = InvalidOid;
 	Oid			array_typelem;
 	Oid			range_typelem;
 	bool		have_anyelement = (rettype == ANYELEMENTOID ||
@@ -1687,6 +1909,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 								   rettype == ANYENUMOID);
 	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);
+	Oid			anycompatible_actual_types[FUNC_MAX_ARGS];
+	int			n_anycompatible_args = 0;
 
 	/*
 	 * Loop through the arguments to see if we have any that are polymorphic.
@@ -1701,7 +1928,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 			decl_type == ANYNONARRAYOID ||
 			decl_type == ANYENUMOID)
 		{
-			have_generics = have_anyelement = true;
+			have_generics_any = have_anyelement = true;
 			if (decl_type == ANYNONARRAYOID)
 				have_anynonarray = true;
 			else if (decl_type == ANYENUMOID)
@@ -1724,14 +1951,18 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 		}
 		else if (decl_type == ANYARRAYOID)
 		{
-			have_generics = true;
+			have_generics_any = true;
+			have_anycompatible_array = true;
+
 			if (actual_type == UNKNOWNOID)
 			{
 				have_unknowns = true;
 				continue;
 			}
+
 			if (allow_poly && decl_type == actual_type)
 				continue;		/* no new information here */
+
 			actual_type = getBaseType(actual_type); /* flatten domains */
 			if (OidIsValid(array_typeid) && actual_type != array_typeid)
 				ereport(ERROR,
@@ -1744,7 +1975,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 		}
 		else if (decl_type == ANYRANGEOID)
 		{
-			have_generics = true;
+			have_generics_any = true;
 			if (actual_type == UNKNOWNOID)
 			{
 				have_unknowns = true;
@@ -1762,128 +1993,300 @@ 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_generics_anycompatible = true;
 
-	/*
-	 * Fast Track: if none of the arguments are polymorphic, return the
-	 * unmodified rettype.  We assume it can't be polymorphic either.
-	 */
-	if (!have_generics)
-		return rettype;
+			if (decl_type == ANYCOMPATIBLENONARRAYOID)
+				have_anycompatible_nonarray = true;
 
-	/* Get the element type based on the array type, if we have one */
-	if (OidIsValid(array_typeid))
-	{
-		if (array_typeid == ANYARRAYOID && !have_anyelement)
-		{
-			/* Special case for ANYARRAY input: okay iff no ANYELEMENT */
-			array_typelem = ANYELEMENTOID;
+			/*
+			 * because declared type will be replaced every time, we don't
+			 * need some special work for unknown types.
+			 */
+			if (actual_type == UNKNOWNOID)
+				continue;
+
+			if (allow_poly && decl_type == actual_type)
+				continue;
+
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != actual_type)
+				anycompatible_actual_types[n_anycompatible_args++] = actual_type;
 		}
-		else
+		else if (decl_type == ANYCOMPATIBLEARRAYOID)
 		{
-			array_typelem = get_element_type(array_typeid);
-			if (!OidIsValid(array_typelem))
+			Oid			anycompatible_elem_type;
+
+			have_generics_anycompatible = true;
+			have_anycompatible_array = true;
+
+			if (actual_type == UNKNOWNOID)
+				continue;
+
+			if (allow_poly && decl_type == actual_type)
+				continue;
+
+			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",
-								"anyarray", format_type_be(array_typeid))));
-		}
+								"anyarray", format_type_be(actual_type))));
 
-		if (!OidIsValid(elem_typeid))
-		{
-			/*
-			 * if we don't have an element type yet, use the one we just got
-			 */
-			elem_typeid = array_typelem;
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != anycompatible_elem_type)
+				anycompatible_actual_types[n_anycompatible_args++] = anycompatible_elem_type;
 		}
-		else if (array_typelem != elem_typeid)
+		else if (decl_type == ANYCOMPATIBLERANGEOID)
 		{
-			/* otherwise, they better match */
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("argument declared %s is not consistent with argument declared %s",
-							"anyarray", "anyelement"),
-					 errdetail("%s versus %s",
-							   format_type_be(array_typeid),
-							   format_type_be(elem_typeid))));
+			Oid			anycompatible_range_typelem;
+
+			have_generics_anycompatible = true;
+			have_anycompatible_range = true;
+
+			if (actual_type == UNKNOWNOID)
+			{
+				have_unknowns = true;
+				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) &&
+				actual_type != anycompatible_range_typeid)
+				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))));
+
+			anycompatible_range_typeid = actual_type;
+			anycompatible_range_typelem = get_range_subtype(anycompatible_range_typeid);
+
+			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(anycompatible_range_typeid))));
+
+			/* collect used type, reduce repeated values */
+			if (n_anycompatible_args == 0 ||
+				anycompatible_actual_types[n_anycompatible_args - 1] != anycompatible_range_typelem)
+				anycompatible_actual_types[n_anycompatible_args++] = anycompatible_range_typelem;
 		}
 	}
 
-	/* Get the element type based on the range type, if we have one */
-	if (OidIsValid(range_typeid))
+	/*
+	 * Fast Track: if none of the arguments are polymorphic, return the
+	 * unmodified rettype.  We assume it can't be polymorphic either.
+	 */
+	if (!have_generics_any && !have_generics_anycompatible)
+		return rettype;
+
+	if (have_generics_any)
 	{
-		if (range_typeid == ANYRANGEOID && !have_anyelement)
+		/* Get the element type based on the array type, if we have one */
+		if (OidIsValid(array_typeid))
 		{
-			/* Special case for ANYRANGE input: okay iff no ANYELEMENT */
-			range_typelem = ANYELEMENTOID;
+			if (array_typeid == ANYARRAYOID && !have_anyelement)
+			{
+				/* Special case for ANYARRAY input: okay iff no ANYELEMENT */
+				array_typelem = ANYELEMENTOID;
+			}
+			else
+			{
+				array_typelem = get_element_type(array_typeid);
+				if (!OidIsValid(array_typelem))
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							 errmsg("argument declared %s is not an array but type %s",
+									"anyarray", format_type_be(array_typeid))));
+			}
+
+			if (!OidIsValid(elem_typeid))
+			{
+				/*
+				 * if we don't have an element type yet, use the one we just
+				 * got
+				 */
+				elem_typeid = array_typelem;
+			}
+			else if (array_typelem != elem_typeid)
+			{
+				/* otherwise, they better match */
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("argument declared %s is not consistent with argument declared %s",
+								"anyarray", "anyelement"),
+						 errdetail("%s versus %s",
+								   format_type_be(array_typeid),
+								   format_type_be(elem_typeid))));
+			}
 		}
-		else
+
+		/* Get the element type based on the range type, if we have one */
+		if (OidIsValid(range_typeid))
 		{
-			range_typelem = get_range_subtype(range_typeid);
-			if (!OidIsValid(range_typelem))
+			if (range_typeid == ANYRANGEOID && !have_anyelement)
+			{
+				/* Special case for ANYRANGE input: okay iff no ANYELEMENT */
+				range_typelem = ANYELEMENTOID;
+			}
+			else
+			{
+				range_typelem = get_range_subtype(range_typeid);
+				if (!OidIsValid(range_typelem))
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							 errmsg("argument declared %s is not a range type but type %s",
+									"anyrange",
+									format_type_be(range_typeid))));
+			}
+
+			if (!OidIsValid(elem_typeid))
+			{
+				/*
+				 * if we don't have an element type yet, use the one we just
+				 * got
+				 */
+				elem_typeid = range_typelem;
+			}
+			else if (range_typelem != elem_typeid)
+			{
+				/* otherwise, they better match */
 				ereport(ERROR,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("argument declared %s is not a range type but type %s",
-								"anyrange",
-								format_type_be(range_typeid))));
+						 errmsg("argument declared %s is not consistent with argument declared %s",
+								"anyrange", "anyelement"),
+						 errdetail("%s versus %s",
+								   format_type_be(range_typeid),
+								   format_type_be(elem_typeid))));
+			}
 		}
 
 		if (!OidIsValid(elem_typeid))
 		{
+			if (allow_poly)
+			{
+				elem_typeid = ANYELEMENTOID;
+				array_typeid = ANYARRAYOID;
+				range_typeid = ANYRANGEOID;
+			}
+			else
+			{
+				/* Only way to get here is if all the generic args are UNKNOWN */
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("could not determine polymorphic type because input has type %s",
+								"unknown")));
+			}
+		}
+
+		if (have_anynonarray && elem_typeid != ANYELEMENTOID)
+		{
 			/*
-			 * if we don't have an element type yet, use the one we just got
+			 * require the element type to not be an array or domain over
+			 * array
 			 */
-			elem_typeid = range_typelem;
+			if (type_is_array_domain(elem_typeid))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("type matched to anynonarray is an array type: %s",
+								format_type_be(elem_typeid))));
 		}
-		else if (range_typelem != elem_typeid)
+
+		if (have_anyenum && elem_typeid != ANYELEMENTOID)
 		{
-			/* otherwise, they better match */
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("argument declared %s is not consistent with argument declared %s",
-							"anyrange", "anyelement"),
-					 errdetail("%s versus %s",
-							   format_type_be(range_typeid),
-							   format_type_be(elem_typeid))));
+			/* require the element type to be an enum */
+			if (!type_is_enum(elem_typeid))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("type matched to anyenum is not an enum type: %s",
+								format_type_be(elem_typeid))));
 		}
 	}
 
-	if (!OidIsValid(elem_typeid))
+	if (have_generics_anycompatible)
 	{
-		if (allow_poly)
+		if (n_anycompatible_args > 0)
 		{
-			elem_typeid = ANYELEMENTOID;
-			array_typeid = ANYARRAYOID;
-			range_typeid = ANYRANGEOID;
+			anycompatible_typeid = select_common_type_from_vector(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))));
+			}
+
+			/* anycompatible_range_typid should be defined already */
+			/* XXX this error message is not very on-point */
+			if (have_anycompatible_range &&
+				!OidIsValid(anycompatible_range_typeid))
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_OBJECT),
+						 errmsg("could not find range type for data type %s",
+								"anycompatiblerange")));
+
+			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 anynonarray is an array type: %s",
+									format_type_be(anycompatible_typeid))));
+			}
 		}
 		else
 		{
-			/* Only way to get here is if all the generic args are UNKNOWN */
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("could not determine polymorphic type because input has type %s",
-							"unknown")));
+			if (allow_poly)
+			{
+				anycompatible_typeid = ANYCOMPATIBLEOID;
+				anycompatible_array_typeid = ANYCOMPATIBLEARRAYOID;
+				anycompatible_range_typeid = ANYCOMPATIBLERANGEOID;
+			}
+			else
+			{
+				/* Only way to get here is if all the generic args are UNKNOWN */
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("could not determine polymorphic common type because input has type %s",
+								"unknown")));
+			}
 		}
-	}
 
-	if (have_anynonarray && elem_typeid != ANYELEMENTOID)
-	{
-		/* require the element type to not be an array or domain over array */
-		if (type_is_array_domain(elem_typeid))
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("type matched to anynonarray is an array type: %s",
-							format_type_be(elem_typeid))));
-	}
+		/* replace polymorphic common types by selected common types */
+		for (j = 0; j < nargs; j++)
+		{
+			Oid			decl_type = declared_arg_types[j];
 
-	if (have_anyenum && elem_typeid != ANYELEMENTOID)
-	{
-		/* require the element type to be an enum */
-		if (!type_is_enum(elem_typeid))
-			ereport(ERROR,
-					(errcode(ERRCODE_DATATYPE_MISMATCH),
-					 errmsg("type matched to anyenum is not an enum type: %s",
-							format_type_be(elem_typeid))));
+			if (decl_type == ANYCOMPATIBLEOID ||
+				decl_type == ANYCOMPATIBLENONARRAYOID)	/* XXX seems wrong? */
+				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;
+		}
 	}
 
 	/*
@@ -1964,6 +2367,35 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
 		rettype == ANYENUMOID)
 		return elem_typeid;
 
+	if (rettype == ANYCOMPATIBLEOID)
+	{
+		if (!OidIsValid(anycompatible_typeid))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("could not find common type")));
+		return anycompatible_typeid;
+	}
+
+	if (rettype == ANYCOMPATIBLEARRAYOID)
+	{
+		if (!OidIsValid(anycompatible_array_typeid))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("could not find common array type")));
+		return anycompatible_array_typeid;
+	}
+
+	/* if we return ANYRANGE use the appropriate argument type */
+	if (rettype == ANYCOMPATIBLERANGEOID)
+	{
+		if (!OidIsValid(anycompatible_range_typeid))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("could not find range type for data type %s",
+							"anycompatiblerange")));
+		return anycompatible_range_typeid;
+	}
+
 	/* we don't return a generic type; send back the original return type */
 	return rettype;
 }
@@ -2059,6 +2491,79 @@ resolve_generic_type(Oid declared_type,
 			return context_actual_type;
 		}
 	}
+	else if (declared_type == ANYCOMPATIBLEARRAYOID)
+	{
+		if (context_declared_type == ANYCOMPATIBLEARRAYOID)
+		{
+			/*
+			 * Use actual type, but it must be an array; or if it's a domain
+			 * over array, use the base array type.
+			 */
+			Oid			context_base_type = getBaseType(context_actual_type);
+			Oid			array_typelem = get_element_type(context_base_type);
+
+			if (!OidIsValid(array_typelem))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("argument declared %s is not an array but type %s",
+								"anycompatiblearray",
+								format_type_be(context_base_type))));
+			return context_base_type;
+		}
+		else if (context_declared_type == ANYCOMPATIBLEOID ||
+				 context_declared_type == ANYCOMPATIBLENONARRAYOID ||
+				 context_declared_type == ANYCOMPATIBLERANGEOID)
+		{
+			/* Use the array type corresponding to actual type */
+			Oid			array_typeid = get_array_type(context_actual_type);
+
+			if (!OidIsValid(array_typeid))
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_OBJECT),
+						 errmsg("could not find array type for data type %s",
+								format_type_be(context_actual_type))));
+			return array_typeid;
+		}
+	}
+	else if (declared_type == ANYCOMPATIBLEOID ||
+			 declared_type == ANYCOMPATIBLENONARRAYOID ||
+			 declared_type == ANYCOMPATIBLERANGEOID)
+	{
+		if (context_declared_type == ANYCOMPATIBLEARRAYOID)
+		{
+			/* Use the element type corresponding to actual type */
+			Oid			context_base_type = getBaseType(context_actual_type);
+			Oid			array_typelem = get_element_type(context_base_type);
+
+			if (!OidIsValid(array_typelem))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("argument declared %s is not an array but type %s",
+								"anycompatiblearray",
+								format_type_be(context_base_type))));
+			return array_typelem;
+		}
+		else if (context_declared_type == ANYCOMPATIBLERANGEOID)
+		{
+			/* Use the element type corresponding to actual type */
+			Oid			context_base_type = getBaseType(context_actual_type);
+			Oid			range_typelem = get_range_subtype(context_base_type);
+
+			if (!OidIsValid(range_typelem))
+				ereport(ERROR,
+						(errcode(ERRCODE_DATATYPE_MISMATCH),
+						 errmsg("argument declared %s is not a range type but type %s",
+								"anycompatiblerange",
+								format_type_be(context_base_type))));
+			return range_typelem;
+		}
+		else if (context_declared_type == ANYCOMPATIBLEOID ||
+				 context_declared_type == ANYCOMPATIBLENONARRAYOID)
+		{
+			/* Use the actual type; it doesn't matter if array or not */
+			return context_actual_type;
+		}
+	}
 	else
 	{
 		/* declared_type isn't polymorphic, so return it as-is */
@@ -2082,11 +2587,12 @@ is_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++)
 		{
@@ -2095,12 +2601,22 @@ is_valid_polymorphic_signature(Oid ret_type,
 		}
 		return false;
 	}
-	else if (IsPolymorphicType(ret_type))
+	else if (IsPolymorphicTypeFamily1(ret_type))
+	{
+		/* Otherwise, any family-1 type can be deduced from any other */
+		for (int i = 0; i < nargs; i++)
+		{
+			if (IsPolymorphicTypeFamily1(declared_arg_types[i]))
+				return true;	/* OK */
+		}
+		return false;
+	}
+	else if (IsPolymorphicTypeFamily2(ret_type))
 	{
-		/* Otherwise, any polymorphic type can be deduced from any other */
+		/* Otherwise, any family-2 type can be deduced from any other */
 		for (int i = 0; i < nargs; i++)
 		{
-			if (IsPolymorphicType(declared_arg_types[i]))
+			if (IsPolymorphicTypeFamily2(declared_arg_types[i]))
 				return true;	/* OK */
 		}
 		return false;
@@ -2206,8 +2722,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 */
@@ -2218,13 +2735,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;
 
@@ -2233,8 +2750,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;
 
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index f78420e..8bb00ab 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -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;
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index b961d29..1e9ca04 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -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;
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 6ab95dc..1f63379 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -178,6 +178,32 @@ anyarray_send(PG_FUNCTION_ARGS)
 }
 
 /*
+ * anycompatiblearray
+ *
+ * XXX anycompatiblearray_recv could actually be made to work, since the
+ * incoming array data will contain the element type OID.  Need to think
+ * through type-safety issues before allowing it, however.
+ */
+PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblearray);
+PSEUDOTYPE_DUMMY_RECEIVE_FUNC(anycompatiblearray);
+
+/*
+ * We may as well allow output, since we do for anyarray.
+ * This code is probably unreachable in practice though.
+ */
+Datum
+anycompatiblearray_out(PG_FUNCTION_ARGS)
+{
+	return array_out(fcinfo);
+}
+
+Datum
+anycompatiblearray_send(PG_FUNCTION_ARGS)
+{
+	return array_send(fcinfo);
+}
+
+/*
  * anyenum
  *
  * We may as well allow output, since enum_out will in fact work.
@@ -204,6 +230,19 @@ anyrange_out(PG_FUNCTION_ARGS)
 }
 
 /*
+ * 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_in		- input routine for pseudo-type VOID.
  *
  * We allow this so that PL functions can return VOID without any special
@@ -339,3 +378,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);
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 0201e4f..5e10449 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -472,10 +472,18 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 	bool		have_anyrange_result = false;
 	bool		have_anynonarray = false;
 	bool		have_anyenum = false;
+	bool		have_anycompatible_result = false;
+	bool		have_anycompatible_array_result = false;
+	bool		have_anycompatible_range_result = false;
+	bool		have_anycompatible_nonarray = false;
 	Oid			anyelement_type = InvalidOid;
 	Oid			anyarray_type = InvalidOid;
 	Oid			anyrange_type = InvalidOid;
+	Oid			anycompatible_type = InvalidOid;
+	Oid			anycompatible_array_type = InvalidOid;
+	Oid			anycompatible_range_type = InvalidOid;
 	Oid			anycollation = InvalidOid;
+	Oid			anycompatcollation = InvalidOid;
 	int			i;
 
 	/* See if there are any polymorphic outputs; quick out if not */
@@ -500,17 +508,37 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 			case ANYRANGEOID:
 				have_anyrange_result = true;
 				break;
+			case ANYCOMPATIBLEOID:
+				have_anycompatible_result = true;
+				break;
+			case ANYCOMPATIBLEARRAYOID:
+				have_anycompatible_array_result = true;
+				break;
+			case ANYCOMPATIBLENONARRAYOID:
+				have_anycompatible_result = true;
+				have_anycompatible_nonarray = true;
+				break;
+			case ANYCOMPATIBLERANGEOID:
+				have_anycompatible_range_result = true;
+				break;
 			default:
 				break;
 		}
 	}
-	if (!have_anyelement_result && !have_anyarray_result &&
-		!have_anyrange_result)
+	if (!have_anyelement_result &&
+		!have_anyarray_result &&
+		!have_anyrange_result &&
+		!have_anycompatible_result &&
+		!have_anycompatible_array_result &&
+		!have_anycompatible_range_result)
 		return true;
 
 	/*
 	 * 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 */
@@ -533,14 +561,37 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 				if (!OidIsValid(anyrange_type))
 					anyrange_type = get_call_expr_argtype(call_expr, i);
 				break;
+			case ANYCOMPATIBLEOID:
+			case ANYCOMPATIBLENONARRAYOID:
+				if (!OidIsValid(anycompatible_type))
+					anycompatible_type = get_call_expr_argtype(call_expr, i);
+				break;
+			case ANYCOMPATIBLEARRAYOID:
+				if (!OidIsValid(anycompatible_array_type))
+					anycompatible_array_type = get_call_expr_argtype(call_expr, i);
+				break;
+			case ANYCOMPATIBLERANGEOID:
+				if (!OidIsValid(anycompatible_range_type))
+					anycompatible_range_type = get_call_expr_argtype(call_expr, i);
+				break;
 			default:
 				break;
 		}
 	}
 
 	/* If nothing found, parser messed up */
-	if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
-		!OidIsValid(anyrange_type))
+	if ((have_anyelement_result || have_anyarray_result ||
+		 have_anyrange_result) &&
+		(!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
+		 !OidIsValid(anyrange_type)))
+		return false;
+
+	if ((have_anycompatible_result ||
+		 have_anycompatible_array_result ||
+		 have_anycompatible_range_result) &&
+		(!OidIsValid(anycompatible_type) &&
+		 !OidIsValid(anycompatible_array_type) &&
+		 !OidIsValid(anycompatible_range_type)))
 		return false;
 
 	/* If needed, deduce one polymorphic type from others */
@@ -563,11 +614,36 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 		}
 	}
 
+	if (have_anycompatible_result && !OidIsValid(anycompatible_type))
+	{
+		if (OidIsValid(anycompatible_array_type))
+			anycompatible_type = resolve_generic_type(ANYCOMPATIBLEOID,
+													  anycompatible_array_type,
+													  ANYCOMPATIBLEARRAYOID);
+
+		if (OidIsValid(anycompatible_range_type))
+		{
+			Oid			subtype = resolve_generic_type(ANYCOMPATIBLEOID,
+													   anycompatible_range_type,
+													   ANYCOMPATIBLERANGEOID);
+
+			/* check for inconsistent array and range results */
+			if (OidIsValid(anycompatible_type) && anycompatible_type != subtype)
+				return false;
+			anycompatible_type = subtype;
+		}
+	}
+
 	if (have_anyarray_result && !OidIsValid(anyarray_type))
 		anyarray_type = resolve_generic_type(ANYARRAYOID,
 											 anyelement_type,
 											 ANYELEMENTOID);
 
+	if (have_anycompatible_array_result && !OidIsValid(anycompatible_array_type))
+		anycompatible_array_type = resolve_generic_type(ANYCOMPATIBLEARRAYOID,
+														anycompatible_type,
+														ANYCOMPATIBLEOID);
+
 	/*
 	 * We can't deduce a range type from other polymorphic inputs, because
 	 * there may be multiple range types for the same subtype.
@@ -575,10 +651,17 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 	if (have_anyrange_result && !OidIsValid(anyrange_type))
 		return false;
 
+	if (have_anycompatible_range_result && !OidIsValid(anycompatible_range_type))
+		return false;
+
 	/* Enforce ANYNONARRAY if needed */
 	if (have_anynonarray && type_is_array(anyelement_type))
 		return false;
 
+	/* Enforce ANYCOMPATIBLENONARRAY if needed */
+	if (have_anycompatible_nonarray && type_is_array(anycompatible_type))
+		return false;
+
 	/* Enforce ANYENUM if needed */
 	if (have_anyenum && !type_is_enum(anyelement_type))
 		return false;
@@ -594,7 +677,12 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 	else if (OidIsValid(anyarray_type))
 		anycollation = get_typcollation(anyarray_type);
 
-	if (OidIsValid(anycollation))
+	if (OidIsValid(anycompatible_type))
+		anycompatcollation = get_typcollation(anycompatible_type);
+	else if (OidIsValid(anycompatible_array_type))
+		anycompatcollation = get_typcollation(anycompatible_array_type);
+
+	if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
 	{
 		/*
 		 * The types are collatable, so consider whether to use a nondefault
@@ -605,6 +693,9 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
 
 		if (OidIsValid(inputcollation))
 			anycollation = inputcollation;
+
+		if (OidIsValid(inputcollation))
+			anycompatcollation = inputcollation;
 	}
 
 	/* And finally replace the tuple column types as needed */
@@ -640,6 +731,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),
+								   anycompatible_type,
+								   -1,
+								   0);
+				TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
+				break;
+			case ANYCOMPATIBLEARRAYOID:
+				TupleDescInitEntry(tupdesc, i + 1,
+								   NameStr(att->attname),
+								   anycompatible_array_type,
+								   -1,
+								   0);
+				TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation);
+				break;
+			case ANYCOMPATIBLERANGEOID:
+				TupleDescInitEntry(tupdesc, i + 1,
+								   NameStr(att->attname),
+								   anycompatible_range_type,
+								   -1,
+								   0);
+				/* no collation should be attached to a range type */
+				break;
 			default:
 				break;
 		}
@@ -664,9 +780,15 @@ 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;
 	Oid			anyelement_type = InvalidOid;
 	Oid			anyarray_type = InvalidOid;
 	Oid			anyrange_type = InvalidOid;
+	Oid			anycompatible_type = InvalidOid;
+	Oid			anycompatible_array_type = InvalidOid;
+	Oid			anycompatible_range_type = InvalidOid;
 	int			inargno;
 	int			i;
 
@@ -725,6 +847,52 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 					argtypes[i] = anyrange_type;
 				}
 				break;
+			case ANYCOMPATIBLEOID:
+			case ANYCOMPATIBLENONARRAYOID:
+				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+					have_anycompatible_result = true;
+				else
+				{
+					if (!OidIsValid(anycompatible_type))
+					{
+						anycompatible_type = get_call_expr_argtype(call_expr,
+																   inargno);
+						if (!OidIsValid(anycompatible_type))
+							return false;
+					}
+					argtypes[i] = anycompatible_type;
+				}
+				break;
+			case ANYCOMPATIBLEARRAYOID:
+				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+					have_anycompatible_array_result = true;
+				else
+				{
+					if (!OidIsValid(anycompatible_array_type))
+					{
+						anycompatible_array_type = get_call_expr_argtype(call_expr,
+																		 inargno);
+						if (!OidIsValid(anycompatible_array_type))
+							return false;
+					}
+					argtypes[i] = anycompatible_array_type;
+				}
+				break;
+			case ANYCOMPATIBLERANGEOID:
+				if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+					have_anycompatible_range_result = true;
+				else
+				{
+					if (!OidIsValid(anycompatible_range_type))
+					{
+						anycompatible_range_type = get_call_expr_argtype(call_expr,
+																		 inargno);
+						if (!OidIsValid(anycompatible_range_type))
+							return false;
+					}
+					argtypes[i] = anycompatible_range_type;
+				}
+				break;
 			default:
 				break;
 		}
@@ -733,48 +901,99 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 	}
 
 	/* Done? */
-	if (!have_anyelement_result && !have_anyarray_result &&
-		!have_anyrange_result)
+	if (!have_anyelement_result &&
+		!have_anyarray_result &&
+		!have_anyrange_result &&
+		!have_anycompatible_result &&
+		!have_anycompatible_array_result &&
+		!have_anycompatible_range_result)
 		return true;
 
-	/* If no input polymorphics, parser messed up */
-	if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
-		!OidIsValid(anyrange_type))
-		return false;
+	if (have_anyelement_result || have_anyarray_result || have_anyrange_result)
+	{
+		/* If no input polymorphics, parser messed up */
+		if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
+			!OidIsValid(anyrange_type))
+			return false;
 
-	/* If needed, deduce one polymorphic type from others */
-	if (have_anyelement_result && !OidIsValid(anyelement_type))
+		/* If needed, deduce one polymorphic type from others */
+		if (have_anyelement_result && !OidIsValid(anyelement_type))
+		{
+			if (OidIsValid(anyarray_type))
+				anyelement_type = resolve_generic_type(ANYELEMENTOID,
+													   anyarray_type,
+													   ANYARRAYOID);
+			if (OidIsValid(anyrange_type))
+			{
+				Oid			subtype = resolve_generic_type(ANYELEMENTOID,
+														   anyrange_type,
+														   ANYRANGEOID);
+
+				/* check for inconsistent array and range results */
+				if (OidIsValid(anyelement_type) && anyelement_type != subtype)
+					return false;
+				anyelement_type = subtype;
+			}
+		}
+
+		if (have_anyarray_result && !OidIsValid(anyarray_type))
+			anyarray_type = resolve_generic_type(ANYARRAYOID,
+												 anyelement_type,
+												 ANYELEMENTOID);
+
+		/*
+		 * We can't deduce a range type from other polymorphic inputs, because
+		 * there may be multiple range types for the same subtype.
+		 */
+		if (have_anyrange_result && !OidIsValid(anyrange_type))
+			return false;
+
+		/* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
+	}
+
+	if (have_anycompatible_result || have_anycompatible_array_result ||
+		have_anycompatible_range_result)
 	{
-		if (OidIsValid(anyarray_type))
-			anyelement_type = resolve_generic_type(ANYELEMENTOID,
-												   anyarray_type,
-												   ANYARRAYOID);
-		if (OidIsValid(anyrange_type))
+		/* If no input polymorphics, parser messed up */
+		if (!OidIsValid(anycompatible_type) &&
+			!OidIsValid(anycompatible_array_type) &&
+			!OidIsValid(anycompatible_range_type))
+			return false;
+
+		if (have_anycompatible_result && !OidIsValid(anycompatible_type))
 		{
-			Oid			subtype = resolve_generic_type(ANYELEMENTOID,
-													   anyrange_type,
-													   ANYRANGEOID);
+			if (OidIsValid(anycompatible_array_type))
+				anycompatible_type = resolve_generic_type(ANYCOMPATIBLEOID,
+														  anycompatible_array_type,
+														  ANYCOMPATIBLEARRAYOID);
 
-			/* check for inconsistent array and range results */
-			if (OidIsValid(anyelement_type) && anyelement_type != subtype)
-				return false;
-			anyelement_type = subtype;
+			if (OidIsValid(anycompatible_range_type))
+			{
+				Oid			subtype = resolve_generic_type(ANYCOMPATIBLEOID,
+														   anyrange_type,
+														   ANYCOMPATIBLERANGEOID);
+
+				/* check for inconsistent array and range results */
+				if (OidIsValid(anycompatible_type) && anycompatible_type != subtype)
+					return false;
+				anycompatible_type = subtype;
+			}
 		}
-	}
 
-	if (have_anyarray_result && !OidIsValid(anyarray_type))
-		anyarray_type = resolve_generic_type(ANYARRAYOID,
-											 anyelement_type,
-											 ANYELEMENTOID);
+		if (have_anycompatible_array_result || !OidIsValid(anycompatible_array_type))
+			anycompatible_array_type = resolve_generic_type(ANYCOMPATIBLEARRAYOID,
+															anycompatible_type,
+															ANYCOMPATIBLEOID);
 
-	/*
-	 * We can't deduce a range type from other polymorphic inputs, because
-	 * there may be multiple range types for the same subtype.
-	 */
-	if (have_anyrange_result && !OidIsValid(anyrange_type))
-		return false;
+		/*
+		 * We can't deduce a range type from other polymorphic inputs, because
+		 * there may be multiple range types for the same subtype.
+		 */
+		if (have_anycompatible_range_result && !OidIsValid(anycompatible_range_type))
+			return false;
 
-	/* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */
+		/* XXX do we need to enforce ANYCOMPATIBLENONARRAY here?  I think not */
+	}
 
 	/* And finally replace the output column types as needed */
 	for (i = 0; i < numargs; i++)
@@ -792,6 +1011,16 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
 			case ANYRANGEOID:
 				argtypes[i] = anyrange_type;
 				break;
+			case ANYCOMPATIBLEOID:
+			case ANYCOMPATIBLENONARRAYOID:
+				argtypes[i] = anycompatible_type;
+				break;
+			case ANYCOMPATIBLEARRAYOID:
+				argtypes[i] = anycompatible_array_type;
+				break;
+			case ANYCOMPATIBLERANGEOID:
+				argtypes[i] = anycompatible_range_type;
+				break;
 			default:
 				break;
 		}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 7fb574f..8387238 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7106,6 +7106,42 @@
 { 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',
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index b00597d..20d5167 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -590,5 +590,30 @@
   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 polymorphic common type that is a range',
+  typname => 'anycompatiblerange', typlen => '-1', typbyval => 'f',
+  typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in',
+  typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-',
+  typalign => 'd', typstorage => 'x' },
 
 ]
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 9789094..7b37562 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -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 */
 
 
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index c8e43e6..828ff5a 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -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:
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index d436d29..838352b 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -1547,3 +1547,177 @@ View definition:
 
 drop view dfview;
 drop function dfunc(anyelement, anyelement, bool);
+create or replace function cttestfunc01(anycompatible, anycompatible)
+returns anycompatible as $$
+begin
+  if $1 > $2 then
+    return $1;
+  else
+    return $2;
+  end if;
+end;
+$$ language plpgsql;
+create or replace function cttestfunc02(anycompatible, anycompatible)
+returns anycompatiblearray as $$
+begin
+  return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc03(anycompatiblearray)
+returns anycompatible as $$
+begin
+  return $1[1];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc04(variadic anycompatiblearray)
+returns anycompatible as $$
+begin
+  return (select min(v) from unnest($1) g(v));
+end;
+$$ language plpgsql;
+create or replace function cttestfunc05(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+begin
+  return $1;
+end;
+$$ language plpgsql;
+create or replace function cttestfunc06(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+begin
+  return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc07(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+  select $1
+$$ language sql;
+create or replace function cttestfunc08(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+select array[$1, $2]
+$$ language sql;
+select cttestfunc01(10, 20);
+ cttestfunc01 
+--------------
+           20
+(1 row)
+
+select cttestfunc01(10.1, 20.1);
+ cttestfunc01 
+--------------
+         20.1
+(1 row)
+
+select cttestfunc01(10, 20.1);
+ cttestfunc01 
+--------------
+         20.1
+(1 row)
+
+select cttestfunc02(10, 20);
+ cttestfunc02 
+--------------
+ {10,20}
+(1 row)
+
+select cttestfunc02(10.1, 20.1);
+ cttestfunc02 
+--------------
+ {10.1,20.1}
+(1 row)
+
+select cttestfunc02(10, 20.1);
+ cttestfunc02 
+--------------
+ {10,20.1}
+(1 row)
+
+select cttestfunc03(ARRAY[10, 20]);
+ cttestfunc03 
+--------------
+           10
+(1 row)
+
+select cttestfunc03(ARRAY[10.1, 20.1]);
+ cttestfunc03 
+--------------
+         10.1
+(1 row)
+
+select cttestfunc03(ARRAY[10, 20.1]);
+ cttestfunc03 
+--------------
+           10
+(1 row)
+
+select cttestfunc04(10, 20);
+ cttestfunc04 
+--------------
+           10
+(1 row)
+
+select cttestfunc04(10.1, 20.1);
+ cttestfunc04 
+--------------
+         10.1
+(1 row)
+
+select cttestfunc04(10, 20.1);
+ cttestfunc04 
+--------------
+           10
+(1 row)
+
+select cttestfunc05(10, 20);
+ cttestfunc05 
+--------------
+ {10,20}
+(1 row)
+
+select cttestfunc05(10.1, 20.1);
+ cttestfunc05 
+--------------
+ {10.1,20.1}
+(1 row)
+
+select cttestfunc05(10, 20.1);
+ cttestfunc05 
+--------------
+ {10,20.1}
+(1 row)
+
+select cttestfunc06(1,1.1);
+ cttestfunc06 
+--------------
+ {1,1.1}
+(1 row)
+
+select cttestfunc07(10, 20);
+ cttestfunc07 
+--------------
+ {10,20}
+(1 row)
+
+select cttestfunc07(10.1, 20.1);
+ cttestfunc07 
+--------------
+ {10.1,20.1}
+(1 row)
+
+select cttestfunc07(10, 20.1);
+ cttestfunc07 
+--------------
+ {10,20.1}
+(1 row)
+
+select cttestfunc08(1,1.1);
+ cttestfunc08 
+--------------
+ {1,1.1}
+(1 row)
+
+-- should to fail
+select cttestfunc06(array[10], array[2]);
+ERROR:  function cttestfunc06(integer[], integer[]) does not exist
+LINE 1: select cttestfunc06(array[10], array[2]);
+               ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index 0360667..566b25b 100644
--- a/src/test/regress/sql/polymorphism.sql
+++ b/src/test/regress/sql/polymorphism.sql
@@ -814,3 +814,91 @@ select * from dfview;
 
 drop view dfview;
 drop function dfunc(anyelement, anyelement, bool);
+
+create or replace function cttestfunc01(anycompatible, anycompatible)
+returns anycompatible as $$
+begin
+  if $1 > $2 then
+    return $1;
+  else
+    return $2;
+  end if;
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc02(anycompatible, anycompatible)
+returns anycompatiblearray as $$
+begin
+  return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc03(anycompatiblearray)
+returns anycompatible as $$
+begin
+  return $1[1];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc04(variadic anycompatiblearray)
+returns anycompatible as $$
+begin
+  return (select min(v) from unnest($1) g(v));
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc05(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+begin
+  return $1;
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc06(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+begin
+  return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc07(variadic anycompatiblearray)
+returns anycompatiblearray as $$
+  select $1
+$$ language sql;
+
+create or replace function cttestfunc08(anycompatiblenonarray, anycompatiblenonarray)
+returns anycompatiblearray as $$
+select array[$1, $2]
+$$ language sql;
+
+
+select cttestfunc01(10, 20);
+select cttestfunc01(10.1, 20.1);
+select cttestfunc01(10, 20.1);
+
+select cttestfunc02(10, 20);
+select cttestfunc02(10.1, 20.1);
+select cttestfunc02(10, 20.1);
+
+select cttestfunc03(ARRAY[10, 20]);
+select cttestfunc03(ARRAY[10.1, 20.1]);
+select cttestfunc03(ARRAY[10, 20.1]);
+
+select cttestfunc04(10, 20);
+select cttestfunc04(10.1, 20.1);
+select cttestfunc04(10, 20.1);
+
+select cttestfunc05(10, 20);
+select cttestfunc05(10.1, 20.1);
+select cttestfunc05(10, 20.1);
+
+select cttestfunc06(1,1.1);
+
+select cttestfunc07(10, 20);
+select cttestfunc07(10.1, 20.1);
+select cttestfunc07(10, 20.1);
+
+select cttestfunc08(1,1.1);
+
+-- should to fail
+select cttestfunc06(array[10], array[2]);
