mirror of
https://github.com/postgres/postgres.git
synced 2025-07-09 22:41:56 +03:00
The original implementation of polymorphic aggregates didn't really get the
checking of argument compatibility right; although the problem is only exposed with multiple-input aggregates in which some arguments are polymorphic and some are not. Per bug #3852 from Sokolov Yura.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.160 2008/01/01 19:45:50 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.161 2008/01/11 18:39:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1255,12 +1255,20 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
* we add the extra condition that the ANYELEMENT type must not be an array.
|
||||
* (This is a no-op if used in combination with ANYARRAY or ANYENUM, but
|
||||
* is an extra restriction if not.)
|
||||
*
|
||||
* 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
|
||||
* either. When allow_poly is true, it is okay to have polymorphic "actual"
|
||||
* arg types, and we can return ANYARRAY or ANYELEMENT as the result. (This
|
||||
* case is currently used only to check compatibility of an aggregate's
|
||||
* declaration with the underlying transfn.)
|
||||
*/
|
||||
Oid
|
||||
enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
Oid *declared_arg_types,
|
||||
int nargs,
|
||||
Oid rettype)
|
||||
Oid rettype,
|
||||
bool allow_poly)
|
||||
{
|
||||
int j;
|
||||
bool have_generics = false;
|
||||
@ -1268,9 +1276,6 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
Oid elem_typeid = InvalidOid;
|
||||
Oid array_typeid = InvalidOid;
|
||||
Oid array_typelem;
|
||||
bool have_anyelement = (rettype == ANYELEMENTOID ||
|
||||
rettype == ANYNONARRAYOID ||
|
||||
rettype == ANYENUMOID);
|
||||
bool have_anynonarray = (rettype == ANYNONARRAYOID);
|
||||
bool have_anyenum = (rettype == ANYENUMOID);
|
||||
|
||||
@ -1287,7 +1292,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
decl_type == ANYNONARRAYOID ||
|
||||
decl_type == ANYENUMOID)
|
||||
{
|
||||
have_generics = have_anyelement = true;
|
||||
have_generics = true;
|
||||
if (decl_type == ANYNONARRAYOID)
|
||||
have_anynonarray = true;
|
||||
else if (decl_type == ANYENUMOID)
|
||||
@ -1297,6 +1302,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
have_unknowns = true;
|
||||
continue;
|
||||
}
|
||||
if (allow_poly && decl_type == actual_type)
|
||||
continue; /* no new information here */
|
||||
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
@ -1314,6 +1321,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
have_unknowns = true;
|
||||
continue;
|
||||
}
|
||||
if (allow_poly && decl_type == actual_type)
|
||||
continue; /* no new information here */
|
||||
if (OidIsValid(array_typeid) && actual_type != array_typeid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
@ -1335,20 +1344,12 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
/* Get the element type based on the array type, if we have one */
|
||||
if (OidIsValid(array_typeid))
|
||||
{
|
||||
if (array_typeid == ANYARRAYOID && !have_anyelement)
|
||||
{
|
||||
/* Special case for ANYARRAY input: okay iff no ANYELEMENT */
|
||||
array_typelem = InvalidOid;
|
||||
}
|
||||
else
|
||||
{
|
||||
array_typelem = get_element_type(array_typeid);
|
||||
if (!OidIsValid(array_typelem))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
||||
format_type_be(array_typeid))));
|
||||
}
|
||||
array_typelem = get_element_type(array_typeid);
|
||||
if (!OidIsValid(array_typelem))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("argument declared \"anyarray\" is not an array but type %s",
|
||||
format_type_be(array_typeid))));
|
||||
|
||||
if (!OidIsValid(elem_typeid))
|
||||
{
|
||||
@ -1370,13 +1371,21 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
}
|
||||
else if (!OidIsValid(elem_typeid))
|
||||
{
|
||||
/* 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 \"unknown\"")));
|
||||
if (allow_poly)
|
||||
{
|
||||
array_typeid = ANYARRAYOID;
|
||||
elem_typeid = ANYELEMENTOID;
|
||||
}
|
||||
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 \"unknown\"")));
|
||||
}
|
||||
}
|
||||
|
||||
if (have_anynonarray)
|
||||
if (have_anynonarray && elem_typeid != ANYELEMENTOID)
|
||||
{
|
||||
/* require the element type to not be an array */
|
||||
if (type_is_array(elem_typeid))
|
||||
@ -1386,7 +1395,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
format_type_be(elem_typeid))));
|
||||
}
|
||||
|
||||
if (have_anyenum)
|
||||
if (have_anyenum && elem_typeid != ANYELEMENTOID)
|
||||
{
|
||||
/* require the element type to be an enum */
|
||||
if (!type_is_enum(elem_typeid))
|
||||
|
Reference in New Issue
Block a user