LCOV - code coverage report
Current view: top level - src/backend/utils/adt - char.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 85.7 % 84 72
Test Date: 2026-07-22 12:15:41 Functions: 78.6 % 14 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 60.9 % 46 28

             Branch data     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                 :      961693 : charin(PG_FUNCTION_ARGS)
      42                 :             : {
      43                 :      961693 :     char       *ch = PG_GETARG_CSTRING(0);
      44                 :             : 
      45   [ +  +  +  - ]:      961693 :     if (strlen(ch) == 4 && ch[0] == '\\' &&
      46   [ +  -  +  -  :          16 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
          +  -  +  -  +  
                -  +  - ]
      47                 :          16 :         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                 :      961677 :     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                 :     1829527 : charout(PG_FUNCTION_ARGS)
      65                 :             : {
      66                 :     1829527 :     char        ch = PG_GETARG_CHAR(0);
      67                 :     1829527 :     char       *result = (char *) palloc(5);
      68                 :             : 
      69         [ +  + ]:     1829527 :     if (IS_HIGHBIT_SET(ch))
      70                 :             :     {
      71                 :           8 :         result[0] = '\\';
      72                 :           8 :         result[1] = TOOCTAL(((unsigned char) ch) >> 6);
      73                 :           8 :         result[2] = TOOCTAL((((unsigned char) ch) >> 3) & 07);
      74                 :           8 :         result[3] = TOOCTAL(((unsigned char) ch) & 07);
      75                 :           8 :         result[4] = '\0';
      76                 :             :     }
      77                 :             :     else
      78                 :             :     {
      79                 :             :         /* This produces acceptable results for 0x00 as well */
      80                 :     1829519 :         result[0] = ch;
      81                 :     1829519 :         result[1] = '\0';
      82                 :             :     }
      83                 :     1829527 :     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                 :     6463874 : chareq(PG_FUNCTION_ARGS)
     128                 :             : {
     129                 :     6463874 :     char        arg1 = PG_GETARG_CHAR(0);
     130                 :     6463874 :     char        arg2 = PG_GETARG_CHAR(1);
     131                 :             : 
     132                 :     6463874 :     PG_RETURN_BOOL(arg1 == arg2);
     133                 :             : }
     134                 :             : 
     135                 :             : Datum
     136                 :     2476739 : charne(PG_FUNCTION_ARGS)
     137                 :             : {
     138                 :     2476739 :     char        arg1 = PG_GETARG_CHAR(0);
     139                 :     2476739 :     char        arg2 = PG_GETARG_CHAR(1);
     140                 :             : 
     141                 :     2476739 :     PG_RETURN_BOOL(arg1 != arg2);
     142                 :             : }
     143                 :             : 
     144                 :             : Datum
     145                 :        2102 : charlt(PG_FUNCTION_ARGS)
     146                 :             : {
     147                 :        2102 :     char        arg1 = PG_GETARG_CHAR(0);
     148                 :        2102 :     char        arg2 = PG_GETARG_CHAR(1);
     149                 :             : 
     150                 :        2102 :     PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
     151                 :             : }
     152                 :             : 
     153                 :             : Datum
     154                 :        1620 : charle(PG_FUNCTION_ARGS)
     155                 :             : {
     156                 :        1620 :     char        arg1 = PG_GETARG_CHAR(0);
     157                 :        1620 :     char        arg2 = PG_GETARG_CHAR(1);
     158                 :             : 
     159                 :        1620 :     PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
     160                 :             : }
     161                 :             : 
     162                 :             : Datum
     163                 :        2028 : chargt(PG_FUNCTION_ARGS)
     164                 :             : {
     165                 :        2028 :     char        arg1 = PG_GETARG_CHAR(0);
     166                 :        2028 :     char        arg2 = PG_GETARG_CHAR(1);
     167                 :             : 
     168                 :        2028 :     PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
     169                 :             : }
     170                 :             : 
     171                 :             : Datum
     172                 :        1420 : charge(PG_FUNCTION_ARGS)
     173                 :             : {
     174                 :        1420 :     char        arg1 = PG_GETARG_CHAR(0);
     175                 :        1420 :     char        arg2 = PG_GETARG_CHAR(1);
     176                 :             : 
     177                 :        1420 :     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                 :         132 : i4tochar(PG_FUNCTION_ARGS)
     191                 :             : {
     192                 :         132 :     int32       arg1 = PG_GETARG_INT32(0);
     193                 :             : 
     194   [ +  -  -  + ]:         132 :     if (arg1 < SCHAR_MIN || arg1 > SCHAR_MAX)
     195         [ #  # ]:           0 :         ereturn(fcinfo->context, (Datum) 0,
     196                 :             :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     197                 :             :                  errmsg("\"char\" out of range")));
     198                 :             : 
     199                 :         132 :     PG_RETURN_CHAR((int8) arg1);
     200                 :             : }
     201                 :             : 
     202                 :             : 
     203                 :             : Datum
     204                 :        8681 : text_char(PG_FUNCTION_ARGS)
     205                 :             : {
     206                 :        8681 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
     207                 :        8681 :     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   [ +  +  +  - ]:        8681 :     if (VARSIZE_ANY_EXHDR(arg1) == 4 && ch[0] == '\\' &&
     215   [ +  -  +  -  :           5 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
          +  -  +  -  +  
                -  +  - ]
     216                 :           5 :         result = (FROMOCTAL(ch[1]) << 6) +
     217                 :           5 :             (FROMOCTAL(ch[2]) << 3) +
     218                 :           5 :             FROMOCTAL(ch[3]);
     219         [ +  + ]:        8676 :     else if (VARSIZE_ANY_EXHDR(arg1) > 0)
     220                 :        8671 :         result = ch[0];
     221                 :             :     else
     222                 :           5 :         result = '\0';
     223                 :             : 
     224                 :        8681 :     PG_RETURN_CHAR(result);
     225                 :             : }
     226                 :             : 
     227                 :             : Datum
     228                 :       39241 : char_text(PG_FUNCTION_ARGS)
     229                 :             : {
     230                 :       39241 :     char        arg1 = PG_GETARG_CHAR(0);
     231                 :       39241 :     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         [ +  + ]:       39241 :     if (IS_HIGHBIT_SET(arg1))
     238                 :             :     {
     239                 :           5 :         SET_VARSIZE(result, VARHDRSZ + 4);
     240                 :           5 :         (VARDATA(result))[0] = '\\';
     241                 :           5 :         (VARDATA(result))[1] = TOOCTAL(((unsigned char) arg1) >> 6);
     242                 :           5 :         (VARDATA(result))[2] = TOOCTAL((((unsigned char) arg1) >> 3) & 07);
     243                 :           5 :         (VARDATA(result))[3] = TOOCTAL(((unsigned char) arg1) & 07);
     244                 :             :     }
     245         [ +  + ]:       39236 :     else if (arg1 != '\0')
     246                 :             :     {
     247                 :       39231 :         SET_VARSIZE(result, VARHDRSZ + 1);
     248                 :       39231 :         *(VARDATA(result)) = arg1;
     249                 :             :     }
     250                 :             :     else
     251                 :           5 :         SET_VARSIZE(result, VARHDRSZ);
     252                 :             : 
     253                 :       39241 :     PG_RETURN_TEXT_P(result);
     254                 :             : }
        

Generated by: LCOV version 2.0-1