Commit e6c178b5 authored by Tom Lane's avatar Tom Lane

Refactor our checks for valid function and aggregate signatures.

pg_proc.c and pg_aggregate.c had near-duplicate copies of the logic
to decide whether a function or aggregate's signature is legal.
This seems like a bad thing even without the problem that the
upcoming "anycompatible" patch would roughly double the complexity
of that logic.  Hence, refactor so that the rules are localized
in new subroutines supplied by parse_coerce.c.  (One could quibble
about just where to add that code, but putting it beside
enforce_generic_type_consistency seems not totally unreasonable.)

The fact that the rules are about to change would mandate some
changes in the wording of the associated error messages in any case.
I ended up spelling things out in a fairly literal fashion in the
errdetail messages, eg "A result of type anyelement requires at
least one input of type anyelement, anyarray, anynonarray, anyenum,
or anyrange."  Perhaps this is overkill, but once there's more than
one subgroup of polymorphic types, people might get confused by
more-abstract messages.

Discussion: https://postgr.es/m/24137.1584139352@sss.pgh.pa.us
parent dbbb5538
...@@ -93,8 +93,6 @@ AggregateCreate(const char *aggName, ...@@ -93,8 +93,6 @@ AggregateCreate(const char *aggName,
Oid mfinalfn = InvalidOid; /* can be omitted */ Oid mfinalfn = InvalidOid; /* can be omitted */
Oid sortop = InvalidOid; /* can be omitted */ Oid sortop = InvalidOid; /* can be omitted */
Oid *aggArgTypes = parameterTypes->values; Oid *aggArgTypes = parameterTypes->values;
bool hasPolyArg;
bool hasInternalArg;
bool mtransIsStrict = false; bool mtransIsStrict = false;
Oid rettype; Oid rettype;
Oid finaltype; Oid finaltype;
...@@ -103,6 +101,7 @@ AggregateCreate(const char *aggName, ...@@ -103,6 +101,7 @@ AggregateCreate(const char *aggName,
int nargs_finalfn; int nargs_finalfn;
Oid procOid; Oid procOid;
TupleDesc tupDesc; TupleDesc tupDesc;
char *detailmsg;
int i; int i;
ObjectAddress myself, ObjectAddress myself,
referenced; referenced;
...@@ -131,36 +130,33 @@ AggregateCreate(const char *aggName, ...@@ -131,36 +130,33 @@ AggregateCreate(const char *aggName,
FUNC_MAX_ARGS - 1, FUNC_MAX_ARGS - 1,
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 * If transtype is polymorphic, must have polymorphic argument also; else
* we will have no way to deduce the actual transtype. * 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, ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine transition data type"), 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 * Likewise for moving-aggregate transtype, if any
*/ */
if (OidIsValid(aggmTransType) && if (OidIsValid(aggmTransType))
IsPolymorphicType(aggmTransType) && !hasPolyArg) {
ereport(ERROR, detailmsg = check_valid_polymorphic_signature(aggmTransType,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), aggArgTypes,
errmsg("cannot determine transition data type"), numArgs);
errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument."))); 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 * An ordered-set aggregate that is VARIADIC must be VARIADIC ANY. In
...@@ -492,12 +488,14 @@ AggregateCreate(const char *aggName, ...@@ -492,12 +488,14 @@ AggregateCreate(const char *aggName,
* that itself violates the rule against polymorphic result with no * that itself violates the rule against polymorphic result with no
* polymorphic input.) * polymorphic input.)
*/ */
if (IsPolymorphicType(finaltype) && !hasPolyArg) detailmsg = check_valid_polymorphic_signature(finaltype,
aggArgTypes,
numArgs);
if (detailmsg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot determine result data type"), errmsg("cannot determine result data type"),
errdetail("An aggregate returning a polymorphic type " errdetail_internal("%s", detailmsg)));
"must have at least one polymorphic argument.")));
/* /*
* Also, the return type can't be INTERNAL unless there's at least one * Also, the return type can't be INTERNAL unless there's at least one
...@@ -505,11 +503,14 @@ AggregateCreate(const char *aggName, ...@@ -505,11 +503,14 @@ AggregateCreate(const char *aggName,
* for regular functions, but at the level of aggregates. We must test * for regular functions, but at the level of aggregates. We must test
* this explicitly because we allow INTERNAL as the transtype. * 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, ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("unsafe use of pseudo-type \"internal\""), 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 * If a moving-aggregate implementation is supplied, look up its finalfn
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
...@@ -97,12 +98,6 @@ ProcedureCreate(const char *procedureName, ...@@ -97,12 +98,6 @@ ProcedureCreate(const char *procedureName,
int allParamCount; int allParamCount;
Oid *allParams; Oid *allParams;
char *paramModes = NULL; char *paramModes = NULL;
bool genericInParam = false;
bool genericOutParam = false;
bool anyrangeInParam = false;
bool anyrangeOutParam = false;
bool internalInParam = false;
bool internalOutParam = false;
Oid variadicType = InvalidOid; Oid variadicType = InvalidOid;
Acl *proacl = NULL; Acl *proacl = NULL;
Relation rel; Relation rel;
...@@ -116,6 +111,7 @@ ProcedureCreate(const char *procedureName, ...@@ -116,6 +111,7 @@ ProcedureCreate(const char *procedureName,
bool is_update; bool is_update;
ObjectAddress myself, ObjectAddress myself,
referenced; referenced;
char *detailmsg;
int i; int i;
Oid trfid; Oid trfid;
...@@ -178,29 +174,34 @@ ProcedureCreate(const char *procedureName, ...@@ -178,29 +174,34 @@ ProcedureCreate(const char *procedureName,
} }
/* /*
* Detect whether we have polymorphic or INTERNAL arguments. The first * Do not allow polymorphic return type unless there is a polymorphic
* loop checks input arguments, the second output arguments. * input argument that we can use to deduce the actual return type.
*/ */
for (i = 0; i < parameterCount; i++) detailmsg = check_valid_polymorphic_signature(returnType,
{ parameterTypes->values,
switch (parameterTypes->values[i]) parameterCount);
{ if (detailmsg)
case ANYARRAYOID: ereport(ERROR,
case ANYELEMENTOID: (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
case ANYNONARRAYOID: errmsg("cannot determine result data type"),
case ANYENUMOID: errdetail_internal("%s", detailmsg)));
genericInParam = true;
break;
case ANYRANGEOID:
genericInParam = true;
anyrangeInParam = true;
break;
case INTERNALOID:
internalInParam = true;
break;
}
}
/*
* 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)) if (allParameterTypes != PointerGetDatum(NULL))
{ {
for (i = 0; i < allParamCount; i++) for (i = 0; i < allParamCount; i++)
...@@ -210,52 +211,26 @@ ProcedureCreate(const char *procedureName, ...@@ -210,52 +211,26 @@ ProcedureCreate(const char *procedureName,
paramModes[i] == PROARGMODE_VARIADIC) paramModes[i] == PROARGMODE_VARIADIC)
continue; /* ignore input-only params */ continue; /* ignore input-only params */
switch (allParams[i]) detailmsg = check_valid_polymorphic_signature(allParams[i],
{ parameterTypes->values,
case ANYARRAYOID: parameterCount);
case ANYELEMENTOID: if (detailmsg)
case ANYNONARRAYOID: ereport(ERROR,
case ANYENUMOID: (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
genericOutParam = true; errmsg("cannot determine result data type"),
break; errdetail_internal("%s", detailmsg)));
case ANYRANGEOID: detailmsg = check_valid_internal_signature(allParams[i],
genericOutParam = true; parameterTypes->values,
anyrangeOutParam = true; parameterCount);
break; if (detailmsg)
case INTERNALOID: ereport(ERROR,
internalOutParam = true; (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
break; errmsg("unsafe use of pseudo-type \"internal\""),
} errdetail_internal("%s", detailmsg)));
} }
} }
/* /* Identify variadic argument type, if any */
* 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.")));
if (paramModes != NULL) if (paramModes != NULL)
{ {
/* /*
......
...@@ -1971,6 +1971,77 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -1971,6 +1971,77 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
return rettype; 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() /* TypeCategory()
* Assign a category to the specified type OID. * Assign a category to the specified type OID.
......
...@@ -80,6 +80,13 @@ extern Oid enforce_generic_type_consistency(const Oid *actual_arg_types, ...@@ -80,6 +80,13 @@ extern Oid enforce_generic_type_consistency(const Oid *actual_arg_types,
Oid rettype, Oid rettype,
bool allow_poly); 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, extern CoercionPathType find_coercion_pathway(Oid targetTypeId,
Oid sourceTypeId, Oid sourceTypeId,
CoercionContext ccontext, CoercionContext ccontext,
......
...@@ -1811,7 +1811,7 @@ begin ...@@ -1811,7 +1811,7 @@ begin
return array[x + 1, x + 2]; return array[x + 1, x + 2];
end$$ language plpgsql; end$$ language plpgsql;
ERROR: cannot determine result data type 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 $$ create function f1(x anyrange) returns anyarray as $$
begin begin
return array[lower(x), upper(x)]; return array[lower(x), upper(x)];
......
...@@ -61,7 +61,7 @@ create function polyf(x anyelement) returns anyrange as $$ ...@@ -61,7 +61,7 @@ create function polyf(x anyelement) returns anyrange as $$
select array[x + 1, x + 2] select array[x + 1, x + 2]
$$ language sql; $$ language sql;
ERROR: cannot determine result data type 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 $$ create function polyf(x anyrange) returns anyarray as $$
select array[lower(x), upper(x)] select array[lower(x), upper(x)]
$$ language sql; $$ language sql;
...@@ -155,7 +155,7 @@ CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[], ...@@ -155,7 +155,7 @@ CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[],
CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray, CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- N P
-- should CREATE -- should CREATE
CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[], CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[],
...@@ -167,11 +167,11 @@ CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[], ...@@ -167,11 +167,11 @@ CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[],
CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray, CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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)) -- Case2 (R = P) && ((B = P) || (B = N))
-- ------------------------------------- -- -------------------------------------
-- S tf1 B tf2 -- S tf1 B tf2
...@@ -226,13 +226,13 @@ ERROR: function tfp(integer[], anyelement) does not exist ...@@ -226,13 +226,13 @@ ERROR: function tfp(integer[], anyelement) does not exist
CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P N N P
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement) -- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P N P N
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp, CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp,
...@@ -248,21 +248,21 @@ ERROR: function tf2p(anyarray, anyelement) does not exist ...@@ -248,21 +248,21 @@ ERROR: function tf2p(anyarray, anyelement) does not exist
CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P P N P
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement) -- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
FINALFUNC = ffp, INITCOND = '{}'); FINALFUNC = ffp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P P P N
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) -- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p, CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p,
...@@ -292,11 +292,11 @@ CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[], ...@@ -292,11 +292,11 @@ CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[],
CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray, CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- N P
-- should CREATE -- should CREATE
CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[], CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[],
...@@ -306,7 +306,7 @@ 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, CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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)) -- Case4 (R = N) && ((B = P) || (B = N))
-- ------------------------------------- -- -------------------------------------
-- S tf1 B tf2 -- S tf1 B tf2
...@@ -360,21 +360,21 @@ ERROR: function tfp(integer[], anyelement) does not exist ...@@ -360,21 +360,21 @@ ERROR: function tfp(integer[], anyelement) does not exist
CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P N N P
-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement) -- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement)
CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, CREATE AGGREGATE myaggn14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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, CREATE AGGREGATE myaggn14b(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray,
INITCOND = '{}'); INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P N P N
-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) -- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int)
CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp, CREATE AGGREGATE myaggn15a(BASETYPE = anyelement, SFUNC = tfnp,
...@@ -396,13 +396,13 @@ ERROR: function tf2p(anyarray, anyelement) does not exist ...@@ -396,13 +396,13 @@ ERROR: function tf2p(anyarray, anyelement) does not exist
CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, CREATE AGGREGATE myaggn17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P P N P
-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement) -- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement)
CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, CREATE AGGREGATE myaggn18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray,
FINALFUNC = ffnp, INITCOND = '{}'); FINALFUNC = ffnp, INITCOND = '{}');
ERROR: cannot determine transition data type 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 -- P P P N
-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) -- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int)
CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p, CREATE AGGREGATE myaggn19a(BASETYPE = anyelement, SFUNC = tf1p,
......
...@@ -1556,7 +1556,7 @@ DROP FUNCTION dup(anyelement); ...@@ -1556,7 +1556,7 @@ DROP FUNCTION dup(anyelement);
CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray) CREATE FUNCTION bad (f1 int, out f2 anyelement, out f3 anyarray)
AS 'select $1, array[$1,$1]' LANGUAGE sql; AS 'select $1, array[$1,$1]' LANGUAGE sql;
ERROR: cannot determine result data type 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 -- table functions
-- --
......
...@@ -1371,12 +1371,12 @@ drop function anyarray_anyrange_func(anyarray, anyrange); ...@@ -1371,12 +1371,12 @@ drop function anyarray_anyrange_func(anyarray, anyrange);
create function bogus_func(anyelement) create function bogus_func(anyelement)
returns anyrange as 'select int4range(1,10)' language sql; returns anyrange as 'select int4range(1,10)' language sql;
ERROR: cannot determine result data type 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 -- should fail
create function bogus_func(int) create function bogus_func(int)
returns anyrange as 'select int4range(1,10)' language sql; returns anyrange as 'select int4range(1,10)' language sql;
ERROR: cannot determine result data type 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) create function range_add_bounds(anyrange)
returns anyelement as 'select lower($1) + upper($1)' language sql; returns anyelement as 'select lower($1) + upper($1)' language sql;
select range_add_bounds(int4range(1, 17)); select range_add_bounds(int4range(1, 17));
...@@ -1521,14 +1521,14 @@ select * from table_succeed(int4range(1,11)); ...@@ -1521,14 +1521,14 @@ select * from table_succeed(int4range(1,11));
create function outparam_fail(i anyelement, out r anyrange, out t text) create function outparam_fail(i anyelement, out r anyrange, out t text)
as $$ select '[1,10]', 'foo' $$ language sql; as $$ select '[1,10]', 'foo' $$ language sql;
ERROR: cannot determine result data type 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 --should fail
create function inoutparam_fail(inout i anyelement, out r anyrange) create function inoutparam_fail(inout i anyelement, out r anyrange)
as $$ select $1, '[1,10]' $$ language sql; as $$ select $1, '[1,10]' $$ language sql;
ERROR: cannot determine result data type 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 --should fail
create function table_fail(i anyelement) returns table(i anyelement, r anyrange) create function table_fail(i anyelement) returns table(i anyelement, r anyrange)
as $$ select $1, '[1,10]' $$ language sql; as $$ select $1, '[1,10]' $$ language sql;
ERROR: cannot determine result data type 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.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment