1
0
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:
Tom Lane
2008-01-11 18:39:41 +00:00
parent df62977d00
commit 89c0a87fda
9 changed files with 133 additions and 57 deletions

View File

@ -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))