LCOV - code coverage report
Current view: top level - src/backend/utils/adt - numutils.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 94.6 % 448 424
Test Date: 2026-04-07 14:16:30 Functions: 94.1 % 17 16
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * numutils.c
       4              :  *    utility functions for I/O of built-in numeric types.
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/utils/adt/numutils.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include <limits.h>
      18              : #include <ctype.h>
      19              : 
      20              : #include "common/int.h"
      21              : #include "port/pg_bitutils.h"
      22              : #include "utils/builtins.h"
      23              : 
      24              : /*
      25              :  * A table of all two-digit numbers. This is used to speed up decimal digit
      26              :  * generation by copying pairs of digits into the final output.
      27              :  */
      28              : static const char DIGIT_TABLE[200] =
      29              : "00" "01" "02" "03" "04" "05" "06" "07" "08" "09"
      30              : "10" "11" "12" "13" "14" "15" "16" "17" "18" "19"
      31              : "20" "21" "22" "23" "24" "25" "26" "27" "28" "29"
      32              : "30" "31" "32" "33" "34" "35" "36" "37" "38" "39"
      33              : "40" "41" "42" "43" "44" "45" "46" "47" "48" "49"
      34              : "50" "51" "52" "53" "54" "55" "56" "57" "58" "59"
      35              : "60" "61" "62" "63" "64" "65" "66" "67" "68" "69"
      36              : "70" "71" "72" "73" "74" "75" "76" "77" "78" "79"
      37              : "80" "81" "82" "83" "84" "85" "86" "87" "88" "89"
      38              : "90" "91" "92" "93" "94" "95" "96" "97" "98" "99";
      39              : 
      40              : /*
      41              :  * Adapted from http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
      42              :  */
      43              : static inline int
      44      8049877 : decimalLength32(const uint32 v)
      45              : {
      46              :     int         t;
      47              :     static const uint32 PowersOfTen[] = {
      48              :         1, 10, 100,
      49              :         1000, 10000, 100000,
      50              :         1000000, 10000000, 100000000,
      51              :         1000000000
      52              :     };
      53              : 
      54              :     /*
      55              :      * Compute base-10 logarithm by dividing the base-2 logarithm by a
      56              :      * good-enough approximation of the base-2 logarithm of 10
      57              :      */
      58      8049877 :     t = (pg_leftmost_one_pos32(v) + 1) * 1233 / 4096;
      59      8049877 :     return t + (v >= PowersOfTen[t]);
      60              : }
      61              : 
      62              : static inline int
      63       367404 : decimalLength64(const uint64 v)
      64              : {
      65              :     int         t;
      66              :     static const uint64 PowersOfTen[] = {
      67              :         UINT64CONST(1), UINT64CONST(10),
      68              :         UINT64CONST(100), UINT64CONST(1000),
      69              :         UINT64CONST(10000), UINT64CONST(100000),
      70              :         UINT64CONST(1000000), UINT64CONST(10000000),
      71              :         UINT64CONST(100000000), UINT64CONST(1000000000),
      72              :         UINT64CONST(10000000000), UINT64CONST(100000000000),
      73              :         UINT64CONST(1000000000000), UINT64CONST(10000000000000),
      74              :         UINT64CONST(100000000000000), UINT64CONST(1000000000000000),
      75              :         UINT64CONST(10000000000000000), UINT64CONST(100000000000000000),
      76              :         UINT64CONST(1000000000000000000), UINT64CONST(10000000000000000000)
      77              :     };
      78              : 
      79              :     /*
      80              :      * Compute base-10 logarithm by dividing the base-2 logarithm by a
      81              :      * good-enough approximation of the base-2 logarithm of 10
      82              :      */
      83       367404 :     t = (pg_leftmost_one_pos64(v) + 1) * 1233 / 4096;
      84       367404 :     return t + (v >= PowersOfTen[t]);
      85              : }
      86              : 
      87              : static const int8 hexlookup[128] = {
      88              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      89              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      90              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      91              :     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
      92              :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      93              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      94              :     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      95              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      96              : };
      97              : 
      98              : /*
      99              :  * Convert input string to a signed 16 bit integer.  Input strings may be
     100              :  * expressed in base-10, hexadecimal, octal, or binary format, all of which
     101              :  * can be prefixed by an optional sign character, either '+' (the default) or
     102              :  * '-' for negative numbers.  Hex strings are recognized by the digits being
     103              :  * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
     104              :  * prefix.  The binary representation is recognized by the 0b or 0B prefix.
     105              :  *
     106              :  * Allows any number of leading or trailing whitespace characters.  Digits may
     107              :  * optionally be separated by a single underscore character.  These can only
     108              :  * come between digits and not before or after the digits.  Underscores have
     109              :  * no effect on the return value and are supported only to assist in improving
     110              :  * the human readability of the input strings.
     111              :  *
     112              :  * pg_strtoint16() will throw ereport() upon bad input format or overflow;
     113              :  * while pg_strtoint16_safe() instead returns such complaints in *escontext,
     114              :  * if it's an ErrorSaveContext.
     115              :  *
     116              :  * NB: Accumulate input as an unsigned number, to deal with two's complement
     117              :  * representation of the most negative number, which can't be represented as a
     118              :  * signed positive number.
     119              :  */
     120              : int16
     121            0 : pg_strtoint16(const char *s)
     122              : {
     123            0 :     return pg_strtoint16_safe(s, NULL);
     124              : }
     125              : 
     126              : int16
     127       546715 : pg_strtoint16_safe(const char *s, Node *escontext)
     128              : {
     129       546715 :     const char *ptr = s;
     130              :     const char *firstdigit;
     131       546715 :     uint16      tmp = 0;
     132       546715 :     bool        neg = false;
     133              :     unsigned char digit;
     134              :     int16       result;
     135              : 
     136              :     /*
     137              :      * The majority of cases are likely to be base-10 digits without any
     138              :      * underscore separator characters.  We'll first try to parse the string
     139              :      * with the assumption that's the case and only fallback on a slower
     140              :      * implementation which handles hex, octal and binary strings and
     141              :      * underscores if the fastpath version cannot parse the string.
     142              :      */
     143              : 
     144              :     /* leave it up to the slow path to look for leading spaces */
     145              : 
     146       546715 :     if (*ptr == '-')
     147              :     {
     148        11056 :         ptr++;
     149        11056 :         neg = true;
     150              :     }
     151              : 
     152              :     /* a leading '+' is uncommon so leave that for the slow path */
     153              : 
     154              :     /* process the first digit */
     155       546715 :     digit = (*ptr - '0');
     156              : 
     157              :     /*
     158              :      * Exploit unsigned arithmetic to save having to check both the upper and
     159              :      * lower bounds of the digit.
     160              :      */
     161       546715 :     if (likely(digit < 10))
     162              :     {
     163       546635 :         ptr++;
     164       546635 :         tmp = digit;
     165              :     }
     166              :     else
     167              :     {
     168              :         /* we need at least one digit */
     169           80 :         goto slow;
     170              :     }
     171              : 
     172              :     /* process remaining digits */
     173              :     for (;;)
     174              :     {
     175       563469 :         digit = (*ptr - '0');
     176              : 
     177       563469 :         if (digit >= 10)
     178       546623 :             break;
     179              : 
     180        16846 :         ptr++;
     181              : 
     182        16846 :         if (unlikely(tmp > -(PG_INT16_MIN / 10)))
     183           12 :             goto out_of_range;
     184              : 
     185        16834 :         tmp = tmp * 10 + digit;
     186              :     }
     187              : 
     188              :     /* when the string does not end in a digit, let the slow path handle it */
     189       546623 :     if (unlikely(*ptr != '\0'))
     190          121 :         goto slow;
     191              : 
     192       546502 :     if (neg)
     193              :     {
     194        11028 :         if (unlikely(pg_neg_u16_overflow(tmp, &result)))
     195            0 :             goto out_of_range;
     196        11028 :         return result;
     197              :     }
     198              : 
     199       535474 :     if (unlikely(tmp > PG_INT16_MAX))
     200            0 :         goto out_of_range;
     201              : 
     202       535474 :     return (int16) tmp;
     203              : 
     204          201 : slow:
     205          201 :     tmp = 0;
     206          201 :     ptr = s;
     207              :     /* no need to reset neg */
     208              : 
     209              :     /* skip leading spaces */
     210          241 :     while (isspace((unsigned char) *ptr))
     211           40 :         ptr++;
     212              : 
     213              :     /* handle sign */
     214          201 :     if (*ptr == '-')
     215              :     {
     216           32 :         ptr++;
     217           32 :         neg = true;
     218              :     }
     219          169 :     else if (*ptr == '+')
     220            0 :         ptr++;
     221              : 
     222              :     /* process digits */
     223          201 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     224              :     {
     225           28 :         firstdigit = ptr += 2;
     226              : 
     227              :         for (;;)
     228              :         {
     229          120 :             if (isxdigit((unsigned char) *ptr))
     230              :             {
     231           88 :                 if (unlikely(tmp > -(PG_INT16_MIN / 16)))
     232            0 :                     goto out_of_range;
     233              : 
     234           88 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     235              :             }
     236           32 :             else if (*ptr == '_')
     237              :             {
     238              :                 /* underscore must be followed by more digits */
     239            4 :                 ptr++;
     240            4 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     241            0 :                     goto invalid_syntax;
     242              :             }
     243              :             else
     244           28 :                 break;
     245              :         }
     246              :     }
     247          173 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     248              :     {
     249           28 :         firstdigit = ptr += 2;
     250              : 
     251              :         for (;;)
     252              :         {
     253          148 :             if (*ptr >= '0' && *ptr <= '7')
     254              :             {
     255          116 :                 if (unlikely(tmp > -(PG_INT16_MIN / 8)))
     256            0 :                     goto out_of_range;
     257              : 
     258          116 :                 tmp = tmp * 8 + (*ptr++ - '0');
     259              :             }
     260           32 :             else if (*ptr == '_')
     261              :             {
     262              :                 /* underscore must be followed by more digits */
     263            4 :                 ptr++;
     264            4 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     265            0 :                     goto invalid_syntax;
     266              :             }
     267              :             else
     268           28 :                 break;
     269              :         }
     270              :     }
     271          145 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     272              :     {
     273           28 :         firstdigit = ptr += 2;
     274              : 
     275              :         for (;;)
     276              :         {
     277          336 :             if (*ptr >= '0' && *ptr <= '1')
     278              :             {
     279          300 :                 if (unlikely(tmp > -(PG_INT16_MIN / 2)))
     280            0 :                     goto out_of_range;
     281              : 
     282          300 :                 tmp = tmp * 2 + (*ptr++ - '0');
     283              :             }
     284           36 :             else if (*ptr == '_')
     285              :             {
     286              :                 /* underscore must be followed by more digits */
     287            8 :                 ptr++;
     288            8 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     289            0 :                     goto invalid_syntax;
     290              :             }
     291              :             else
     292           28 :                 break;
     293              :         }
     294              :     }
     295              :     else
     296              :     {
     297          117 :         firstdigit = ptr;
     298              : 
     299              :         for (;;)
     300              :         {
     301          250 :             if (*ptr >= '0' && *ptr <= '9')
     302              :             {
     303          121 :                 if (unlikely(tmp > -(PG_INT16_MIN / 10)))
     304            0 :                     goto out_of_range;
     305              : 
     306          121 :                 tmp = tmp * 10 + (*ptr++ - '0');
     307              :             }
     308          129 :             else if (*ptr == '_')
     309              :             {
     310              :                 /* underscore may not be first */
     311           24 :                 if (unlikely(ptr == firstdigit))
     312            4 :                     goto invalid_syntax;
     313              :                 /* and it must be followed by more digits */
     314           20 :                 ptr++;
     315           20 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     316            8 :                     goto invalid_syntax;
     317              :             }
     318              :             else
     319          105 :                 break;
     320              :         }
     321              :     }
     322              : 
     323              :     /* require at least one digit */
     324          189 :     if (unlikely(ptr == firstdigit))
     325           80 :         goto invalid_syntax;
     326              : 
     327              :     /* allow trailing whitespace, but not other trailing chars */
     328          133 :     while (isspace((unsigned char) *ptr))
     329           24 :         ptr++;
     330              : 
     331          109 :     if (unlikely(*ptr != '\0'))
     332           17 :         goto invalid_syntax;
     333              : 
     334           92 :     if (neg)
     335              :     {
     336           28 :         if (unlikely(pg_neg_u16_overflow(tmp, &result)))
     337           12 :             goto out_of_range;
     338           16 :         return result;
     339              :     }
     340              : 
     341           64 :     if (tmp > PG_INT16_MAX)
     342           12 :         goto out_of_range;
     343              : 
     344           52 :     return (int16) tmp;
     345              : 
     346           36 : out_of_range:
     347           36 :     ereturn(escontext, 0,
     348              :             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     349              :              errmsg("value \"%s\" is out of range for type %s",
     350              :                     s, "smallint")));
     351              : 
     352          109 : invalid_syntax:
     353          109 :     ereturn(escontext, 0,
     354              :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     355              :              errmsg("invalid input syntax for type %s: \"%s\"",
     356              :                     "smallint", s)));
     357              : }
     358              : 
     359              : /*
     360              :  * Convert input string to a signed 32 bit integer.  Input strings may be
     361              :  * expressed in base-10, hexadecimal, octal, or binary format, all of which
     362              :  * can be prefixed by an optional sign character, either '+' (the default) or
     363              :  * '-' for negative numbers.  Hex strings are recognized by the digits being
     364              :  * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
     365              :  * prefix.  The binary representation is recognized by the 0b or 0B prefix.
     366              :  *
     367              :  * Allows any number of leading or trailing whitespace characters.  Digits may
     368              :  * optionally be separated by a single underscore character.  These can only
     369              :  * come between digits and not before or after the digits.  Underscores have
     370              :  * no effect on the return value and are supported only to assist in improving
     371              :  * the human readability of the input strings.
     372              :  *
     373              :  * pg_strtoint32() will throw ereport() upon bad input format or overflow;
     374              :  * while pg_strtoint32_safe() instead returns such complaints in *escontext,
     375              :  * if it's an ErrorSaveContext.
     376              :  *
     377              :  * NB: Accumulate input as an unsigned number, to deal with two's complement
     378              :  * representation of the most negative number, which can't be represented as a
     379              :  * signed positive number.
     380              :  */
     381              : int32
     382         7223 : pg_strtoint32(const char *s)
     383              : {
     384         7223 :     return pg_strtoint32_safe(s, NULL);
     385              : }
     386              : 
     387              : int32
     388      2960147 : pg_strtoint32_safe(const char *s, Node *escontext)
     389              : {
     390      2960147 :     const char *ptr = s;
     391              :     const char *firstdigit;
     392      2960147 :     uint32      tmp = 0;
     393      2960147 :     bool        neg = false;
     394              :     unsigned char digit;
     395              :     int32       result;
     396              : 
     397              :     /*
     398              :      * The majority of cases are likely to be base-10 digits without any
     399              :      * underscore separator characters.  We'll first try to parse the string
     400              :      * with the assumption that's the case and only fallback on a slower
     401              :      * implementation which handles hex, octal and binary strings and
     402              :      * underscores if the fastpath version cannot parse the string.
     403              :      */
     404              : 
     405              :     /* leave it up to the slow path to look for leading spaces */
     406              : 
     407      2960147 :     if (*ptr == '-')
     408              :     {
     409        29733 :         ptr++;
     410        29733 :         neg = true;
     411              :     }
     412              : 
     413              :     /* a leading '+' is uncommon so leave that for the slow path */
     414              : 
     415              :     /* process the first digit */
     416      2960147 :     digit = (*ptr - '0');
     417              : 
     418              :     /*
     419              :      * Exploit unsigned arithmetic to save having to check both the upper and
     420              :      * lower bounds of the digit.
     421              :      */
     422      2960147 :     if (likely(digit < 10))
     423              :     {
     424      2959777 :         ptr++;
     425      2959777 :         tmp = digit;
     426              :     }
     427              :     else
     428              :     {
     429              :         /* we need at least one digit */
     430          370 :         goto slow;
     431              :     }
     432              : 
     433              :     /* process remaining digits */
     434              :     for (;;)
     435              :     {
     436      8617096 :         digit = (*ptr - '0');
     437              : 
     438      8617096 :         if (digit >= 10)
     439      2958935 :             break;
     440              : 
     441      5658161 :         ptr++;
     442              : 
     443      5658161 :         if (unlikely(tmp > -(PG_INT32_MIN / 10)))
     444          842 :             goto out_of_range;
     445              : 
     446      5657319 :         tmp = tmp * 10 + digit;
     447              :     }
     448              : 
     449              :     /* when the string does not end in a digit, let the slow path handle it */
     450      2958935 :     if (unlikely(*ptr != '\0'))
     451          826 :         goto slow;
     452              : 
     453      2958109 :     if (neg)
     454              :     {
     455        29697 :         if (unlikely(pg_neg_u32_overflow(tmp, &result)))
     456            0 :             goto out_of_range;
     457        29697 :         return result;
     458              :     }
     459              : 
     460      2928412 :     if (unlikely(tmp > PG_INT32_MAX))
     461          131 :         goto out_of_range;
     462              : 
     463      2928281 :     return (int32) tmp;
     464              : 
     465         1196 : slow:
     466         1196 :     tmp = 0;
     467         1196 :     ptr = s;
     468              :     /* no need to reset neg */
     469              : 
     470              :     /* skip leading spaces */
     471         1293 :     while (isspace((unsigned char) *ptr))
     472           97 :         ptr++;
     473              : 
     474              :     /* handle sign */
     475         1196 :     if (*ptr == '-')
     476              :     {
     477           40 :         ptr++;
     478           40 :         neg = true;
     479              :     }
     480         1156 :     else if (*ptr == '+')
     481            4 :         ptr++;
     482              : 
     483              :     /* process digits */
     484         1196 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     485              :     {
     486          552 :         firstdigit = ptr += 2;
     487              : 
     488              :         for (;;)
     489              :         {
     490         2804 :             if (isxdigit((unsigned char) *ptr))
     491              :             {
     492         2289 :                 if (unlikely(tmp > -(PG_INT32_MIN / 16)))
     493           45 :                     goto out_of_range;
     494              : 
     495         2244 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     496              :             }
     497          515 :             else if (*ptr == '_')
     498              :             {
     499              :                 /* underscore must be followed by more digits */
     500            8 :                 ptr++;
     501            8 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     502            0 :                     goto invalid_syntax;
     503              :             }
     504              :             else
     505          507 :                 break;
     506              :         }
     507              :     }
     508          644 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     509              :     {
     510           68 :         firstdigit = ptr += 2;
     511              : 
     512              :         for (;;)
     513              :         {
     514          648 :             if (*ptr >= '0' && *ptr <= '7')
     515              :             {
     516          588 :                 if (unlikely(tmp > -(PG_INT32_MIN / 8)))
     517           16 :                     goto out_of_range;
     518              : 
     519          572 :                 tmp = tmp * 8 + (*ptr++ - '0');
     520              :             }
     521           60 :             else if (*ptr == '_')
     522              :             {
     523              :                 /* underscore must be followed by more digits */
     524            8 :                 ptr++;
     525            8 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     526            0 :                     goto invalid_syntax;
     527              :             }
     528              :             else
     529           52 :                 break;
     530              :         }
     531              :     }
     532          576 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     533              :     {
     534           69 :         firstdigit = ptr += 2;
     535              : 
     536              :         for (;;)
     537              :         {
     538         1737 :             if (*ptr >= '0' && *ptr <= '1')
     539              :             {
     540         1669 :                 if (unlikely(tmp > -(PG_INT32_MIN / 2)))
     541           17 :                     goto out_of_range;
     542              : 
     543         1652 :                 tmp = tmp * 2 + (*ptr++ - '0');
     544              :             }
     545           68 :             else if (*ptr == '_')
     546              :             {
     547              :                 /* underscore must be followed by more digits */
     548           16 :                 ptr++;
     549           16 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     550            0 :                     goto invalid_syntax;
     551              :             }
     552              :             else
     553           52 :                 break;
     554              :         }
     555              :     }
     556              :     else
     557              :     {
     558          507 :         firstdigit = ptr;
     559              : 
     560              :         for (;;)
     561              :         {
     562         1397 :             if (*ptr >= '0' && *ptr <= '9')
     563              :             {
     564          762 :                 if (unlikely(tmp > -(PG_INT32_MIN / 10)))
     565           17 :                     goto out_of_range;
     566              : 
     567          745 :                 tmp = tmp * 10 + (*ptr++ - '0');
     568              :             }
     569          635 :             else if (*ptr == '_')
     570              :             {
     571              :                 /* underscore may not be first */
     572          157 :                 if (unlikely(ptr == firstdigit))
     573            4 :                     goto invalid_syntax;
     574              :                 /* and it must be followed by more digits */
     575          153 :                 ptr++;
     576          153 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     577            8 :                     goto invalid_syntax;
     578              :             }
     579              :             else
     580          478 :                 break;
     581              :         }
     582              :     }
     583              : 
     584              :     /* require at least one digit */
     585         1089 :     if (unlikely(ptr == firstdigit))
     586          337 :         goto invalid_syntax;
     587              : 
     588              :     /* allow trailing whitespace, but not other trailing chars */
     589          808 :     while (isspace((unsigned char) *ptr))
     590           56 :         ptr++;
     591              : 
     592          752 :     if (unlikely(*ptr != '\0'))
     593           53 :         goto invalid_syntax;
     594              : 
     595          699 :     if (neg)
     596              :     {
     597           28 :         if (unlikely(pg_neg_u32_overflow(tmp, &result)))
     598           12 :             goto out_of_range;
     599           16 :         return result;
     600              :     }
     601              : 
     602          671 :     if (tmp > PG_INT32_MAX)
     603           48 :         goto out_of_range;
     604              : 
     605          623 :     return (int32) tmp;
     606              : 
     607         1128 : out_of_range:
     608         1128 :     ereturn(escontext, 0,
     609              :             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     610              :              errmsg("value \"%s\" is out of range for type %s",
     611              :                     s, "integer")));
     612              : 
     613          402 : invalid_syntax:
     614          402 :     ereturn(escontext, 0,
     615              :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     616              :              errmsg("invalid input syntax for type %s: \"%s\"",
     617              :                     "integer", s)));
     618              : }
     619              : 
     620              : /*
     621              :  * Convert input string to a signed 64 bit integer.  Input strings may be
     622              :  * expressed in base-10, hexadecimal, octal, or binary format, all of which
     623              :  * can be prefixed by an optional sign character, either '+' (the default) or
     624              :  * '-' for negative numbers.  Hex strings are recognized by the digits being
     625              :  * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
     626              :  * prefix.  The binary representation is recognized by the 0b or 0B prefix.
     627              :  *
     628              :  * Allows any number of leading or trailing whitespace characters.  Digits may
     629              :  * optionally be separated by a single underscore character.  These can only
     630              :  * come between digits and not before or after the digits.  Underscores have
     631              :  * no effect on the return value and are supported only to assist in improving
     632              :  * the human readability of the input strings.
     633              :  *
     634              :  * pg_strtoint64() will throw ereport() upon bad input format or overflow;
     635              :  * while pg_strtoint64_safe() instead returns such complaints in *escontext,
     636              :  * if it's an ErrorSaveContext.
     637              :  *
     638              :  * NB: Accumulate input as an unsigned number, to deal with two's complement
     639              :  * representation of the most negative number, which can't be represented as a
     640              :  * signed positive number.
     641              :  */
     642              : int64
     643            7 : pg_strtoint64(const char *s)
     644              : {
     645            7 :     return pg_strtoint64_safe(s, NULL);
     646              : }
     647              : 
     648              : int64
     649        88354 : pg_strtoint64_safe(const char *s, Node *escontext)
     650              : {
     651        88354 :     const char *ptr = s;
     652              :     const char *firstdigit;
     653        88354 :     uint64      tmp = 0;
     654        88354 :     bool        neg = false;
     655              :     unsigned char digit;
     656              :     int64       result;
     657              : 
     658              :     /*
     659              :      * The majority of cases are likely to be base-10 digits without any
     660              :      * underscore separator characters.  We'll first try to parse the string
     661              :      * with the assumption that's the case and only fallback on a slower
     662              :      * implementation which handles hex, octal and binary strings and
     663              :      * underscores if the fastpath version cannot parse the string.
     664              :      */
     665              : 
     666              :     /* leave it up to the slow path to look for leading spaces */
     667              : 
     668        88354 :     if (*ptr == '-')
     669              :     {
     670         1013 :         ptr++;
     671         1013 :         neg = true;
     672              :     }
     673              : 
     674              :     /* a leading '+' is uncommon so leave that for the slow path */
     675              : 
     676              :     /* process the first digit */
     677        88354 :     digit = (*ptr - '0');
     678              : 
     679              :     /*
     680              :      * Exploit unsigned arithmetic to save having to check both the upper and
     681              :      * lower bounds of the digit.
     682              :      */
     683        88354 :     if (likely(digit < 10))
     684              :     {
     685        88217 :         ptr++;
     686        88217 :         tmp = digit;
     687              :     }
     688              :     else
     689              :     {
     690              :         /* we need at least one digit */
     691          137 :         goto slow;
     692              :     }
     693              : 
     694              :     /* process remaining digits */
     695              :     for (;;)
     696              :     {
     697       212541 :         digit = (*ptr - '0');
     698              : 
     699       212541 :         if (digit >= 10)
     700        88057 :             break;
     701              : 
     702       124484 :         ptr++;
     703              : 
     704       124484 :         if (unlikely(tmp > -(PG_INT64_MIN / 10)))
     705          160 :             goto out_of_range;
     706              : 
     707       124324 :         tmp = tmp * 10 + digit;
     708              :     }
     709              : 
     710              :     /* when the string does not end in a digit, let the slow path handle it */
     711        88057 :     if (unlikely(*ptr != '\0'))
     712         6965 :         goto slow;
     713              : 
     714        81092 :     if (neg)
     715              :     {
     716          582 :         if (unlikely(pg_neg_u64_overflow(tmp, &result)))
     717           12 :             goto out_of_range;
     718          570 :         return result;
     719              :     }
     720              : 
     721        80510 :     if (unlikely(tmp > PG_INT64_MAX))
     722           12 :         goto out_of_range;
     723              : 
     724        80498 :     return (int64) tmp;
     725              : 
     726         7102 : slow:
     727         7102 :     tmp = 0;
     728         7102 :     ptr = s;
     729              :     /* no need to reset neg */
     730              : 
     731              :     /* skip leading spaces */
     732         7151 :     while (isspace((unsigned char) *ptr))
     733           49 :         ptr++;
     734              : 
     735              :     /* handle sign */
     736         7102 :     if (*ptr == '-')
     737              :     {
     738          427 :         ptr++;
     739          427 :         neg = true;
     740              :     }
     741         6675 :     else if (*ptr == '+')
     742           32 :         ptr++;
     743              : 
     744              :     /* process digits */
     745         7102 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     746              :     {
     747           83 :         firstdigit = ptr += 2;
     748              : 
     749              :         for (;;)
     750              :         {
     751         1114 :             if (isxdigit((unsigned char) *ptr))
     752              :             {
     753         1027 :                 if (unlikely(tmp > -(PG_INT64_MIN / 16)))
     754            0 :                     goto out_of_range;
     755              : 
     756         1027 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     757              :             }
     758           87 :             else if (*ptr == '_')
     759              :             {
     760              :                 /* underscore must be followed by more digits */
     761            4 :                 ptr++;
     762            4 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     763            0 :                     goto invalid_syntax;
     764              :             }
     765              :             else
     766           83 :                 break;
     767              :         }
     768              :     }
     769         7019 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     770              :     {
     771           56 :         firstdigit = ptr += 2;
     772              : 
     773              :         for (;;)
     774              :         {
     775          912 :             if (*ptr >= '0' && *ptr <= '7')
     776              :             {
     777          852 :                 if (unlikely(tmp > -(PG_INT64_MIN / 8)))
     778            0 :                     goto out_of_range;
     779              : 
     780          852 :                 tmp = tmp * 8 + (*ptr++ - '0');
     781              :             }
     782           60 :             else if (*ptr == '_')
     783              :             {
     784              :                 /* underscore must be followed by more digits */
     785            4 :                 ptr++;
     786            4 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     787            0 :                     goto invalid_syntax;
     788              :             }
     789              :             else
     790           56 :                 break;
     791              :         }
     792              :     }
     793         6963 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     794              :     {
     795           56 :         firstdigit = ptr += 2;
     796              : 
     797              :         for (;;)
     798              :         {
     799         2536 :             if (*ptr >= '0' && *ptr <= '1')
     800              :             {
     801         2472 :                 if (unlikely(tmp > -(PG_INT64_MIN / 2)))
     802            0 :                     goto out_of_range;
     803              : 
     804         2472 :                 tmp = tmp * 2 + (*ptr++ - '0');
     805              :             }
     806           64 :             else if (*ptr == '_')
     807              :             {
     808              :                 /* underscore must be followed by more digits */
     809            8 :                 ptr++;
     810            8 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     811            0 :                     goto invalid_syntax;
     812              :             }
     813              :             else
     814           56 :                 break;
     815              :         }
     816              :     }
     817              :     else
     818              :     {
     819         6907 :         firstdigit = ptr;
     820              : 
     821              :         for (;;)
     822              :         {
     823        17410 :             if (*ptr >= '0' && *ptr <= '9')
     824              :             {
     825        10423 :                 if (unlikely(tmp > -(PG_INT64_MIN / 10)))
     826            0 :                     goto out_of_range;
     827              : 
     828        10423 :                 tmp = tmp * 10 + (*ptr++ - '0');
     829              :             }
     830         6987 :             else if (*ptr == '_')
     831              :             {
     832              :                 /* underscore may not be first */
     833           92 :                 if (unlikely(ptr == firstdigit))
     834            4 :                     goto invalid_syntax;
     835              :                 /* and it must be followed by more digits */
     836           88 :                 ptr++;
     837           88 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     838            8 :                     goto invalid_syntax;
     839              :             }
     840              :             else
     841         6895 :                 break;
     842              :         }
     843              :     }
     844              : 
     845              :     /* require at least one digit */
     846         7090 :     if (unlikely(ptr == firstdigit))
     847          100 :         goto invalid_syntax;
     848              : 
     849              :     /* allow trailing whitespace, but not other trailing chars */
     850         7034 :     while (isspace((unsigned char) *ptr))
     851           44 :         ptr++;
     852              : 
     853         6990 :     if (unlikely(*ptr != '\0'))
     854         6741 :         goto invalid_syntax;
     855              : 
     856          249 :     if (neg)
     857              :     {
     858           76 :         if (unlikely(pg_neg_u64_overflow(tmp, &result)))
     859           24 :             goto out_of_range;
     860           52 :         return result;
     861              :     }
     862              : 
     863          173 :     if (tmp > PG_INT64_MAX)
     864           24 :         goto out_of_range;
     865              : 
     866          149 :     return (int64) tmp;
     867              : 
     868          232 : out_of_range:
     869          232 :     ereturn(escontext, 0,
     870              :             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     871              :              errmsg("value \"%s\" is out of range for type %s",
     872              :                     s, "bigint")));
     873              : 
     874         6853 : invalid_syntax:
     875         6853 :     ereturn(escontext, 0,
     876              :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     877              :              errmsg("invalid input syntax for type %s: \"%s\"",
     878              :                     "bigint", s)));
     879              : }
     880              : 
     881              : /*
     882              :  * Convert input string to an unsigned 32 bit integer.
     883              :  *
     884              :  * Allows any number of leading or trailing whitespace characters.
     885              :  *
     886              :  * If endloc isn't NULL, store a pointer to the rest of the string there,
     887              :  * so that caller can parse the rest.  Otherwise, it's an error if anything
     888              :  * but whitespace follows.
     889              :  *
     890              :  * typname is what is reported in error messages.
     891              :  *
     892              :  * If escontext points to an ErrorSaveContext node, that is filled instead
     893              :  * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
     894              :  * to detect errors.
     895              :  */
     896              : uint32
     897      4026170 : uint32in_subr(const char *s, char **endloc,
     898              :               const char *typname, Node *escontext)
     899              : {
     900              :     uint32      result;
     901              :     unsigned long cvt;
     902              :     char       *endptr;
     903              : 
     904      4026170 :     errno = 0;
     905      4026170 :     cvt = strtoul(s, &endptr, 0);
     906              : 
     907              :     /*
     908              :      * strtoul() normally only sets ERANGE.  On some systems it may also set
     909              :      * EINVAL, which simply means it couldn't parse the input string.  Be sure
     910              :      * to report that the same way as the standard error indication (that
     911              :      * endptr == s).
     912              :      */
     913      4026170 :     if ((errno && errno != ERANGE) || endptr == s)
     914           40 :         ereturn(escontext, 0,
     915              :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     916              :                  errmsg("invalid input syntax for type %s: \"%s\"",
     917              :                         typname, s)));
     918              : 
     919      4026130 :     if (errno == ERANGE)
     920            8 :         ereturn(escontext, 0,
     921              :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     922              :                  errmsg("value \"%s\" is out of range for type %s",
     923              :                         s, typname)));
     924              : 
     925      4026122 :     if (endloc)
     926              :     {
     927              :         /* caller wants to deal with rest of string */
     928       357270 :         *endloc = endptr;
     929              :     }
     930              :     else
     931              :     {
     932              :         /* allow only whitespace after number */
     933      3668928 :         while (*endptr && isspace((unsigned char) *endptr))
     934           76 :             endptr++;
     935      3668852 :         if (*endptr)
     936           24 :             ereturn(escontext, 0,
     937              :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     938              :                      errmsg("invalid input syntax for type %s: \"%s\"",
     939              :                             typname, s)));
     940              :     }
     941              : 
     942      4026098 :     result = (uint32) cvt;
     943              : 
     944              :     /*
     945              :      * Cope with possibility that unsigned long is wider than uint32, in which
     946              :      * case strtoul will not raise an error for some values that are out of
     947              :      * the range of uint32.
     948              :      *
     949              :      * For backwards compatibility, we want to accept inputs that are given
     950              :      * with a minus sign, so allow the input value if it matches after either
     951              :      * signed or unsigned extension to long.
     952              :      *
     953              :      * To ensure consistent results on 32-bit and 64-bit platforms, make sure
     954              :      * the error message is the same as if strtoul() had returned ERANGE.
     955              :      */
     956              : #if PG_UINT32_MAX != ULONG_MAX
     957      4026098 :     if (cvt != (unsigned long) result &&
     958           28 :         cvt != (unsigned long) ((int) result))
     959           20 :         ereturn(escontext, 0,
     960              :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     961              :                  errmsg("value \"%s\" is out of range for type %s",
     962              :                         s, typname)));
     963              : #endif
     964              : 
     965      4026078 :     return result;
     966              : }
     967              : 
     968              : /*
     969              :  * Convert input string to an unsigned 64 bit integer.
     970              :  *
     971              :  * Allows any number of leading or trailing whitespace characters.
     972              :  *
     973              :  * If endloc isn't NULL, store a pointer to the rest of the string there,
     974              :  * so that caller can parse the rest.  Otherwise, it's an error if anything
     975              :  * but whitespace follows.
     976              :  *
     977              :  * typname is what is reported in error messages.
     978              :  *
     979              :  * If escontext points to an ErrorSaveContext node, that is filled instead
     980              :  * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
     981              :  * to detect errors.
     982              :  */
     983              : uint64
     984         2709 : uint64in_subr(const char *s, char **endloc,
     985              :               const char *typname, Node *escontext)
     986              : {
     987              :     uint64      result;
     988              :     char       *endptr;
     989              : 
     990         2709 :     errno = 0;
     991         2709 :     result = strtou64(s, &endptr, 0);
     992              : 
     993              :     /*
     994              :      * strtoul[l] normally only sets ERANGE.  On some systems it may also set
     995              :      * EINVAL, which simply means it couldn't parse the input string.  Be sure
     996              :      * to report that the same way as the standard error indication (that
     997              :      * endptr == s).
     998              :      */
     999         2709 :     if ((errno && errno != ERANGE) || endptr == s)
    1000           28 :         ereturn(escontext, 0,
    1001              :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1002              :                  errmsg("invalid input syntax for type %s: \"%s\"",
    1003              :                         typname, s)));
    1004              : 
    1005         2681 :     if (errno == ERANGE)
    1006           24 :         ereturn(escontext, 0,
    1007              :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1008              :                  errmsg("value \"%s\" is out of range for type %s",
    1009              :                         s, typname)));
    1010              : 
    1011         2657 :     if (endloc)
    1012              :     {
    1013              :         /* caller wants to deal with rest of string */
    1014            0 :         *endloc = endptr;
    1015              :     }
    1016              :     else
    1017              :     {
    1018              :         /* allow only whitespace after number */
    1019         2733 :         while (*endptr && isspace((unsigned char) *endptr))
    1020           76 :             endptr++;
    1021         2657 :         if (*endptr)
    1022           24 :             ereturn(escontext, 0,
    1023              :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1024              :                      errmsg("invalid input syntax for type %s: \"%s\"",
    1025              :                             typname, s)));
    1026              :     }
    1027              : 
    1028         2633 :     return result;
    1029              : }
    1030              : 
    1031              : /*
    1032              :  * pg_itoa: converts a signed 16-bit integer to its string representation
    1033              :  * and returns strlen(a).
    1034              :  *
    1035              :  * Caller must ensure that 'a' points to enough memory to hold the result
    1036              :  * (at least 7 bytes, counting a leading sign and trailing NUL).
    1037              :  *
    1038              :  * It doesn't seem worth implementing this separately.
    1039              :  */
    1040              : int
    1041       395224 : pg_itoa(int16 i, char *a)
    1042              : {
    1043       395224 :     return pg_ltoa((int32) i, a);
    1044              : }
    1045              : 
    1046              : /*
    1047              :  * pg_ultoa_n: converts an unsigned 32-bit integer to its string representation,
    1048              :  * not NUL-terminated, and returns the length of that string representation
    1049              :  *
    1050              :  * Caller must ensure that 'a' points to enough memory to hold the result (at
    1051              :  * least 10 bytes)
    1052              :  */
    1053              : int
    1054     10635563 : pg_ultoa_n(uint32 value, char *a)
    1055              : {
    1056              :     int         olength,
    1057     10635563 :                 i = 0;
    1058              : 
    1059              :     /* Degenerate case */
    1060     10635563 :     if (value == 0)
    1061              :     {
    1062      2585686 :         *a = '0';
    1063      2585686 :         return 1;
    1064              :     }
    1065              : 
    1066      8049877 :     olength = decimalLength32(value);
    1067              : 
    1068              :     /* Compute the result string. */
    1069      9332194 :     while (value >= 10000)
    1070              :     {
    1071      1282317 :         const uint32 c = value - 10000 * (value / 10000);
    1072      1282317 :         const uint32 c0 = (c % 100) << 1;
    1073      1282317 :         const uint32 c1 = (c / 100) << 1;
    1074              : 
    1075      1282317 :         char       *pos = a + olength - i;
    1076              : 
    1077      1282317 :         value /= 10000;
    1078              : 
    1079      1282317 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1080      1282317 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1081      1282317 :         i += 4;
    1082              :     }
    1083      8049877 :     if (value >= 100)
    1084              :     {
    1085      3530551 :         const uint32 c = (value % 100) << 1;
    1086              : 
    1087      3530551 :         char       *pos = a + olength - i;
    1088              : 
    1089      3530551 :         value /= 100;
    1090              : 
    1091      3530551 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1092      3530551 :         i += 2;
    1093              :     }
    1094      8049877 :     if (value >= 10)
    1095              :     {
    1096      4004591 :         const uint32 c = value << 1;
    1097              : 
    1098      4004591 :         char       *pos = a + olength - i;
    1099              : 
    1100      4004591 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1101              :     }
    1102              :     else
    1103              :     {
    1104      4045286 :         *a = (char) ('0' + value);
    1105              :     }
    1106              : 
    1107      8049877 :     return olength;
    1108              : }
    1109              : 
    1110              : /*
    1111              :  * pg_ltoa: converts a signed 32-bit integer to its string representation and
    1112              :  * returns strlen(a).
    1113              :  *
    1114              :  * It is the caller's responsibility to ensure that a is at least 12 bytes long,
    1115              :  * which is enough room to hold a minus sign, a maximally long int32, and the
    1116              :  * above terminating NUL.
    1117              :  */
    1118              : int
    1119     10556142 : pg_ltoa(int32 value, char *a)
    1120              : {
    1121     10556142 :     uint32      uvalue = (uint32) value;
    1122     10556142 :     int         len = 0;
    1123              : 
    1124     10556142 :     if (value < 0)
    1125              :     {
    1126       330361 :         uvalue = (uint32) 0 - uvalue;
    1127       330361 :         a[len++] = '-';
    1128              :     }
    1129     10556142 :     len += pg_ultoa_n(uvalue, a + len);
    1130     10556142 :     a[len] = '\0';
    1131     10556142 :     return len;
    1132              : }
    1133              : 
    1134              : /*
    1135              :  * Get the decimal representation, not NUL-terminated, and return the length of
    1136              :  * same.  Caller must ensure that a points to at least MAXINT8LEN bytes.
    1137              :  */
    1138              : int
    1139       412254 : pg_ulltoa_n(uint64 value, char *a)
    1140              : {
    1141              :     int         olength,
    1142       412254 :                 i = 0;
    1143              :     uint32      value2;
    1144              : 
    1145              :     /* Degenerate case */
    1146       412254 :     if (value == 0)
    1147              :     {
    1148        44850 :         *a = '0';
    1149        44850 :         return 1;
    1150              :     }
    1151              : 
    1152       367404 :     olength = decimalLength64(value);
    1153              : 
    1154              :     /* Compute the result string. */
    1155       379727 :     while (value >= 100000000)
    1156              :     {
    1157        12323 :         const uint64 q = value / 100000000;
    1158        12323 :         uint32      value3 = (uint32) (value - 100000000 * q);
    1159              : 
    1160        12323 :         const uint32 c = value3 % 10000;
    1161        12323 :         const uint32 d = value3 / 10000;
    1162        12323 :         const uint32 c0 = (c % 100) << 1;
    1163        12323 :         const uint32 c1 = (c / 100) << 1;
    1164        12323 :         const uint32 d0 = (d % 100) << 1;
    1165        12323 :         const uint32 d1 = (d / 100) << 1;
    1166              : 
    1167        12323 :         char       *pos = a + olength - i;
    1168              : 
    1169        12323 :         value = q;
    1170              : 
    1171        12323 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1172        12323 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1173        12323 :         memcpy(pos - 6, DIGIT_TABLE + d0, 2);
    1174        12323 :         memcpy(pos - 8, DIGIT_TABLE + d1, 2);
    1175        12323 :         i += 8;
    1176              :     }
    1177              : 
    1178              :     /* Switch to 32-bit for speed */
    1179       367404 :     value2 = (uint32) value;
    1180              : 
    1181       367404 :     if (value2 >= 10000)
    1182              :     {
    1183        17512 :         const uint32 c = value2 - 10000 * (value2 / 10000);
    1184        17512 :         const uint32 c0 = (c % 100) << 1;
    1185        17512 :         const uint32 c1 = (c / 100) << 1;
    1186              : 
    1187        17512 :         char       *pos = a + olength - i;
    1188              : 
    1189        17512 :         value2 /= 10000;
    1190              : 
    1191        17512 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1192        17512 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1193        17512 :         i += 4;
    1194              :     }
    1195       367404 :     if (value2 >= 100)
    1196              :     {
    1197       118583 :         const uint32 c = (value2 % 100) << 1;
    1198       118583 :         char       *pos = a + olength - i;
    1199              : 
    1200       118583 :         value2 /= 100;
    1201              : 
    1202       118583 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1203       118583 :         i += 2;
    1204              :     }
    1205       367404 :     if (value2 >= 10)
    1206              :     {
    1207        76645 :         const uint32 c = value2 << 1;
    1208        76645 :         char       *pos = a + olength - i;
    1209              : 
    1210        76645 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1211              :     }
    1212              :     else
    1213       290759 :         *a = (char) ('0' + value2);
    1214              : 
    1215       367404 :     return olength;
    1216              : }
    1217              : 
    1218              : /*
    1219              :  * pg_lltoa: converts a signed 64-bit integer to its string representation and
    1220              :  * returns strlen(a).
    1221              :  *
    1222              :  * Caller must ensure that 'a' points to enough memory to hold the result
    1223              :  * (at least MAXINT8LEN + 1 bytes, counting a leading sign and trailing NUL).
    1224              :  */
    1225              : int
    1226       174985 : pg_lltoa(int64 value, char *a)
    1227              : {
    1228       174985 :     uint64      uvalue = value;
    1229       174985 :     int         len = 0;
    1230              : 
    1231       174985 :     if (value < 0)
    1232              :     {
    1233         1759 :         uvalue = (uint64) 0 - uvalue;
    1234         1759 :         a[len++] = '-';
    1235              :     }
    1236              : 
    1237       174985 :     len += pg_ulltoa_n(uvalue, a + len);
    1238       174985 :     a[len] = '\0';
    1239       174985 :     return len;
    1240              : }
    1241              : 
    1242              : 
    1243              : /*
    1244              :  * pg_ultostr_zeropad
    1245              :  *      Converts 'value' into a decimal string representation stored at 'str'.
    1246              :  *      'minwidth' specifies the minimum width of the result; any extra space
    1247              :  *      is filled up by prefixing the number with zeros.
    1248              :  *
    1249              :  * Returns the ending address of the string result (the last character written
    1250              :  * plus 1).  Note that no NUL terminator is written.
    1251              :  *
    1252              :  * The intended use-case for this function is to build strings that contain
    1253              :  * multiple individual numbers, for example:
    1254              :  *
    1255              :  *  str = pg_ultostr_zeropad(str, hours, 2);
    1256              :  *  *str++ = ':';
    1257              :  *  str = pg_ultostr_zeropad(str, mins, 2);
    1258              :  *  *str++ = ':';
    1259              :  *  str = pg_ultostr_zeropad(str, secs, 2);
    1260              :  *  *str = '\0';
    1261              :  *
    1262              :  * Note: Caller must ensure that 'str' points to enough memory to hold the
    1263              :  * result.
    1264              :  */
    1265              : char *
    1266       462844 : pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth)
    1267              : {
    1268              :     int         len;
    1269              : 
    1270              :     Assert(minwidth > 0);
    1271              : 
    1272       462844 :     if (value < 100 && minwidth == 2)    /* Short cut for common case */
    1273              :     {
    1274       385659 :         memcpy(str, DIGIT_TABLE + value * 2, 2);
    1275       385659 :         return str + 2;
    1276              :     }
    1277              : 
    1278        77185 :     len = pg_ultoa_n(value, str);
    1279        77185 :     if (len >= minwidth)
    1280        76729 :         return str + len;
    1281              : 
    1282          456 :     memmove(str + minwidth - len, str, len);
    1283          456 :     memset(str, '0', minwidth - len);
    1284          456 :     return str + minwidth;
    1285              : }
    1286              : 
    1287              : /*
    1288              :  * pg_ultostr
    1289              :  *      Converts 'value' into a decimal string representation stored at 'str'.
    1290              :  *
    1291              :  * Returns the ending address of the string result (the last character written
    1292              :  * plus 1).  Note that no NUL terminator is written.
    1293              :  *
    1294              :  * The intended use-case for this function is to build strings that contain
    1295              :  * multiple individual numbers, for example:
    1296              :  *
    1297              :  *  str = pg_ultostr(str, a);
    1298              :  *  *str++ = ' ';
    1299              :  *  str = pg_ultostr(str, b);
    1300              :  *  *str = '\0';
    1301              :  *
    1302              :  * Note: Caller must ensure that 'str' points to enough memory to hold the
    1303              :  * result.
    1304              :  */
    1305              : char *
    1306         2198 : pg_ultostr(char *str, uint32 value)
    1307              : {
    1308         2198 :     int         len = pg_ultoa_n(value, str);
    1309              : 
    1310         2198 :     return str + len;
    1311              : }
        

Generated by: LCOV version 2.0-1