I wrote: > While running down loose ends in my domains-over-composite patch, > I wondered why parse_func.c's FuncNameAsType() excludes composite > types as possible type names. > ... > There might still be an argument for rejecting the case on the grounds > that it's confusing or likely to be user error, but I'm not sure.
After studying the code more closely, I realized that there are only two cases this restriction actually rejects, because no other cases with a composite destination type could get past the restrictions on a function-like cast in func_get_detail: 1. Function-style coercion of an unknown literal, eg SELECT int8_tbl('(1,2)'); But I do not see any good argument why this should be rejected for composite types when it works for other types. 2. Coercion of a composite type to itself, eg SELECT int8_tbl(int8_tbl) FROM int8_tbl; SELECT int8_tbl.int8_tbl FROM int8_tbl; find_coercion_pathway would report that as a RELABELTYPE case, whereas it would not recognize any other coercion to a composite type as either RELABELTYPE or COERCEVIAIO. (At least, not unless the user has added such casts with CREATE CAST; in which case I think he's entitled to expect that the system would be willing to use them.) On the whole, probably restriction #2 is a good thing; if we were to lift it, I think we'd start getting complaints about "why does my table seem to have a column named after itself", rather like the complaints we got about "why does my table seem to have a column named "text"" before we put in the other arbitrary-seeming restriction in func_get_detail. However, the existing code is certainly an opaque and undocumented way of enforcing #2, plus it breaks #1 for no very good reason. So I think we should remove the restriction in FuncNameAsType and instead enforce #2 in a narrowly tailored way, as in the attached patch. regards, tom lane
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 2f2f2c7..050779b 100644 *** a/src/backend/parser/parse_func.c --- b/src/backend/parser/parse_func.c *************** func_get_detail(List *funcname, *** 1357,1362 **** --- 1357,1367 ---- * never supported that historically, so we can insist that people * write it as a normal cast instead. * + * We also reject the specific case of casting a composite type to + * itself (with RELABELTYPE). That's not really a useful thing to do, + * and it would likely produce user complaints about "why does my + * table seem to have a column named after itself?" + * * We also reject the specific case of COERCEVIAIO for a composite * source type and a string-category target type. This is a case that * find_coercion_pathway() allows by default, but experience has shown *************** func_get_detail(List *funcname, *** 1395,1401 **** switch (cpathtype) { case COERCION_PATH_RELABELTYPE: ! iscoercion = true; break; case COERCION_PATH_COERCEVIAIO: if ((sourceType == RECORDOID || --- 1400,1411 ---- switch (cpathtype) { case COERCION_PATH_RELABELTYPE: ! if (sourceType == targetType && ! (sourceType == RECORDOID || ! ISCOMPLEX(sourceType))) ! iscoercion = false; ! else ! iscoercion = true; break; case COERCION_PATH_COERCEVIAIO: if ((sourceType == RECORDOID || *************** make_fn_arguments(ParseState *pstate, *** 1761,1767 **** * convenience routine to see if a function name matches a type name * * Returns the OID of the matching type, or InvalidOid if none. We ignore ! * shell types and complex types. */ static Oid FuncNameAsType(List *funcname) --- 1771,1777 ---- * convenience routine to see if a function name matches a type name * * Returns the OID of the matching type, or InvalidOid if none. We ignore ! * shell types, since casting to a shell type would be useless. */ static Oid FuncNameAsType(List *funcname) *************** FuncNameAsType(List *funcname) *** 1773,1780 **** if (typtup == NULL) return InvalidOid; ! if (((Form_pg_type) GETSTRUCT(typtup))->typisdefined && ! !OidIsValid(typeTypeRelid(typtup))) result = typeTypeId(typtup); else result = InvalidOid; --- 1783,1789 ---- if (typtup == NULL) return InvalidOid; ! if (((Form_pg_type) GETSTRUCT(typtup))->typisdefined) result = typeTypeId(typtup); else result = InvalidOid;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers