1 /*------------------------------------------------------------------------- 2 * 3 * format_type.c 4 * Display type names "nicely". 5 * 6 * 7 * Portions Copyright (c) 1996-2020, 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 "mb/pg_wchar.h" 24 #include "utils/builtins.h" 25 #include "utils/lsyscache.h" 26 #include "utils/numeric.h" 27 #include "utils/syscache.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 && 140 typeform->typstorage != TYPSTORAGE_PLAIN) 141 { 142 /* Switch our attention to the array element type */ 143 ReleaseSysCache(tuple); 144 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type)); 145 if (!HeapTupleIsValid(tuple)) 146 { 147 if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0) 148 return pstrdup("???[]"); addTypeForNEON(MVT VT,MVT PromotedLdStVT,MVT PromotedBitwiseVT)149 else 150 elog(ERROR, "cache lookup failed for type %u", type_oid); 151 } 152 typeform = (Form_pg_type) GETSTRUCT(tuple); 153 type_oid = array_base_type; 154 is_array = true; 155 } 156 else 157 is_array = false; 158 159 with_typemod = (flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0 && (typemod >= 0); 160 161 /* 162 * See if we want to special-case the output for certain built-in types. 163 * Note that these special cases should all correspond to special 164 * productions in gram.y, to ensure that the type name will be taken as a 165 * system type, not a user type of the same name. 166 * 167 * If we do not provide a special-case output here, the type name will be 168 * handled the same way as a user type name --- in particular, it will be 169 * double-quoted if it matches any lexer keyword. This behavior is 170 * essential for some cases, such as types "bit" and "char". 171 */ 172 buf = NULL; /* flag for no special case */ 173 174 switch (type_oid) 175 { 176 case BITOID: 177 if (with_typemod) 178 buf = printTypmod("bit", typemod, typeform->typmodout); 179 else if ((flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0) 180 { 181 /* 182 * bit with typmod -1 is not the same as BIT, which means 183 * BIT(1) per SQL spec. Report it as the quoted typename so 184 * that parser will not assign a bogus typmod. 185 */ 186 } 187 else 188 buf = pstrdup("bit"); 189 break; 190 191 case BOOLOID: 192 buf = pstrdup("boolean"); 193 break; 194 195 case BPCHAROID: 196 if (with_typemod) 197 buf = printTypmod("character", typemod, typeform->typmodout); 198 else if ((flags & FORMAT_TYPE_TYPEMOD_GIVEN) != 0) 199 { 200 /* 201 * bpchar with typmod -1 is not the same as CHARACTER, which 202 * means CHARACTER(1) per SQL spec. Report it as bpchar so 203 * that parser will not assign a bogus typmod. 204 */ 205 } 206 else 207 buf = pstrdup("character"); 208 break; 209 210 case FLOAT4OID: 211 buf = pstrdup("real"); 212 break; addDRTypeForNEON(MVT VT)213 214 case FLOAT8OID: 215 buf = pstrdup("double precision"); 216 break; 217 addQRTypeForNEON(MVT VT)218 case INT2OID: 219 buf = pstrdup("smallint"); 220 break; 221 222 case INT4OID: ARMTargetLowering(const TargetMachine & TM,const ARMSubtarget & STI)223 buf = pstrdup("integer"); 224 break; 225 226 case INT8OID: 227 buf = pstrdup("bigint"); 228 break; 229 230 case NUMERICOID: 231 if (with_typemod) 232 buf = printTypmod("numeric", typemod, typeform->typmodout); 233 else 234 buf = pstrdup("numeric"); 235 break; 236 237 case INTERVALOID: 238 if (with_typemod) 239 buf = printTypmod("interval", typemod, typeform->typmodout); 240 else 241 buf = pstrdup("interval"); 242 break; 243 244 case TIMEOID: 245 if (with_typemod) 246 buf = printTypmod("time", typemod, typeform->typmodout); 247 else 248 buf = pstrdup("time without time zone"); 249 break; 250 251 case TIMETZOID: 252 if (with_typemod) 253 buf = printTypmod("time", typemod, typeform->typmodout); 254 else 255 buf = pstrdup("time with time zone"); 256 break; 257 258 case TIMESTAMPOID: 259 if (with_typemod) 260 buf = printTypmod("timestamp", typemod, typeform->typmodout); 261 else 262 buf = pstrdup("timestamp without time zone"); 263 break; 264 265 case TIMESTAMPTZOID: 266 if (with_typemod) 267 buf = printTypmod("timestamp", typemod, typeform->typmodout); 268 else 269 buf = pstrdup("timestamp with time zone"); 270 break; 271 272 case VARBITOID: 273 if (with_typemod) 274 buf = printTypmod("bit varying", typemod, typeform->typmodout); 275 else 276 buf = pstrdup("bit varying"); 277 break; 278 279 case VARCHAROID: 280 if (with_typemod) 281 buf = printTypmod("character varying", typemod, typeform->typmodout); 282 else 283 buf = pstrdup("character varying"); 284 break; 285 } 286 287 if (buf == NULL) 288 { 289 /* 290 * Default handling: report the name as it appears in the catalog. 291 * Here, we must qualify the name if it is not visible in the search 292 * path or if caller requests it; and we must double-quote it if it's 293 * not a standard identifier or if it matches any keyword. 294 */ 295 char *nspname; 296 char *typname; 297 298 if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 && 299 TypeIsVisible(type_oid)) 300 nspname = NULL; 301 else 302 nspname = get_namespace_name_or_temp(typeform->typnamespace); 303 304 typname = NameStr(typeform->typname); 305 306 buf = quote_qualified_identifier(nspname, typname); 307 308 if (with_typemod) 309 buf = printTypmod(buf, typemod, typeform->typmodout); 310 } 311 312 if (is_array) 313 buf = psprintf("%s[]", buf); 314 315 ReleaseSysCache(tuple); 316 317 return buf; 318 } 319 320 /* 321 * This version is for use within the backend in error messages, etc. 322 * One difference is that it will fail for an invalid type. 323 * 324 * The result is always a palloc'd string. 325 */ 326 char * 327 format_type_be(Oid type_oid) 328 { 329 return format_type_extended(type_oid, -1, 0); 330 } 331 332 /* 333 * This version returns a name that is always qualified (unless it's one 334 * of the SQL-keyword type names, such as TIMESTAMP WITH TIME ZONE). 335 */ 336 char * 337 format_type_be_qualified(Oid type_oid) 338 { 339 return format_type_extended(type_oid, -1, FORMAT_TYPE_FORCE_QUALIFY); 340 } 341 342 /* 343 * This version allows a nondefault typemod to be specified. 344 */ 345 char * 346 format_type_with_typemod(Oid type_oid, int32 typemod) 347 { 348 return format_type_extended(type_oid, typemod, FORMAT_TYPE_TYPEMOD_GIVEN); 349 } 350 351 /* 352 * Add typmod decoration to the basic type name 353 */ 354 static char * 355 printTypmod(const char *typname, int32 typmod, Oid typmodout) 356 { 357 char *res; 358 359 /* Shouldn't be called if typmod is -1 */ 360 Assert(typmod >= 0); 361 362 if (typmodout == InvalidOid) 363 { 364 /* Default behavior: just print the integer typmod with parens */ 365 res = psprintf("%s(%d)", typname, (int) typmod); 366 } 367 else 368 { 369 /* Use the type-specific typmodout procedure */ 370 char *tmstr; 371 372 tmstr = DatumGetCString(OidFunctionCall1(typmodout, 373 Int32GetDatum(typmod))); 374 res = psprintf("%s%s", typname, tmstr); 375 } 376 377 return res; 378 } 379 380 381 /* 382 * type_maximum_size --- determine maximum width of a variable-width column 383 * 384 * If the max width is indeterminate, return -1. In particular, we return 385 * -1 for any type not known to this routine. We assume the caller has 386 * already determined that the type is a variable-width type, so it's not 387 * necessary to look up the type's pg_type tuple here. 388 * 389 * This may appear unrelated to format_type(), but in fact the two routines 390 * share knowledge of the encoding of typmod for different types, so it's 391 * convenient to keep them together. (XXX now that most of this knowledge 392 * has been pushed out of format_type into the typmodout functions, it's 393 * interesting to wonder if it's worth trying to factor this code too...) 394 */ 395 int32 396 type_maximum_size(Oid type_oid, int32 typemod) 397 { 398 if (typemod < 0) 399 return -1; 400 401 switch (type_oid) 402 { 403 case BPCHAROID: 404 case VARCHAROID: 405 /* typemod includes varlena header */ 406 407 /* typemod is in characters not bytes */ 408 return (typemod - VARHDRSZ) * 409 pg_encoding_max_length(GetDatabaseEncoding()) 410 + VARHDRSZ; 411 412 case NUMERICOID: 413 return numeric_maximum_size(typemod); 414 415 case VARBITOID: 416 case BITOID: 417 /* typemod is the (max) number of bits */ 418 return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE 419 + 2 * sizeof(int32); 420 } 421 422 /* Unknown type, or unlimited-width type such as 'text' */ 423 return -1; 424 } 425 426 427 /* 428 * oidvectortypes - converts a vector of type OIDs to "typname" list 429 */ 430 Datum 431 oidvectortypes(PG_FUNCTION_ARGS) 432 { 433 oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); 434 char *result; 435 int numargs = oidArray->dim1; 436 int num; 437 size_t total; 438 size_t left; 439 440 total = 20 * numargs + 1; 441 result = palloc(total); 442 result[0] = '\0'; 443 left = total - 1; 444 445 for (num = 0; num < numargs; num++) 446 { 447 char *typename = format_type_extended(oidArray->values[num], -1, 448 FORMAT_TYPE_ALLOW_INVALID); 449 size_t slen = strlen(typename); 450 451 if (left < (slen + 2)) 452 { 453 total += slen + 2; 454 result = repalloc(result, total); 455 left += slen + 2; 456 } 457 458 if (num > 0) 459 { 460 strcat(result, ", "); 461 left -= 2; 462 } 463 strcat(result, typename); 464 left -= slen; 465 } 466 467 PG_RETURN_TEXT_P(cstring_to_text(result)); 468 } 469