diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 0b7face4cc..7d887ea24a 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; @@ -103,6 +101,7 @@ AggregateCreate(const char *aggName, int nargs_finalfn; Oid procOid; TupleDesc tupDesc; + char *detailmsg; int i; ObjectAddress myself, referenced; @@ -131,36 +130,33 @@ 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) + detailmsg = check_valid_polymorphic_signature(aggTransType, + aggArgTypes, + numArgs); + if (detailmsg) 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_internal("%s", detailmsg))); /* * Likewise for moving-aggregate transtype, if any */ - if (OidIsValid(aggmTransType) && - IsPolymorphicType(aggmTransType) && !hasPolyArg) - 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."))); + if (OidIsValid(aggmTransType)) + { + detailmsg = check_valid_polymorphic_signature(aggmTransType, + aggArgTypes, + numArgs); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine transition data type"), + errdetail_internal("%s", detailmsg))); + } /* * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In @@ -492,12 +488,14 @@ AggregateCreate(const char *aggName, * that itself violates the rule against polymorphic result with no * polymorphic input.) */ - if (IsPolymorphicType(finaltype) && !hasPolyArg) + detailmsg = check_valid_polymorphic_signature(finaltype, + aggArgTypes, + numArgs); + if (detailmsg) 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_internal("%s", detailmsg))); /* * Also, the return type can't be INTERNAL unless there's at least one @@ -505,11 +503,14 @@ 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) + detailmsg = check_valid_internal_signature(finaltype, + aggArgTypes, + numArgs); + if (detailmsg) 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."))); + errdetail_internal("%s", detailmsg))); /* * If a moving-aggregate implementation is supplied, look up its finalfn diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 423fd79d94..0cac936cef 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; @@ -116,6 +111,7 @@ ProcedureCreate(const char *procedureName, bool is_update; ObjectAddress myself, referenced; + char *detailmsg; int i; Oid trfid; @@ -178,29 +174,34 @@ 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; - } - } + detailmsg = check_valid_polymorphic_signature(returnType, + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine result data type"), + errdetail_internal("%s", detailmsg))); + /* + * Also, do not allow return type INTERNAL unless at least one input + * argument is INTERNAL. + */ + detailmsg = check_valid_internal_signature(returnType, + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail_internal("%s", detailmsg))); + + /* + * Apply the same tests to any OUT arguments. + */ if (allParameterTypes != PointerGetDatum(NULL)) { for (i = 0; i < allParamCount; i++) @@ -210,52 +211,26 @@ 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; - } + detailmsg = check_valid_polymorphic_signature(allParams[i], + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("cannot determine result data type"), + errdetail_internal("%s", detailmsg))); + detailmsg = check_valid_internal_signature(allParams[i], + parameterTypes->values, + parameterCount); + if (detailmsg) + ereport(ERROR, + (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), + errmsg("unsafe use of pseudo-type \"internal\""), + errdetail_internal("%s", detailmsg))); } } - /* - * 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 f1afd8fca3..c3fb51d35d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1971,6 +1971,77 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, return rettype; } +/* + * check_valid_polymorphic_signature() + * Is a proposed function signature valid per polymorphism rules? + * + * Returns NULL if the signature is valid (either ret_type is not polymorphic, + * or it can be deduced from the given declared argument types). Otherwise, + * returns a palloc'd, already translated errdetail string saying why not. + */ +char * +check_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 NULL; /* OK */ + } + return psprintf(_("A result of type %s requires at least one input of type %s."), + format_type_be(ret_type), format_type_be(ret_type)); + } + 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 NULL; /* OK */ + } + return psprintf(_("A result of type %s requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange."), + format_type_be(ret_type)); + } + else + return NULL; /* OK, ret_type is not polymorphic */ +} + +/* + * check_valid_internal_signature() + * Is a proposed function signature valid per INTERNAL safety rules? + * + * Returns NULL if OK, or a suitable error message 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.) It's overkill to return the error detail message, since there + * is only one possibility, but we do it like this to keep the API similar to + * check_valid_polymorphic_signature(). + */ +char * +check_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 NULL; /* OK */ + } + return pstrdup(_("A result of type internal requires at least one input of type internal.")); + } + else + return NULL; /* OK, ret_type is not INTERNAL */ +} + /* TypeCategory() * Assign a category to the specified type OID. diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index ff9219dda9..8686eaacbc 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -80,6 +80,13 @@ extern Oid enforce_generic_type_consistency(const Oid *actual_arg_types, Oid rettype, bool allow_poly); +extern char *check_valid_polymorphic_signature(Oid ret_type, + const Oid *declared_arg_types, + int nargs); +extern char *check_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/plpgsql.out b/src/test/regress/expected/plpgsql.out index f94ae10e00..dfc10e3242 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -1811,7 +1811,7 @@ begin return array[x + 1, x + 2]; end$$ language plpgsql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A result of type anyrange requires at least one input of type anyrange. create function f1(x anyrange) returns anyarray as $$ begin return array[lower(x), upper(x)]; diff --git a/src/test/regress/expected/polymorphism.out b/src/test/regress/expected/polymorphism.out index 1271ea4a99..331562de19 100644 --- a/src/test/regress/expected/polymorphism.out +++ b/src/test/regress/expected/polymorphism.out @@ -61,7 +61,7 @@ create function polyf(x anyelement) returns anyrange as $$ select array[x + 1, x + 2] $$ language sql; ERROR: cannot determine result data type -DETAIL: A function returning "anyrange" must have at least one "anyrange" argument. +DETAIL: A result of type anyrange requires at least one input of type anyrange. create function polyf(x anyrange) returns anyarray as $$ select array[lower(x), upper(x)] $$ language sql; @@ -155,7 +155,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- N P -- should CREATE CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[], @@ -167,11 +167,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- Case2 (R = P) && ((B = P) || (B = N)) -- ------------------------------------- -- S tf1 B tf2 @@ -226,13 +226,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- P N P N -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp, @@ -248,21 +248,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- P P P N -- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p, @@ -292,11 +292,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- N P -- should CREATE CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[], @@ -306,7 +306,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- Case4 (R = N) && ((B = P) || (B = N)) -- ------------------------------------- -- S tf1 B tf2 @@ -360,21 +360,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- P N P N -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp, @@ -396,13 +396,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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- 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: A result of type anyarray requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- 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 a70060ba01..cdfc43e854 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 result of type anyelement requires at least one input of type anyelement, anyarray, anynonarray, anyenum, or anyrange. -- -- table functions -- diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index 348235a15e..a28741a888 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 result of type anyrange requires at least one input of type anyrange. -- 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 result of type anyrange requires at least one input of type anyrange. create function range_add_bounds(anyrange) returns anyelement as 'select lower($1) + upper($1)' language sql; select range_add_bounds(int4range(1, 17)); @@ -1521,14 +1521,14 @@ select * from table_succeed(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 result of type anyrange requires at least one input of type anyrange. --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 result of type anyrange requires at least one input of type anyrange. --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 result of type anyrange requires at least one input of type anyrange.