LCOV - code coverage report
Current view: top level - src/backend/utils/adt - char.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 81.0 % 84 68
Test Date: 2026-03-01 15:14:58 Functions: 71.4 % 14 10
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * char.c
       4              :  *    Functions for the built-in type "char" (not to be confused with
       5              :  *    bpchar, which is the SQL CHAR(n) type).
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  *
      11              :  * IDENTIFICATION
      12              :  *    src/backend/utils/adt/char.c
      13              :  *
      14              :  *-------------------------------------------------------------------------
      15              :  */
      16              : #include "postgres.h"
      17              : 
      18              : #include <limits.h>
      19              : 
      20              : #include "libpq/pqformat.h"
      21              : #include "utils/fmgrprotos.h"
      22              : #include "varatt.h"
      23              : 
      24              : #define ISOCTAL(c)   (((c) >= '0') && ((c) <= '7'))
      25              : #define TOOCTAL(c)   ((c) + '0')
      26              : #define FROMOCTAL(c) ((unsigned char) (c) - '0')
      27              : 
      28              : 
      29              : /*****************************************************************************
      30              :  *   USER I/O ROUTINES                                                       *
      31              :  *****************************************************************************/
      32              : 
      33              : /*
      34              :  *      charin          - converts "x" to 'x'
      35              :  *
      36              :  * This accepts the formats charout produces.  If we have multibyte input
      37              :  * that is not in the form '\ooo', then we take its first byte as the value
      38              :  * and silently discard the rest; this is a backwards-compatibility provision.
      39              :  */
      40              : Datum
      41       856127 : charin(PG_FUNCTION_ARGS)
      42              : {
      43       856127 :     char       *ch = PG_GETARG_CSTRING(0);
      44              : 
      45       856127 :     if (strlen(ch) == 4 && ch[0] == '\\' &&
      46           12 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
      47           12 :         PG_RETURN_CHAR((FROMOCTAL(ch[1]) << 6) +
      48              :                        (FROMOCTAL(ch[2]) << 3) +
      49              :                        FROMOCTAL(ch[3]));
      50              :     /* This will do the right thing for a zero-length input string */
      51       856115 :     PG_RETURN_CHAR(ch[0]);
      52              : }
      53              : 
      54              : /*
      55              :  *      charout         - converts 'x' to "x"
      56              :  *
      57              :  * The possible output formats are:
      58              :  * 1. 0x00 is represented as an empty string.
      59              :  * 2. 0x01..0x7F are represented as a single ASCII byte.
      60              :  * 3. 0x80..0xFF are represented as \ooo (backslash and 3 octal digits).
      61              :  * Case 3 is meant to match the traditional "escape" format of bytea.
      62              :  */
      63              : Datum
      64      2013929 : charout(PG_FUNCTION_ARGS)
      65              : {
      66      2013929 :     char        ch = PG_GETARG_CHAR(0);
      67      2013929 :     char       *result = (char *) palloc(5);
      68              : 
      69      2013929 :     if (IS_HIGHBIT_SET(ch))
      70              :     {
      71            6 :         result[0] = '\\';
      72            6 :         result[1] = TOOCTAL(((unsigned char) ch) >> 6);
      73            6 :         result[2] = TOOCTAL((((unsigned char) ch) >> 3) & 07);
      74            6 :         result[3] = TOOCTAL(((unsigned char) ch) & 07);
      75            6 :         result[4] = '\0';
      76              :     }
      77              :     else
      78              :     {
      79              :         /* This produces acceptable results for 0x00 as well */
      80      2013923 :         result[0] = ch;
      81      2013923 :         result[1] = '\0';
      82              :     }
      83      2013929 :     PG_RETURN_CSTRING(result);
      84              : }
      85              : 
      86              : /*
      87              :  *      charrecv            - converts external binary format to char
      88              :  *
      89              :  * The external representation is one byte, with no character set
      90              :  * conversion.  This is somewhat dubious, perhaps, but in many
      91              :  * cases people use char for a 1-byte binary type.
      92              :  */
      93              : Datum
      94            0 : charrecv(PG_FUNCTION_ARGS)
      95              : {
      96            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
      97              : 
      98            0 :     PG_RETURN_CHAR(pq_getmsgbyte(buf));
      99              : }
     100              : 
     101              : /*
     102              :  *      charsend            - converts char to binary format
     103              :  */
     104              : Datum
     105            0 : charsend(PG_FUNCTION_ARGS)
     106              : {
     107            0 :     char        arg1 = PG_GETARG_CHAR(0);
     108              :     StringInfoData buf;
     109              : 
     110            0 :     pq_begintypsend(&buf);
     111            0 :     pq_sendbyte(&buf, arg1);
     112            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     113              : }
     114              : 
     115              : /*****************************************************************************
     116              :  *   PUBLIC ROUTINES                                                         *
     117              :  *****************************************************************************/
     118              : 
     119              : /*
     120              :  * NOTE: comparisons are done as though char is unsigned (uint8).
     121              :  * Conversions to and from integer are done as though char is signed (int8).
     122              :  *
     123              :  * You wanted consistency?
     124              :  */
     125              : 
     126              : Datum
     127      5799112 : chareq(PG_FUNCTION_ARGS)
     128              : {
     129      5799112 :     char        arg1 = PG_GETARG_CHAR(0);
     130      5799112 :     char        arg2 = PG_GETARG_CHAR(1);
     131              : 
     132      5799112 :     PG_RETURN_BOOL(arg1 == arg2);
     133              : }
     134              : 
     135              : Datum
     136      2588858 : charne(PG_FUNCTION_ARGS)
     137              : {
     138      2588858 :     char        arg1 = PG_GETARG_CHAR(0);
     139      2588858 :     char        arg2 = PG_GETARG_CHAR(1);
     140              : 
     141      2588858 :     PG_RETURN_BOOL(arg1 != arg2);
     142              : }
     143              : 
     144              : Datum
     145         1548 : charlt(PG_FUNCTION_ARGS)
     146              : {
     147         1548 :     char        arg1 = PG_GETARG_CHAR(0);
     148         1548 :     char        arg2 = PG_GETARG_CHAR(1);
     149              : 
     150         1548 :     PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
     151              : }
     152              : 
     153              : Datum
     154         1212 : charle(PG_FUNCTION_ARGS)
     155              : {
     156         1212 :     char        arg1 = PG_GETARG_CHAR(0);
     157         1212 :     char        arg2 = PG_GETARG_CHAR(1);
     158              : 
     159         1212 :     PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
     160              : }
     161              : 
     162              : Datum
     163         1521 : chargt(PG_FUNCTION_ARGS)
     164              : {
     165         1521 :     char        arg1 = PG_GETARG_CHAR(0);
     166         1521 :     char        arg2 = PG_GETARG_CHAR(1);
     167              : 
     168         1521 :     PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
     169              : }
     170              : 
     171              : Datum
     172         1065 : charge(PG_FUNCTION_ARGS)
     173              : {
     174         1065 :     char        arg1 = PG_GETARG_CHAR(0);
     175         1065 :     char        arg2 = PG_GETARG_CHAR(1);
     176              : 
     177         1065 :     PG_RETURN_BOOL((uint8) arg1 >= (uint8) arg2);
     178              : }
     179              : 
     180              : 
     181              : Datum
     182            0 : chartoi4(PG_FUNCTION_ARGS)
     183              : {
     184            0 :     char        arg1 = PG_GETARG_CHAR(0);
     185              : 
     186            0 :     PG_RETURN_INT32((int32) ((int8) arg1));
     187              : }
     188              : 
     189              : Datum
     190            0 : i4tochar(PG_FUNCTION_ARGS)
     191              : {
     192            0 :     int32       arg1 = PG_GETARG_INT32(0);
     193              : 
     194            0 :     if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
     195            0 :         ereport(ERROR,
     196              :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     197              :                  errmsg("\"char\" out of range")));
     198              : 
     199            0 :     PG_RETURN_CHAR((int8) arg1);
     200              : }
     201              : 
     202              : 
     203              : Datum
     204         7075 : text_char(PG_FUNCTION_ARGS)
     205              : {
     206         7075 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
     207         7075 :     char       *ch = VARDATA_ANY(arg1);
     208              :     char        result;
     209              : 
     210              :     /*
     211              :      * Conversion rules are the same as in charin(), but here we need to
     212              :      * handle the empty-string case honestly.
     213              :      */
     214         7075 :     if (VARSIZE_ANY_EXHDR(arg1) == 4 && ch[0] == '\\' &&
     215            3 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
     216            3 :         result = (FROMOCTAL(ch[1]) << 6) +
     217            3 :             (FROMOCTAL(ch[2]) << 3) +
     218            3 :             FROMOCTAL(ch[3]);
     219         7072 :     else if (VARSIZE_ANY_EXHDR(arg1) > 0)
     220         7069 :         result = ch[0];
     221              :     else
     222            3 :         result = '\0';
     223              : 
     224         7075 :     PG_RETURN_CHAR(result);
     225              : }
     226              : 
     227              : Datum
     228        35531 : char_text(PG_FUNCTION_ARGS)
     229              : {
     230        35531 :     char        arg1 = PG_GETARG_CHAR(0);
     231        35531 :     text       *result = palloc(VARHDRSZ + 4);
     232              : 
     233              :     /*
     234              :      * Conversion rules are the same as in charout(), but here we need to be
     235              :      * honest about converting 0x00 to an empty string.
     236              :      */
     237        35531 :     if (IS_HIGHBIT_SET(arg1))
     238              :     {
     239            3 :         SET_VARSIZE(result, VARHDRSZ + 4);
     240            3 :         (VARDATA(result))[0] = '\\';
     241            3 :         (VARDATA(result))[1] = TOOCTAL(((unsigned char) arg1) >> 6);
     242            3 :         (VARDATA(result))[2] = TOOCTAL((((unsigned char) arg1) >> 3) & 07);
     243            3 :         (VARDATA(result))[3] = TOOCTAL(((unsigned char) arg1) & 07);
     244              :     }
     245        35528 :     else if (arg1 != '\0')
     246              :     {
     247        35525 :         SET_VARSIZE(result, VARHDRSZ + 1);
     248        35525 :         *(VARDATA(result)) = arg1;
     249              :     }
     250              :     else
     251            3 :         SET_VARSIZE(result, VARHDRSZ);
     252              : 
     253        35531 :     PG_RETURN_TEXT_P(result);
     254              : }
        

Generated by: LCOV version 2.0-1