LCOV - code coverage report
Current view: top level - src/backend/utils/adt - format_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 137 165 83.0 %
Date: 2020-06-03 10:06:28 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-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       28516 : format_type(PG_FUNCTION_ARGS)
      60             : {
      61             :     Oid         type_oid;
      62             :     int32       typemod;
      63             :     char       *result;
      64       28516 :     bits16      flags = FORMAT_TYPE_ALLOW_INVALID;
      65             : 
      66             :     /* Since this function is not strict, we must test for null args */
      67       28516 :     if (PG_ARGISNULL(0))
      68         484 :         PG_RETURN_NULL();
      69             : 
      70       28032 :     type_oid = PG_GETARG_OID(0);
      71             : 
      72       28032 :     if (PG_ARGISNULL(1))
      73        3796 :         typemod = -1;
      74             :     else
      75             :     {
      76       24236 :         typemod = PG_GETARG_INT32(1);
      77       24236 :         flags |= FORMAT_TYPE_TYPEMOD_GIVEN;
      78             :     }
      79             : 
      80       28032 :     result = format_type_extended(type_oid, typemod, flags);
      81             : 
      82       28032 :     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      493466 : 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      493466 :     if (type_oid == InvalidOid && (flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     118          18 :         return pstrdup("-");
     119             : 
     120      493448 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
     121      493448 :     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      493448 :     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      493448 :     array_base_type = typeform->typelem;
     138             : 
     139      493448 :     if (array_base_type != InvalidOid &&
     140       22424 :         typeform->typstorage != TYPSTORAGE_PLAIN)
     141             :     {
     142             :         /* Switch our attention to the array element type */
     143       20106 :         ReleaseSysCache(tuple);
     144       20106 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
     145       20106 :         if (!HeapTupleIsValid(tuple))
     146             :         {
     147           0 :             if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     148           0 :                 return pstrdup("???[]");
     149             :             else
     150           0 :                 elog(ERROR, "cache lookup failed for type %u", type_oid);
     151             :         }
     152       20106 :         typeform = (Form_pg_type) GETSTRUCT(tuple);
     153       20106 :         type_oid = array_base_type;
     154       20106 :         is_array = true;
     155             :     }
     156             :     else
     157      473342 :         is_array = false;
     158             : 
     159      493448 :     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      493448 :     buf = NULL;                 /* flag for no special case */
     173             : 
     174      493448 :     switch (type_oid)
     175             :     {
     176         240 :         case BITOID:
     177         240 :             if (with_typemod)
     178         134 :                 buf = printTypmod("bit", typemod, typeform->typmodout);
     179         106 :             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          68 :                 buf = pstrdup("bit");
     189         240 :             break;
     190             : 
     191        7416 :         case BOOLOID:
     192        7416 :             buf = pstrdup("boolean");
     193        7416 :             break;
     194             : 
     195        1312 :         case BPCHAROID:
     196        1312 :             if (with_typemod)
     197         444 :                 buf = printTypmod("character", typemod, typeform->typmodout);
     198         868 :             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         452 :                 buf = pstrdup("character");
     208        1312 :             break;
     209             : 
     210         642 :         case FLOAT4OID:
     211         642 :             buf = pstrdup("real");
     212         642 :             break;
     213             : 
     214        2074 :         case FLOAT8OID:
     215        2074 :             buf = pstrdup("double precision");
     216        2074 :             break;
     217             : 
     218         946 :         case INT2OID:
     219         946 :             buf = pstrdup("smallint");
     220         946 :             break;
     221             : 
     222      137894 :         case INT4OID:
     223      137894 :             buf = pstrdup("integer");
     224      137894 :             break;
     225             : 
     226        3420 :         case INT8OID:
     227        3420 :             buf = pstrdup("bigint");
     228        3420 :             break;
     229             : 
     230        1222 :         case NUMERICOID:
     231        1222 :             if (with_typemod)
     232         144 :                 buf = printTypmod("numeric", typemod, typeform->typmodout);
     233             :             else
     234        1078 :                 buf = pstrdup("numeric");
     235        1222 :             break;
     236             : 
     237         206 :         case INTERVALOID:
     238         206 :             if (with_typemod)
     239           0 :                 buf = printTypmod("interval", typemod, typeform->typmodout);
     240             :             else
     241         206 :                 buf = pstrdup("interval");
     242         206 :             break;
     243             : 
     244         148 :         case TIMEOID:
     245         148 :             if (with_typemod)
     246           6 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     247             :             else
     248         142 :                 buf = pstrdup("time without time zone");
     249         148 :             break;
     250             : 
     251         152 :         case TIMETZOID:
     252         152 :             if (with_typemod)
     253           6 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     254             :             else
     255         146 :                 buf = pstrdup("time with time zone");
     256         152 :             break;
     257             : 
     258         224 :         case TIMESTAMPOID:
     259         224 :             if (with_typemod)
     260           6 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     261             :             else
     262         218 :                 buf = pstrdup("timestamp without time zone");
     263         224 :             break;
     264             : 
     265         354 :         case TIMESTAMPTZOID:
     266         354 :             if (with_typemod)
     267           6 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     268             :             else
     269         348 :                 buf = pstrdup("timestamp with time zone");
     270         354 :             break;
     271             : 
     272         164 :         case VARBITOID:
     273         164 :             if (with_typemod)
     274          86 :                 buf = printTypmod("bit varying", typemod, typeform->typmodout);
     275             :             else
     276          78 :                 buf = pstrdup("bit varying");
     277         164 :             break;
     278             : 
     279         572 :         case VARCHAROID:
     280         572 :             if (with_typemod)
     281         116 :                 buf = printTypmod("character varying", typemod, typeform->typmodout);
     282             :             else
     283         456 :                 buf = pstrdup("character varying");
     284         572 :             break;
     285             :     }
     286             : 
     287      493448 :     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      673030 :         if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 &&
     299      336114 :             TypeIsVisible(type_oid))
     300      327878 :             nspname = NULL;
     301             :         else
     302        9038 :             nspname = get_namespace_name_or_temp(typeform->typnamespace);
     303             : 
     304      336916 :         typname = NameStr(typeform->typname);
     305             : 
     306      336916 :         buf = quote_qualified_identifier(nspname, typname);
     307             : 
     308      336916 :         if (with_typemod)
     309           4 :             buf = printTypmod(buf, typemod, typeform->typmodout);
     310             :     }
     311             : 
     312      493448 :     if (is_array)
     313       20106 :         buf = psprintf("%s[]", buf);
     314             : 
     315      493448 :     ReleaseSysCache(tuple);
     316             : 
     317      493448 :     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      450430 : format_type_be(Oid type_oid)
     328             : {
     329      450430 :     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        1296 : format_type_be_qualified(Oid type_oid)
     338             : {
     339        1296 :     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       12846 : format_type_with_typemod(Oid type_oid, int32 typemod)
     347             : {
     348       12846 :     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         952 : 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         952 :     if (typmodout == InvalidOid)
     363             :     {
     364             :         /* Default behavior: just print the integer typmod with parens */
     365           0 :         res = psprintf("%s(%d)", typname, (int) typmod);
     366             :     }
     367             :     else
     368             :     {
     369             :         /* Use the type-specific typmodout procedure */
     370             :         char       *tmstr;
     371             : 
     372         952 :         tmstr = DatumGetCString(OidFunctionCall1(typmodout,
     373             :                                                  Int32GetDatum(typmod)));
     374         952 :         res = psprintf("%s%s", typname, tmstr);
     375             :     }
     376             : 
     377         952 :     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      429498 : type_maximum_size(Oid type_oid, int32 typemod)
     397             : {
     398      429498 :     if (typemod < 0)
     399      408850 :         return -1;
     400             : 
     401       20648 :     switch (type_oid)
     402             :     {
     403       14122 :         case BPCHAROID:
     404             :         case VARCHAROID:
     405             :             /* typemod includes varlena header */
     406             : 
     407             :             /* typemod is in characters not bytes */
     408       28244 :             return (typemod - VARHDRSZ) *
     409       14122 :                 pg_encoding_max_length(GetDatabaseEncoding())
     410       14122 :                 + VARHDRSZ;
     411             : 
     412        5438 :         case NUMERICOID:
     413        5438 :             return numeric_maximum_size(typemod);
     414             : 
     415         812 :         case VARBITOID:
     416             :         case BITOID:
     417             :             /* typemod is the (max) number of bits */
     418         812 :             return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
     419         812 :                 + 2 * sizeof(int32);
     420             :     }
     421             : 
     422             :     /* Unknown type, or unlimited-width type such as 'text' */
     423         276 :     return -1;
     424             : }
     425             : 
     426             : 
     427             : /*
     428             :  * oidvectortypes           - converts a vector of type OIDs to "typname" list
     429             :  */
     430             : Datum
     431           0 : oidvectortypes(PG_FUNCTION_ARGS)
     432             : {
     433           0 :     oidvector  *oidArray = (oidvector *) PG_GETARG_POINTER(0);
     434             :     char       *result;
     435           0 :     int         numargs = oidArray->dim1;
     436             :     int         num;
     437             :     size_t      total;
     438             :     size_t      left;
     439             : 
     440           0 :     total = 20 * numargs + 1;
     441           0 :     result = palloc(total);
     442           0 :     result[0] = '\0';
     443           0 :     left = total - 1;
     444             : 
     445           0 :     for (num = 0; num < numargs; num++)
     446             :     {
     447           0 :         char       *typename = format_type_extended(oidArray->values[num], -1,
     448             :                                                     FORMAT_TYPE_ALLOW_INVALID);
     449           0 :         size_t      slen = strlen(typename);
     450             : 
     451           0 :         if (left < (slen + 2))
     452             :         {
     453           0 :             total += slen + 2;
     454           0 :             result = repalloc(result, total);
     455           0 :             left += slen + 2;
     456             :         }
     457             : 
     458           0 :         if (num > 0)
     459             :         {
     460           0 :             strcat(result, ", ");
     461           0 :             left -= 2;
     462             :         }
     463           0 :         strcat(result, typename);
     464           0 :         left -= slen;
     465             :     }
     466             : 
     467           0 :     PG_RETURN_TEXT_P(cstring_to_text(result));
     468             : }

Generated by: LCOV version 1.13