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-02-17 17:20:33 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      7209912 : 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      7209912 :     t = (pg_leftmost_one_pos32(v) + 1) * 1233 / 4096;
      59      7209912 :     return t + (v >= PowersOfTen[t]);
      60              : }
      61              : 
      62              : static inline int
      63       324107 : 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       324107 :     t = (pg_leftmost_one_pos64(v) + 1) * 1233 / 4096;
      84       324107 :     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       487307 : pg_strtoint16_safe(const char *s, Node *escontext)
     128              : {
     129       487307 :     const char *ptr = s;
     130              :     const char *firstdigit;
     131       487307 :     uint16      tmp = 0;
     132       487307 :     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       487307 :     if (*ptr == '-')
     147              :     {
     148         9883 :         ptr++;
     149         9883 :         neg = true;
     150              :     }
     151              : 
     152              :     /* a leading '+' is uncommon so leave that for the slow path */
     153              : 
     154              :     /* process the first digit */
     155       487307 :     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       487307 :     if (likely(digit < 10))
     162              :     {
     163       487247 :         ptr++;
     164       487247 :         tmp = digit;
     165              :     }
     166              :     else
     167              :     {
     168              :         /* we need at least one digit */
     169           60 :         goto slow;
     170              :     }
     171              : 
     172              :     /* process remaining digits */
     173              :     for (;;)
     174              :     {
     175       502343 :         digit = (*ptr - '0');
     176              : 
     177       502343 :         if (digit >= 10)
     178       487238 :             break;
     179              : 
     180        15105 :         ptr++;
     181              : 
     182        15105 :         if (unlikely(tmp > -(PG_INT16_MIN / 10)))
     183            9 :             goto out_of_range;
     184              : 
     185        15096 :         tmp = tmp * 10 + digit;
     186              :     }
     187              : 
     188              :     /* when the string does not end in a digit, let the slow path handle it */
     189       487238 :     if (unlikely(*ptr != '\0'))
     190           91 :         goto slow;
     191              : 
     192       487147 :     if (neg)
     193              :     {
     194         9862 :         if (unlikely(pg_neg_u16_overflow(tmp, &result)))
     195            0 :             goto out_of_range;
     196         9862 :         return result;
     197              :     }
     198              : 
     199       477285 :     if (unlikely(tmp > PG_INT16_MAX))
     200            0 :         goto out_of_range;
     201              : 
     202       477285 :     return (int16) tmp;
     203              : 
     204          151 : slow:
     205          151 :     tmp = 0;
     206          151 :     ptr = s;
     207              :     /* no need to reset neg */
     208              : 
     209              :     /* skip leading spaces */
     210          181 :     while (isspace((unsigned char) *ptr))
     211           30 :         ptr++;
     212              : 
     213              :     /* handle sign */
     214          151 :     if (*ptr == '-')
     215              :     {
     216           24 :         ptr++;
     217           24 :         neg = true;
     218              :     }
     219          127 :     else if (*ptr == '+')
     220            0 :         ptr++;
     221              : 
     222              :     /* process digits */
     223          151 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     224              :     {
     225           21 :         firstdigit = ptr += 2;
     226              : 
     227              :         for (;;)
     228              :         {
     229           90 :             if (isxdigit((unsigned char) *ptr))
     230              :             {
     231           66 :                 if (unlikely(tmp > -(PG_INT16_MIN / 16)))
     232            0 :                     goto out_of_range;
     233              : 
     234           66 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     235              :             }
     236           24 :             else if (*ptr == '_')
     237              :             {
     238              :                 /* underscore must be followed by more digits */
     239            3 :                 ptr++;
     240            3 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     241            0 :                     goto invalid_syntax;
     242              :             }
     243              :             else
     244           21 :                 break;
     245              :         }
     246              :     }
     247          130 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     248              :     {
     249           21 :         firstdigit = ptr += 2;
     250              : 
     251              :         for (;;)
     252              :         {
     253          111 :             if (*ptr >= '0' && *ptr <= '7')
     254              :             {
     255           87 :                 if (unlikely(tmp > -(PG_INT16_MIN / 8)))
     256            0 :                     goto out_of_range;
     257              : 
     258           87 :                 tmp = tmp * 8 + (*ptr++ - '0');
     259              :             }
     260           24 :             else if (*ptr == '_')
     261              :             {
     262              :                 /* underscore must be followed by more digits */
     263            3 :                 ptr++;
     264            3 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     265            0 :                     goto invalid_syntax;
     266              :             }
     267              :             else
     268           21 :                 break;
     269              :         }
     270              :     }
     271          109 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     272              :     {
     273           21 :         firstdigit = ptr += 2;
     274              : 
     275              :         for (;;)
     276              :         {
     277          252 :             if (*ptr >= '0' && *ptr <= '1')
     278              :             {
     279          225 :                 if (unlikely(tmp > -(PG_INT16_MIN / 2)))
     280            0 :                     goto out_of_range;
     281              : 
     282          225 :                 tmp = tmp * 2 + (*ptr++ - '0');
     283              :             }
     284           27 :             else if (*ptr == '_')
     285              :             {
     286              :                 /* underscore must be followed by more digits */
     287            6 :                 ptr++;
     288            6 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     289            0 :                     goto invalid_syntax;
     290              :             }
     291              :             else
     292           21 :                 break;
     293              :         }
     294              :     }
     295              :     else
     296              :     {
     297           88 :         firstdigit = ptr;
     298              : 
     299              :         for (;;)
     300              :         {
     301          188 :             if (*ptr >= '0' && *ptr <= '9')
     302              :             {
     303           91 :                 if (unlikely(tmp > -(PG_INT16_MIN / 10)))
     304            0 :                     goto out_of_range;
     305              : 
     306           91 :                 tmp = tmp * 10 + (*ptr++ - '0');
     307              :             }
     308           97 :             else if (*ptr == '_')
     309              :             {
     310              :                 /* underscore may not be first */
     311           18 :                 if (unlikely(ptr == firstdigit))
     312            3 :                     goto invalid_syntax;
     313              :                 /* and it must be followed by more digits */
     314           15 :                 ptr++;
     315           15 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     316            6 :                     goto invalid_syntax;
     317              :             }
     318              :             else
     319           79 :                 break;
     320              :         }
     321              :     }
     322              : 
     323              :     /* require at least one digit */
     324          142 :     if (unlikely(ptr == firstdigit))
     325           60 :         goto invalid_syntax;
     326              : 
     327              :     /* allow trailing whitespace, but not other trailing chars */
     328          100 :     while (isspace((unsigned char) *ptr))
     329           18 :         ptr++;
     330              : 
     331           82 :     if (unlikely(*ptr != '\0'))
     332           13 :         goto invalid_syntax;
     333              : 
     334           69 :     if (neg)
     335              :     {
     336           21 :         if (unlikely(pg_neg_u16_overflow(tmp, &result)))
     337            9 :             goto out_of_range;
     338           12 :         return result;
     339              :     }
     340              : 
     341           48 :     if (tmp > PG_INT16_MAX)
     342            9 :         goto out_of_range;
     343              : 
     344           39 :     return (int16) tmp;
     345              : 
     346           27 : out_of_range:
     347           27 :     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           82 : invalid_syntax:
     353           82 :     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         5819 : pg_strtoint32(const char *s)
     383              : {
     384         5819 :     return pg_strtoint32_safe(s, NULL);
     385              : }
     386              : 
     387              : int32
     388      2500552 : pg_strtoint32_safe(const char *s, Node *escontext)
     389              : {
     390      2500552 :     const char *ptr = s;
     391              :     const char *firstdigit;
     392      2500552 :     uint32      tmp = 0;
     393      2500552 :     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      2500552 :     if (*ptr == '-')
     408              :     {
     409        27421 :         ptr++;
     410        27421 :         neg = true;
     411              :     }
     412              : 
     413              :     /* a leading '+' is uncommon so leave that for the slow path */
     414              : 
     415              :     /* process the first digit */
     416      2500552 :     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      2500552 :     if (likely(digit < 10))
     423              :     {
     424      2500296 :         ptr++;
     425      2500296 :         tmp = digit;
     426              :     }
     427              :     else
     428              :     {
     429              :         /* we need at least one digit */
     430          256 :         goto slow;
     431              :     }
     432              : 
     433              :     /* process remaining digits */
     434              :     for (;;)
     435              :     {
     436      7082373 :         digit = (*ptr - '0');
     437              : 
     438      7082373 :         if (digit >= 10)
     439      2499625 :             break;
     440              : 
     441      4582748 :         ptr++;
     442              : 
     443      4582748 :         if (unlikely(tmp > -(PG_INT32_MIN / 10)))
     444          671 :             goto out_of_range;
     445              : 
     446      4582077 :         tmp = tmp * 10 + digit;
     447              :     }
     448              : 
     449              :     /* when the string does not end in a digit, let the slow path handle it */
     450      2499625 :     if (unlikely(*ptr != '\0'))
     451          707 :         goto slow;
     452              : 
     453      2498918 :     if (neg)
     454              :     {
     455        27394 :         if (unlikely(pg_neg_u32_overflow(tmp, &result)))
     456            0 :             goto out_of_range;
     457        27394 :         return result;
     458              :     }
     459              : 
     460      2471524 :     if (unlikely(tmp > PG_INT32_MAX))
     461          103 :         goto out_of_range;
     462              : 
     463      2471421 :     return (int32) tmp;
     464              : 
     465          963 : slow:
     466          963 :     tmp = 0;
     467          963 :     ptr = s;
     468              :     /* no need to reset neg */
     469              : 
     470              :     /* skip leading spaces */
     471         1038 :     while (isspace((unsigned char) *ptr))
     472           75 :         ptr++;
     473              : 
     474              :     /* handle sign */
     475          963 :     if (*ptr == '-')
     476              :     {
     477           30 :         ptr++;
     478           30 :         neg = true;
     479              :     }
     480          933 :     else if (*ptr == '+')
     481            3 :         ptr++;
     482              : 
     483              :     /* process digits */
     484          963 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     485              :     {
     486          499 :         firstdigit = ptr += 2;
     487              : 
     488              :         for (;;)
     489              :         {
     490         2471 :             if (isxdigit((unsigned char) *ptr))
     491              :             {
     492         2005 :                 if (unlikely(tmp > -(PG_INT32_MIN / 16)))
     493           39 :                     goto out_of_range;
     494              : 
     495         1966 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     496              :             }
     497          466 :             else if (*ptr == '_')
     498              :             {
     499              :                 /* underscore must be followed by more digits */
     500            6 :                 ptr++;
     501            6 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     502            0 :                     goto invalid_syntax;
     503              :             }
     504              :             else
     505          460 :                 break;
     506              :         }
     507              :     }
     508          464 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     509              :     {
     510           51 :         firstdigit = ptr += 2;
     511              : 
     512              :         for (;;)
     513              :         {
     514          486 :             if (*ptr >= '0' && *ptr <= '7')
     515              :             {
     516          441 :                 if (unlikely(tmp > -(PG_INT32_MIN / 8)))
     517           12 :                     goto out_of_range;
     518              : 
     519          429 :                 tmp = tmp * 8 + (*ptr++ - '0');
     520              :             }
     521           45 :             else if (*ptr == '_')
     522              :             {
     523              :                 /* underscore must be followed by more digits */
     524            6 :                 ptr++;
     525            6 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     526            0 :                     goto invalid_syntax;
     527              :             }
     528              :             else
     529           39 :                 break;
     530              :         }
     531              :     }
     532          413 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     533              :     {
     534           52 :         firstdigit = ptr += 2;
     535              : 
     536              :         for (;;)
     537              :         {
     538         1311 :             if (*ptr >= '0' && *ptr <= '1')
     539              :             {
     540         1260 :                 if (unlikely(tmp > -(PG_INT32_MIN / 2)))
     541           13 :                     goto out_of_range;
     542              : 
     543         1247 :                 tmp = tmp * 2 + (*ptr++ - '0');
     544              :             }
     545           51 :             else if (*ptr == '_')
     546              :             {
     547              :                 /* underscore must be followed by more digits */
     548           12 :                 ptr++;
     549           12 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     550            0 :                     goto invalid_syntax;
     551              :             }
     552              :             else
     553           39 :                 break;
     554              :         }
     555              :     }
     556              :     else
     557              :     {
     558          361 :         firstdigit = ptr;
     559              : 
     560              :         for (;;)
     561              :         {
     562         1058 :             if (*ptr >= '0' && *ptr <= '9')
     563              :             {
     564          596 :                 if (unlikely(tmp > -(PG_INT32_MIN / 10)))
     565           14 :                     goto out_of_range;
     566              : 
     567          582 :                 tmp = tmp * 10 + (*ptr++ - '0');
     568              :             }
     569          462 :             else if (*ptr == '_')
     570              :             {
     571              :                 /* underscore may not be first */
     572          124 :                 if (unlikely(ptr == firstdigit))
     573            3 :                     goto invalid_syntax;
     574              :                 /* and it must be followed by more digits */
     575          121 :                 ptr++;
     576          121 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     577            6 :                     goto invalid_syntax;
     578              :             }
     579              :             else
     580          338 :                 break;
     581              :         }
     582              :     }
     583              : 
     584              :     /* require at least one digit */
     585          876 :     if (unlikely(ptr == firstdigit))
     586          229 :         goto invalid_syntax;
     587              : 
     588              :     /* allow trailing whitespace, but not other trailing chars */
     589          689 :     while (isspace((unsigned char) *ptr))
     590           42 :         ptr++;
     591              : 
     592          647 :     if (unlikely(*ptr != '\0'))
     593           40 :         goto invalid_syntax;
     594              : 
     595          607 :     if (neg)
     596              :     {
     597           21 :         if (unlikely(pg_neg_u32_overflow(tmp, &result)))
     598            9 :             goto out_of_range;
     599           12 :         return result;
     600              :     }
     601              : 
     602          586 :     if (tmp > PG_INT32_MAX)
     603           36 :         goto out_of_range;
     604              : 
     605          550 :     return (int32) tmp;
     606              : 
     607          897 : out_of_range:
     608          897 :     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          278 : invalid_syntax:
     614          278 :     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        78538 : pg_strtoint64_safe(const char *s, Node *escontext)
     650              : {
     651        78538 :     const char *ptr = s;
     652              :     const char *firstdigit;
     653        78538 :     uint64      tmp = 0;
     654        78538 :     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        78538 :     if (*ptr == '-')
     669              :     {
     670          826 :         ptr++;
     671          826 :         neg = true;
     672              :     }
     673              : 
     674              :     /* a leading '+' is uncommon so leave that for the slow path */
     675              : 
     676              :     /* process the first digit */
     677        78538 :     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        78538 :     if (likely(digit < 10))
     684              :     {
     685        78433 :         ptr++;
     686        78433 :         tmp = digit;
     687              :     }
     688              :     else
     689              :     {
     690              :         /* we need at least one digit */
     691          105 :         goto slow;
     692              :     }
     693              : 
     694              :     /* process remaining digits */
     695              :     for (;;)
     696              :     {
     697       197648 :         digit = (*ptr - '0');
     698              : 
     699       197648 :         if (digit >= 10)
     700        78313 :             break;
     701              : 
     702       119335 :         ptr++;
     703              : 
     704       119335 :         if (unlikely(tmp > -(PG_INT64_MIN / 10)))
     705          120 :             goto out_of_range;
     706              : 
     707       119215 :         tmp = tmp * 10 + digit;
     708              :     }
     709              : 
     710              :     /* when the string does not end in a digit, let the slow path handle it */
     711        78313 :     if (unlikely(*ptr != '\0'))
     712         5313 :         goto slow;
     713              : 
     714        73000 :     if (neg)
     715              :     {
     716          500 :         if (unlikely(pg_neg_u64_overflow(tmp, &result)))
     717            9 :             goto out_of_range;
     718          491 :         return result;
     719              :     }
     720              : 
     721        72500 :     if (unlikely(tmp > PG_INT64_MAX))
     722            9 :         goto out_of_range;
     723              : 
     724        72491 :     return (int64) tmp;
     725              : 
     726         5418 : slow:
     727         5418 :     tmp = 0;
     728         5418 :     ptr = s;
     729              :     /* no need to reset neg */
     730              : 
     731              :     /* skip leading spaces */
     732         5455 :     while (isspace((unsigned char) *ptr))
     733           37 :         ptr++;
     734              : 
     735              :     /* handle sign */
     736         5418 :     if (*ptr == '-')
     737              :     {
     738          323 :         ptr++;
     739          323 :         neg = true;
     740              :     }
     741         5095 :     else if (*ptr == '+')
     742           24 :         ptr++;
     743              : 
     744              :     /* process digits */
     745         5418 :     if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
     746              :     {
     747           67 :         firstdigit = ptr += 2;
     748              : 
     749              :         for (;;)
     750              :         {
     751          902 :             if (isxdigit((unsigned char) *ptr))
     752              :             {
     753          832 :                 if (unlikely(tmp > -(PG_INT64_MIN / 16)))
     754            0 :                     goto out_of_range;
     755              : 
     756          832 :                 tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
     757              :             }
     758           70 :             else if (*ptr == '_')
     759              :             {
     760              :                 /* underscore must be followed by more digits */
     761            3 :                 ptr++;
     762            3 :                 if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
     763            0 :                     goto invalid_syntax;
     764              :             }
     765              :             else
     766           67 :                 break;
     767              :         }
     768              :     }
     769         5351 :     else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
     770              :     {
     771           42 :         firstdigit = ptr += 2;
     772              : 
     773              :         for (;;)
     774              :         {
     775          684 :             if (*ptr >= '0' && *ptr <= '7')
     776              :             {
     777          639 :                 if (unlikely(tmp > -(PG_INT64_MIN / 8)))
     778            0 :                     goto out_of_range;
     779              : 
     780          639 :                 tmp = tmp * 8 + (*ptr++ - '0');
     781              :             }
     782           45 :             else if (*ptr == '_')
     783              :             {
     784              :                 /* underscore must be followed by more digits */
     785            3 :                 ptr++;
     786            3 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
     787            0 :                     goto invalid_syntax;
     788              :             }
     789              :             else
     790           42 :                 break;
     791              :         }
     792              :     }
     793         5309 :     else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
     794              :     {
     795           42 :         firstdigit = ptr += 2;
     796              : 
     797              :         for (;;)
     798              :         {
     799         1902 :             if (*ptr >= '0' && *ptr <= '1')
     800              :             {
     801         1854 :                 if (unlikely(tmp > -(PG_INT64_MIN / 2)))
     802            0 :                     goto out_of_range;
     803              : 
     804         1854 :                 tmp = tmp * 2 + (*ptr++ - '0');
     805              :             }
     806           48 :             else if (*ptr == '_')
     807              :             {
     808              :                 /* underscore must be followed by more digits */
     809            6 :                 ptr++;
     810            6 :                 if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
     811            0 :                     goto invalid_syntax;
     812              :             }
     813              :             else
     814           42 :                 break;
     815              :         }
     816              :     }
     817              :     else
     818              :     {
     819         5267 :         firstdigit = ptr;
     820              : 
     821              :         for (;;)
     822              :         {
     823        13261 :             if (*ptr >= '0' && *ptr <= '9')
     824              :             {
     825         7933 :                 if (unlikely(tmp > -(PG_INT64_MIN / 10)))
     826            0 :                     goto out_of_range;
     827              : 
     828         7933 :                 tmp = tmp * 10 + (*ptr++ - '0');
     829              :             }
     830         5328 :             else if (*ptr == '_')
     831              :             {
     832              :                 /* underscore may not be first */
     833           70 :                 if (unlikely(ptr == firstdigit))
     834            3 :                     goto invalid_syntax;
     835              :                 /* and it must be followed by more digits */
     836           67 :                 ptr++;
     837           67 :                 if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
     838            6 :                     goto invalid_syntax;
     839              :             }
     840              :             else
     841         5258 :                 break;
     842              :         }
     843              :     }
     844              : 
     845              :     /* require at least one digit */
     846         5409 :     if (unlikely(ptr == firstdigit))
     847           77 :         goto invalid_syntax;
     848              : 
     849              :     /* allow trailing whitespace, but not other trailing chars */
     850         5365 :     while (isspace((unsigned char) *ptr))
     851           33 :         ptr++;
     852              : 
     853         5332 :     if (unlikely(*ptr != '\0'))
     854         5140 :         goto invalid_syntax;
     855              : 
     856          192 :     if (neg)
     857              :     {
     858           57 :         if (unlikely(pg_neg_u64_overflow(tmp, &result)))
     859           18 :             goto out_of_range;
     860           39 :         return result;
     861              :     }
     862              : 
     863          135 :     if (tmp > PG_INT64_MAX)
     864           18 :         goto out_of_range;
     865              : 
     866          117 :     return (int64) tmp;
     867              : 
     868          174 : out_of_range:
     869          174 :     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         5226 : invalid_syntax:
     875         5226 :     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      3594493 : 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      3594493 :     errno = 0;
     905      3594493 :     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      3594493 :     if ((errno && errno != ERANGE) || endptr == s)
     914           30 :         ereturn(escontext, 0,
     915              :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     916              :                  errmsg("invalid input syntax for type %s: \"%s\"",
     917              :                         typname, s)));
     918              : 
     919      3594463 :     if (errno == ERANGE)
     920            6 :         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      3594457 :     if (endloc)
     926              :     {
     927              :         /* caller wants to deal with rest of string */
     928       318747 :         *endloc = endptr;
     929              :     }
     930              :     else
     931              :     {
     932              :         /* allow only whitespace after number */
     933      3275767 :         while (*endptr && isspace((unsigned char) *endptr))
     934           57 :             endptr++;
     935      3275710 :         if (*endptr)
     936           18 :             ereturn(escontext, 0,
     937              :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     938              :                      errmsg("invalid input syntax for type %s: \"%s\"",
     939              :                             typname, s)));
     940              :     }
     941              : 
     942      3594439 :     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      3594439 :     if (cvt != (unsigned long) result &&
     958           21 :         cvt != (unsigned long) ((int) result))
     959           15 :         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      3594424 :     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         2030 : uint64in_subr(const char *s, char **endloc,
     985              :               const char *typname, Node *escontext)
     986              : {
     987              :     uint64      result;
     988              :     char       *endptr;
     989              : 
     990         2030 :     errno = 0;
     991         2030 :     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         2030 :     if ((errno && errno != ERANGE) || endptr == s)
    1000           21 :         ereturn(escontext, 0,
    1001              :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1002              :                  errmsg("invalid input syntax for type %s: \"%s\"",
    1003              :                         typname, s)));
    1004              : 
    1005         2009 :     if (errno == ERANGE)
    1006           18 :         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         1991 :     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         2048 :         while (*endptr && isspace((unsigned char) *endptr))
    1020           57 :             endptr++;
    1021         1991 :         if (*endptr)
    1022           18 :             ereturn(escontext, 0,
    1023              :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1024              :                      errmsg("invalid input syntax for type %s: \"%s\"",
    1025              :                             typname, s)));
    1026              :     }
    1027              : 
    1028         1973 :     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       348815 : pg_itoa(int16 i, char *a)
    1042              : {
    1043       348815 :     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      9268373 : pg_ultoa_n(uint32 value, char *a)
    1055              : {
    1056              :     int         olength,
    1057      9268373 :                 i = 0;
    1058              : 
    1059              :     /* Degenerate case */
    1060      9268373 :     if (value == 0)
    1061              :     {
    1062      2058461 :         *a = '0';
    1063      2058461 :         return 1;
    1064              :     }
    1065              : 
    1066      7209912 :     olength = decimalLength32(value);
    1067              : 
    1068              :     /* Compute the result string. */
    1069      8287524 :     while (value >= 10000)
    1070              :     {
    1071      1077612 :         const uint32 c = value - 10000 * (value / 10000);
    1072      1077612 :         const uint32 c0 = (c % 100) << 1;
    1073      1077612 :         const uint32 c1 = (c / 100) << 1;
    1074              : 
    1075      1077612 :         char       *pos = a + olength - i;
    1076              : 
    1077      1077612 :         value /= 10000;
    1078              : 
    1079      1077612 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1080      1077612 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1081      1077612 :         i += 4;
    1082              :     }
    1083      7209912 :     if (value >= 100)
    1084              :     {
    1085      3170549 :         const uint32 c = (value % 100) << 1;
    1086              : 
    1087      3170549 :         char       *pos = a + olength - i;
    1088              : 
    1089      3170549 :         value /= 100;
    1090              : 
    1091      3170549 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1092      3170549 :         i += 2;
    1093              :     }
    1094      7209912 :     if (value >= 10)
    1095              :     {
    1096      3647756 :         const uint32 c = value << 1;
    1097              : 
    1098      3647756 :         char       *pos = a + olength - i;
    1099              : 
    1100      3647756 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1101              :     }
    1102              :     else
    1103              :     {
    1104      3562156 :         *a = (char) ('0' + value);
    1105              :     }
    1106              : 
    1107      7209912 :     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      9200065 : pg_ltoa(int32 value, char *a)
    1120              : {
    1121      9200065 :     uint32      uvalue = (uint32) value;
    1122      9200065 :     int         len = 0;
    1123              : 
    1124      9200065 :     if (value < 0)
    1125              :     {
    1126       259596 :         uvalue = (uint32) 0 - uvalue;
    1127       259596 :         a[len++] = '-';
    1128              :     }
    1129      9200065 :     len += pg_ultoa_n(uvalue, a + len);
    1130      9200065 :     a[len] = '\0';
    1131      9200065 :     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       357943 : pg_ulltoa_n(uint64 value, char *a)
    1140              : {
    1141              :     int         olength,
    1142       357943 :                 i = 0;
    1143              :     uint32      value2;
    1144              : 
    1145              :     /* Degenerate case */
    1146       357943 :     if (value == 0)
    1147              :     {
    1148        33836 :         *a = '0';
    1149        33836 :         return 1;
    1150              :     }
    1151              : 
    1152       324107 :     olength = decimalLength64(value);
    1153              : 
    1154              :     /* Compute the result string. */
    1155       334339 :     while (value >= 100000000)
    1156              :     {
    1157        10232 :         const uint64 q = value / 100000000;
    1158        10232 :         uint32      value3 = (uint32) (value - 100000000 * q);
    1159              : 
    1160        10232 :         const uint32 c = value3 % 10000;
    1161        10232 :         const uint32 d = value3 / 10000;
    1162        10232 :         const uint32 c0 = (c % 100) << 1;
    1163        10232 :         const uint32 c1 = (c / 100) << 1;
    1164        10232 :         const uint32 d0 = (d % 100) << 1;
    1165        10232 :         const uint32 d1 = (d / 100) << 1;
    1166              : 
    1167        10232 :         char       *pos = a + olength - i;
    1168              : 
    1169        10232 :         value = q;
    1170              : 
    1171        10232 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1172        10232 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1173        10232 :         memcpy(pos - 6, DIGIT_TABLE + d0, 2);
    1174        10232 :         memcpy(pos - 8, DIGIT_TABLE + d1, 2);
    1175        10232 :         i += 8;
    1176              :     }
    1177              : 
    1178              :     /* Switch to 32-bit for speed */
    1179       324107 :     value2 = (uint32) value;
    1180              : 
    1181       324107 :     if (value2 >= 10000)
    1182              :     {
    1183        15125 :         const uint32 c = value2 - 10000 * (value2 / 10000);
    1184        15125 :         const uint32 c0 = (c % 100) << 1;
    1185        15125 :         const uint32 c1 = (c / 100) << 1;
    1186              : 
    1187        15125 :         char       *pos = a + olength - i;
    1188              : 
    1189        15125 :         value2 /= 10000;
    1190              : 
    1191        15125 :         memcpy(pos - 2, DIGIT_TABLE + c0, 2);
    1192        15125 :         memcpy(pos - 4, DIGIT_TABLE + c1, 2);
    1193        15125 :         i += 4;
    1194              :     }
    1195       324107 :     if (value2 >= 100)
    1196              :     {
    1197       112497 :         const uint32 c = (value2 % 100) << 1;
    1198       112497 :         char       *pos = a + olength - i;
    1199              : 
    1200       112497 :         value2 /= 100;
    1201              : 
    1202       112497 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1203       112497 :         i += 2;
    1204              :     }
    1205       324107 :     if (value2 >= 10)
    1206              :     {
    1207        70089 :         const uint32 c = value2 << 1;
    1208        70089 :         char       *pos = a + olength - i;
    1209              : 
    1210        70089 :         memcpy(pos - 2, DIGIT_TABLE + c, 2);
    1211              :     }
    1212              :     else
    1213       254018 :         *a = (char) ('0' + value2);
    1214              : 
    1215       324107 :     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       164138 : pg_lltoa(int64 value, char *a)
    1227              : {
    1228       164138 :     uint64      uvalue = value;
    1229       164138 :     int         len = 0;
    1230              : 
    1231       164138 :     if (value < 0)
    1232              :     {
    1233         1358 :         uvalue = (uint64) 0 - uvalue;
    1234         1358 :         a[len++] = '-';
    1235              :     }
    1236              : 
    1237       164138 :     len += pg_ulltoa_n(uvalue, a + len);
    1238       164138 :     a[len] = '\0';
    1239       164138 :     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       416038 : pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth)
    1267              : {
    1268              :     int         len;
    1269              : 
    1270              :     Assert(minwidth > 0);
    1271              : 
    1272       416038 :     if (value < 100 && minwidth == 2)    /* Short cut for common case */
    1273              :     {
    1274       349426 :         memcpy(str, DIGIT_TABLE + value * 2, 2);
    1275       349426 :         return str + 2;
    1276              :     }
    1277              : 
    1278        66612 :     len = pg_ultoa_n(value, str);
    1279        66612 :     if (len >= minwidth)
    1280        66261 :         return str + len;
    1281              : 
    1282          351 :     memmove(str + minwidth - len, str, len);
    1283          351 :     memset(str, '0', minwidth - len);
    1284          351 :     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         1659 : pg_ultostr(char *str, uint32 value)
    1307              : {
    1308         1659 :     int         len = pg_ultoa_n(value, str);
    1309              : 
    1310         1659 :     return str + len;
    1311              : }
        

Generated by: LCOV version 2.0-1