0001-refactoring.patch
text/x-diff
Filename: 0001-refactoring.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
Series: patch 0001
| File | + | − |
|---|---|---|
| src/backend/catalog/pg_aggregate.c | 15 | 21 |
| src/backend/catalog/pg_proc.c | 40 | 70 |
| src/backend/parser/parse_coerce.c | 65 | 0 |
| src/backend/utils/adt/pseudotypes.c | 99 | 178 |
| src/include/parser/parse_coerce.h | 7 | 0 |
| src/test/regress/expected/polymorphism.out | 18 | 18 |
| src/test/regress/expected/rangefuncs.out | 1 | 1 |
| src/test/regress/expected/rangetypes.out | 5 | 5 |
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.