LCOV - code coverage report
Current view: top level - src/backend/utils/adt - format_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 117 145 80.7 %
Date: 2019-06-19 16:07:09 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-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       26714 : format_type(PG_FUNCTION_ARGS)
      60             : {
      61             :     Oid         type_oid;
      62             :     int32       typemod;
      63             :     char       *result;
      64       26714 :     bits16      flags = FORMAT_TYPE_ALLOW_INVALID;
      65             : 
      66             :     /* Since this function is not strict, we must test for null args */
      67       26714 :     if (PG_ARGISNULL(0))
      68         466 :         PG_RETURN_NULL();
      69             : 
      70       26248 :     type_oid = PG_GETARG_OID(0);
      71             : 
      72       26248 :     if (PG_ARGISNULL(1))
      73        3168 :         typemod = -1;
      74             :     else
      75             :     {
      76       23080 :         typemod = PG_GETARG_INT32(1);
      77       23080 :         flags |= FORMAT_TYPE_TYPEMOD_GIVEN;
      78             :     }
      79             : 
      80       26248 :     result = format_type_extended(type_oid, typemod, flags);
      81             : 
      82       26248 :     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      481462 : 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      481462 :     if (type_oid == InvalidOid && (flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     118          18 :         return pstrdup("-");
     119             : 
     120      481444 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
     121      481444 :     if (!HeapTupleIsValid(tuple))
     122             :     {
     123           0 :         if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     124           0 :             return pstrdup("???");
     125             :         else
     126           0 :             elog(ERROR, "cache lookup failed for type %u", type_oid);
     127             :     }
     128      481444 :     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      481444 :     array_base_type = typeform->typelem;
     138             : 
     139      481444 :     if (array_base_type != InvalidOid && typeform->typstorage != 'p')
     140             :     {
     141             :         /* Switch our attention to the array element type */
     142       17068 :         ReleaseSysCache(tuple);
     143       17068 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
     144       17068 :         if (!HeapTupleIsValid(tuple))
     145             :         {
     146           0 :             if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     147           0 :                 return pstrdup("???[]");
     148             :             else
     149           0 :                 elog(ERROR, "cache lookup failed for type %u", type_oid);
     150             :         }
     151       17068 :         typeform = (Form_pg_type) GETSTRUCT(tuple);
     152       17068 :         type_oid = array_base_type;
     153       17068 :         is_array = true;
     154             :     }
     155             :     else
     156      464376 :         is_array = false;
     157             : 
     158      481444 :     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      481444 :     buf = NULL;                 /* flag for no special case */
     172             : 
     173      481444 :     switch (type_oid)
     174             :     {
     175             :         case BITOID:
     176         232 :             if (with_typemod)
     177         134 :                 buf = printTypmod("bit", typemod, typeform->typmodout);
     178          98 :             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          60 :                 buf = pstrdup("bit");
     188         232 :             break;
     189             : 
     190             :         case BOOLOID:
     191        7396 :             buf = pstrdup("boolean");
     192        7396 :             break;
     193             : 
     194             :         case BPCHAROID:
     195        1208 :             if (with_typemod)
     196         444 :                 buf = printTypmod("character", typemod, typeform->typmodout);
     197         764 :             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         380 :                 buf = pstrdup("character");
     207        1208 :             break;
     208             : 
     209             :         case FLOAT4OID:
     210         450 :             buf = pstrdup("real");
     211         450 :             break;
     212             : 
     213             :         case FLOAT8OID:
     214        1724 :             buf = pstrdup("double precision");
     215        1724 :             break;
     216             : 
     217             :         case INT2OID:
     218         942 :             buf = pstrdup("smallint");
     219         942 :             break;
     220             : 
     221             :         case INT4OID:
     222      135488 :             buf = pstrdup("integer");
     223      135488 :             break;
     224             : 
     225             :         case INT8OID:
     226        3196 :             buf = pstrdup("bigint");
     227        3196 :             break;
     228             : 
     229             :         case NUMERICOID:
     230        1040 :             if (with_typemod)
     231         136 :                 buf = printTypmod("numeric", typemod, typeform->typmodout);
     232             :             else
     233         904 :                 buf = pstrdup("numeric");
     234        1040 :             break;
     235             : 
     236             :         case INTERVALOID:
     237         206 :             if (with_typemod)
     238           0 :                 buf = printTypmod("interval", typemod, typeform->typmodout);
     239             :             else
     240         206 :                 buf = pstrdup("interval");
     241         206 :             break;
     242             : 
     243             :         case TIMEOID:
     244         148 :             if (with_typemod)
     245           6 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     246             :             else
     247         142 :                 buf = pstrdup("time without time zone");
     248         148 :             break;
     249             : 
     250             :         case TIMETZOID:
     251         152 :             if (with_typemod)
     252           6 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     253             :             else
     254         146 :                 buf = pstrdup("time with time zone");
     255         152 :             break;
     256             : 
     257             :         case TIMESTAMPOID:
     258         204 :             if (with_typemod)
     259           6 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     260             :             else
     261         198 :                 buf = pstrdup("timestamp without time zone");
     262         204 :             break;
     263             : 
     264             :         case TIMESTAMPTZOID:
     265         326 :             if (with_typemod)
     266           6 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     267             :             else
     268         320 :                 buf = pstrdup("timestamp with time zone");
     269         326 :             break;
     270             : 
     271             :         case VARBITOID:
     272         156 :             if (with_typemod)
     273          86 :                 buf = printTypmod("bit varying", typemod, typeform->typmodout);
     274             :             else
     275          70 :                 buf = pstrdup("bit varying");
     276         156 :             break;
     277             : 
     278             :         case VARCHAROID:
     279         542 :             if (with_typemod)
     280         110 :                 buf = printTypmod("character varying", typemod, typeform->typmodout);
     281             :             else
     282         432 :                 buf = pstrdup("character varying");
     283         542 :             break;
     284             :     }
     285             : 
     286      481444 :     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      656114 :         if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 &&
     298      327658 :             TypeIsVisible(type_oid))
     299      319408 :             nspname = NULL;
     300             :         else
     301        9048 :             nspname = get_namespace_name_or_temp(typeform->typnamespace);
     302             : 
     303      328456 :         typname = NameStr(typeform->typname);
     304             : 
     305      328456 :         buf = quote_qualified_identifier(nspname, typname);
     306             : 
     307      328456 :         if (with_typemod)
     308           4 :             buf = printTypmod(buf, typemod, typeform->typmodout);
     309             :     }
     310             : 
     311      481444 :     if (is_array)
     312       17068 :         buf = psprintf("%s[]", buf);
     313             : 
     314      481444 :     ReleaseSysCache(tuple);
     315             : 
     316      481444 :     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      442180 : format_type_be(Oid type_oid)
     327             : {
     328      442180 :     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        1286 : format_type_be_qualified(Oid type_oid)
     337             : {
     338        1286 :     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       10914 : format_type_with_typemod(Oid type_oid, int32 typemod)
     346             : {
     347       10914 :     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         938 : 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         938 :     if (typmodout == InvalidOid)
     362             :     {
     363             :         /* Default behavior: just print the integer typmod with parens */
     364           0 :         res = psprintf("%s(%d)", typname, (int) typmod);
     365             :     }
     366             :     else
     367             :     {
     368             :         /* Use the type-specific typmodout procedure */
     369             :         char       *tmstr;
     370             : 
     371         938 :         tmstr = DatumGetCString(OidFunctionCall1(typmodout,
     372             :                                                  Int32GetDatum(typmod)));
     373         938 :         res = psprintf("%s%s", typname, tmstr);
     374             :     }
     375             : 
     376         938 :     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      430414 : type_maximum_size(Oid type_oid, int32 typemod)
     396             : {
     397      430414 :     if (typemod < 0)
     398      411506 :         return -1;
     399             : 
     400       18908 :     switch (type_oid)
     401             :     {
     402             :         case BPCHAROID:
     403             :         case VARCHAROID:
     404             :             /* typemod includes varlena header */
     405             : 
     406             :             /* typemod is in characters not bytes */
     407       25140 :             return (typemod - VARHDRSZ) *
     408       12570 :                 pg_encoding_max_length(GetDatabaseEncoding())
     409       12570 :                 + VARHDRSZ;
     410             : 
     411             :         case NUMERICOID:
     412        5282 :             return numeric_maximum_size(typemod);
     413             : 
     414             :         case VARBITOID:
     415             :         case BITOID:
     416             :             /* typemod is the (max) number of bits */
     417         780 :             return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
     418         780 :                 + 2 * sizeof(int32);
     419             :     }
     420             : 
     421             :     /* Unknown type, or unlimited-width type such as 'text' */
     422         276 :     return -1;
     423             : }
     424             : 
     425             : 
     426             : /*
     427             :  * oidvectortypes           - converts a vector of type OIDs to "typname" list
     428             :  */
     429             : Datum
     430           0 : oidvectortypes(PG_FUNCTION_ARGS)
     431             : {
     432           0 :     oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
     433             :     char       *result;
     434           0 :     int         numargs = oidArray->dim1;
     435             :     int         num;
     436             :     size_t      total;
     437             :     size_t      left;
     438             : 
     439           0 :     total = 20 * numargs + 1;
     440           0 :     result = palloc(total);
     441           0 :     result[0] = '\0';
     442           0 :     left = total - 1;
     443             : 
     444           0 :     for (num = 0; num < numargs; num++)
     445             :     {
     446           0 :         char       *typename = format_type_extended(oidArray->values[num], -1,
     447             :                                                     FORMAT_TYPE_ALLOW_INVALID);
     448           0 :         size_t      slen = strlen(typename);
     449             : 
     450           0 :         if (left < (slen + 2))
     451             :         {
     452           0 :             total += slen + 2;
     453           0 :             result = repalloc(result, total);
     454           0 :             left += slen + 2;
     455             :         }
     456             : 
     457           0 :         if (num > 0)
     458             :         {
     459           0 :             strcat(result, ", ");
     460           0 :             left -= 2;
     461             :         }
     462           0 :         strcat(result, typename);
     463           0 :         left -= slen;
     464             :     }
     465             : 
     466           0 :     PG_RETURN_TEXT_P(cstring_to_text(result));
     467             : }

Generated by: LCOV version 1.13