1 /*-------------------------------------------------------------------------
4 * Display type names "nicely".
7 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/format_type.c,v 1.27 2002/03/19 02:18:21 momjian Exp $
13 *-------------------------------------------------------------------------
21 #include "catalog/pg_type.h"
22 #include "utils/builtins.h"
23 #include "utils/datetime.h"
24 #include "utils/numeric.h"
25 #include "utils/syscache.h"
27 #include "mb/pg_wchar.h"
31 #define MASK(b) (1 << (b))
33 #define MAX_INT32_LEN 11
34 #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
36 static char *format_type_internal(Oid type_oid, int32 typemod,
37 bool typemod_given, bool allow_invalid);
38 static char *psnprintf(size_t len, const char *fmt, ...)
39 /* This lets gcc check the format string for consistency. */
40 __attribute__((format(printf, 2, 3)));
44 * SQL function: format_type(type_oid, typemod)
46 * `type_oid' is from pg_type.oid, `typemod' is from
47 * pg_attribute.atttypmod. This function will get the type name and
48 * format it and the modifier to canonical SQL format, if the type is
49 * a standard type. Otherwise you just get pg_type.typname back,
50 * double quoted if it contains funny characters.
52 * If typemod is NULL then we are formatting a type name in a context where
53 * no typemod is available, eg a function argument or result type. This
54 * yields a slightly different result from specifying typemod = -1 in some
55 * cases. Given typemod = -1 we feel compelled to produce an output that
56 * the parser will interpret as having typemod -1, so that pg_dump will
57 * produce CREATE TABLE commands that recreate the original state. But
58 * given NULL typemod, we assume that the parser's interpretation of
59 * typemod doesn't matter, and so we are willing to output a slightly
60 * "prettier" representation of the same type. For example, type = bpchar
61 * and typemod = NULL gets you "character", whereas typemod = -1 gets you
62 * "bpchar" --- the former will be interpreted as character(1) by the
63 * parser, which does not yield typemod -1.
65 * XXX encoding a meaning in typemod = NULL is ugly; it'd have been
66 * cleaner to make two functions of one and two arguments respectively.
67 * Not worth changing it now, however.
70 format_type(PG_FUNCTION_ARGS)
76 /* Since this function is not strict, we must test for null args */
80 type_oid = PG_GETARG_OID(0);
84 result = format_type_internal(type_oid, -1, false, true);
88 typemod = PG_GETARG_INT32(1);
89 result = format_type_internal(type_oid, typemod, true, true);
92 PG_RETURN_DATUM(_textin(result));
96 * This version is for use within the backend in error messages, etc.
97 * One difference is that it will fail for an invalid type.
99 * The result is always a palloc'd string.
102 format_type_be(Oid type_oid)
104 return format_type_internal(type_oid, -1, false, false);
108 * This version allows a nondefault typemod to be specified.
111 format_type_with_typemod(Oid type_oid, int32 typemod)
113 return format_type_internal(type_oid, typemod, true, false);
119 format_type_internal(Oid type_oid, int32 typemod,
120 bool typemod_given, bool allow_invalid)
122 bool with_typemod = typemod_given && (typemod >= 0);
131 if (type_oid == InvalidOid && allow_invalid)
134 tuple = SearchSysCache(TYPEOID,
135 ObjectIdGetDatum(type_oid),
137 if (!HeapTupleIsValid(tuple))
140 return pstrdup("???");
142 elog(ERROR, "could not locate data type with oid %u in catalog",
146 array_base_type = ((Form_pg_type) GETSTRUCT(tuple))->typelem;
147 typlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
148 typtype = ((Form_pg_type) GETSTRUCT(tuple))->typtype;
151 * Domains look alot like arrays, so lets process them first, and return
152 * back to avoid the array and 'standard' formatting procedures that are
153 * use for base types.
155 if (typtype == 'd') {
156 name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
159 * Double-quote the name if it's not a standard identifier.
160 * Note this is *necessary* for ruleutils.c's use.
162 if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
163 || isdigit((unsigned char) name[0]))
164 buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
168 ReleaseSysCache(tuple);
173 if (array_base_type != InvalidOid && typlen < 0)
175 /* Switch our attention to the array element type */
176 ReleaseSysCache(tuple);
177 tuple = SearchSysCache(TYPEOID,
178 ObjectIdGetDatum(array_base_type),
180 if (!HeapTupleIsValid(tuple))
183 return pstrdup("???[]");
185 elog(ERROR, "could not locate data type with oid %u in catalog",
189 type_oid = array_base_type;
198 buf = psnprintf(5 + MAX_INT32_LEN + 1, "bit(%d)",
200 else if (typemod_given)
203 * bit with typmod -1 is not the same as BIT, which means
204 * BIT(1) per SQL spec. Report it as the quoted typename
205 * so that parser will not assign a bogus typmod.
207 buf = pstrdup("\"bit\"");
210 buf = pstrdup("bit");
214 buf = pstrdup("boolean");
219 buf = psnprintf(11 + MAX_INT32_LEN + 1, "character(%d)",
220 (int) (typemod - VARHDRSZ));
221 else if (typemod_given)
224 * bpchar with typmod -1 is not the same as CHARACTER,
225 * which means CHARACTER(1) per SQL spec. Report it as
226 * bpchar so that parser will not assign a bogus typmod.
228 buf = pstrdup("bpchar");
231 buf = pstrdup("character");
236 * This char type is the single-byte version. You have to
237 * double-quote it to get at it in the parser.
239 buf = pstrdup("\"char\"");
243 buf = pstrdup("real");
247 buf = pstrdup("double precision");
251 buf = pstrdup("smallint");
255 buf = pstrdup("integer");
259 buf = pstrdup("bigint");
264 buf = psnprintf(10 + 2 * MAX_INT32_LEN + 1, "numeric(%d,%d)",
265 ((typemod - VARHDRSZ) >> 16) & 0xffff,
266 (typemod - VARHDRSZ) & 0xffff);
268 buf = pstrdup("numeric");
274 int fields = typemod >> 16;
275 int precision = typemod & 0xFFFF;
276 const char *fieldstr;
293 fieldstr = " minute";
296 fieldstr = " second";
298 case MASK(YEAR) | MASK(MONTH):
299 fieldstr = " year to month";
301 case MASK(DAY) | MASK(HOUR):
302 fieldstr = " day to hour";
304 case MASK(DAY) | MASK(HOUR) | MASK(MINUTE):
305 fieldstr = " day to minute";
307 case MASK(DAY) | MASK(HOUR) | MASK(MINUTE) | MASK(SECOND):
308 fieldstr = " day to second";
310 case MASK(HOUR) | MASK(MINUTE):
311 fieldstr = " hour to minute";
313 case MASK(HOUR) | MASK(MINUTE) | MASK(SECOND):
314 fieldstr = " hour to second";
316 case MASK(MINUTE) | MASK(SECOND):
317 fieldstr = " minute to second";
323 elog(LOG, "Invalid INTERVAL typmod 0x%x", typemod);
327 if (precision != 0xFFFF)
328 buf = psnprintf(100, "interval(%d)%s",
329 precision, fieldstr);
331 buf = psnprintf(100, "interval%s",
335 buf = pstrdup("interval");
340 buf = psnprintf(50, "time(%d) without time zone",
343 buf = pstrdup("time without time zone");
348 buf = psnprintf(50, "time(%d) with time zone",
351 buf = pstrdup("time with time zone");
356 buf = psnprintf(50, "timestamp(%d) without time zone",
359 buf = pstrdup("timestamp without time zone");
364 buf = psnprintf(50, "timestamp(%d) with time zone",
367 buf = pstrdup("timestamp with time zone");
372 buf = psnprintf(13 + MAX_INT32_LEN + 1, "bit varying(%d)",
375 buf = pstrdup("bit varying");
380 buf = psnprintf(19 + MAX_INT32_LEN + 1,
381 "character varying(%d)",
382 (int) (typemod - VARHDRSZ));
384 buf = pstrdup("character varying");
388 name = NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname);
390 * Double-quote the name if it's not a standard identifier.
391 * Note this is *necessary* for ruleutils.c's use.
393 if (strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789_") != strlen(name)
394 || isdigit((unsigned char) name[0]))
395 buf = psnprintf(strlen(name) + 3, "\"%s\"", name);
402 buf = psnprintf(strlen(buf) + 3, "%s[]", buf);
404 ReleaseSysCache(tuple);
411 * type_maximum_size --- determine maximum width of a varlena column
413 * If the max width is indeterminate, return -1. In particular, we return
414 * -1 for any type not known to this routine. We assume the caller has
415 * already determined that the type is a varlena type, so it's not
416 * necessary to look up the type's pg_type tuple here.
418 * This may appear unrelated to format_type(), but in fact the two routines
419 * share knowledge of the encoding of typmod for different types, so it's
420 * convenient to keep them together.
423 type_maximum_size(Oid type_oid, int32 typemod)
432 /* typemod includes varlena header */
434 /* typemod is in characters not bytes */
435 return (typemod - VARHDRSZ) *
436 pg_encoding_max_length(GetDatabaseEncoding())
443 /* precision (ie, max # of digits) is in upper bits of typmod */
444 if (typemod > VARHDRSZ)
446 int precision = ((typemod - VARHDRSZ) >> 16) & 0xffff;
448 /* Numeric stores 2 decimal digits/byte, plus header */
449 return (precision + 1) / 2 + NUMERIC_HDRSZ;
455 /* typemod is the (max) number of bits */
456 return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
460 /* Unknown type, or unlimited-width type such as 'text' */
466 * oidvectortypes - converts a vector of type OIDs to "typname" list
468 * The interface for this function is wrong: it should be told how many
469 * OIDs are significant in the input vector, so that trailing InvalidOid
470 * argument types can be recognized.
473 oidvectortypes(PG_FUNCTION_ARGS)
475 Oid *oidArray = (Oid *) PG_GETARG_POINTER(0);
482 /* Try to guess how many args there are :-( */
484 for (num = 0; num < FUNC_MAX_ARGS; num++)
486 if (oidArray[num] != InvalidOid)
490 total = 20 * numargs + 1;
491 result = palloc(total);
495 for (num = 0; num < numargs; num++)
497 char *typename = format_type_internal(oidArray[num], -1,
499 size_t slen = strlen(typename);
501 if (left < (slen + 2))
504 result = repalloc(result, total);
510 strcat(result, ", ");
513 strcat(result, typename);
517 PG_RETURN_DATUM(_textin(result));
521 /* snprintf into a palloc'd string */
523 psnprintf(size_t len, const char *fmt, ...)
531 vsnprintf(buf, len, fmt, ap);