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