diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 0b7face..354d00a 100644 --- a/src/backend/catalog/pg_aggregate.c +++ b/src/backend/catalog/pg_aggregate.c @@ -93,8 +93,6 @@ AggregateCreate(const char *aggName, Oid mfinalfn = InvalidOid; /* can be omitted */ Oid sortop = InvalidOid; /* can be omitted */ Oid *aggArgTypes = parameterTypes->values; - bool hasPolyArg; - bool hasInternalArg; bool mtransIsStrict = false; Oid rettype; Oid finaltype; @@ -131,36 +129,29 @@ AggregateCreate(const char *aggName, FUNC_MAX_ARGS - 1, FUNC_MAX_ARGS - 1))); - /* check for polymorphic and INTERNAL arguments */ - hasPolyArg = false; - hasInternalArg = false; - for (i = 0; i < numArgs; i++) - { - if (IsPolymorphicType(aggArgTypes[i])) - hasPolyArg = true; - else if (aggArgTypes[i] == INTERNALOID) - hasInternalArg = true; - } - /* * 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 (!is_valid_polymorphic_signature(aggTransType, + aggArgTypes, + numArgs)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine transition data type"), - errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument."))); + errdetail("An aggregate using a polymorphic transition type must have at least one matching polymorphic argument."))); /* * Likewise for moving-aggregate transtype, if any */ if (OidIsValid(aggmTransType) && - IsPolymorphicType(aggmTransType) && !hasPolyArg) + !is_valid_polymorphic_signature(aggmTransType, + aggArgTypes, + numArgs)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine transition data type"), - errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument."))); + errdetail("An aggregate using a polymorphic transition type must have at least one matching polymorphic argument."))); /* * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In @@ -492,12 +483,13 @@ AggregateCreate(const char *aggName, * that itself violates the rule against polymorphic result with no * polymorphic input.) */ - if (IsPolymorphicType(finaltype) && !hasPolyArg) + if (!is_valid_polymorphic_signature(finaltype, + aggArgTypes, + numArgs)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot determine result data type"), - errdetail("An aggregate returning a polymorphic type " - "must have at least one polymorphic argument."))); + errdetail("An aggregate returning a polymorphic type must have at least one matching polymorphic argument."))); /* * Also, the return type can't be INTERNAL unless there's at least one @@ -505,7 +497,9 @@ AggregateCreate(const char *aggName, * for regular functions, but at the level of aggregates. We must test * this explicitly because we allow INTERNAL as the transtype. */ - if (finaltype == INTERNALOID && !hasInternalArg) + if (!is_valid_internal_signature(finaltype, + aggArgTypes, + numArgs)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("unsafe use of pseudo-type \"internal\""), diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 423fd79..c96a055 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -32,6 +32,7 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "parser/parse_coerce.h" #include "parser/parse_type.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" @@ -97,12 +98,6 @@ ProcedureCreate(const char *procedureName, int allParamCount; Oid *allParams; char *paramModes = NULL; - bool genericInParam = false; - bool genericOutParam = false; - bool anyrangeInParam = false; - bool anyrangeOutParam = false; - bool internalInParam = false; - bool internalOutParam = false; Oid variadicType = InvalidOid; Acl *proacl = NULL; Relation rel; @@ -178,29 +173,32 @@ ProcedureCreate(const char *procedureName, } /* - * Detect whether we have polymorphic or INTERNAL arguments. The first - * loop checks input arguments, the second output arguments. + * Do not allow polymorphic return type unless there is a polymorphic + * input argument that we can use to deduce the actual return type. */ - for (i = 0; i < parameterCount; i++) - { - switch (parameterTypes->values[i]) - { - case ANYARRAYOID: - case ANYELEMENTOID: - case ANYNONARRAYOID: - case ANYENUMOID: - genericInParam = true; - break; - case ANYRANGEOID: - genericInParam = true; - anyrangeInParam = true; - break; - case INTERNALOID: - internalInParam = true; - break; - } - } + if (!is_valid_polymorphic_signature(returnType, + parameterTypes->values, + parameterCount)) + 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 matching polymorphic argument."))); + + /* + * Also, do not allow return type INTERNAL unless at least one input + * argument is INTERNAL. + */ + if (!is_valid_internal_signature(returnType, + parameterTypes->values, + parameterCount)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); + /* + * Apply the same tests to any OUT arguments. + */ if (allParameterTypes != PointerGetDatum(NULL)) { for (i = 0; i < allParamCount; i++) @@ -210,52 +208,24 @@ ProcedureCreate(const char *procedureName, paramModes[i] == PROARGMODE_VARIADIC) continue; /* ignore input-only params */ - switch (allParams[i]) - { - case ANYARRAYOID: - case ANYELEMENTOID: - case ANYNONARRAYOID: - case ANYENUMOID: - genericOutParam = true; - break; - case ANYRANGEOID: - genericOutParam = true; - anyrangeOutParam = true; - break; - case INTERNALOID: - internalOutParam = true; - break; - } + if (!is_valid_polymorphic_signature(allParams[i], + parameterTypes->values, + parameterCount)) + 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 matching polymorphic argument."))); + if (!is_valid_internal_signature(allParams[i], + parameterTypes->values, + parameterCount)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); } } - /* - * Do not allow polymorphic return type unless at least one input argument - * is polymorphic. ANYRANGE return type is even stricter: must have an - * ANYRANGE input (since we can't deduce the specific range type from - * ANYELEMENT). Also, do not allow return type INTERNAL unless at least - * one input argument is INTERNAL. - */ - if ((IsPolymorphicType(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 ((returnType == ANYRANGEOID || anyrangeOutParam) && - !anyrangeInParam) - ereport(ERROR, - (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("cannot determine result data type"), - errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument."))); - - if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) - ereport(ERROR, - (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), - errmsg("unsafe use of pseudo-type \"internal\""), - errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); - + /* Identify variadic argument type, if any */ if (paramModes != NULL) { /* diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 929f758..7318b72 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -2070,6 +2070,71 @@ resolve_generic_type(Oid declared_type, return InvalidOid; /* keep compiler quiet */ } +/* + * is_valid_polymorphic_signature() + * Is a proposed function signature valid per polymorphism rules? + * + * Returns false if ret_type is polymorphic but cannot be inferred from + * the given declared argument types. + */ +bool +is_valid_polymorphic_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs) +{ + if (ret_type == ANYRANGEOID) + { + /* + * ANYRANGE requires an ANYRANGE input, else we can't tell which of + * several range types with the same element type to use. + */ + for (int i = 0; i < nargs; i++) + { + if (declared_arg_types[i] == ret_type) + return true; /* OK */ + } + return false; + } + else if (IsPolymorphicType(ret_type)) + { + /* Otherwise, any polymorphic type can be deduced from any other */ + for (int i = 0; i < nargs; i++) + { + if (IsPolymorphicType(declared_arg_types[i])) + return true; /* OK */ + } + return false; + } + else + return true; /* OK, ret_type is not polymorphic */ +} + +/* + * is_valid_internal_signature() + * Is a proposed function signature valid per INTERNAL safety rules? + * + * Returns false if ret_type is INTERNAL but none of the declared arg types + * are. It's unsafe to create such a function since it would allow + * invocation of INTERNAL-consuming functions directly from SQL. + */ +bool +is_valid_internal_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs) +{ + if (ret_type == INTERNALOID) + { + for (int i = 0; i < nargs; i++) + { + if (declared_arg_types[i] == ret_type) + return true; /* OK */ + } + return false; + } + else + return true; /* OK, ret_type is not INTERNAL */ +} + /* TypeCategory() * Assign a category to the specified type OID. diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 4653fc3..6ab95dc 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -29,6 +29,74 @@ /* + * Generate input and output functions for a pseudotype that will reject all + * input and output attempts. (But for some types, only the input function + * need be dummy.) + */ +#define PSEUDOTYPE_DUMMY_INPUT_FUNC(typname) \ +Datum \ +typname##_in(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot accept a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +extern int no_such_variable + +#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \ +PSEUDOTYPE_DUMMY_INPUT_FUNC(typname); \ +\ +Datum \ +typname##_out(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot display a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +extern int no_such_variable + +/* + * Likewise for binary send/receive functions. We don't bother with these + * at all for many pseudotypes, but some have them. (By convention, if + * a type has a send function it should have a receive function, even if + * that's only dummy.) + */ +#define PSEUDOTYPE_DUMMY_RECEIVE_FUNC(typname) \ +Datum \ +typname##_recv(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot accept a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +extern int no_such_variable + +#define PSEUDOTYPE_DUMMY_BINARY_IO_FUNCS(typname) \ +PSEUDOTYPE_DUMMY_RECEIVE_FUNC(typname); \ +\ +Datum \ +typname##_send(PG_FUNCTION_ARGS) \ +{ \ + ereport(ERROR, \ + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ + errmsg("cannot display a value of type %s", #typname))); \ +\ + PG_RETURN_VOID(); /* keep compiler quiet */ \ +} \ +\ +extern int no_such_variable + + +/* * cstring_in - input routine for pseudo-type CSTRING. * * We might as well allow this to support constructs like "foo_in('blah')". @@ -84,22 +152,18 @@ cstring_send(PG_FUNCTION_ARGS) } /* - * anyarray_in - input routine for pseudo-type ANYARRAY. + * anyarray + * + * XXX anyarray_recv 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 -anyarray_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "anyarray"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} +PSEUDOTYPE_DUMMY_INPUT_FUNC(anyarray); +PSEUDOTYPE_DUMMY_RECEIVE_FUNC(anyarray); /* - * anyarray_out - output routine for pseudo-type ANYARRAY. - * - * We may as well allow this, since array_out will in fact work. + * We need to allow output so that, e.g., pg_statistic columns can be + * printed. */ Datum anyarray_out(PG_FUNCTION_ARGS) @@ -107,53 +171,19 @@ anyarray_out(PG_FUNCTION_ARGS) return array_out(fcinfo); } -/* - * anyarray_recv - binary input routine for pseudo-type ANYARRAY. - * - * 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 -anyarray_recv(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "anyarray"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anyarray_send - binary output routine for pseudo-type ANYARRAY. - * - * We may as well allow this, since array_send will in fact work. - */ Datum anyarray_send(PG_FUNCTION_ARGS) { return array_send(fcinfo); } - /* - * anyenum_in - input routine for pseudo-type ANYENUM. - */ -Datum -anyenum_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "anyenum"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anyenum_out - output routine for pseudo-type ANYENUM. + * anyenum * - * We may as well allow this, since enum_out will in fact work. + * We may as well allow output, since enum_out will in fact work. */ +PSEUDOTYPE_DUMMY_INPUT_FUNC(anyenum); + Datum anyenum_out(PG_FUNCTION_ARGS) { @@ -161,23 +191,12 @@ anyenum_out(PG_FUNCTION_ARGS) } /* - * anyrange_in - input routine for pseudo-type ANYRANGE. - */ -Datum -anyrange_in(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "anyrange"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * anyrange_out - output routine for pseudo-type ANYRANGE. + * anyrange * - * We may as well allow this, since range_out will in fact work. + * We may as well allow output, since range_out will in fact work. */ +PSEUDOTYPE_DUMMY_INPUT_FUNC(anyrange); + Datum anyrange_out(PG_FUNCTION_ARGS) { @@ -264,29 +283,20 @@ shell_out(PG_FUNCTION_ARGS) /* - * pg_node_tree_in - input routine for type PG_NODE_TREE. + * pg_node_tree * * pg_node_tree isn't really a pseudotype --- it's real enough to be a table * column --- but it presently has no operations of its own, and disallows * input too, so its I/O functions seem to fit here as much as anywhere. + * + * We disallow input of pg_node_tree values because the SQL functions that + * operate on the type are not secure against malformed input. */ -Datum -pg_node_tree_in(PG_FUNCTION_ARGS) -{ - /* - * We disallow input of pg_node_tree values because the SQL functions that - * operate on the type are not secure against malformed input. - */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "pg_node_tree"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - +PSEUDOTYPE_DUMMY_INPUT_FUNC(pg_node_tree); +PSEUDOTYPE_DUMMY_RECEIVE_FUNC(pg_node_tree); /* - * pg_node_tree_out - output routine for type PG_NODE_TREE. + * We do want to allow output, though. * * The internal representation is the same as TEXT, so just pass it off. */ @@ -296,22 +306,6 @@ pg_node_tree_out(PG_FUNCTION_ARGS) return textout(fcinfo); } -/* - * pg_node_tree_recv - binary input routine for type PG_NODE_TREE. - */ -Datum -pg_node_tree_recv(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "pg_node_tree"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * pg_node_tree_send - binary output routine for type PG_NODE_TREE. - */ Datum pg_node_tree_send(PG_FUNCTION_ARGS) { @@ -319,102 +313,29 @@ pg_node_tree_send(PG_FUNCTION_ARGS) } /* - * pg_ddl_command_in - input routine for type PG_DDL_COMMAND. + * pg_ddl_command * * Like pg_node_tree, pg_ddl_command isn't really a pseudotype; it's here for * the same reasons as that one. - */ -Datum -pg_ddl_command_in(PG_FUNCTION_ARGS) -{ - /* - * Disallow input of pg_ddl_command value. - */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "pg_ddl_command"))); - - PG_RETURN_VOID(); /* keep compiler quiet */ -} - -/* - * pg_ddl_command_out - output routine for type PG_DDL_COMMAND. * - * We don't have any good way to output this type directly, so punt. - */ -Datum -pg_ddl_command_out(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot output a value of type %s", "pg_ddl_command"))); - - PG_RETURN_VOID(); -} - -/* - * pg_ddl_command_recv - binary input routine for type PG_DDL_COMMAND. - */ -Datum -pg_ddl_command_recv(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot accept a value of type %s", "pg_ddl_command"))); - - PG_RETURN_VOID(); -} - -/* - * pg_ddl_command_send - binary output routine for type PG_DDL_COMMAND. + * We don't have any good way to output this type directly, so punt + * for output as well as input. */ -Datum -pg_ddl_command_send(PG_FUNCTION_ARGS) -{ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("cannot output a value of type %s", "pg_ddl_command"))); - - PG_RETURN_VOID(); -} +PSEUDOTYPE_DUMMY_IO_FUNCS(pg_ddl_command); +PSEUDOTYPE_DUMMY_BINARY_IO_FUNCS(pg_ddl_command); /* - * Generate input and output functions for a pseudotype that will reject all - * input and output attempts. + * Dummy I/O functions for various other pseudotypes. */ -#define PSEUDOTYPE_DUMMY_IO_FUNCS(typname) \ -\ -Datum \ -typname##_in(PG_FUNCTION_ARGS) \ -{ \ - ereport(ERROR, \ - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ - errmsg("cannot accept a value of type %s", #typname))); \ -\ - PG_RETURN_VOID(); /* keep compiler quiet */ \ -} \ -\ -Datum \ -typname##_out(PG_FUNCTION_ARGS) \ -{ \ - ereport(ERROR, \ - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \ - errmsg("cannot display a value of type %s", #typname))); \ -\ - PG_RETURN_VOID(); /* keep compiler quiet */ \ -} \ -\ -extern int no_such_variable - PSEUDOTYPE_DUMMY_IO_FUNCS(any); PSEUDOTYPE_DUMMY_IO_FUNCS(trigger); PSEUDOTYPE_DUMMY_IO_FUNCS(event_trigger); PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler); +PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(internal); PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); -PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler); diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index d6a95c1..fce84d6 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -83,6 +83,13 @@ extern Oid resolve_generic_type(Oid declared_type, Oid context_actual_type, Oid context_declared_type); +extern bool is_valid_polymorphic_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs); +extern bool is_valid_internal_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs); + extern CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index 986417a..d436d29 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -81,7 +81,7 @@ CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[], CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- N P -- should CREATE CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[], @@ -93,11 +93,11 @@ CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[], CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- Case2 (R = P) && ((B = P) || (B = N)) -- ------------------------------------- -- S tf1 B tf2 @@ -152,13 +152,13 @@ ERROR: function tfp(integer[], anyelement) does not exist CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P N N P -- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement) CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P N P N -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp, @@ -174,21 +174,21 @@ ERROR: function tf2p(anyarray, anyelement) does not exist CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P P N P -- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement) CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P P P N -- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p, @@ -218,11 +218,11 @@ CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[], CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- N P -- should CREATE CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[], @@ -232,7 +232,7 @@ CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[], CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- Case4 (R = N) && ((B = P) || (B = N)) -- ------------------------------------- -- S tf1 B tf2 @@ -286,21 +286,21 @@ ERROR: function tfp(integer[], anyelement) does not exist CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P N N P -- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement) CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P N P N -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp, @@ -322,13 +322,13 @@ ERROR: function tf2p(anyarray, anyelement) does not exist CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P P N P -- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement) CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, FINALFUNC = ffnp, INITCOND = '{}'); ERROR: cannot determine transition data type -DETAIL: An aggregate using a polymorphic transition type must have at least one polymorphic argument. +DETAIL: An aggregate using a polymorphic transition type must have at least one matching polymorphic argument. -- P P P N -- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p, diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index a70060b..ac1abf6 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -1556,7 +1556,7 @@ DROP FUNCTION dup(anyelement); CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray) AS 'select $1, array[$1,$1]' LANGUAGE sql; ERROR: cannot determine result data type -DETAIL: A function returning a polymorphic type must have at least one polymorphic argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument. -- -- table functions -- diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 220f2d9..fc82f87 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -1371,12 +1371,12 @@ drop function anyarray_anyrange_func(anyarray, anyrange); create function bogus_func(anyelement) returns anyrange as 'select int4range(1,10)' language sql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument. -- should fail create function bogus_func(int) returns anyrange as 'select int4range(1,10)' language sql; ERROR: cannot determine result data type -DETAIL: A function returning a polymorphic type must have at least one polymorphic argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument. create function range_add_bounds(anyrange) returns anyelement as 'select lower($1) + upper($1)' language sql; select range_add_bounds(int4range(1, 17)); @@ -1510,14 +1510,14 @@ select * from table_succeed(123, int4range(1,11)); create function outparam_fail(i anyelement, out r anyrange, out t text) as $$ select '[1,10]', 'foo' $$ language sql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument. --should fail create function inoutparam_fail(inout i anyelement, out r anyrange) as $$ select $1, '[1,10]' $$ language sql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument. --should fail create function table_fail(i anyelement) returns table(i anyelement, r anyrange) as $$ select $1, '[1,10]' $$ language sql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A function returning a polymorphic type must have at least one matching polymorphic argument.