From a26116c6cbf4117e8efaa7cfc5bacc887f01517f Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Sat, 17 Feb 2018 19:02:15 -0300 Subject: [PATCH] Refactor format_type APIs to be more modular Introduce a new format_type_extended, with a flags bitmask argument that can modify the default behavior. A few compatibility and readability wrappers remain: format_type_be format_type_be_qualified format_type_with_typemod while format_type_with_typemod_qualified, which had a single caller, is removed. Author: Michael Paquier, some revisions by me Discussion: 20180213035107.GA2915@paquier.xyz --- contrib/postgres_fdw/deparse.c | 10 ++- src/backend/utils/adt/format_type.c | 134 ++++++++++++++-------------- src/include/utils/builtins.h | 9 +- 3 files changed, 81 insertions(+), 72 deletions(-) diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index f4b38c65ac..02894a7e35 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -854,10 +854,12 @@ foreign_expr_walker(Node *node, static char * deparse_type_name(Oid type_oid, int32 typemod) { - if (is_builtin(type_oid)) - return format_type_with_typemod(type_oid, typemod); - else - return format_type_with_typemod_qualified(type_oid, typemod); + uint8 flags = FORMAT_TYPE_TYPEMOD_GIVEN; + + if (!is_builtin(type_oid)) + flags |= FORMAT_TYPE_FORCE_QUALIFY; + + return format_type_extended(type_oid, typemod, flags); } /* diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index de3da3607a..872574fdd5 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -28,9 +28,6 @@ #define MAX_INT32_LEN 11 -static char *format_type_internal(Oid type_oid, int32 typemod, - bool typemod_given, bool allow_invalid, - bool force_qualify); static char *printTypmod(const char *typname, int32 typmod, Oid typmodout); @@ -72,81 +69,52 @@ format_type(PG_FUNCTION_ARGS) PG_RETURN_NULL(); type_oid = PG_GETARG_OID(0); + typemod = PG_ARGISNULL(1) ? -1 : PG_GETARG_INT32(1); - if (PG_ARGISNULL(1)) - result = format_type_internal(type_oid, -1, false, true, false); - else - { - typemod = PG_GETARG_INT32(1); - result = format_type_internal(type_oid, typemod, true, true, false); - } + result = format_type_extended(type_oid, typemod, + FORMAT_TYPE_TYPEMOD_GIVEN | + FORMAT_TYPE_ALLOW_INVALID); PG_RETURN_TEXT_P(cstring_to_text(result)); } /* - * This version is for use within the backend in error messages, etc. - * One difference is that it will fail for an invalid type. + * format_type_extended + * Generate a possibly-qualified type name. * - * The result is always a palloc'd string. - */ -char * -format_type_be(Oid type_oid) -{ - return format_type_internal(type_oid, -1, false, false, false); -} - -/* - * This version returns a name that is always qualified (unless it's one - * of the SQL-keyword type names, such as TIMESTAMP WITH TIME ZONE). - */ -char * -format_type_be_qualified(Oid type_oid) -{ - return format_type_internal(type_oid, -1, false, false, true); -} - -/* - * This version allows a nondefault typemod to be specified. - */ -char * -format_type_with_typemod(Oid type_oid, int32 typemod) -{ - return format_type_internal(type_oid, typemod, true, false, false); -} - -/* - * This version allows a nondefault typemod to be specified, and forces - * qualification of normal type names. + * The default is to only qualify if the type is not in the search path, to + * ignore the given typmod, and to raise an error if a non-existent type_oid is + * given. + * + * The following bits in 'flags' modify the behavior: + * - FORMAT_TYPE_TYPEMOD_GIVEN + * consider the given typmod in the output (may be -1 to request + * the default behavior) + * + * - FORMAT_TYPE_ALLOW_INVALID + * if the type OID is invalid or unknown, return ??? or such instead + * of failing + * + * - FORMAT_TYPE_FORCE_QUALIFY + * always schema-qualify type names, regardless of search_path */ char * -format_type_with_typemod_qualified(Oid type_oid, int32 typemod) +format_type_extended(Oid type_oid, int32 typemod, bits16 flags) { - return format_type_internal(type_oid, typemod, true, false, true); -} - -/* - * Common workhorse. - */ -static char * -format_type_internal(Oid type_oid, int32 typemod, - bool typemod_given, bool allow_invalid, - bool force_qualify) -{ - bool with_typemod = typemod_given && (typemod >= 0); HeapTuple tuple; Form_pg_type typeform; Oid array_base_type; bool is_array; char *buf; + bool with_typemod; - if (type_oid == InvalidOid && allow_invalid) + if (type_oid == InvalidOid && (flags & FORMAT_TYPE_ALLOW_INVALID) != 0) return pstrdup("-"); tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid)); if (!HeapTupleIsValid(tuple)) { - if (allow_invalid) + if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0) return pstrdup("???"); else elog(ERROR, "cache lookup failed for type %u", type_oid); @@ -162,15 +130,14 @@ format_type_internal(Oid type_oid, int32 typemod, */ array_base_type = typeform->typelem; - if (array_base_type != InvalidOid && - typeform->typstorage != 'p') + if (array_base_type != InvalidOid && typeform->typstorage != 'p') { /* Switch our attention to the array element type */ ReleaseSysCache(tuple); tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type)); if (!HeapTupleIsValid(tuple)) { - if (allow_invalid) + if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0) return pstrdup("???[]"); else elog(ERROR, "cache lookup failed for type %u", type_oid); @@ -182,6 +149,8 @@ format_type_internal(Oid type_oid, int32 typemod, else is_array = false; + with_typemod = (flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0 && (typemod >= 0); + /* * See if we want to special-case the output for certain built-in types. * Note that these special cases should all correspond to special @@ -200,7 +169,7 @@ format_type_internal(Oid type_oid, int32 typemod, case BITOID: if (with_typemod) buf = printTypmod("bit", typemod, typeform->typmodout); - else if (typemod_given) + else if ((flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0) { /* * bit with typmod -1 is not the same as BIT, which means @@ -219,7 +188,7 @@ format_type_internal(Oid type_oid, int32 typemod, case BPCHAROID: if (with_typemod) buf = printTypmod("character", typemod, typeform->typmodout); - else if (typemod_given) + else if ((flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0) { /* * bpchar with typmod -1 is not the same as CHARACTER, which @@ -313,13 +282,14 @@ format_type_internal(Oid type_oid, int32 typemod, /* * Default handling: report the name as it appears in the catalog. * Here, we must qualify the name if it is not visible in the search - * path, and we must double-quote it if it's not a standard identifier - * or if it matches any keyword. + * path or if caller requests it; and we must double-quote it if it's + * not a standard identifier or if it matches any keyword. */ char *nspname; char *typname; - if (!force_qualify && TypeIsVisible(type_oid)) + if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 && + TypeIsVisible(type_oid)) nspname = NULL; else nspname = get_namespace_name_or_temp(typeform->typnamespace); @@ -340,6 +310,36 @@ format_type_internal(Oid type_oid, int32 typemod, return buf; } +/* + * This version is for use within the backend in error messages, etc. + * One difference is that it will fail for an invalid type. + * + * The result is always a palloc'd string. + */ +char * +format_type_be(Oid type_oid) +{ + return format_type_extended(type_oid, -1, 0); +} + +/* + * This version returns a name that is always qualified (unless it's one + * of the SQL-keyword type names, such as TIMESTAMP WITH TIME ZONE). + */ +char * +format_type_be_qualified(Oid type_oid) +{ + return format_type_extended(type_oid, -1, FORMAT_TYPE_FORCE_QUALIFY); +} + +/* + * This version allows a nondefault typemod to be specified. + */ +char * +format_type_with_typemod(Oid type_oid, int32 typemod) +{ + return format_type_extended(type_oid, typemod, FORMAT_TYPE_TYPEMOD_GIVEN); +} /* * Add typmod decoration to the basic type name @@ -437,8 +437,8 @@ oidvectortypes(PG_FUNCTION_ARGS) for (num = 0; num < numargs; num++) { - char *typename = format_type_internal(oidArray->values[num], -1, - false, true, false); + char *typename = format_type_extended(oidArray->values[num], -1, + FORMAT_TYPE_ALLOW_INVALID); size_t slen = strlen(typename); if (left < (slen + 2)) diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 8bb57c5829..3e462f1a9c 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -112,10 +112,17 @@ extern void clean_ipv6_addr(int addr_family, char *addr); extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS); /* format_type.c */ + +/* Control flags for format_type_extended */ +#define FORMAT_TYPE_TYPEMOD_GIVEN 0x01 /* typemod defined by caller */ +#define FORMAT_TYPE_ALLOW_INVALID 0x02 /* allow invalid types */ +#define FORMAT_TYPE_FORCE_QUALIFY 0x04 /* force qualification of type */ +extern char *format_type_extended(Oid type_oid, int32 typemod, bits16 flags); + extern char *format_type_be(Oid type_oid); extern char *format_type_be_qualified(Oid type_oid); extern char *format_type_with_typemod(Oid type_oid, int32 typemod); -extern char *format_type_with_typemod_qualified(Oid type_oid, int32 typemod); + extern int32 type_maximum_size(Oid type_oid, int32 typemod); /* quote.c */ -- 2.40.0