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