* Display type names "nicely".
*
*
- * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
#include "utils/syscache.h"
#include "mb/pg_wchar.h"
-#define MAX_INT32_LEN 11
-
-static char *format_type_internal(Oid type_oid, int32 typemod,
- bool typemod_given, bool allow_invalid);
static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
-static char *
-psnprintf(size_t len, const char *fmt,...)
-/* This lets gcc check the format string for consistency. */
-__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
/*
* double quoted if it contains funny characters or matches a keyword.
*
* If typemod is NULL then we are formatting a type name in a context where
- * no typemod is available, eg a function argument or result type. This
+ * no typemod is available, eg a function argument or result type. This
* yields a slightly different result from specifying typemod = -1 in some
* cases. Given typemod = -1 we feel compelled to produce an output that
* the parser will interpret as having typemod -1, so that pg_dump will
- * produce CREATE TABLE commands that recreate the original state. But
+ * produce CREATE TABLE commands that recreate the original state. But
* given NULL typemod, we assume that the parser's interpretation of
* typemod doesn't matter, and so we are willing to output a slightly
- * "prettier" representation of the same type. For example, type = bpchar
+ * "prettier" representation of the same type. For example, type = bpchar
* and typemod = NULL gets you "character", whereas typemod = -1 gets you
* "bpchar" --- the former will be interpreted as character(1) by the
* parser, which does not yield typemod -1.
Oid type_oid;
int32 typemod;
char *result;
+ bits16 flags = FORMAT_TYPE_ALLOW_INVALID;
/* Since this function is not strict, we must test for null args */
if (PG_ARGISNULL(0))
type_oid = PG_GETARG_OID(0);
if (PG_ARGISNULL(1))
- result = format_type_internal(type_oid, -1, false, true);
+ typemod = -1;
else
{
typemod = PG_GETARG_INT32(1);
- result = format_type_internal(type_oid, typemod, true, true);
+ flags |= FORMAT_TYPE_TYPEMOD_GIVEN;
}
+ result = format_type_extended(type_oid, typemod, flags);
+
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);
-}
-
-/*
- * This version allows a nondefault typemod to be specified.
+ * The default behavior 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
+ * include the typmod in the output (typmod could still be -1 though)
+ * - 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
+ *
+ * Note that TYPEMOD_GIVEN is not interchangeable with "typemod == -1";
+ * see the comments above for format_type().
+ *
+ * Returns a palloc'd string.
*/
char *
-format_type_with_typemod(Oid type_oid, int32 typemod)
+format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
{
- return format_type_internal(type_oid, typemod, true, false);
-}
-
-
-
-static char *
-format_type_internal(Oid type_oid, int32 typemod,
- bool typemod_given, bool allow_invalid)
-{
- 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);
*/
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);
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
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
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
/*
* 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 (TypeIsVisible(type_oid))
+ if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 &&
+ TypeIsVisible(type_oid))
nspname = NULL;
else
- nspname = get_namespace_name(typeform->typnamespace);
+ nspname = get_namespace_name_or_temp(typeform->typnamespace);
typname = NameStr(typeform->typname);
}
if (is_array)
- buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
+ buf = psprintf("%s[]", buf);
ReleaseSysCache(tuple);
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
if (typmodout == InvalidOid)
{
/* Default behavior: just print the integer typmod with parens */
- res = psnprintf(strlen(typname) + MAX_INT32_LEN + 3, "%s(%d)",
- typname, (int) typmod);
+ res = psprintf("%s(%d)", typname, (int) typmod);
}
else
{
tmstr = DatumGetCString(OidFunctionCall1(typmodout,
Int32GetDatum(typmod)));
- res = psnprintf(strlen(typname) + strlen(tmstr) + 1, "%s%s",
- typname, tmstr);
+ res = psprintf("%s%s", typname, tmstr);
}
return res;
for (num = 0; num < numargs; num++)
{
- char *typename = format_type_internal(oidArray->values[num], -1,
- false, true);
+ char *typename = format_type_extended(oidArray->values[num], -1,
+ FORMAT_TYPE_ALLOW_INVALID);
size_t slen = strlen(typename);
if (left < (slen + 2))
PG_RETURN_TEXT_P(cstring_to_text(result));
}
-
-
-/* snprintf into a palloc'd string */
-static char *
-psnprintf(size_t len, const char *fmt,...)
-{
- va_list ap;
- char *buf;
-
- buf = palloc(len);
-
- va_start(ap, fmt);
- vsnprintf(buf, len, fmt, ap);
- va_end(ap);
-
- return buf;
-}