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

Generated by: LCOV version 1.11