LCOV - code coverage report
Current view: top level - src/backend/utils/adt - format_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL 14devel Lines: 140 172 81.4 %
Date: 2021-01-26 02:06:48 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13