LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - format_type.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 81.5 % 173 141 32 141
Current Date: 2023-04-08 15:15:32 Functions: 87.5 % 8 7 1 7
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * format_type.c
       4                 :  *    Display type names "nicely".
       5                 :  *
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, 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 CBC       33812 : format_type(PG_FUNCTION_ARGS)
      61                 : {
      62                 :     Oid         type_oid;
      63                 :     int32       typemod;
      64                 :     char       *result;
      65           33812 :     bits16      flags = FORMAT_TYPE_ALLOW_INVALID;
      66                 : 
      67                 :     /* Since this function is not strict, we must test for null args */
      68           33812 :     if (PG_ARGISNULL(0))
      69             434 :         PG_RETURN_NULL();
      70                 : 
      71           33378 :     type_oid = PG_GETARG_OID(0);
      72                 : 
      73           33378 :     if (PG_ARGISNULL(1))
      74           12283 :         typemod = -1;
      75                 :     else
      76                 :     {
      77           21095 :         typemod = PG_GETARG_INT32(1);
      78           21095 :         flags |= FORMAT_TYPE_TYPEMOD_GIVEN;
      79                 :     }
      80                 : 
      81           33378 :     result = format_type_extended(type_oid, typemod, flags);
      82                 : 
      83           33378 :     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          294014 : 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          294014 :     if (type_oid == InvalidOid)
     122                 :     {
     123              19 :         if ((flags & FORMAT_TYPE_INVALID_AS_NULL) != 0)
     124               9 :             return NULL;
     125              10 :         else if ((flags & FORMAT_TYPE_ALLOW_INVALID) != 0)
     126              10 :             return pstrdup("-");
     127                 :     }
     128                 : 
     129          293995 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
     130          293995 :     if (!HeapTupleIsValid(tuple))
     131                 :     {
     132 UBC           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 CBC      293995 :     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          293995 :     array_base_type = typeform->typelem;
     148                 : 
     149          293995 :     if (IsTrueArrayType(typeform) &&
     150           19686 :         typeform->typstorage != TYPSTORAGE_PLAIN)
     151                 :     {
     152                 :         /* Switch our attention to the array element type */
     153           19623 :         ReleaseSysCache(tuple);
     154           19623 :         tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(array_base_type));
     155           19623 :         if (!HeapTupleIsValid(tuple))
     156                 :         {
     157 UBC           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 CBC       19623 :         typeform = (Form_pg_type) GETSTRUCT(tuple);
     165           19623 :         type_oid = array_base_type;
     166           19623 :         is_array = true;
     167                 :     }
     168                 :     else
     169          274372 :         is_array = false;
     170                 : 
     171          293995 :     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          293995 :     buf = NULL;                 /* flag for no special case */
     185                 : 
     186          293995 :     switch (type_oid)
     187                 :     {
     188             283 :         case BITOID:
     189             283 :             if (with_typemod)
     190             110 :                 buf = printTypmod("bit", typemod, typeform->typmodout);
     191             173 :             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             145 :                 buf = pstrdup("bit");
     201             283 :             break;
     202                 : 
     203            6172 :         case BOOLOID:
     204            6172 :             buf = pstrdup("boolean");
     205            6172 :             break;
     206                 : 
     207            1178 :         case BPCHAROID:
     208            1178 :             if (with_typemod)
     209             389 :                 buf = printTypmod("character", typemod, typeform->typmodout);
     210             789 :             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             458 :                 buf = pstrdup("character");
     220            1178 :             break;
     221                 : 
     222             667 :         case FLOAT4OID:
     223             667 :             buf = pstrdup("real");
     224             667 :             break;
     225                 : 
     226            1865 :         case FLOAT8OID:
     227            1865 :             buf = pstrdup("double precision");
     228            1865 :             break;
     229                 : 
     230            1034 :         case INT2OID:
     231            1034 :             buf = pstrdup("smallint");
     232            1034 :             break;
     233                 : 
     234           76303 :         case INT4OID:
     235           76303 :             buf = pstrdup("integer");
     236           76303 :             break;
     237                 : 
     238            3310 :         case INT8OID:
     239            3310 :             buf = pstrdup("bigint");
     240            3310 :             break;
     241                 : 
     242            1360 :         case NUMERICOID:
     243            1360 :             if (with_typemod)
     244             185 :                 buf = printTypmod("numeric", typemod, typeform->typmodout);
     245                 :             else
     246            1175 :                 buf = pstrdup("numeric");
     247            1360 :             break;
     248                 : 
     249             312 :         case INTERVALOID:
     250             312 :             if (with_typemod)
     251 UBC           0 :                 buf = printTypmod("interval", typemod, typeform->typmodout);
     252                 :             else
     253 CBC         312 :                 buf = pstrdup("interval");
     254             312 :             break;
     255                 : 
     256             284 :         case TIMEOID:
     257             284 :             if (with_typemod)
     258               5 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     259                 :             else
     260             279 :                 buf = pstrdup("time without time zone");
     261             284 :             break;
     262                 : 
     263             253 :         case TIMETZOID:
     264             253 :             if (with_typemod)
     265               5 :                 buf = printTypmod("time", typemod, typeform->typmodout);
     266                 :             else
     267             248 :                 buf = pstrdup("time with time zone");
     268             253 :             break;
     269                 : 
     270             311 :         case TIMESTAMPOID:
     271             311 :             if (with_typemod)
     272               5 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     273                 :             else
     274             306 :                 buf = pstrdup("timestamp without time zone");
     275             311 :             break;
     276                 : 
     277             441 :         case TIMESTAMPTZOID:
     278             441 :             if (with_typemod)
     279               5 :                 buf = printTypmod("timestamp", typemod, typeform->typmodout);
     280                 :             else
     281             436 :                 buf = pstrdup("timestamp with time zone");
     282             441 :             break;
     283                 : 
     284             179 :         case VARBITOID:
     285             179 :             if (with_typemod)
     286              66 :                 buf = printTypmod("bit varying", typemod, typeform->typmodout);
     287                 :             else
     288             113 :                 buf = pstrdup("bit varying");
     289             179 :             break;
     290                 : 
     291             602 :         case VARCHAROID:
     292             602 :             if (with_typemod)
     293              87 :                 buf = printTypmod("character varying", typemod, typeform->typmodout);
     294                 :             else
     295             515 :                 buf = pstrdup("character varying");
     296             602 :             break;
     297                 :     }
     298                 : 
     299          293995 :     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          399064 :         if ((flags & FORMAT_TYPE_FORCE_QUALIFY) == 0 &&
     311          199264 :             TypeIsVisible(type_oid))
     312          195649 :             nspname = NULL;
     313                 :         else
     314            4151 :             nspname = get_namespace_name_or_temp(typeform->typnamespace);
     315                 : 
     316          199800 :         typname = NameStr(typeform->typname);
     317                 : 
     318          199800 :         buf = quote_qualified_identifier(nspname, typname);
     319                 : 
     320          199800 :         if (with_typemod)
     321               3 :             buf = printTypmod(buf, typemod, typeform->typmodout);
     322                 :     }
     323                 : 
     324          293995 :     if (is_array)
     325           19623 :         buf = psprintf("%s[]", buf);
     326                 : 
     327          293995 :     ReleaseSysCache(tuple);
     328                 : 
     329          293995 :     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          218641 : format_type_be(Oid type_oid)
     340                 : {
     341          218641 :     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             424 : format_type_be_qualified(Oid type_oid)
     350                 : {
     351             424 :     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           12982 : format_type_with_typemod(Oid type_oid, int32 typemod)
     359                 : {
     360           12982 :     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             860 : printTypmod(const char *typname, int32 typmod, Oid typmodout)
     368                 : {
     369                 :     char       *res;
     370                 : 
     371                 :     /* Shouldn't be called if typmod is -1 */
     372             860 :     Assert(typmod >= 0);
     373                 : 
     374             860 :     if (typmodout == InvalidOid)
     375                 :     {
     376                 :         /* Default behavior: just print the integer typmod with parens */
     377 UBC           0 :         res = psprintf("%s(%d)", typname, (int) typmod);
     378                 :     }
     379                 :     else
     380                 :     {
     381                 :         /* Use the type-specific typmodout procedure */
     382                 :         char       *tmstr;
     383                 : 
     384 CBC         860 :         tmstr = DatumGetCString(OidFunctionCall1(typmodout,
     385                 :                                                  Int32GetDatum(typmod)));
     386             860 :         res = psprintf("%s%s", typname, tmstr);
     387                 :     }
     388                 : 
     389             860 :     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          302105 : type_maximum_size(Oid type_oid, int32 typemod)
     409                 : {
     410          302105 :     if (typemod < 0)
     411          288250 :         return -1;
     412                 : 
     413           13855 :     switch (type_oid)
     414                 :     {
     415            9271 :         case BPCHAROID:
     416                 :         case VARCHAROID:
     417                 :             /* typemod includes varlena header */
     418                 : 
     419                 :             /* typemod is in characters not bytes */
     420           18542 :             return (typemod - VARHDRSZ) *
     421            9271 :                 pg_encoding_max_length(GetDatabaseEncoding())
     422            9271 :                 + VARHDRSZ;
     423                 : 
     424            3766 :         case NUMERICOID:
     425            3766 :             return numeric_maximum_size(typemod);
     426                 : 
     427             608 :         case VARBITOID:
     428                 :         case BITOID:
     429                 :             /* typemod is the (max) number of bits */
     430             608 :             return (typemod + (BITS_PER_BYTE - 1)) / BITS_PER_BYTE
     431             608 :                 + 2 * sizeof(int32);
     432                 :     }
     433                 : 
     434                 :     /* Unknown type, or unlimited-width type such as 'text' */
     435             210 :     return -1;
     436                 : }
     437                 : 
     438                 : 
     439                 : /*
     440                 :  * oidvectortypes           - converts a vector of type OIDs to "typname" list
     441                 :  */
     442                 : Datum
     443 UBC           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 v1.16-55-g56c0a2a