Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * format_type.c
4 : * Display type names "nicely".
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/adt/format_type.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include <ctype.h>
19 :
20 : #include "access/htup_details.h"
21 : #include "catalog/namespace.h"
22 : #include "catalog/pg_type.h"
23 : #include "utils/builtins.h"
24 : #include "utils/lsyscache.h"
25 : #include "utils/numeric.h"
26 : #include "utils/syscache.h"
27 : #include "mb/pg_wchar.h"
28 :
29 : #define MAX_INT32_LEN 11
30 :
31 : static char *format_type_internal(Oid type_oid, int32 typemod,
32 : bool typemod_given, bool allow_invalid,
33 : bool force_qualify);
34 : static char *printTypmod(const char *typname, int32 typmod, Oid typmodout);
35 :
36 :
37 : /*
38 : * SQL function: format_type(type_oid, typemod)
39 : *
40 : * `type_oid' is from pg_type.oid, `typemod' is from
41 : * pg_attribute.atttypmod. This function will get the type name and
42 : * format it and the modifier to canonical SQL format, if the type is
43 : * a standard type. Otherwise you just get pg_type.typname back,
44 : * double quoted if it contains funny characters or matches a keyword.
45 : *
46 : * If typemod is NULL then we are formatting a type name in a context where
47 : * no typemod is available, eg a function argument or result type. This
48 : * yields a slightly different result from specifying typemod = -1 in some
49 : * cases. Given typemod = -1 we feel compelled to produce an output that
50 : * the parser will interpret as having typemod -1, so that pg_dump will
51 : * produce CREATE TABLE commands that recreate the original state. But
52 : * given NULL typemod, we assume that the parser's interpretation of
53 : * typemod doesn't matter, and so we are willing to output a slightly
54 : * "prettier" representation of the same type. For example, type = bpchar
55 : * and typemod = NULL gets you "character", whereas typemod = -1 gets you
56 : * "bpchar" --- the former will be interpreted as character(1) by the
57 : * parser, which does not yield typemod -1.
58 : *
59 : * XXX encoding a meaning in typemod = NULL is ugly; it'd have been
60 : * cleaner to make two functions of one and two arguments respectively.
61 : * Not worth changing it now, however.
62 : */
63 : Datum
64 647 : format_type(PG_FUNCTION_ARGS)
65 : {
66 : Oid type_oid;
67 : int32 typemod;
68 : char *result;
69 :
70 : /* Since this function is not strict, we must test for null args */
71 647 : if (PG_ARGISNULL(0))
72 0 : PG_RETURN_NULL();
73 :
74 647 : type_oid = PG_GETARG_OID(0);
75 :
76 647 : if (PG_ARGISNULL(1))
77 22 : result = format_type_internal(type_oid, -1, false, true, false);
78 : else
79 : {
80 625 : typemod = PG_GETARG_INT32(1);
81 625 : result = format_type_internal(type_oid, typemod, true, true, false);
82 : }
83 :
84 647 : PG_RETURN_TEXT_P(cstring_to_text(result));
85 : }
86 :
87 : /*
88 : * This version is for use within the backend in error messages, etc.
89 : * One difference is that it will fail for an invalid type.
90 : *
91 : * The result is always a palloc'd string.
92 : */
93 : char *
94 4871 : format_type_be(Oid type_oid)
95 : {
96 4871 : return format_type_internal(type_oid, -1, false, false, false);
97 : }
98 :
99 : /*
100 : * This version returns a name that is always qualified (unless it's one
101 : * of the SQL-keyword type names, such as TIMESTAMP WITH TIME ZONE).
102 : */
103 : char *
104 210 : format_type_be_qualified(Oid type_oid)
105 : {
106 210 : return format_type_internal(type_oid, -1, false, false, true);
107 : }
108 :
109 : /*
110 : * This version allows a nondefault typemod to be specified.
111 : */
112 : char *
113 1925 : format_type_with_typemod(Oid type_oid, int32 typemod)
114 : {
115 1925 : return format_type_internal(type_oid, typemod, true, false, false);
116 : }
117 :
118 : /*
119 : * This version allows a nondefault typemod to be specified, and forces
120 : * qualification of normal type names.
121 : */
122 : char *
123 0 : format_type_with_typemod_qualified(Oid type_oid, int32 typemod)
124 : {
125 0 : return format_type_internal(type_oid, typemod, true, false, true);
126 : }
127 :
128 : /*
129 : * Common workhorse.
130 : */
131 : static char *
132 7653 : format_type_internal(Oid type_oid, int32 typemod,
133 : bool typemod_given, bool allow_invalid,
134 : bool force_qualify)
135 : {
136 7653 : bool with_typemod = typemod_given && (typemod >= 0);
137 : HeapTuple tuple;
138 : Form_pg_type typeform;
139 : Oid array_base_type;
140 : bool is_array;
141 : char *buf;
142 :
143 7653 : if (type_oid == InvalidOid && allow_invalid)
144 0 : return pstrdup("-");
145 :
146 7653 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
147 7653 : if (!HeapTupleIsValid(tuple))
148 : {
149 0 : if (allow_invalid)
150 0 : return pstrdup("???");
151 : else
152 0 : elog(ERROR, "cache lookup failed for type %u", type_oid);
153 : }
154 7653 : typeform = (Form_pg_type) GETSTRUCT(tuple);
155 :
156 : /*
157 : * Check if it's a regular (variable length) array type. Fixed-length
158 : * array types such as "name" shouldn't get deconstructed. As of Postgres
159 : * 8.1, rather than checking typlen we check the toast property, and don't
160 : * deconstruct "plain storage" array types --- this is because we don't
161 : * want to show oidvector as oid[].
162 : */
163 7653 : array_base_type = typeform->typelem;
164 :
165 9518 : if (array_base_type != InvalidOid &&
166 1865 : typeform->typstorage != 'p')
167 : {
168 : /* Switch our attention to the array element type */
169 1494 : ReleaseSysCache(tuple);
170 1494 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
171 1494 : if (!HeapTupleIsValid(tuple))
172 : {
173 0 : if (allow_invalid)
174 0 : return pstrdup("???[]");
175 : else
176 0 : elog(ERROR, "cache lookup failed for type %u", type_oid);
177 : }
178 1494 : typeform = (Form_pg_type) GETSTRUCT(tuple);
179 1494 : type_oid = array_base_type;
180 1494 : is_array = true;
181 : }
182 : else
183 6159 : is_array = false;
184 :
185 : /*
186 : * See if we want to special-case the output for certain built-in types.
187 : * Note that these special cases should all correspond to special
188 : * productions in gram.y, to ensure that the type name will be taken as a
189 : * system type, not a user type of the same name.
190 : *
191 : * If we do not provide a special-case output here, the type name will be
192 : * handled the same way as a user type name --- in particular, it will be
193 : * double-quoted if it matches any lexer keyword. This behavior is
194 : * essential for some cases, such as types "bit" and "char".
195 : */
196 7653 : buf = NULL; /* flag for no special case */
197 :
198 7653 : switch (type_oid)
199 : {
200 : case BITOID:
201 27 : if (with_typemod)
202 15 : buf = printTypmod("bit", typemod, typeform->typmodout);
203 12 : else if (typemod_given)
204 : {
205 : /*
206 : * bit with typmod -1 is not the same as BIT, which means
207 : * BIT(1) per SQL spec. Report it as the quoted typename so
208 : * that parser will not assign a bogus typmod.
209 : */
210 : }
211 : else
212 12 : buf = pstrdup("bit");
213 27 : break;
214 :
215 : case BOOLOID:
216 37 : buf = pstrdup("boolean");
217 37 : break;
218 :
219 : case BPCHAROID:
220 74 : if (with_typemod)
221 3 : buf = printTypmod("character", typemod, typeform->typmodout);
222 71 : else if (typemod_given)
223 : {
224 : /*
225 : * bpchar with typmod -1 is not the same as CHARACTER, which
226 : * means CHARACTER(1) per SQL spec. Report it as bpchar so
227 : * that parser will not assign a bogus typmod.
228 : */
229 : }
230 : else
231 32 : buf = pstrdup("character");
232 74 : break;
233 :
234 : case FLOAT4OID:
235 70 : buf = pstrdup("real");
236 70 : break;
237 :
238 : case FLOAT8OID:
239 146 : buf = pstrdup("double precision");
240 146 : break;
241 :
242 : case INT2OID:
243 116 : buf = pstrdup("smallint");
244 116 : break;
245 :
246 : case INT4OID:
247 911 : buf = pstrdup("integer");
248 911 : break;
249 :
250 : case INT8OID:
251 175 : buf = pstrdup("bigint");
252 175 : break;
253 :
254 : case NUMERICOID:
255 48 : if (with_typemod)
256 4 : buf = printTypmod("numeric", typemod, typeform->typmodout);
257 : else
258 44 : buf = pstrdup("numeric");
259 48 : break;
260 :
261 : case INTERVALOID:
262 29 : if (with_typemod)
263 0 : buf = printTypmod("interval", typemod, typeform->typmodout);
264 : else
265 29 : buf = pstrdup("interval");
266 29 : break;
267 :
268 : case TIMEOID:
269 29 : if (with_typemod)
270 0 : buf = printTypmod("time", typemod, typeform->typmodout);
271 : else
272 29 : buf = pstrdup("time without time zone");
273 29 : break;
274 :
275 : case TIMETZOID:
276 32 : if (with_typemod)
277 0 : buf = printTypmod("time", typemod, typeform->typmodout);
278 : else
279 32 : buf = pstrdup("time with time zone");
280 32 : break;
281 :
282 : case TIMESTAMPOID:
283 30 : if (with_typemod)
284 0 : buf = printTypmod("timestamp", typemod, typeform->typmodout);
285 : else
286 30 : buf = pstrdup("timestamp without time zone");
287 30 : break;
288 :
289 : case TIMESTAMPTZOID:
290 42 : if (with_typemod)
291 0 : buf = printTypmod("timestamp", typemod, typeform->typmodout);
292 : else
293 42 : buf = pstrdup("timestamp with time zone");
294 42 : break;
295 :
296 : case VARBITOID:
297 27 : if (with_typemod)
298 15 : buf = printTypmod("bit varying", typemod, typeform->typmodout);
299 : else
300 12 : buf = pstrdup("bit varying");
301 27 : break;
302 :
303 : case VARCHAROID:
304 39 : if (with_typemod)
305 9 : buf = printTypmod("character varying", typemod, typeform->typmodout);
306 : else
307 30 : buf = pstrdup("character varying");
308 39 : break;
309 : }
310 :
311 7653 : if (buf == NULL)
312 : {
313 : /*
314 : * Default handling: report the name as it appears in the catalog.
315 : * Here, we must qualify the name if it is not visible in the search
316 : * path, and we must double-quote it if it's not a standard identifier
317 : * or if it matches any keyword.
318 : */
319 : char *nspname;
320 : char *typname;
321 :
322 5860 : if (!force_qualify && TypeIsVisible(type_oid))
323 5155 : nspname = NULL;
324 : else
325 705 : nspname = get_namespace_name_or_temp(typeform->typnamespace);
326 :
327 5860 : typname = NameStr(typeform->typname);
328 :
329 5860 : buf = quote_qualified_identifier(nspname, typname);
330 :
331 5860 : if (with_typemod)
332 1 : buf = printTypmod(buf, typemod, typeform->typmodout);
333 : }
334 :
335 7653 : if (is_array)
336 1494 : buf = psprintf("%s[]", buf);
337 :
338 7653 : ReleaseSysCache(tuple);
339 :
340 7653 : return buf;
341 : }
342 :
343 :
344 : /*
345 : * Add typmod decoration to the basic type name
346 : */
347 : static char *
348 47 : printTypmod(const char *typname, int32 typmod, Oid typmodout)
349 : {
350 : char *res;
351 :
352 : /* Shouldn't be called if typmod is -1 */
353 47 : Assert(typmod >= 0);
354 :
355 47 : if (typmodout == InvalidOid)
356 : {
357 : /* Default behavior: just print the integer typmod with parens */
358 0 : res = psprintf("%s(%d)", typname, (int) typmod);
359 : }
360 : else
361 : {
362 : /* Use the type-specific typmodout procedure */
363 : char *tmstr;
364 :
365 47 : tmstr = DatumGetCString(OidFunctionCall1(typmodout,
366 : Int32GetDatum(typmod)));
367 47 : res = psprintf("%s%s", typname, tmstr);
368 : }
369 :
370 47 : return res;
371 : }
372 :
373 :
374 : /*
375 : * type_maximum_size --- determine maximum width of a variable-width column
376 : *
377 : * If the max width is indeterminate, return -1. In particular, we return
378 : * -1 for any type not known to this routine. We assume the caller has
379 : * already determined that the type is a variable-width type, so it's not
380 : * necessary to look up the type's pg_type tuple here.
381 : *
382 : * This may appear unrelated to format_type(), but in fact the two routines
383 : * share knowledge of the encoding of typmod for different types, so it's
384 : * convenient to keep them together. (XXX now that most of this knowledge
385 : * has been pushed out of format_type into the typmodout functions, it's
386 : * interesting to wonder if it's worth trying to factor this code too...)
387 : */
388 : int32
389 24335 : type_maximum_size(Oid type_oid, int32 typemod)
390 : {
391 24335 : if (typemod < 0)
392 21535 : return -1;
393 :
394 2800 : switch (type_oid)
395 : {
396 : case BPCHAROID:
397 : case VARCHAROID:
398 : /* typemod includes varlena header */
399 :
400 : /* typemod is in characters not bytes */
401 4002 : return (typemod - VARHDRSZ) *
402 2001 : pg_encoding_max_length(GetDatabaseEncoding())
403 : + VARHDRSZ;
404 :
405 : case NUMERICOID:
406 571 : return numeric_maximum_size(typemod);
407 :
408 : case VARBITOID:
409 : case BITOID:
410 : /* typemod is the (max) number of bits */
411 318 : return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
412 159 : + 2 * sizeof(int32);
413 : }
414 :
415 : /* Unknown type, or unlimited-width type such as 'text' */
416 69 : return -1;
417 : }
418 :
419 :
420 : /*
421 : * oidvectortypes - converts a vector of type OIDs to "typname" list
422 : */
423 : Datum
424 0 : oidvectortypes(PG_FUNCTION_ARGS)
425 : {
426 0 : oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0);
427 : char *result;
428 0 : int numargs = oidArray->dim1;
429 : int num;
430 : size_t total;
431 : size_t left;
432 :
433 0 : total = 20 * numargs + 1;
434 0 : result = palloc(total);
435 0 : result[0] = '\0';
436 0 : left = total - 1;
437 :
438 0 : for (num = 0; num < numargs; num++)
439 : {
440 0 : char *typename = format_type_internal(oidArray->values[num], -1,
441 : false, true, false);
442 0 : size_t slen = strlen(typename);
443 :
444 0 : if (left < (slen + 2))
445 : {
446 0 : total += slen + 2;
447 0 : result = repalloc(result, total);
448 0 : left += slen + 2;
449 : }
450 :
451 0 : if (num > 0)
452 : {
453 0 : strcat(result, ", ");
454 0 : left -= 2;
455 : }
456 0 : strcat(result, typename);
457 0 : left -= slen;
458 : }
459 :
460 0 : PG_RETURN_TEXT_P(cstring_to_text(result));
461 : }
|