Commit b7ea0e8c authored by Tom Lane's avatar Tom Lane

Fix bugs in polymorphic-argument resolution for multiranges.

We failed to deal with an UNKNOWN-type input for
anycompatiblemultirange; that should throw an error indicating
that we don't know how to resolve the multirange type.

We also failed to infer the type of an anycompatiblerange output
from an anycompatiblemultirange input or vice versa.

Per bug #17066 from Alexander Lakhin.  Back-patch to v14
where multiranges were added.

Discussion: https://postgr.es/m/17066-16a37f6223a8470b@postgresql.org
parent fd90f6ba
...@@ -1579,8 +1579,10 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) ...@@ -1579,8 +1579,10 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
* 1) All arguments declared ANYELEMENT must have the same datatype. * 1) All arguments declared ANYELEMENT must have the same datatype.
* 2) All arguments declared ANYARRAY must have the same datatype, * 2) All arguments declared ANYARRAY must have the same datatype,
* which must be a varlena array type. * which must be a varlena array type.
* 3) All arguments declared ANYRANGE or ANYMULTIRANGE must be a range or * 3) All arguments declared ANYRANGE must be the same range type.
* multirange type, all derived from the same base datatype. * Similarly, all arguments declared ANYMULTIRANGE must be the same
* multirange type; and if both of these appear, the ANYRANGE type
* must be the element type of the ANYMULTIRANGE type.
* 4) If there are arguments of more than one of these polymorphic types, * 4) If there are arguments of more than one of these polymorphic types,
* the array element type and/or range subtype must be the same as each * the array element type and/or range subtype must be the same as each
* other and the same as the ANYELEMENT type. * other and the same as the ANYELEMENT type.
...@@ -1605,9 +1607,11 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) ...@@ -1605,9 +1607,11 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
* let us choose one over another. Furthermore, that range's subtype * let us choose one over another. Furthermore, that range's subtype
* must exactly match the common supertype chosen by rule 7. * must exactly match the common supertype chosen by rule 7.
* 10) All ANYCOMPATIBLEMULTIRANGE arguments must be the exact same multirange * 10) All ANYCOMPATIBLEMULTIRANGE arguments must be the exact same multirange
* type (after domain flattening), since we have no preference rule that would * type (after domain flattening), since we have no preference rule that
* let us choose one over another. Furthermore, that multirange's range's * would let us choose one over another. Furthermore, if ANYCOMPATIBLERANGE
* subtype must exactly match the common supertype chosen by rule 7. * also appears, that range type must be the multirange's element type;
* otherwise, the multirange's range's subtype must exactly match the
* common supertype chosen by rule 7.
* *
* Domains over arrays match ANYARRAY, and are immediately flattened to their * 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 * base type. (Thus, for example, we will consider it a match if one ANYARRAY
...@@ -1616,9 +1620,9 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) ...@@ -1616,9 +1620,9 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
* for ANYCOMPATIBLEARRAY and ANYCOMPATIBLENONARRAY. * for ANYCOMPATIBLEARRAY and ANYCOMPATIBLENONARRAY.
* *
* Similarly, domains over ranges match ANYRANGE or ANYCOMPATIBLERANGE, * Similarly, domains over ranges match ANYRANGE or ANYCOMPATIBLERANGE,
* and are immediately flattened to their base type, and domains over * and are immediately flattened to their base type. Likewise, domains
* multiranges match ANYMULTIRANGE or ANYCOMPATIBLEMULTIRANGE and are immediately * over multiranges match ANYMULTIRANGE or ANYCOMPATIBLEMULTIRANGE and are
* flattened to their base type. * immediately flattened to their base type.
* *
* Note that domains aren't currently considered to match ANYENUM, * Note that domains aren't currently considered to match ANYENUM,
* even if their base type would match. * even if their base type would match.
...@@ -1760,26 +1764,7 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1760,26 +1764,7 @@ check_generic_type_consistency(const Oid *actual_arg_types,
anycompatible_multirange_typelem = get_multirange_range(actual_type); anycompatible_multirange_typelem = get_multirange_range(actual_type);
if (!OidIsValid(anycompatible_multirange_typelem)) if (!OidIsValid(anycompatible_multirange_typelem))
return false; /* not a multirange type */ return false; /* not a multirange type */
/* we'll consider the subtype below */
if (OidIsValid(anycompatible_range_typeid))
{
/*
* ANYCOMPATIBLEMULTIRANGE and ANYCOMPATIBLERANGE
* arguments must match
*/
if (anycompatible_range_typeid != anycompatible_multirange_typelem)
return false;
}
else
{
anycompatible_range_typeid = anycompatible_multirange_typelem;
anycompatible_range_typelem = get_range_subtype(anycompatible_range_typeid);
if (!OidIsValid(anycompatible_range_typelem))
return false; /* not a range type */
}
/* collect the subtype for common-supertype choice */
anycompatible_actual_types[n_anycompatible_args++] =
anycompatible_range_typelem;
} }
} }
} }
...@@ -1825,28 +1810,7 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1825,28 +1810,7 @@ check_generic_type_consistency(const Oid *actual_arg_types,
} }
} }
/* Get the element type based on the range type, if we have one */ /* Deduce range type from multirange type, or check that they agree */
if (OidIsValid(range_typeid))
{
range_typelem = get_range_subtype(range_typeid);
if (!OidIsValid(range_typelem))
return false; /* should be a range, but isn't */
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 */
return false;
}
}
/* Get the element type based on the multirange type, if we have one */
if (OidIsValid(multirange_typeid)) if (OidIsValid(multirange_typeid))
{ {
Oid multirange_typelem; Oid multirange_typelem;
...@@ -1857,9 +1821,7 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1857,9 +1821,7 @@ check_generic_type_consistency(const Oid *actual_arg_types,
if (!OidIsValid(range_typeid)) if (!OidIsValid(range_typeid))
{ {
/* /* If we don't have a range type yet, use the one we just got */
* If we don't have a range type yet, use the one we just got
*/
range_typeid = multirange_typelem; range_typeid = multirange_typelem;
range_typelem = get_range_subtype(multirange_typelem); range_typelem = get_range_subtype(multirange_typelem);
if (!OidIsValid(range_typelem)) if (!OidIsValid(range_typelem))
...@@ -1870,6 +1832,14 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1870,6 +1832,14 @@ check_generic_type_consistency(const Oid *actual_arg_types,
/* otherwise, they better match */ /* otherwise, they better match */
return false; return false;
} }
}
/* 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))
return false; /* should be a range, but isn't */
if (!OidIsValid(elem_typeid)) if (!OidIsValid(elem_typeid))
{ {
...@@ -1899,6 +1869,27 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1899,6 +1869,27 @@ check_generic_type_consistency(const Oid *actual_arg_types,
return false; return false;
} }
/* Deduce range type from multirange type, or check that they agree */
if (OidIsValid(anycompatible_multirange_typeid))
{
if (OidIsValid(anycompatible_range_typeid))
{
if (anycompatible_multirange_typelem !=
anycompatible_range_typeid)
return false;
}
else
{
anycompatible_range_typeid = anycompatible_multirange_typelem;
anycompatible_range_typelem = get_range_subtype(anycompatible_range_typeid);
if (!OidIsValid(anycompatible_range_typelem))
return false; /* not a range type */
/* collect the subtype for common-supertype choice */
anycompatible_actual_types[n_anycompatible_args++] =
anycompatible_range_typelem;
}
}
/* Check matching of ANYCOMPATIBLE-family arguments, if any */ /* Check matching of ANYCOMPATIBLE-family arguments, if any */
if (n_anycompatible_args > 0) if (n_anycompatible_args > 0)
{ {
...@@ -1966,39 +1957,41 @@ check_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1966,39 +1957,41 @@ check_generic_type_consistency(const Oid *actual_arg_types,
* 2) If return type is ANYARRAY, and any argument is ANYARRAY, use the * 2) If return type is ANYARRAY, and any argument is ANYARRAY, use the
* argument's actual type as the function's return type. * argument's actual type as the function's return type.
* 3) Similarly, if return type is ANYRANGE or ANYMULTIRANGE, and any * 3) Similarly, if return type is ANYRANGE or ANYMULTIRANGE, and any
* argument is ANYRANGE or ANYMULTIRANGE, use that argument's * argument is ANYRANGE or ANYMULTIRANGE, use that argument's actual type
* actual type, range type or multirange type as the function's return * (or the corresponding range or multirange type) as the function's return
* type. * type.
* 4) Otherwise, if return type is ANYMULTIRANGE, and any argument is * 4) Otherwise, if return type is ANYELEMENT or ANYARRAY, and there is
* ANYMULTIRANGE, use the argument's actual type as the function's return * at least one ANYELEMENT, ANYARRAY, ANYRANGE, or ANYMULTIRANGE input,
* type. Or if any argument is ANYRANGE, use its multirange type as the * deduce the return type from those inputs, or throw error if we can't.
* function's return type. * 5) Otherwise, if return type is ANYRANGE or ANYMULTIRANGE, throw error.
* 5) Otherwise, if return type is ANYELEMENT or ANYARRAY, and there is
* at least one ANYELEMENT, ANYARRAY, or ANYRANGE input, deduce the
* return type from those inputs, or throw error if we can't.
* 6) Otherwise, if return type is ANYRANGE or ANYMULTIRANGE, throw error.
* (We have no way to select a specific range type if the arguments don't * (We have no way to select a specific range type if the arguments don't
* include ANYRANGE.) * include ANYRANGE or ANYMULTIRANGE.)
* 6) ANYENUM is treated the same as ANYELEMENT except that if it is used
* (alone or in combination with plain ANYELEMENT), we add the extra * (alone or in combination with plain ANYELEMENT), we add the extra
* condition that the ANYELEMENT type must be an enum. * condition that the ANYELEMENT type must be an enum.
* 8) ANYNONARRAY is treated the same as ANYELEMENT except that if it is used, * 7) ANYNONARRAY is treated the same as ANYELEMENT except that if it is used,
* we add the extra condition that the ANYELEMENT type must not be an array. * 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 * (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
* is an extra restriction if not.) * is an extra restriction if not.)
* 9) ANYCOMPATIBLE, ANYCOMPATIBLEARRAY, ANYCOMPATIBLENONARRAY, and * 8) ANYCOMPATIBLE, ANYCOMPATIBLEARRAY, and ANYCOMPATIBLENONARRAY are handled
* ANYCOMPATIBLERANGE are handled by resolving the common supertype * by resolving the common supertype of those arguments (or their element
* of those arguments (or their element types/subtypes, for array and range * types, for array inputs), and then coercing all those arguments to the
* inputs), and then coercing all those arguments to the common supertype, * common supertype, or the array type over the common supertype for
* or the array type over the common supertype for ANYCOMPATIBLEARRAY. * ANYCOMPATIBLEARRAY.
* For ANYCOMPATIBLERANGE, there must be at least one non-UNKNOWN input, * 9) For ANYCOMPATIBLERANGE and ANYCOMPATIBLEMULTIRANGE, there must be at
* all such inputs must be the same range type, and that type's subtype * least one non-UNKNOWN input matching those arguments, and all such
* must equal the common supertype. * inputs must be the same range type (or its multirange type, as
* appropriate), since we cannot deduce a range type from non-range types.
* Furthermore, the range type's subtype is included while choosing the
* common supertype for ANYCOMPATIBLE et al, and it must exactly match
* that common supertype.
* *
* Domains over arrays or ranges match ANYARRAY or ANYRANGE arguments, * Domains over arrays or ranges match ANYARRAY or ANYRANGE arguments,
* respectively, and are immediately flattened to their base type. (In * respectively, and are immediately flattened to their base type. (In
* particular, if the return type is also ANYARRAY or ANYRANGE, we'll set * particular, if the return type is also ANYARRAY or ANYRANGE, we'll set
* it to the base type not the domain type.) The same is true for * it to the base type not the domain type.) The same is true for
* ANYCOMPATIBLEARRAY and ANYCOMPATIBLERANGE. * ANYMULTIRANGE, ANYCOMPATIBLEARRAY, ANYCOMPATIBLERANGE, and
* ANYCOMPATIBLEMULTIRANGE.
* *
* When allow_poly is false, we are not expecting any of the actual_arg_types * When allow_poly is false, we are not expecting any of the actual_arg_types
* to be polymorphic, and we should not return a polymorphic result type * to be polymorphic, and we should not return a polymorphic result type
...@@ -2046,13 +2039,13 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2046,13 +2039,13 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
Oid anycompatible_range_typelem = InvalidOid; Oid anycompatible_range_typelem = InvalidOid;
Oid anycompatible_multirange_typeid = InvalidOid; Oid anycompatible_multirange_typeid = InvalidOid;
Oid anycompatible_multirange_typelem = InvalidOid; Oid anycompatible_multirange_typelem = InvalidOid;
Oid range_typelem;
Oid multirange_typelem;
bool have_anynonarray = (rettype == ANYNONARRAYOID); bool have_anynonarray = (rettype == ANYNONARRAYOID);
bool have_anyenum = (rettype == ANYENUMOID); bool have_anyenum = (rettype == ANYENUMOID);
bool have_anymultirange = (rettype == ANYMULTIRANGEOID);
bool have_anycompatible_nonarray = (rettype == ANYCOMPATIBLENONARRAYOID); bool have_anycompatible_nonarray = (rettype == ANYCOMPATIBLENONARRAYOID);
bool have_anycompatible_array = (rettype == ANYCOMPATIBLEARRAYOID); bool have_anycompatible_array = (rettype == ANYCOMPATIBLEARRAYOID);
bool have_anycompatible_range = (rettype == ANYCOMPATIBLERANGEOID); bool have_anycompatible_range = (rettype == ANYCOMPATIBLERANGEOID);
bool have_anycompatible_multirange = (rettype == ANYCOMPATIBLEMULTIRANGEOID);
int n_poly_args = 0; /* this counts all family-1 arguments */ int n_poly_args = 0; /* this counts all family-1 arguments */
int n_anycompatible_args = 0; /* this counts only non-unknowns */ int n_anycompatible_args = 0; /* this counts only non-unknowns */
Oid anycompatible_actual_types[FUNC_MAX_ARGS]; Oid anycompatible_actual_types[FUNC_MAX_ARGS];
...@@ -2135,6 +2128,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2135,6 +2128,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
else if (decl_type == ANYMULTIRANGEOID) else if (decl_type == ANYMULTIRANGEOID)
{ {
n_poly_args++; n_poly_args++;
have_anymultirange = true;
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
{ {
have_poly_unknowns = true; have_poly_unknowns = true;
...@@ -2223,6 +2217,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2223,6 +2217,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
else if (decl_type == ANYCOMPATIBLEMULTIRANGEOID) else if (decl_type == ANYCOMPATIBLEMULTIRANGEOID)
{ {
have_poly_anycompatible = true; have_poly_anycompatible = true;
have_anycompatible_multirange = true;
if (actual_type == UNKNOWNOID) if (actual_type == UNKNOWNOID)
continue; continue;
if (allow_poly && decl_type == actual_type) if (allow_poly && decl_type == actual_type)
...@@ -2243,15 +2238,13 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2243,15 +2238,13 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
{ {
anycompatible_multirange_typeid = actual_type; anycompatible_multirange_typeid = actual_type;
anycompatible_multirange_typelem = get_multirange_range(actual_type); anycompatible_multirange_typelem = get_multirange_range(actual_type);
anycompatible_range_typelem = get_range_subtype(anycompatible_multirange_typelem);
if (!OidIsValid(anycompatible_multirange_typelem)) if (!OidIsValid(anycompatible_multirange_typelem))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not a multirange type but type %s", errmsg("argument declared %s is not a multirange type but type %s",
"anycompatiblemultirange", "anycompatiblemultirange",
format_type_be(actual_type)))); format_type_be(actual_type))));
/* collect the subtype for common-supertype choice */ /* we'll consider the subtype below */
anycompatible_actual_types[n_anycompatible_args++] = anycompatible_range_typelem;
} }
} }
} }
...@@ -2319,43 +2312,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2319,43 +2312,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
} }
} }
/* Get the element type based on the range type, if we have one */ /* Deduce range type from multirange type, or vice versa */
if (OidIsValid(range_typeid))
{
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 consistent with argument declared %s",
"anyrange", "anyelement"),
errdetail("%s versus %s",
format_type_be(range_typeid),
format_type_be(elem_typeid))));
}
}
else
range_typelem = InvalidOid;
/* Get the element type based on the multirange type, if we have one */
if (OidIsValid(multirange_typeid)) if (OidIsValid(multirange_typeid))
{ {
Oid multirange_typelem;
multirange_typelem = get_multirange_range(multirange_typeid); multirange_typelem = get_multirange_range(multirange_typeid);
if (!OidIsValid(multirange_typelem)) if (!OidIsValid(multirange_typelem))
ereport(ERROR, ereport(ERROR,
...@@ -2366,11 +2327,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2366,11 +2327,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
if (!OidIsValid(range_typeid)) if (!OidIsValid(range_typeid))
{ {
/* /* if we don't have a range type yet, use the one we just got */
* If we don't have a range type yet, use the one we just got
*/
range_typeid = multirange_typelem; range_typeid = multirange_typelem;
range_typelem = get_range_subtype(range_typeid);
} }
else if (multirange_typelem != range_typeid) else if (multirange_typelem != range_typeid)
{ {
...@@ -2383,6 +2341,25 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2383,6 +2341,25 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
format_type_be(multirange_typeid), format_type_be(multirange_typeid),
format_type_be(range_typeid)))); format_type_be(range_typeid))));
} }
}
else if (have_anymultirange && OidIsValid(range_typeid))
{
multirange_typeid = get_range_multirange(range_typeid);
/* We'll complain below if that didn't work */
}
/* Get the element type based on the range type, if we have one */
if (OidIsValid(range_typeid))
{
Oid range_typelem;
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 (!OidIsValid(elem_typeid))
{ {
...@@ -2398,14 +2375,12 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2398,14 +2375,12 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not consistent with argument declared %s", errmsg("argument declared %s is not consistent with argument declared %s",
"anymultirange", "anyelement"), "anyrange", "anyelement"),
errdetail("%s versus %s", errdetail("%s versus %s",
format_type_be(multirange_typeid), format_type_be(range_typeid),
format_type_be(elem_typeid)))); format_type_be(elem_typeid))));
} }
} }
else
multirange_typelem = InvalidOid;
if (!OidIsValid(elem_typeid)) if (!OidIsValid(elem_typeid))
{ {
...@@ -2456,6 +2431,46 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2456,6 +2431,46 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
/* Check matching of family-2 polymorphic arguments, if any */ /* Check matching of family-2 polymorphic arguments, if any */
if (have_poly_anycompatible) if (have_poly_anycompatible)
{ {
/* Deduce range type from multirange type, or vice versa */
if (OidIsValid(anycompatible_multirange_typeid))
{
if (OidIsValid(anycompatible_range_typeid))
{
if (anycompatible_multirange_typelem !=
anycompatible_range_typeid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not consistent with argument declared %s",
"anycompatiblemultirange",
"anycompatiblerange"),
errdetail("%s versus %s",
format_type_be(anycompatible_multirange_typeid),
format_type_be(anycompatible_range_typeid))));
}
else
{
anycompatible_range_typeid = anycompatible_multirange_typelem;
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 multirange type but type %s",
"anycompatiblemultirange",
format_type_be(anycompatible_multirange_typeid))));
/* this enables element type matching check below */
have_anycompatible_range = true;
/* collect the subtype for common-supertype choice */
anycompatible_actual_types[n_anycompatible_args++] =
anycompatible_range_typelem;
}
}
else if (have_anycompatible_multirange &&
OidIsValid(anycompatible_range_typeid))
{
anycompatible_multirange_typeid = get_range_multirange(anycompatible_range_typeid);
/* We'll complain below if that didn't work */
}
if (n_anycompatible_args > 0) if (n_anycompatible_args > 0)
{ {
anycompatible_typeid = anycompatible_typeid =
...@@ -2494,6 +2509,27 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2494,6 +2509,27 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
format_type_be(anycompatible_typeid)))); format_type_be(anycompatible_typeid))));
} }
if (have_anycompatible_multirange)
{
/* we can't infer a multirange type from the others */
if (!OidIsValid(anycompatible_multirange_typeid))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not determine polymorphic type %s because input has type %s",
"anycompatiblemultirange", "unknown")));
/*
* the anycompatible type must exactly match the multirange
* element type
*/
if (anycompatible_range_typelem != anycompatible_typeid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("anycompatiblemultirange type %s does not match anycompatible type %s",
format_type_be(anycompatible_multirange_typeid),
format_type_be(anycompatible_typeid))));
}
if (have_anycompatible_nonarray) if (have_anycompatible_nonarray)
{ {
/* /*
...@@ -2522,7 +2558,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2522,7 +2558,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
* Only way to get here is if all the family-2 polymorphic * Only way to get here is if all the family-2 polymorphic
* arguments have UNKNOWN inputs. Resolve to TEXT as * arguments have UNKNOWN inputs. Resolve to TEXT as
* select_common_type() would do. That doesn't license us to * select_common_type() would do. That doesn't license us to
* use TEXTRANGE, though. * use TEXTRANGE or TEXTMULTIRANGE, though.
*/ */
anycompatible_typeid = TEXTOID; anycompatible_typeid = TEXTOID;
anycompatible_array_typeid = TEXTARRAYOID; anycompatible_array_typeid = TEXTARRAYOID;
...@@ -2531,6 +2567,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2531,6 +2567,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not determine polymorphic type %s because input has type %s", errmsg("could not determine polymorphic type %s because input has type %s",
"anycompatiblerange", "unknown"))); "anycompatiblerange", "unknown")));
if (have_anycompatible_multirange)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not determine polymorphic type %s because input has type %s",
"anycompatiblemultirange", "unknown")));
} }
} }
...@@ -2602,10 +2643,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2602,10 +2643,11 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
{ {
if (!OidIsValid(multirange_typeid)) if (!OidIsValid(multirange_typeid))
{ {
/* we can't infer a multirange type from the others */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not find multirange type for data type %s", errmsg("could not determine polymorphic type %s because input has type %s",
format_type_be(elem_typeid)))); "anymultirange", "unknown")));
} }
declared_arg_types[j] = multirange_typeid; declared_arg_types[j] = multirange_typeid;
} }
...@@ -2640,7 +2682,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2640,7 +2682,7 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
if (!OidIsValid(range_typeid)) if (!OidIsValid(range_typeid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not determine polymorphic type %s because input has type %s", errmsg_internal("could not determine polymorphic type %s because input has type %s",
"anyrange", "unknown"))); "anyrange", "unknown")));
return range_typeid; return range_typeid;
} }
...@@ -2648,16 +2690,12 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -2648,16 +2690,12 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
/* if we return ANYMULTIRANGE use the appropriate argument type */ /* if we return ANYMULTIRANGE use the appropriate argument type */
if (rettype == ANYMULTIRANGEOID) if (rettype == ANYMULTIRANGEOID)
{ {
/* this error is unreachable if the function signature is valid: */
if (!OidIsValid(multirange_typeid)) if (!OidIsValid(multirange_typeid))
{
if (OidIsValid(range_typeid))
multirange_typeid = get_range_multirange(range_typeid);
else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not find multirange type for data type %s", errmsg_internal("could not determine polymorphic type %s because input has type %s",
format_type_be(elem_typeid)))); "anymultirange", "unknown")));
}
return multirange_typeid; return multirange_typeid;
} }
...@@ -2777,7 +2815,7 @@ check_valid_polymorphic_signature(Oid ret_type, ...@@ -2777,7 +2815,7 @@ check_valid_polymorphic_signature(Oid ret_type,
return NULL; /* OK */ return NULL; /* OK */
} }
/* Keep this list in sync with IsPolymorphicTypeFamily2! */ /* Keep this list in sync with IsPolymorphicTypeFamily2! */
return psprintf(_("A result of type %s requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, or anycompatiblerange."), return psprintf(_("A result of type %s requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, anycompatiblerange, or anycompatiblemultirange."),
format_type_be(ret_type)); format_type_be(ret_type));
} }
else else
...@@ -2917,7 +2955,7 @@ IsBinaryCoercible(Oid srctype, Oid targettype) ...@@ -2917,7 +2955,7 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
if (type_is_range(srctype)) if (type_is_range(srctype))
return true; return true;
/* Also accept any multirange type as coercible to ANMULTIYRANGE */ /* Also, any multirange type is coercible to ANY[COMPATIBLE]MULTIRANGE */
if (targettype == ANYMULTIRANGEOID || targettype == ANYCOMPATIBLEMULTIRANGEOID) if (targettype == ANYMULTIRANGEOID || targettype == ANYCOMPATIBLEMULTIRANGEOID)
if (type_is_multirange(srctype)) if (type_is_multirange(srctype))
return true; return true;
......
...@@ -179,6 +179,72 @@ LINE 2: from polyf(11, array[1, 2.2], 42, 34.5); ...@@ -179,6 +179,72 @@ LINE 2: from polyf(11, array[1, 2.2], 42, 34.5);
HINT: No function matches the given name and argument types. You might need to add explicit type casts. HINT: No function matches the given name and argument types. You might need to add explicit type casts.
drop function polyf(a anyelement, b anyarray, drop function polyf(a anyelement, b anyarray,
c anycompatible, d anycompatible); c anycompatible, d anycompatible);
create function polyf(anyrange) returns anymultirange
as 'select multirange($1);' language sql;
select polyf(int4range(1,10));
polyf
----------
{[1,10)}
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type because input has type unknown
drop function polyf(anyrange);
create function polyf(anymultirange) returns anyelement
as 'select lower($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
polyf
-------
1
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type because input has type unknown
drop function polyf(anymultirange);
create function polyf(anycompatiblerange) returns anycompatiblemultirange
as 'select multirange($1);' language sql;
select polyf(int4range(1,10));
polyf
----------
{[1,10)}
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
drop function polyf(anycompatiblerange);
create function polyf(anymultirange) returns anyrange
as 'select range_merge($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
polyf
--------
[1,30)
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type because input has type unknown
drop function polyf(anymultirange);
create function polyf(anycompatiblemultirange) returns anycompatiblerange
as 'select range_merge($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
polyf
--------
[1,30)
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type anycompatiblerange because input has type unknown
drop function polyf(anycompatiblemultirange);
create function polyf(anycompatiblemultirange) returns anycompatible
as 'select lower($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
polyf
-------
1
(1 row)
select polyf(null);
ERROR: could not determine polymorphic type anycompatiblemultirange because input has type unknown
drop function polyf(anycompatiblemultirange);
-- --
-- Polymorphic aggregate tests -- Polymorphic aggregate tests
-- --
...@@ -1914,7 +1980,7 @@ LINE 1: select x, pg_typeof(x) from anyctest(11.2, multirange(int4ra... ...@@ -1914,7 +1980,7 @@ LINE 1: select x, pg_typeof(x) from anyctest(11.2, multirange(int4ra...
^ ^
HINT: No function matches the given name and argument types. You might need to add explicit type casts. HINT: No function matches the given name and argument types. You might need to add explicit type casts.
select x, pg_typeof(x) from anyctest(11.2, '{[4,7)}') x; -- fail select x, pg_typeof(x) from anyctest(11.2, '{[4,7)}') x; -- fail
ERROR: could not identify anycompatiblemultirange type ERROR: could not determine polymorphic type anycompatiblemultirange because input has type unknown
drop function anyctest(anycompatible, anycompatiblemultirange); drop function anyctest(anycompatible, anycompatiblemultirange);
create function anyctest(anycompatiblemultirange, anycompatiblemultirange) create function anyctest(anycompatiblemultirange, anycompatiblemultirange)
returns anycompatible as $$ returns anycompatible as $$
......
...@@ -1609,7 +1609,7 @@ DROP FUNCTION dup(f1 anycompatiblerange); ...@@ -1609,7 +1609,7 @@ DROP FUNCTION dup(f1 anycompatiblerange);
CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray) CREATE FUNCTION bad (f1 anyarray, out f2 anycompatible, out f3 anycompatiblearray)
AS 'select $1, array[$1,$1]' LANGUAGE sql; AS 'select $1, array[$1,$1]' LANGUAGE sql;
ERROR: cannot determine result data type ERROR: cannot determine result data type
DETAIL: A result of type anycompatible requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, or anycompatiblerange. DETAIL: A result of type anycompatible requires at least one input of type anycompatible, anycompatiblearray, anycompatiblenonarray, anycompatiblerange, or anycompatiblemultirange.
-- --
-- table functions -- table functions
-- --
......
...@@ -126,6 +126,54 @@ select x, pg_typeof(x), y, pg_typeof(y) ...@@ -126,6 +126,54 @@ select x, pg_typeof(x), y, pg_typeof(y)
drop function polyf(a anyelement, b anyarray, drop function polyf(a anyelement, b anyarray,
c anycompatible, d anycompatible); c anycompatible, d anycompatible);
create function polyf(anyrange) returns anymultirange
as 'select multirange($1);' language sql;
select polyf(int4range(1,10));
select polyf(null);
drop function polyf(anyrange);
create function polyf(anymultirange) returns anyelement
as 'select lower($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
select polyf(null);
drop function polyf(anymultirange);
create function polyf(anycompatiblerange) returns anycompatiblemultirange
as 'select multirange($1);' language sql;
select polyf(int4range(1,10));
select polyf(null);
drop function polyf(anycompatiblerange);
create function polyf(anymultirange) returns anyrange
as 'select range_merge($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
select polyf(null);
drop function polyf(anymultirange);
create function polyf(anycompatiblemultirange) returns anycompatiblerange
as 'select range_merge($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
select polyf(null);
drop function polyf(anycompatiblemultirange);
create function polyf(anycompatiblemultirange) returns anycompatible
as 'select lower($1);' language sql;
select polyf(int4multirange(int4range(1,10), int4range(20,30)));
select polyf(null);
drop function polyf(anycompatiblemultirange);
-- --
-- Polymorphic aggregate tests -- Polymorphic aggregate tests
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment