aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_aggregate.c29
-rw-r--r--src/backend/executor/nodeAgg.c5
-rw-r--r--src/backend/optimizer/util/clauses.c5
-rw-r--r--src/backend/parser/parse_coerce.c61
-rw-r--r--src/backend/parser/parse_func.c5
-rw-r--r--src/backend/parser/parse_oper.c8
-rw-r--r--src/include/parser/parse_coerce.h5
-rw-r--r--src/test/regress/expected/polymorphism.out36
-rw-r--r--src/test/regress/sql/polymorphism.sql36
9 files changed, 133 insertions, 57 deletions
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 449a3256ad3..bfdd429b23a 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.89 2008/01/01 19:45:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.90 2008/01/11 18:39:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -296,7 +296,6 @@ lookup_agg_function(List *fnName,
FuncDetailCode fdresult;
AclResult aclresult;
int i;
- bool allPolyArgs = true;
/*
* func_get_detail looks up the function in the catalogs, does
@@ -322,25 +321,15 @@ lookup_agg_function(List *fnName,
func_signature_string(fnName, nargs, input_types))));
/*
- * If the given type(s) are all polymorphic, there's nothing we can check.
- * Otherwise, enforce consistency, and possibly refine the result type.
+ * If there are any polymorphic types involved, enforce consistency, and
+ * possibly refine the result type. It's OK if the result is still
+ * polymorphic at this point, though.
*/
- for (i = 0; i < nargs; i++)
- {
- if (!IsPolymorphicType(input_types[i]))
- {
- allPolyArgs = false;
- break;
- }
- }
-
- if (!allPolyArgs)
- {
- *rettype = enforce_generic_type_consistency(input_types,
- true_oid_array,
- nargs,
- *rettype);
- }
+ *rettype = enforce_generic_type_consistency(input_types,
+ true_oid_array,
+ nargs,
+ *rettype,
+ true);
/*
* func_get_detail will find functions requiring run-time argument type
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 9551e9ddd23..0fac11a5371 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -61,7 +61,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.155 2008/01/01 19:45:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.156 2008/01/11 18:39:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1433,7 +1433,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggtranstype = enforce_generic_type_consistency(inputTypes,
declaredArgTypes,
agg_nargs,
- aggtranstype);
+ aggtranstype,
+ false);
pfree(declaredArgTypes);
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 01f3be3ba34..bee9c7a9dda 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.253 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.254 2008/01/11 18:39:40 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -448,7 +448,8 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
aggtranstype = enforce_generic_type_consistency(inputTypes,
declaredArgTypes,
agg_nargs,
- aggtranstype);
+ aggtranstype,
+ false);
pfree(declaredArgTypes);
}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 388d98b3436..24676404340 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -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))
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index a7c1425ef3e..a66d714838b 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.200 2008/01/01 19:45:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.201 2008/01/11 18:39:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -235,7 +235,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
rettype = enforce_generic_type_consistency(actual_arg_types,
declared_arg_types,
nargs,
- rettype);
+ rettype,
+ false);
/* perform the necessary typecasting of arguments */
make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types);
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 1bd58cdbceb..6b23fbb9e9a 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.100 2008/01/01 19:45:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.101 2008/01/11 18:39:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1006,7 +1006,8 @@ make_scalar_array_op(ParseState *pstate, List *opname,
rettype = enforce_generic_type_consistency(actual_arg_types,
declared_arg_types,
2,
- opform->oprresult);
+ opform->oprresult,
+ false);
/*
* Check that operator result is boolean
@@ -1116,7 +1117,8 @@ make_op_expr(ParseState *pstate, Operator op,
rettype = enforce_generic_type_consistency(actual_arg_types,
declared_arg_types,
nargs,
- opform->oprresult);
+ opform->oprresult,
+ false);
/* perform the necessary typecasting of arguments */
make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index c5b2b48ec3b..ab36a0c1969 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.74 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.75 2008/01/11 18:39:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -81,7 +81,8 @@ extern bool check_generic_type_consistency(Oid *actual_arg_types,
extern Oid enforce_generic_type_consistency(Oid *actual_arg_types,
Oid *declared_arg_types,
int nargs,
- Oid rettype);
+ Oid rettype,
+ bool allow_poly);
extern Oid resolve_generic_type(Oid declared_type,
Oid context_actual_type,
Oid context_declared_type);
diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out
index de393a05288..a208203c6d3 100644
--- a/src/test/regress/expected/polymorphism.out
+++ b/src/test/regress/expected/polymorphism.out
@@ -577,3 +577,39 @@ select q2, sql_if(q2 > 0, q2, q2 + 1) from int8_tbl;
-4567890123456789 | -4567890123456788
(5 rows)
+-- another kind of polymorphic aggregate
+create function add_group(grp anyarray, ad anyelement, size integer)
+ returns anyarray
+ as $$
+begin
+ if grp is null then
+ return array[ad];
+ end if;
+ if array_upper(grp, 1) < size then
+ return grp || ad;
+ end if;
+ return grp;
+end;
+$$
+ language plpgsql immutable;
+create aggregate build_group(anyelement, integer) (
+ SFUNC = add_group,
+ STYPE = anyarray
+);
+select build_group(q1,3) from int8_tbl;
+ build_group
+----------------------------
+ {123,123,4567890123456789}
+(1 row)
+
+-- this should fail because stype isn't compatible with arg
+create aggregate build_group(int8, integer) (
+ SFUNC = add_group,
+ STYPE = int2[]
+);
+ERROR: function add_group(smallint[], bigint, integer) does not exist
+-- but we can make a non-poly agg from a poly sfunc if types are OK
+create aggregate build_group(int8, integer) (
+ SFUNC = add_group,
+ STYPE = int8[]
+);
diff --git a/src/test/regress/sql/polymorphism.sql b/src/test/regress/sql/polymorphism.sql
index c2bf14b48f0..2df963952f4 100644
--- a/src/test/regress/sql/polymorphism.sql
+++ b/src/test/regress/sql/polymorphism.sql
@@ -390,3 +390,39 @@ select case when $1 then $2 else $3 end $$ language sql;
select f1, sql_if(f1 > 0, bleat(f1), bleat(f1 + 1)) from int4_tbl;
select q2, sql_if(q2 > 0, q2, q2 + 1) from int8_tbl;
+
+-- another kind of polymorphic aggregate
+
+create function add_group(grp anyarray, ad anyelement, size integer)
+ returns anyarray
+ as $$
+begin
+ if grp is null then
+ return array[ad];
+ end if;
+ if array_upper(grp, 1) < size then
+ return grp || ad;
+ end if;
+ return grp;
+end;
+$$
+ language plpgsql immutable;
+
+create aggregate build_group(anyelement, integer) (
+ SFUNC = add_group,
+ STYPE = anyarray
+);
+
+select build_group(q1,3) from int8_tbl;
+
+-- this should fail because stype isn't compatible with arg
+create aggregate build_group(int8, integer) (
+ SFUNC = add_group,
+ STYPE = int2[]
+);
+
+-- but we can make a non-poly agg from a poly sfunc if types are OK
+create aggregate build_group(int8, integer) (
+ SFUNC = add_group,
+ STYPE = int8[]
+);