aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_coerce.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-03-17 19:36:41 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-03-17 19:36:41 -0400
commite6c178b5b73ac1fb822829e6d9b99e3fc1129c21 (patch)
treecc458fdcb6761971a6c5f6ce1cfd86ac27edfe9f /src/backend/parser/parse_coerce.c
parentdbbb55385cf5eb75837eb3eb7ca1f14e2beb5a63 (diff)
downloadpostgresql-e6c178b5b73ac1fb822829e6d9b99e3fc1129c21.tar.gz
postgresql-e6c178b5b73ac1fb822829e6d9b99e3fc1129c21.zip
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
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r--src/backend/parser/parse_coerce.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index f1afd8fca32..c3fb51d35d9 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.