LCOV - code coverage report
Current view: top level - src/backend/utils/adt - char.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 68 84 81.0 %
Date: 2024-07-18 17:11:54 Functions: 10 14 71.4 %
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-2024, 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     1293212 : charin(PG_FUNCTION_ARGS)
      42             : {
      43     1293212 :     char       *ch = PG_GETARG_CSTRING(0);
      44             : 
      45     1293212 :     if (strlen(ch) == 4 && ch[0] == '\\' &&
      46          24 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
      47          24 :         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     1293188 :     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     2771074 : charout(PG_FUNCTION_ARGS)
      65             : {
      66     2771074 :     char        ch = PG_GETARG_CHAR(0);
      67     2771074 :     char       *result = (char *) palloc(5);
      68             : 
      69     2771074 :     if (IS_HIGHBIT_SET(ch))
      70             :     {
      71          12 :         result[0] = '\\';
      72          12 :         result[1] = TOOCTAL(((unsigned char) ch) >> 6);
      73          12 :         result[2] = TOOCTAL((((unsigned char) ch) >> 3) & 07);
      74          12 :         result[3] = TOOCTAL(((unsigned char) ch) & 07);
      75          12 :         result[4] = '\0';
      76             :     }
      77             :     else
      78             :     {
      79             :         /* This produces acceptable results for 0x00 as well */
      80     2771062 :         result[0] = ch;
      81     2771062 :         result[1] = '\0';
      82             :     }
      83     2771074 :     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     5334136 : chareq(PG_FUNCTION_ARGS)
     128             : {
     129     5334136 :     char        arg1 = PG_GETARG_CHAR(0);
     130     5334136 :     char        arg2 = PG_GETARG_CHAR(1);
     131             : 
     132     5334136 :     PG_RETURN_BOOL(arg1 == arg2);
     133             : }
     134             : 
     135             : Datum
     136     3496450 : charne(PG_FUNCTION_ARGS)
     137             : {
     138     3496450 :     char        arg1 = PG_GETARG_CHAR(0);
     139     3496450 :     char        arg2 = PG_GETARG_CHAR(1);
     140             : 
     141     3496450 :     PG_RETURN_BOOL(arg1 != arg2);
     142             : }
     143             : 
     144             : Datum
     145        3096 : charlt(PG_FUNCTION_ARGS)
     146             : {
     147        3096 :     char        arg1 = PG_GETARG_CHAR(0);
     148        3096 :     char        arg2 = PG_GETARG_CHAR(1);
     149             : 
     150        3096 :     PG_RETURN_BOOL((uint8) arg1 < (uint8) arg2);
     151             : }
     152             : 
     153             : Datum
     154        2424 : charle(PG_FUNCTION_ARGS)
     155             : {
     156        2424 :     char        arg1 = PG_GETARG_CHAR(0);
     157        2424 :     char        arg2 = PG_GETARG_CHAR(1);
     158             : 
     159        2424 :     PG_RETURN_BOOL((uint8) arg1 <= (uint8) arg2);
     160             : }
     161             : 
     162             : Datum
     163        3042 : chargt(PG_FUNCTION_ARGS)
     164             : {
     165        3042 :     char        arg1 = PG_GETARG_CHAR(0);
     166        3042 :     char        arg2 = PG_GETARG_CHAR(1);
     167             : 
     168        3042 :     PG_RETURN_BOOL((uint8) arg1 > (uint8) arg2);
     169             : }
     170             : 
     171             : Datum
     172        2130 : charge(PG_FUNCTION_ARGS)
     173             : {
     174        2130 :     char        arg1 = PG_GETARG_CHAR(0);
     175        2130 :     char        arg2 = PG_GETARG_CHAR(1);
     176             : 
     177        2130 :     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       11070 : text_char(PG_FUNCTION_ARGS)
     205             : {
     206       11070 :     text       *arg1 = PG_GETARG_TEXT_PP(0);
     207       11070 :     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       11070 :     if (VARSIZE_ANY_EXHDR(arg1) == 4 && ch[0] == '\\' &&
     215           6 :         ISOCTAL(ch[1]) && ISOCTAL(ch[2]) && ISOCTAL(ch[3]))
     216           6 :         result = (FROMOCTAL(ch[1]) << 6) +
     217           6 :             (FROMOCTAL(ch[2]) << 3) +
     218           6 :             FROMOCTAL(ch[3]);
     219       11064 :     else if (VARSIZE_ANY_EXHDR(arg1) > 0)
     220       11058 :         result = ch[0];
     221             :     else
     222           6 :         result = '\0';
     223             : 
     224       11070 :     PG_RETURN_CHAR(result);
     225             : }
     226             : 
     227             : Datum
     228       48278 : char_text(PG_FUNCTION_ARGS)
     229             : {
     230       48278 :     char        arg1 = PG_GETARG_CHAR(0);
     231       48278 :     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       48278 :     if (IS_HIGHBIT_SET(arg1))
     238             :     {
     239           6 :         SET_VARSIZE(result, VARHDRSZ + 4);
     240           6 :         (VARDATA(result))[0] = '\\';
     241           6 :         (VARDATA(result))[1] = TOOCTAL(((unsigned char) arg1) >> 6);
     242           6 :         (VARDATA(result))[2] = TOOCTAL((((unsigned char) arg1) >> 3) & 07);
     243           6 :         (VARDATA(result))[3] = TOOCTAL(((unsigned char) arg1) & 07);
     244             :     }
     245       48272 :     else if (arg1 != '\0')
     246             :     {
     247       48266 :         SET_VARSIZE(result, VARHDRSZ + 1);
     248       48266 :         *(VARDATA(result)) = arg1;
     249             :     }
     250             :     else
     251           6 :         SET_VARSIZE(result, VARHDRSZ);
     252             : 
     253       48278 :     PG_RETURN_TEXT_P(result);
     254             : }

Generated by: LCOV version 1.14