1 /*-------------------------------------------------------------------------
2  *
3  * format_type.c
4  *	  Display type names "nicely".
5  *
6  *
7  * Portions Copyright (c) 1996-2016, 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
format_type(PG_FUNCTION_ARGS)64 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 	if (PG_ARGISNULL(0))
72 		PG_RETURN_NULL();
73 
74 	type_oid = PG_GETARG_OID(0);
75 
76 	if (PG_ARGISNULL(1))
77 		result = format_type_internal(type_oid, -1, false, true, false);
78 	else
79 	{
80 		typemod = PG_GETARG_INT32(1);
81 		result = format_type_internal(type_oid, typemod, true, true, false);
82 	}
83 
84 	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 *
format_type_be(Oid type_oid)94 format_type_be(Oid type_oid)
95 {
96 	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 *
format_type_be_qualified(Oid type_oid)104 format_type_be_qualified(Oid type_oid)
105 {
106 	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 *
format_type_with_typemod(Oid type_oid,int32 typemod)113 format_type_with_typemod(Oid type_oid, int32 typemod)
114 {
115 	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 *
format_type_with_typemod_qualified(Oid type_oid,int32 typemod)123 format_type_with_typemod_qualified(Oid type_oid, int32 typemod)
124 {
125 	return format_type_internal(type_oid, typemod, true, false, true);
126 }
127 
128 /*
129  * Common workhorse.
130  */
131 static char *
format_type_internal(Oid type_oid,int32 typemod,bool typemod_given,bool allow_invalid,bool force_qualify)132 format_type_internal(Oid type_oid, int32 typemod,
133 					 bool typemod_given, bool allow_invalid,
134 					 bool force_qualify)
135 {
136 	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 	if (type_oid == InvalidOid && allow_invalid)
144 		return pstrdup("-");
145 
146 	tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
147 	if (!HeapTupleIsValid(tuple))
148 	{
149 		if (allow_invalid)
150 			return pstrdup("???");
151 		else
152 			elog(ERROR, "cache lookup failed for type %u", type_oid);
153 	}
154 	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 	array_base_type = typeform->typelem;
164 
165 	if (array_base_type != InvalidOid &&
166 		typeform->typstorage != 'p')
167 	{
168 		/* Switch our attention to the array element type */
169 		ReleaseSysCache(tuple);
170 		tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
171 		if (!HeapTupleIsValid(tuple))
172 		{
173 			if (allow_invalid)
174 				return pstrdup("???[]");
175 			else
176 				elog(ERROR, "cache lookup failed for type %u", type_oid);
177 		}
178 		typeform = (Form_pg_type) GETSTRUCT(tuple);
179 		type_oid = array_base_type;
180 		is_array = true;
181 	}
182 	else
183 		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 	buf = NULL;					/* flag for no special case */
197 
198 	switch (type_oid)
199 	{
200 		case BITOID:
201 			if (with_typemod)
202 				buf = printTypmod("bit", typemod, typeform->typmodout);
203 			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 				buf = pstrdup("bit");
213 			break;
214 
215 		case BOOLOID:
216 			buf = pstrdup("boolean");
217 			break;
218 
219 		case BPCHAROID:
220 			if (with_typemod)
221 				buf = printTypmod("character", typemod, typeform->typmodout);
222 			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 				buf = pstrdup("character");
232 			break;
233 
234 		case FLOAT4OID:
235 			buf = pstrdup("real");
236 			break;
237 
238 		case FLOAT8OID:
239 			buf = pstrdup("double precision");
240 			break;
241 
242 		case INT2OID:
243 			buf = pstrdup("smallint");
244 			break;
245 
246 		case INT4OID:
247 			buf = pstrdup("integer");
248 			break;
249 
250 		case INT8OID:
251 			buf = pstrdup("bigint");
252 			break;
253 
254 		case NUMERICOID:
255 			if (with_typemod)
256 				buf = printTypmod("numeric", typemod, typeform->typmodout);
257 			else
258 				buf = pstrdup("numeric");
259 			break;
260 
261 		case INTERVALOID:
262 			if (with_typemod)
263 				buf = printTypmod("interval", typemod, typeform->typmodout);
264 			else
265 				buf = pstrdup("interval");
266 			break;
267 
268 		case TIMEOID:
269 			if (with_typemod)
270 				buf = printTypmod("time", typemod, typeform->typmodout);
271 			else
272 				buf = pstrdup("time without time zone");
273 			break;
274 
275 		case TIMETZOID:
276 			if (with_typemod)
277 				buf = printTypmod("time", typemod, typeform->typmodout);
278 			else
279 				buf = pstrdup("time with time zone");
280 			break;
281 
282 		case TIMESTAMPOID:
283 			if (with_typemod)
284 				buf = printTypmod("timestamp", typemod, typeform->typmodout);
285 			else
286 				buf = pstrdup("timestamp without time zone");
287 			break;
288 
289 		case TIMESTAMPTZOID:
290 			if (with_typemod)
291 				buf = printTypmod("timestamp", typemod, typeform->typmodout);
292 			else
293 				buf = pstrdup("timestamp with time zone");
294 			break;
295 
296 		case VARBITOID:
297 			if (with_typemod)
298 				buf = printTypmod("bit varying", typemod, typeform->typmodout);
299 			else
300 				buf = pstrdup("bit varying");
301 			break;
302 
303 		case VARCHAROID:
304 			if (with_typemod)
305 				buf = printTypmod("character varying", typemod, typeform->typmodout);
306 			else
307 				buf = pstrdup("character varying");
308 			break;
309 	}
310 
311 	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 		if (!force_qualify && TypeIsVisible(type_oid))
323 			nspname = NULL;
324 		else
325 			nspname = get_namespace_name_or_temp(typeform->typnamespace);
326 
327 		typname = NameStr(typeform->typname);
328 
329 		buf = quote_qualified_identifier(nspname, typname);
330 
331 		if (with_typemod)
332 			buf = printTypmod(buf, typemod, typeform->typmodout);
333 	}
334 
335 	if (is_array)
336 		buf = psprintf("%s[]", buf);
337 
338 	ReleaseSysCache(tuple);
339 
340 	return buf;
341 }
342 
343 
344 /*
345  * Add typmod decoration to the basic type name
346  */
347 static char *
printTypmod(const char * typname,int32 typmod,Oid typmodout)348 printTypmod(const char *typname, int32 typmod, Oid typmodout)
349 {
350 	char	   *res;
351 
352 	/* Shouldn't be called if typmod is -1 */
353 	Assert(typmod >= 0);
354 
355 	if (typmodout == InvalidOid)
356 	{
357 		/* Default behavior: just print the integer typmod with parens */
358 		res = psprintf("%s(%d)", typname, (int) typmod);
359 	}
360 	else
361 	{
362 		/* Use the type-specific typmodout procedure */
363 		char	   *tmstr;
364 
365 		tmstr = DatumGetCString(OidFunctionCall1(typmodout,
366 												 Int32GetDatum(typmod)));
367 		res = psprintf("%s%s", typname, tmstr);
368 	}
369 
370 	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
type_maximum_size(Oid type_oid,int32 typemod)389 type_maximum_size(Oid type_oid, int32 typemod)
390 {
391 	if (typemod < 0)
392 		return -1;
393 
394 	switch (type_oid)
395 	{
396 		case BPCHAROID:
397 		case VARCHAROID:
398 			/* typemod includes varlena header */
399 
400 			/* typemod is in characters not bytes */
401 			return (typemod - VARHDRSZ) *
402 				pg_encoding_max_length(GetDatabaseEncoding())
403 				+ VARHDRSZ;
404 
405 		case NUMERICOID:
406 			return numeric_maximum_size(typemod);
407 
408 		case VARBITOID:
409 		case BITOID:
410 			/* typemod is the (max) number of bits */
411 			return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
412 				+ 2 * sizeof(int32);
413 	}
414 
415 	/* Unknown type, or unlimited-width type such as 'text' */
416 	return -1;
417 }
418 
419 
420 /*
421  * oidvectortypes			- converts a vector of type OIDs to "typname" list
422  */
423 Datum
oidvectortypes(PG_FUNCTION_ARGS)424 oidvectortypes(PG_FUNCTION_ARGS)
425 {
426 	oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
427 	char	   *result;
428 	int			numargs = oidArray->dim1;
429 	int			num;
430 	size_t		total;
431 	size_t		left;
432 
433 	total = 20 * numargs + 1;
434 	result = palloc(total);
435 	result[0] = '\0';
436 	left = total - 1;
437 
438 	for (num = 0; num < numargs; num++)
439 	{
440 		char	   *typename = format_type_internal(oidArray->values[num], -1,
441 													false, true, false);
442 		size_t		slen = strlen(typename);
443 
444 		if (left < (slen + 2))
445 		{
446 			total += slen + 2;
447 			result = repalloc(result, total);
448 			left += slen + 2;
449 		}
450 
451 		if (num > 0)
452 		{
453 			strcat(result, ", ");
454 			left -= 2;
455 		}
456 		strcat(result, typename);
457 		left -= slen;
458 	}
459 
460 	PG_RETURN_TEXT_P(cstring_to_text(result));
461 }
462