diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index ed0ee584c9..f9d10204e3 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4761,6 +4761,14 @@ SELECT * FROM pg_attribute
anyrange
+
+ commontype
+
+
+
+ commontypearray
+
+
void
@@ -4870,6 +4878,34 @@ SELECT * FROM pg_attribute
).
+
+ commontype
+ Indicates that a function accepts any data type. Values
+ are converted to real common type.
+ (see ).
+
+
+
+ commontypearray
+ Indicates that a function accepts any array data type. The
+ elements of array are converted to common type of these values.
+ (see ).
+
+
+
+ commontypenonarray
+ Indicates that a function accepts any non-array data type
+ (see ).
+
+
+
+ commontyperange
+ Indicates that a function accepts any range data type
+ (see and
+ ). The subtype can be used for
+ deduction of common type.
+
+
cstring
Indicates that a function accepts or returns a null-terminated C string.
diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml
index a6b77c1cfe..dece346c03 100644
--- a/doc/src/sgml/extend.sgml
+++ b/doc/src/sgml/extend.sgml
@@ -231,7 +231,7 @@
Five pseudo-types of special interest are anyelement,
anyarray, anynonarray, anyenum,
- and anyrange,
+ anyrange, commontype and commontypearray.
which are collectively called polymorphic types.
Any function declared using these types is said to be
a polymorphic function. A polymorphic function can
@@ -267,6 +267,15 @@
be an enum type.
+
+ Second family of polymorphic types are types commontype and
+ commontypearray. These types are similar to types
+ anyelement and anyarray. The arguments declared
+ as anyelement requires same real type of passed values. For
+ commontype's arguments is selected common type, and later
+ all these arguments are casted to this common type.
+
+
Thus, when more than one argument position is declared with a polymorphic
type, the net effect is that only certain combinations of actual argument
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index cc3806e85d..d5013ec12d 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -133,7 +133,7 @@ AggregateCreate(const char *aggName,
hasInternalArg = false;
for (i = 0; i < numArgs; i++)
{
- if (IsPolymorphicType(aggArgTypes[i]))
+ if (IsPolymorphicTypeAny(aggArgTypes[i]))
hasPolyArg = true;
else if (aggArgTypes[i] == INTERNALOID)
hasInternalArg = true;
@@ -143,7 +143,7 @@ AggregateCreate(const char *aggName,
* If transtype is polymorphic, must have polymorphic argument also; else
* we will have no way to deduce the actual transtype.
*/
- if (IsPolymorphicType(aggTransType) && !hasPolyArg)
+ if (IsPolymorphicTypeAny(aggTransType) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine transition data type"),
@@ -153,7 +153,7 @@ AggregateCreate(const char *aggName,
* Likewise for moving-aggregate transtype, if any
*/
if (OidIsValid(aggmTransType) &&
- IsPolymorphicType(aggmTransType) && !hasPolyArg)
+ IsPolymorphicTypeAny(aggmTransType) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine transition data type"),
@@ -489,7 +489,7 @@ AggregateCreate(const char *aggName,
* that itself violates the rule against polymorphic result with no
* polymorphic input.)
*/
- if (IsPolymorphicType(finaltype) && !hasPolyArg)
+ if (IsPolymorphicTypeAny(finaltype) && !hasPolyArg)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot determine result data type"),
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index db780616e6..1e98db47ee 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -102,6 +102,10 @@ ProcedureCreate(const char *procedureName,
bool anyrangeOutParam = false;
bool internalInParam = false;
bool internalOutParam = false;
+ bool commonInParam = false;
+ bool commonOutParam = false;
+ bool commonrangeInParam = false;
+ bool commonrangeOutParam = false;
Oid variadicType = InvalidOid;
Acl *proacl = NULL;
Relation rel;
@@ -197,6 +201,15 @@ ProcedureCreate(const char *procedureName,
case INTERNALOID:
internalInParam = true;
break;
+ case COMMONTYPEOID:
+ case COMMONTYPEARRAYOID:
+ case COMMONTYPENONARRAYOID:
+ commonInParam = true;
+ break;
+ case COMMONTYPERANGEOID:
+ commonInParam = true;
+ commonrangeInParam = true;
+ break;
}
}
@@ -224,6 +237,15 @@ ProcedureCreate(const char *procedureName,
case INTERNALOID:
internalOutParam = true;
break;
+ case COMMONTYPEOID:
+ case COMMONTYPEARRAYOID:
+ case COMMONTYPENONARRAYOID:
+ commonOutParam = true;
+ break;
+ case COMMONTYPERANGEOID:
+ commonOutParam = true;
+ commonrangeOutParam = true;
+ break;
}
}
}
@@ -235,13 +257,20 @@ ProcedureCreate(const char *procedureName,
* ANYELEMENT). Also, do not allow return type INTERNAL unless at least
* one input argument is INTERNAL.
*/
- if ((IsPolymorphicType(returnType) || genericOutParam)
+ if ((IsPolymorphicTypeAny(returnType) || genericOutParam)
&& !genericInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine result data type"),
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
+ if ((IsPolymorphicTypeCommon(returnType) || commonOutParam)
+ && !commonInParam)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("cannot determine result data type"),
+ errdetail("A function returning \"commontype\" or \"commontypearray\" must have at least one \"commontype\" or \"commontypearray\" argument.")));
+
if ((returnType == ANYRANGEOID || anyrangeOutParam) &&
!anyrangeInParam)
ereport(ERROR,
@@ -249,6 +278,13 @@ ProcedureCreate(const char *procedureName,
errmsg("cannot determine result data type"),
errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument.")));
+ if ((returnType == COMMONTYPERANGEOID || commonrangeOutParam) &&
+ !commonrangeInParam)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ errmsg("cannot determine result data type"),
+ errdetail("A function returning \"commontyperange\" must have at least one \"commontyperange\" argument.")));
+
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
@@ -286,6 +322,9 @@ ProcedureCreate(const char *procedureName,
case ANYARRAYOID:
variadicType = ANYELEMENTOID;
break;
+ case COMMONTYPEARRAYOID:
+ variadicType = COMMONTYPEOID;
+ break;
default:
variadicType = get_element_type(allParams[i]);
if (!OidIsValid(variadicType))
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index d00765fbc7..b64fe12adf 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -334,7 +334,7 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
transTypeId = typenameTypeId(NULL, transType);
transTypeType = get_typtype(transTypeId);
if (transTypeType == TYPTYPE_PSEUDO &&
- !IsPolymorphicType(transTypeId))
+ !IsPolymorphicTypeAny(transTypeId))
{
if (transTypeId == INTERNALOID && superuser())
/* okay */ ;
@@ -375,7 +375,7 @@ DefineAggregate(ParseState *pstate, List *name, List *args, bool oldstyle, List
mtransTypeId = typenameTypeId(NULL, mtransType);
mtransTypeType = get_typtype(mtransTypeId);
if (mtransTypeType == TYPTYPE_PSEUDO &&
- !IsPolymorphicType(mtransTypeId))
+ !IsPolymorphicTypeAny(mtransTypeId))
{
if (mtransTypeId == INTERNALOID && superuser())
/* okay */ ;
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ac401689c8..88d099c2a0 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 COMMONTYPEARRAYOID:
case ANYOID:
/* okay */
break;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 5b2b8d2969..59d31ab615 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -256,7 +256,7 @@ CheckIndexCompatible(Oid oldId,
irel = index_open(oldId, AccessShareLock); /* caller probably has a lock */
for (i = 0; i < old_natts; i++)
{
- if (IsPolymorphicType(get_opclass_input_type(classObjectId[i])) &&
+ if (IsPolymorphicTypeAny(get_opclass_input_type(classObjectId[i])) &&
TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
{
ret = false;
@@ -284,7 +284,7 @@ CheckIndexCompatible(Oid oldId,
right;
op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
- if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
+ if ((IsPolymorphicTypeAny(left) || IsPolymorphicTypeAny(right)) &&
TupleDescAttr(irel->rd_att, i)->atttypid != typeObjectId[i])
{
ret = false;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ff76499137..0f3db83d32 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -7586,7 +7586,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
*/
old_check_ok = (new_pathtype == old_pathtype &&
new_castfunc == old_castfunc &&
- (!IsPolymorphicType(pfeqop_right) ||
+ (!IsPolymorphicTypeAny(pfeqop_right) ||
new_fktype == old_fktype));
}
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 6e134ae1d2..50a5a69e3b 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -499,7 +499,7 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
* For a polymorphic-input-type opclass, just keep the same exposed type.
* RECORD opclasses work like polymorphic-type ones for this purpose.
*/
- if (IsPolymorphicType(req_type) || req_type == RECORDOID)
+ if (IsPolymorphicTypeAny(req_type) || req_type == RECORDOID)
req_type = expr_type;
/*
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 8ed3816866..a0856181e9 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -1870,7 +1870,7 @@ resolve_aggregate_transtype(Oid aggfuncid,
int numArguments)
{
/* resolve actual type of transition state, if polymorphic */
- if (IsPolymorphicType(aggtranstype))
+ if (IsPolymorphicTypeAny(aggtranstype))
{
/* have to fetch the agg's declared input types... */
Oid *declaredArgTypes;
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 3840252a5b..eb461c0079 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -169,7 +169,9 @@ coerce_type(ParseState *pstate, Node *node,
}
if (targetTypeId == ANYOID ||
targetTypeId == ANYELEMENTOID ||
- targetTypeId == ANYNONARRAYOID)
+ targetTypeId == ANYNONARRAYOID ||
+ targetTypeId == COMMONTYPEOID ||
+ targetTypeId == COMMONTYPENONARRAYOID)
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
@@ -187,7 +189,9 @@ coerce_type(ParseState *pstate, Node *node,
}
if (targetTypeId == ANYARRAYOID ||
targetTypeId == ANYENUMOID ||
- targetTypeId == ANYRANGEOID)
+ targetTypeId == ANYRANGEOID ||
+ targetTypeId == COMMONTYPEARRAYOID ||
+ targetTypeId == COMMONTYPERANGEOID)
{
/*
* Assume can_coerce_type verified that implicit coercion is okay.
@@ -1389,6 +1393,100 @@ select_common_type(ParseState *pstate, List *exprs, const char *context,
return ptype;
}
+/*
+ * 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, lc
+ * points to the first list item with type different from pexpr's; we need
+ * not re-examine any items the previous loop advanced over.
+ */
+ 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.
@@ -1485,6 +1583,12 @@ check_generic_type_consistency(const Oid *actual_arg_types,
bool have_anyelement = false;
bool have_anynonarray = false;
bool have_anyenum = false;
+ bool have_commontypenonarray = false;
+ bool have_commontype_range = false;
+ bool have_generic_common = false;
+ Oid commontype_range_typeid = InvalidOid;
+ Oid commontype_actual_types[FUNC_MAX_ARGS];
+ int n_commontype_args = 0;
/*
* Loop through the arguments to see if we have any that are polymorphic.
@@ -1528,6 +1632,72 @@ check_generic_type_consistency(const Oid *actual_arg_types,
return false;
range_typeid = actual_type;
}
+ else if (decl_type == COMMONTYPEOID ||
+ decl_type == COMMONTYPENONARRAYOID)
+ {
+ have_generic_common = true;
+ if (decl_type == COMMONTYPENONARRAYOID)
+ have_commontypenonarray = true;
+ if (actual_type == UNKNOWNOID)
+ continue;
+
+ /* collect used type, reduce repeated values * */
+ if (n_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != actual_type)
+ commontype_actual_types[n_commontype_args++] = actual_type;
+ }
+ else if (decl_type == COMMONTYPEARRAYOID)
+ {
+ Oid commontype_elem_type;
+
+ have_generic_common = true;
+
+ if (actual_type == UNKNOWNOID)
+ continue;
+
+ actual_type = getBaseType(actual_type); /* flatten domains */
+ commontype_elem_type = get_element_type(actual_type);
+
+ if (!OidIsValid(commontype_elem_type))
+ return false;
+
+ /* collect used type, reduce repeated values * */
+ if (n_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != commontype_elem_type)
+ commontype_actual_types[n_commontype_args++] = commontype_elem_type;
+ }
+ else if (decl_type == COMMONTYPERANGEOID)
+ {
+ Oid commontype_range_typelem;
+
+ have_generic_common = true;
+ have_commontype_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(commontype_range_typeid) &&
+ commontype_range_typeid != actual_type)
+ return false;
+
+ commontype_range_typelem = get_range_subtype(actual_type);
+ if (!OidIsValid(commontype_range_typelem))
+ return false;
+
+ if (!OidIsValid(commontype_range_typeid))
+ commontype_range_typeid = actual_type;
+
+ /* collect used type, reduce repeated values * */
+ if (n_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != commontype_range_typelem)
+ commontype_actual_types[n_commontype_args++] = commontype_range_typelem;
+ }
}
/* Get the element type based on the array type, if we have one */
@@ -1594,6 +1764,37 @@ check_generic_type_consistency(const Oid *actual_arg_types,
return false;
}
+ /* check commontype collected data */
+ if (have_generic_common)
+ {
+ if (n_commontype_args > 0)
+ {
+ Oid commontype_typeid;
+
+ commontype_typeid = select_common_type_from_vector(n_commontype_args,
+ commontype_actual_types,
+ true);
+
+ if (!OidIsValid(commontype_typeid))
+ return false;
+
+ if (have_commontypenonarray)
+ {
+ /* require the commontype type to not be an array or domain over array */
+ if (type_is_array_domain(commontype_typeid))
+ return false;
+ }
+
+ if (have_commontype_range && !OidIsValid(commontype_range_typeid))
+ return false;
+
+ return true;
+ }
+
+ /* is not possible derive common type */
+ return false;
+ }
+
/* Looks valid */
return true;
}
@@ -1676,11 +1877,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_common = false;
bool have_unknowns = false;
Oid elem_typeid = InvalidOid;
Oid array_typeid = InvalidOid;
Oid range_typeid = InvalidOid;
+ Oid commontype_typeid = InvalidOid;
+ Oid commontype_array_typeid = InvalidOid;
+ Oid commontype_range_typeid = InvalidOid;
Oid array_typelem;
Oid range_typelem;
bool have_anyelement = (rettype == ANYELEMENTOID ||
@@ -1688,6 +1893,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
rettype == ANYENUMOID);
bool have_anynonarray = (rettype == ANYNONARRAYOID);
bool have_anyenum = (rettype == ANYENUMOID);
+ bool have_commontype_nonarray = (rettype == COMMONTYPENONARRAYOID);
+ bool have_commontype_array = (rettype == COMMONTYPEARRAYOID);
+ bool have_commontype_range = (rettype == COMMONTYPERANGEOID);
+ Oid commontype_actual_types[FUNC_MAX_ARGS];
+ int n_commontype_args = 0;
/*
* Loop through the arguments to see if we have any that are polymorphic.
@@ -1702,7 +1912,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)
@@ -1725,14 +1935,18 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
}
else if (decl_type == ANYARRAYOID)
{
- have_generics = true;
+ have_generics_any = true;
+ have_commontype_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,
@@ -1745,7 +1959,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;
@@ -1763,128 +1977,289 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
format_type_be(actual_type))));
range_typeid = actual_type;
}
+ else if (decl_type == COMMONTYPEOID ||
+ decl_type == COMMONTYPENONARRAYOID)
+ {
+ have_generics_common = true;
+
+ if (decl_type == COMMONTYPENONARRAYOID)
+ have_commontype_nonarray = true;
+ /*
+ * 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_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != actual_type)
+ commontype_actual_types[n_commontype_args++] = actual_type;
+ }
+ else if (decl_type == COMMONTYPEARRAYOID)
+ {
+ Oid commontype_elem_type;
+
+ have_generics_common = true;
+ have_commontype_array = true;
+
+ if (actual_type == UNKNOWNOID)
+ continue;
+
+ if (allow_poly && decl_type == actual_type)
+ continue;
+
+ actual_type = getBaseType(actual_type); /* flatten domains */
+ commontype_elem_type = get_element_type(actual_type);
+
+ if (!OidIsValid(commontype_elem_type))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument declared %s is not an array but type %s",
+ "anyarray", format_type_be(actual_type))));
+
+ /* collect used type, reduce repeated values * */
+ if (n_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != commontype_elem_type)
+ commontype_actual_types[n_commontype_args++] = commontype_elem_type;
+ }
+ else if (decl_type == COMMONTYPERANGEOID)
+ {
+ Oid commontype_range_typelem;
+
+ have_generics_common = true;
+ have_commontype_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(commontype_range_typeid) &&
+ actual_type != commontype_range_typeid)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("arguments declared \"anyrange\" are not all alike"),
+ errdetail("%s versus %s",
+ format_type_be(commontype_range_typeid),
+ format_type_be(actual_type))));
+
+ commontype_range_typeid = actual_type;
+ commontype_range_typelem = get_range_subtype(commontype_range_typeid);
+
+ if (!OidIsValid(commontype_range_typelem))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("argument declared %s is not a range type but type %s",
+ "anyrange",
+ format_type_be(commontype_range_typeid))));
+
+ /* collect used type, reduce repeated values * */
+ if (n_commontype_args == 0 ||
+ commontype_actual_types[n_commontype_args - 1] != commontype_range_typelem)
+ commontype_actual_types[n_commontype_args++] = commontype_range_typelem;
+ }
}
/*
* Fast Track: if none of the arguments are polymorphic, return the
* unmodified rettype. We assume it can't be polymorphic either.
*/
- if (!have_generics)
+ if (!have_generics_any && !have_generics_common)
return rettype;
- /* Get the element type based on the array type, if we have one */
- if (OidIsValid(array_typeid))
+ if (have_generics_any)
{
- if (array_typeid == ANYARRAYOID && !have_anyelement)
+ /* Get the element type based on the array type, if we have one */
+ if (OidIsValid(array_typeid))
{
- /* Special case for ANYARRAY input: okay iff no ANYELEMENT */
- array_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))
{
- array_typelem = get_element_type(array_typeid);
- if (!OidIsValid(array_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 an array but type %s",
- "anyarray", format_type_be(array_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 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))));
+ 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")));
+ }
}
- }
- /* Get the element type based on the range type, if we have one */
- if (OidIsValid(range_typeid))
- {
- if (range_typeid == ANYRANGEOID && !have_anyelement)
+ if (have_anynonarray && elem_typeid != ANYELEMENTOID)
{
- /* Special case for ANYRANGE input: okay iff no ANYELEMENT */
- range_typelem = ANYELEMENTOID;
- }
- else
- {
- range_typelem = get_range_subtype(range_typeid);
- if (!OidIsValid(range_typelem))
+ /* 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("argument declared %s is not a range type but type %s",
- "anyrange",
- format_type_be(range_typeid))));
+ errmsg("type matched to anynonarray is an array type: %s",
+ format_type_be(elem_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)
+ 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_common)
{
- if (allow_poly)
+ if (n_commontype_args > 0)
{
- elem_typeid = ANYELEMENTOID;
- array_typeid = ANYARRAYOID;
- range_typeid = ANYRANGEOID;
+ commontype_typeid = select_common_type_from_vector(n_commontype_args,
+ commontype_actual_types,
+ false);
+
+ if (have_commontype_array)
+ {
+ commontype_array_typeid = get_array_type(commontype_typeid);
+
+ if (!OidIsValid(commontype_array_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(commontype_typeid))));
+ }
+
+ /* commontype_range_typid should be defined already */
+ if (have_commontype_range && !OidIsValid(commontype_range_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find range type for data type %s",
+ "commontyperange")));
+
+ if (have_commontype_nonarray)
+ {
+ /* require the element type to not be an array or domain over array */
+ if (type_is_array_domain(commontype_typeid))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("type matched to anynonarray is an array type: %s",
+ format_type_be(commontype_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)
+ {
+ commontype_typeid = COMMONTYPEOID;
+ commontype_array_typeid = COMMONTYPEARRAYOID;
+ commontype_range_typeid = COMMONTYPERANGEOID;
+ }
+ 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 == COMMONTYPEOID ||
+ decl_type == COMMONTYPENONARRAYOID)
+ declared_arg_types[j] = commontype_typeid;
+ else if (decl_type == COMMONTYPEARRAYOID)
+ declared_arg_types[j] = commontype_array_typeid;
+ else if (decl_type == COMMONTYPERANGEOID)
+ declared_arg_types[j] = commontype_range_typeid;
+ }
}
/*
@@ -1965,6 +2340,41 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
rettype == ANYENUMOID)
return elem_typeid;
+ if (rettype == COMMONTYPEOID)
+ {
+ if (!OidIsValid(commontype_typeid))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find common type")));
+ }
+ return commontype_typeid;
+ }
+
+ if (rettype == COMMONTYPEARRAYOID)
+ {
+ if (!OidIsValid(commontype_array_typeid))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find common array type")));
+ }
+ return commontype_array_typeid;
+ }
+
+ /* if we return ANYRANGE use the appropriate argument type */
+ if (rettype == COMMONTYPERANGEOID)
+ {
+ if (!OidIsValid(commontype_range_typeid))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find range type for data type %s",
+ "commontyperange")));
+ }
+ return commontype_range_typeid;
+ }
+
/* we don't return a generic type; send back the original return type */
return rettype;
}
@@ -2060,6 +2470,75 @@ resolve_generic_type(Oid declared_type,
return context_actual_type;
}
}
+ else if (declared_type == COMMONTYPEARRAYOID)
+ {
+ if (context_declared_type == COMMONTYPEARRAYOID)
+ {
+ /*
+ * 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",
+ "anyarray", format_type_be(context_base_type))));
+ return context_base_type;
+ }
+ else if (context_declared_type == COMMONTYPEOID ||
+ context_declared_type == COMMONTYPENONARRAYOID ||
+ context_declared_type == COMMONTYPERANGEOID)
+ {
+ /* 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 == COMMONTYPEOID ||
+ declared_type == COMMONTYPENONARRAYOID)
+ {
+ if (context_declared_type == COMMONTYPEARRAYOID)
+ {
+ /* 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",
+ "commontypearray", format_type_be(context_base_type))));
+ return array_typelem;
+ }
+ else if (context_declared_type == COMMONTYPERANGEOID)
+ {
+ /* 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",
+ "anyrange", format_type_be(context_base_type))));
+ return range_typelem;
+ }
+ else if (context_declared_type == COMMONTYPEOID ||
+ context_declared_type == COMMONTYPENONARRAYOID)
+ {
+ /* 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 */
@@ -2142,8 +2621,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 COMMONTYPE */
+ if (targettype == ANYOID || targettype == ANYELEMENTOID ||
+ targettype == COMMONTYPEARRAYOID)
return true;
/* If srctype is a domain, reduce to its base type */
@@ -2155,7 +2635,7 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
return true;
/* Also accept any array type as coercible to ANYARRAY */
- if (targettype == ANYARRAYOID)
+ if (targettype == ANYARRAYOID || targettype == COMMONTYPEARRAYOID)
if (type_is_array(srctype))
return true;
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 24f0d5c08c..99ca904b8e 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -953,7 +953,7 @@ make_scalar_array_op(ParseState *pstate, List *opname,
* enforce_generic_type_consistency may or may not have replaced a
* polymorphic type with a real one.
*/
- if (IsPolymorphicType(declared_arg_types[1]))
+ if (IsPolymorphicTypeAny(declared_arg_types[1]))
{
/* assume the actual array type is OK */
res_atypeId = atypeId;
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index f21c9b32a6..aee4b5aed0 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -1787,7 +1787,7 @@ get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
*/
*need_relabel = (key->parttypid[col] != key->partopcintype[col] &&
key->partopcintype[col] != RECORDOID &&
- !IsPolymorphicType(key->partopcintype[col]));
+ !IsPolymorphicTypeAny(key->partopcintype[col]));
return operoid;
}
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index de0d0723b7..bf165dbc0c 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -1399,7 +1399,7 @@ json_categorize_type(Oid typoid,
default:
/* Check for arrays and composites */
if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
- || typoid == RECORDARRAYOID)
+ || typoid == COMMONTYPEARRAYOID || 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 c02c8569f2..aa9eab48f8 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -648,7 +648,7 @@ jsonb_categorize_type(Oid typoid,
default:
/* Check for arrays and composites */
if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
- || typoid == RECORDARRAYOID)
+ || typoid == COMMONTYPEARRAYOID || 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 6194dcd2fe..f84a80590e 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -135,6 +135,33 @@ anyarray_send(PG_FUNCTION_ARGS)
return array_send(fcinfo);
}
+/*
+ * commontypearray_recv - binary input routine for pseudo-type COMMONARRAY.
+ *
+ * XXX this 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.
+ */
+Datum
+commontypearray_recv(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type %s", "commontypearray")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+/*
+ * commontypearray_send - binary output routine for pseudo-type COMMONTYPEARRAY.
+ *
+ * We may as well allow this, since array_send will in fact work.
+ */
+Datum
+commontypearray_send(PG_FUNCTION_ARGS)
+{
+ return array_send(fcinfo);
+}
/*
* anyenum_in - input routine for pseudo-type ANYENUM.
@@ -184,6 +211,30 @@ anyrange_out(PG_FUNCTION_ARGS)
return range_out(fcinfo);
}
+/*
+ * commontyperange_in - input routine for pseudo-type COMMONTYPERANGE.
+ */
+Datum
+commontyperange_in(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type %s", "commontyperange")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+/*
+ * commontyperange_out - output routine for pseudo-type COMMONTYPERANGE.
+ *
+ * We may as well allow this, since range_out will in fact work.
+ */
+Datum
+commontyperange_out(PG_FUNCTION_ARGS)
+{
+ return range_out(fcinfo);
+}
+
/*
* void_in - input routine for pseudo-type VOID.
*
@@ -418,3 +469,6 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(internal);
PSEUDOTYPE_DUMMY_IO_FUNCS(opaque);
PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement);
PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray);
+PSEUDOTYPE_DUMMY_IO_FUNCS(commontype);
+PSEUDOTYPE_DUMMY_IO_FUNCS(commontypearray);
+PSEUDOTYPE_DUMMY_IO_FUNCS(commontypenonarray);
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index a5e77a208e..9f8200a947 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -440,10 +440,18 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
bool have_anyrange_result = false;
bool have_anynonarray = false;
bool have_anyenum = false;
+ bool have_commontype_result = false;
+ bool have_commontypearray_result = false;
+ bool have_commontyperange_result = false;
+ bool have_commontypenonarray = false;
Oid anyelement_type = InvalidOid;
Oid anyarray_type = InvalidOid;
Oid anyrange_type = InvalidOid;
+ Oid commontype_type = InvalidOid;
+ Oid commontypearray_type = InvalidOid;
+ Oid commontyperange_type = InvalidOid;
Oid anycollation = InvalidOid;
+ Oid ctcollation = InvalidOid;
int i;
/* See if there are any polymorphic outputs; quick out if not */
@@ -468,12 +476,27 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
case ANYRANGEOID:
have_anyrange_result = true;
break;
+ case COMMONTYPEOID:
+ have_commontype_result = true;
+ break;
+ case COMMONTYPEARRAYOID:
+ have_commontypearray_result = true;
+ break;
+ case COMMONTYPENONARRAYOID:
+ have_commontype_result = true;
+ have_commontypenonarray = true;
+ break;
+ case COMMONTYPERANGEOID:
+ have_commontyperange_result = true;
+ break;
default:
break;
}
}
if (!have_anyelement_result && !have_anyarray_result &&
- !have_anyrange_result)
+ !have_anyrange_result &&
+ !have_commontype_result && !have_commontypearray_result &&
+ !have_commontyperange_result)
return true;
/*
@@ -501,14 +524,29 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
if (!OidIsValid(anyrange_type))
anyrange_type = get_call_expr_argtype(call_expr, i);
break;
+ case COMMONTYPEOID:
+ case COMMONTYPENONARRAYOID:
+ if (!OidIsValid(commontype_type))
+ commontype_type = get_call_expr_argtype(call_expr, i);
+ break;
+ case COMMONTYPEARRAYOID:
+ if (!OidIsValid(commontypearray_type))
+ commontypearray_type = get_call_expr_argtype(call_expr, i);
+ break;
+ case COMMONTYPERANGEOID:
+ if (!OidIsValid(commontyperange_type))
+ commontyperange_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 needed, deduce one polymorphic type from others */
@@ -536,6 +574,31 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
anyelement_type,
ANYELEMENTOID);
+ if (have_commontypearray_result && !OidIsValid(commontypearray_type))
+ commontypearray_type = resolve_generic_type(COMMONTYPEARRAYOID,
+ commontype_type,
+ COMMONTYPEOID);
+
+ if (have_commontype_result && !OidIsValid(commontype_type))
+ {
+ if (OidIsValid(commontypearray_type))
+ commontype_type = resolve_generic_type(COMMONTYPEOID,
+ commontypearray_type,
+ COMMONTYPEARRAYOID);
+
+ if (OidIsValid(commontyperange_type))
+ {
+ Oid subtype = resolve_generic_type(COMMONTYPEOID,
+ commontyperange_type,
+ COMMONTYPERANGEOID);
+
+ /* check for inconsistent array and range results */
+ if (OidIsValid(commontype_type) && commontype_type != subtype)
+ return false;
+ commontype_type = subtype;
+ }
+ }
+
/*
* We can't deduce a range type from other polymorphic inputs, because
* there may be multiple range types for the same subtype.
@@ -543,10 +606,17 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
if (have_anyrange_result && !OidIsValid(anyrange_type))
return false;
+ if (have_commontyperange_result && !OidIsValid(commontyperange_type))
+ return false;
+
/* Enforce ANYNONARRAY if needed */
if (have_anynonarray && type_is_array(anyelement_type))
return false;
+ /* Enforce COMMONTYPENONARRAY if needed */
+ if (have_commontypenonarray && type_is_array(commontype_type))
+ return false;
+
/* Enforce ANYENUM if needed */
if (have_anyenum && !type_is_enum(anyelement_type))
return false;
@@ -562,7 +632,12 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
else if (OidIsValid(anyarray_type))
anycollation = get_typcollation(anyarray_type);
- if (OidIsValid(anycollation))
+ if (OidIsValid(commontype_type))
+ ctcollation = get_typcollation(commontype_type);
+ else if (OidIsValid(commontypearray_type))
+ ctcollation = get_typcollation(commontypearray_type);
+
+ if (OidIsValid(anycollation) || OidIsValid(ctcollation))
{
/*
* The types are collatable, so consider whether to use a nondefault
@@ -573,6 +648,9 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
if (OidIsValid(inputcollation))
anycollation = inputcollation;
+
+ if (OidIsValid(inputcollation))
+ ctcollation = inputcollation;
}
/* And finally replace the tuple column types as needed */
@@ -608,6 +686,31 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
0);
/* no collation should be attached to a range type */
break;
+ case COMMONTYPEOID:
+ case COMMONTYPENONARRAYOID:
+ TupleDescInitEntry(tupdesc, i + 1,
+ NameStr(att->attname),
+ commontype_type,
+ -1,
+ 0);
+ TupleDescInitEntryCollation(tupdesc, i + 1, ctcollation);
+ break;
+ case COMMONTYPEARRAYOID:
+ TupleDescInitEntry(tupdesc, i + 1,
+ NameStr(att->attname),
+ commontypearray_type,
+ -1,
+ 0);
+ TupleDescInitEntryCollation(tupdesc, i + 1, ctcollation);
+ break;
+ case COMMONTYPERANGEOID:
+ TupleDescInitEntry(tupdesc, i + 1,
+ NameStr(att->attname),
+ commontyperange_type,
+ -1,
+ 0);
+ /* no collation should be attached to a range type */
+ break;
default:
break;
}
@@ -632,9 +735,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_commontype_result = false;
+ bool have_commontypearray_result = false;
+ bool have_commontyperange_result = false;
Oid anyelement_type = InvalidOid;
Oid anyarray_type = InvalidOid;
Oid anyrange_type = InvalidOid;
+ Oid commontype_type = InvalidOid;
+ Oid commontypearray_type = InvalidOid;
+ Oid commontyperange_type = InvalidOid;
int inargno;
int i;
@@ -693,6 +802,52 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
argtypes[i] = anyrange_type;
}
break;
+ case COMMONTYPEOID:
+ case COMMONTYPENONARRAYOID:
+ if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+ have_commontype_result = true;
+ else
+ {
+ if (!OidIsValid(commontype_type))
+ {
+ commontype_type = get_call_expr_argtype(call_expr,
+ inargno);
+ if (!OidIsValid(commontype_type))
+ return false;
+ }
+ argtypes[i] = commontype_type;
+ }
+ break;
+ case COMMONTYPEARRAYOID:
+ if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+ have_commontypearray_result = true;
+ else
+ {
+ if (!OidIsValid(commontypearray_type))
+ {
+ commontypearray_type = get_call_expr_argtype(call_expr,
+ inargno);
+ if (!OidIsValid(commontypearray_type))
+ return false;
+ }
+ argtypes[i] = commontypearray_type;
+ }
+ break;
+ case COMMONTYPERANGEOID:
+ if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
+ have_commontyperange_result = true;
+ else
+ {
+ if (!OidIsValid(commontyperange_type))
+ {
+ commontyperange_type = get_call_expr_argtype(call_expr,
+ inargno);
+ if (!OidIsValid(commontyperange_type))
+ return false;
+ }
+ argtypes[i] = commontyperange_type;
+ }
+ break;
default:
break;
}
@@ -702,47 +857,94 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
/* Done? */
if (!have_anyelement_result && !have_anyarray_result &&
- !have_anyrange_result)
+ !have_anyrange_result &&
+ !have_commontype_result && !have_commontypearray_result)
return true;
- /* 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 (have_anyelement_result || have_anyarray_result || have_anyrange_result)
{
- 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);
+ /* If no input polymorphics, parser messed up */
+ if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
+ !OidIsValid(anyrange_type))
+ return false;
- /* check for inconsistent array and range results */
- if (OidIsValid(anyelement_type) && anyelement_type != subtype)
- return false;
- anyelement_type = subtype;
+ /* 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_anyarray_result && !OidIsValid(anyarray_type))
- anyarray_type = resolve_generic_type(ANYARRAYOID,
- anyelement_type,
- ANYELEMENTOID);
+ if (have_commontype_result || have_commontypearray_result ||
+ have_commontyperange_result)
+ {
+ /* If no input polymorphics, parser messed up */
+ if (!OidIsValid(commontype_type) && !OidIsValid(commontypearray_type) &&
+ !OidIsValid(commontyperange_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_anyrange_result && !OidIsValid(anyrange_type))
- return false;
+ if (have_commontype_result && !OidIsValid(commontype_type))
+ {
+ if (OidIsValid(commontypearray_type))
+ {
+ commontype_type = resolve_generic_type(COMMONTYPEOID,
+ commontypearray_type,
+ COMMONTYPEARRAYOID);
+
+ if (OidIsValid(commontyperange_type))
+ {
+ Oid subtype = resolve_generic_type(COMMONTYPEOID,
+ anyrange_type,
+ COMMONTYPERANGEOID);
+
+ /* check for inconsistent array and range results */
+ if (OidIsValid(commontype_type) && commontype_type != subtype)
+ return false;
+ commontype_type = subtype;
+ }
+ }
+ }
- /* XXX do we need to enforce ANYNONARRAY or ANYENUM here? I think not */
+ if (have_commontypearray_result || !OidIsValid(commontypearray_type))
+ commontypearray_type = resolve_generic_type(COMMONTYPEARRAYOID,
+ commontype_type,
+ COMMONTYPEOID);
+
+ /*
+ * We can't deduce a range type from other polymorphic inputs, because
+ * there may be multiple range types for the same subtype.
+ */
+ if (have_commontyperange_result && !OidIsValid(commontyperange_type))
+ return false;
+ }
/* And finally replace the output column types as needed */
for (i = 0; i < numargs; i++)
@@ -760,6 +962,16 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
case ANYRANGEOID:
argtypes[i] = anyrange_type;
break;
+ case COMMONTYPEOID:
+ case COMMONTYPENONARRAYOID:
+ argtypes[i] = commontype_type;
+ break;
+ case COMMONTYPEARRAYOID:
+ argtypes[i] = commontypearray_type;
+ break;
+ case COMMONTYPERANGEOID:
+ argtypes[i] = commontyperange_type;
+ break;
default:
break;
}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3ecc2e12c3..3579257e03 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6952,6 +6952,12 @@
{ oid => '2778', descr => 'I/O',
proname => 'anynonarray_out', prorettype => 'cstring',
proargtypes => 'anynonarray', prosrc => 'anynonarray_out' },
+{ oid => '4007', descr => 'I/O',
+ proname => 'commontypenonarray_in', prorettype => 'commontypenonarray',
+ proargtypes => 'cstring', prosrc => 'commontypenonarray_in' },
+{ oid => '4008', descr => 'I/O',
+ proname => 'commontypenonarray_out', prorettype => 'cstring',
+ proargtypes => 'commontypenonarray', prosrc => 'commontypenonarray_out' },
{ oid => '3116', descr => 'I/O',
proname => 'fdw_handler_in', proisstrict => 'f', prorettype => 'fdw_handler',
proargtypes => 'cstring', prosrc => 'fdw_handler_in' },
@@ -6971,6 +6977,18 @@
{ oid => '3312', descr => 'I/O',
proname => 'tsm_handler_out', prorettype => 'cstring',
proargtypes => 'tsm_handler', prosrc => 'tsm_handler_out' },
+{ oid => '4001', descr => 'I/O',
+ proname => 'commontype_in', prorettype => 'commontype',
+ proargtypes => 'cstring', prosrc => 'commontype_in' },
+{ oid => '4002', descr => 'I/O',
+ proname => 'commontype_out', prorettype => 'cstring',
+ proargtypes => 'commontype', prosrc => 'commontype_out' },
+{ oid => '4003', descr => 'I/O',
+ proname => 'commontypearray_in', prorettype => 'commontypearray',
+ proargtypes => 'cstring', prosrc => 'commontypearray_in' },
+{ oid => '4004', descr => 'I/O',
+ proname => 'commontypearray_out', prorettype => 'cstring',
+ proargtypes => 'commontypearray', prosrc => 'commontypearray_out' },
# tablesample method handlers
{ oid => '3313', descr => 'BERNOULLI tablesample method handler',
@@ -7468,6 +7486,12 @@
{ oid => '3447', descr => 'I/O',
proname => 'macaddr8_send', prorettype => 'bytea', proargtypes => 'macaddr8',
prosrc => 'macaddr8_send' },
+{ oid => '2462', descr => 'I/O',
+ proname => 'commontypearray_recv', provolatile => 's', prorettype => 'commontypearray',
+ proargtypes => 'internal', prosrc => 'commontypearray_recv' },
+{ oid => '2463', descr => 'I/O',
+ proname => 'commontypearray_send', provolatile => 's', prorettype => 'bytea',
+ proargtypes => 'commontypearray', prosrc => 'commontypearray_send' },
# System-view support functions with pretty-print option
{ oid => '2504', descr => 'source text of a rule with pretty-print option',
@@ -9335,6 +9359,12 @@
{ oid => '3833', descr => 'I/O',
proname => 'anyrange_out', provolatile => 's', prorettype => 'cstring',
proargtypes => 'anyrange', prosrc => 'anyrange_out' },
+{ oid => '4005', descr => 'I/O',
+ proname => 'commontyperange_in', provolatile => 's', prorettype => 'commontyperange',
+ proargtypes => 'cstring oid int4', prosrc => 'commontyperange_in' },
+{ oid => '4006', descr => 'I/O',
+ proname => 'commontyperange_out', provolatile => 's', prorettype => 'cstring',
+ proargtypes => 'commontyperange', prosrc => 'commontyperange_out' },
{ oid => '3834', descr => 'I/O',
proname => 'range_in', provolatile => 's', prorettype => 'anyrange',
proargtypes => 'cstring oid int4', prosrc => 'range_in' },
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 4b7750d439..3a77a67981 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -585,5 +585,25 @@
typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p',
typcategory => 'P', typinput => 'anyrange_in', typoutput => 'anyrange_out',
typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' },
-
+{ oid => '3996', descr => 'pseudo-type representing a polymorphic common type',
+ typname => 'commontype', typlen => '4', typbyval => 't', typtype => 'p',
+ typcategory => 'P', typinput => 'commontype_in',
+ typoutput => 'commontype_out', typreceive => '-', typsend => '-',
+ typalign => 'i' },
+{ oid => '3998', descr => 'pseudo-type representing a polymorphic array type of common type elements',
+ typname => 'commontypearray', typlen => '-1', typbyval => 'f', typtype => 'p',
+ typcategory => 'P', typinput => 'commontypearray_in', typoutput => 'commontypearray_out',
+ typreceive => 'commontypearray_recv', typsend => 'commontypearray_send', typalign => 'd',
+ typstorage => 'x' },
+{ oid => '4072',
+ descr => 'pseudo-type representing a polymorphic common type that is not an array',
+ typname => 'commontypenonarray', typlen => '4', typbyval => 't', typtype => 'p',
+ typcategory => 'P', typinput => 'commontypenonarray_in',
+ typoutput => 'commontypenonarray_out', typreceive => '-', typsend => '-',
+ typalign => 'i' },
+{ oid => '4073',
+ descr => 'pseudo-type representing a polymorphic common type that is a range',
+ typname => 'commontyperange', typlen => '-1', typbyval => 'f', typtype => 'p',
+ typcategory => 'P', typinput => 'commontyperange_in', typoutput => 'commontyperange_out',
+ typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' }
]
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 24d114b575..8b3580e699 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -280,13 +280,23 @@ typedef FormData_pg_type *Form_pg_type;
#define TYPCATEGORY_UNKNOWN 'X'
/* Is a type OID a polymorphic pseudotype? (Beware of multiple evaluation) */
-#define IsPolymorphicType(typid) \
+#define IsPolymorphicTypeAny(typid) \
((typid) == ANYELEMENTOID || \
(typid) == ANYARRAYOID || \
(typid) == ANYNONARRAYOID || \
(typid) == ANYENUMOID || \
(typid) == ANYRANGEOID)
+#define IsPolymorphicTypeCommon(typid) \
+ ((typid) == COMMONTYPEOID || \
+ (typid) == COMMONTYPEARRAYOID || \
+ (typid) == COMMONTYPENONARRAYOID || \
+ (typid) == COMMONTYPERANGEOID)
+
+#define IsPolymorphicType(typid) \
+ (IsPolymorphicTypeAny(typid) || \
+ IsPolymorphicTypeCommon(typid))
+
#endif /* EXPOSE_TO_CLIENT_CODE */
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 3b8e137ab5..15c7a61368 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -507,11 +507,11 @@ do_compile(FunctionCallInfo fcinfo,
{
if (forValidator)
{
- if (rettypeid == ANYARRAYOID)
+ if (rettypeid == ANYARRAYOID || rettypeid == COMMONTYPEARRAYOID)
rettypeid = INT4ARRAYOID;
else if (rettypeid == ANYRANGEOID)
rettypeid = INT4RANGEOID;
- else /* ANYELEMENT or ANYNONARRAY */
+ else /* ANYELEMENT or ANYNONARRAY or COMMONTYPE */
rettypeid = INT4OID;
/* XXX what could we use for ANYENUM? */
}
@@ -2412,12 +2412,16 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID: /* XXX dubious */
+ case COMMONTYPEOID:
+ case COMMONTYPENONARRAYOID:
argtypes[i] = INT4OID;
break;
case ANYARRAYOID:
+ case COMMONTYPEARRAYOID:
argtypes[i] = INT4ARRAYOID;
break;
case ANYRANGEOID:
+ case COMMONTYPERANGEOID:
argtypes[i] = INT4RANGEOID;
break;
default:
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index 986417a188..1d661915e7 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(commontype, commontype)
+returns commontype as $$
+begin
+ if $1 > $2 then
+ return $1;
+ else
+ return $2;
+ end if;
+end;
+$$ language plpgsql;
+create or replace function cttestfunc02(commontype, commontype)
+returns commontypearray as $$
+begin
+ return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc03(commontypearray)
+returns commontype as $$
+begin
+ return $1[1];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc04(variadic commontypearray)
+returns commontype as $$
+begin
+ return (select min(v) from unnest($1) g(v));
+end;
+$$ language plpgsql;
+create or replace function cttestfunc05(variadic commontypearray)
+returns commontypearray as $$
+begin
+ return $1;
+end;
+$$ language plpgsql;
+create or replace function cttestfunc06(commontypenonarray, commontypenonarray)
+returns commontypearray as $$
+begin
+ return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+create or replace function cttestfunc07(variadic commontypearray)
+returns commontypearray as $$
+ select $1
+$$ language sql;
+create or replace function cttestfunc08(commontypenonarray, commontypenonarray)
+returns commontypearray 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 03606671d9..ea1a810f40 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(commontype, commontype)
+returns commontype as $$
+begin
+ if $1 > $2 then
+ return $1;
+ else
+ return $2;
+ end if;
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc02(commontype, commontype)
+returns commontypearray as $$
+begin
+ return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc03(commontypearray)
+returns commontype as $$
+begin
+ return $1[1];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc04(variadic commontypearray)
+returns commontype as $$
+begin
+ return (select min(v) from unnest($1) g(v));
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc05(variadic commontypearray)
+returns commontypearray as $$
+begin
+ return $1;
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc06(commontypenonarray, commontypenonarray)
+returns commontypearray as $$
+begin
+ return ARRAY[$1, $2];
+end;
+$$ language plpgsql;
+
+create or replace function cttestfunc07(variadic commontypearray)
+returns commontypearray as $$
+ select $1
+$$ language sql;
+
+create or replace function cttestfunc08(commontypenonarray, commontypenonarray)
+returns commontypearray 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]);