LCOV - code coverage report
Current view: top level - src/backend/utils/adt - numutils.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 141 170 82.9 %
Date: 2019-06-18 07:06:57 Functions: 9 9 100.0 %
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-2019, 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 <math.h>
      18             : #include <limits.h>
      19             : #include <ctype.h>
      20             : 
      21             : #include "common/int.h"
      22             : #include "utils/builtins.h"
      23             : 
      24             : /*
      25             :  * pg_atoi: convert string to integer
      26             :  *
      27             :  * allows any number of leading or trailing whitespace characters.
      28             :  *
      29             :  * 'size' is the sizeof() the desired integral result (1, 2, or 4 bytes).
      30             :  *
      31             :  * c, if not 0, is a terminator character that may appear after the
      32             :  * integer (plus whitespace).  If 0, the string must end after the integer.
      33             :  *
      34             :  * Unlike plain atoi(), this will throw ereport() upon bad input format or
      35             :  * overflow.
      36             :  */
      37             : int32
      38       84962 : pg_atoi(const char *s, int size, int c)
      39             : {
      40             :     long        l;
      41             :     char       *badp;
      42             : 
      43             :     /*
      44             :      * Some versions of strtol treat the empty string as an error, but some
      45             :      * seem not to.  Make an explicit test to be sure we catch it.
      46             :      */
      47       84962 :     if (s == NULL)
      48           0 :         elog(ERROR, "NULL pointer");
      49       84962 :     if (*s == 0)
      50           0 :         ereport(ERROR,
      51             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      52             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      53             :                         "integer", s)));
      54             : 
      55       84962 :     errno = 0;
      56       84962 :     l = strtol(s, &badp, 10);
      57             : 
      58             :     /* We made no progress parsing the string, so bail out */
      59       84962 :     if (s == badp)
      60           0 :         ereport(ERROR,
      61             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      62             :                  errmsg("invalid input syntax for type %s: \"%s\"",
      63             :                         "integer", s)));
      64             : 
      65       84962 :     switch (size)
      66             :     {
      67             :         case sizeof(int32):
      68       84872 :             if (errno == ERANGE
      69             : #if defined(HAVE_LONG_INT_64)
      70             :             /* won't get ERANGE on these with 64-bit longs... */
      71       84872 :                 || l < INT_MIN || l > INT_MAX
      72             : #endif
      73             :                 )
      74           0 :                 ereport(ERROR,
      75             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      76             :                          errmsg("value \"%s\" is out of range for type %s", s,
      77             :                                 "integer")));
      78       84872 :             break;
      79             :         case sizeof(int16):
      80          90 :             if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
      81           0 :                 ereport(ERROR,
      82             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      83             :                          errmsg("value \"%s\" is out of range for type %s", s,
      84             :                                 "smallint")));
      85          90 :             break;
      86             :         case sizeof(int8):
      87           0 :             if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
      88           0 :                 ereport(ERROR,
      89             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      90             :                          errmsg("value \"%s\" is out of range for 8-bit integer", s)));
      91           0 :             break;
      92             :         default:
      93           0 :             elog(ERROR, "unsupported result size: %d", size);
      94             :     }
      95             : 
      96             :     /*
      97             :      * Skip any trailing whitespace; if anything but whitespace remains before
      98             :      * the terminating character, bail out
      99             :      */
     100      169924 :     while (*badp && *badp != c && isspace((unsigned char) *badp))
     101           0 :         badp++;
     102             : 
     103       84962 :     if (*badp && *badp != c)
     104           0 :         ereport(ERROR,
     105             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     106             :                  errmsg("invalid input syntax for type %s: \"%s\"",
     107             :                         "integer", s)));
     108             : 
     109       84962 :     return (int32) l;
     110             : }
     111             : 
     112             : /*
     113             :  * Convert input string to a signed 16 bit integer.
     114             :  *
     115             :  * Allows any number of leading or trailing whitespace characters. Will throw
     116             :  * ereport() upon bad input format or overflow.
     117             :  *
     118             :  * NB: Accumulate input as a negative number, to deal with two's complement
     119             :  * representation of the most negative number, which can't be represented as a
     120             :  * positive number.
     121             :  */
     122             : int16
     123     2430400 : pg_strtoint16(const char *s)
     124             : {
     125     2430400 :     const char *ptr = s;
     126     2430400 :     int16       tmp = 0;
     127     2430400 :     bool        neg = false;
     128             : 
     129             :     /* skip leading spaces */
     130     4860840 :     while (likely(*ptr) && isspace((unsigned char) *ptr))
     131          40 :         ptr++;
     132             : 
     133             :     /* handle sign */
     134     2430400 :     if (*ptr == '-')
     135             :     {
     136       49618 :         ptr++;
     137       49618 :         neg = true;
     138             :     }
     139     2380782 :     else if (*ptr == '+')
     140           0 :         ptr++;
     141             : 
     142             :     /* require at least one digit */
     143     2430400 :     if (unlikely(!isdigit((unsigned char) *ptr)))
     144          20 :         goto invalid_syntax;
     145             : 
     146             :     /* process digits */
     147     7355988 :     while (*ptr && isdigit((unsigned char) *ptr))
     148             :     {
     149     2495232 :         int8        digit = (*ptr++ - '0');
     150             : 
     151     4990460 :         if (unlikely(pg_mul_s16_overflow(tmp, 10, &tmp)) ||
     152     2495228 :             unlikely(pg_sub_s16_overflow(tmp, digit, &tmp)))
     153             :             goto out_of_range;
     154             :     }
     155             : 
     156             :     /* allow trailing whitespace, but not other trailing chars */
     157     4860776 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
     158          24 :         ptr++;
     159             : 
     160     2430376 :     if (unlikely(*ptr != '\0'))
     161          12 :         goto invalid_syntax;
     162             : 
     163     2430364 :     if (!neg)
     164             :     {
     165             :         /* could fail if input is most negative number */
     166     2380750 :         if (unlikely(tmp == PG_INT16_MIN))
     167           0 :             goto out_of_range;
     168     2380750 :         tmp = -tmp;
     169             :     }
     170             : 
     171     2430364 :     return tmp;
     172             : 
     173             : out_of_range:
     174           4 :     ereport(ERROR,
     175             :             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     176             :              errmsg("value \"%s\" is out of range for type %s",
     177             :                     s, "smallint")));
     178             : 
     179             : invalid_syntax:
     180          32 :     ereport(ERROR,
     181             :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     182             :              errmsg("invalid input syntax for type %s: \"%s\"",
     183             :                     "smallint", s)));
     184             : 
     185             :     return 0;                   /* keep compiler quiet */
     186             : }
     187             : 
     188             : /*
     189             :  * Convert input string to a signed 32 bit integer.
     190             :  *
     191             :  * Allows any number of leading or trailing whitespace characters. Will throw
     192             :  * ereport() upon bad input format or overflow.
     193             :  *
     194             :  * NB: Accumulate input as a negative number, to deal with two's complement
     195             :  * representation of the most negative number, which can't be represented as a
     196             :  * positive number.
     197             :  */
     198             : int32
     199     4839824 : pg_strtoint32(const char *s)
     200             : {
     201     4839824 :     const char *ptr = s;
     202     4839824 :     int32       tmp = 0;
     203     4839824 :     bool        neg = false;
     204             : 
     205             :     /* skip leading spaces */
     206     9679730 :     while (likely(*ptr) && isspace((unsigned char) *ptr))
     207          82 :         ptr++;
     208             : 
     209             :     /* handle sign */
     210     4839824 :     if (*ptr == '-')
     211             :     {
     212      185242 :         ptr++;
     213      185242 :         neg = true;
     214             :     }
     215     4654582 :     else if (*ptr == '+')
     216           0 :         ptr++;
     217             : 
     218             :     /* require at least one digit */
     219     4839824 :     if (unlikely(!isdigit((unsigned char) *ptr)))
     220          76 :         goto invalid_syntax;
     221             : 
     222             :     /* process digits */
     223    20671578 :     while (*ptr && isdigit((unsigned char) *ptr))
     224             :     {
     225    10992086 :         int8        digit = (*ptr++ - '0');
     226             : 
     227    21984168 :         if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||
     228    10992082 :             unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))
     229             :             goto out_of_range;
     230             :     }
     231             : 
     232             :     /* allow trailing whitespace, but not other trailing chars */
     233     9679544 :     while (*ptr != '\0' && isspace((unsigned char) *ptr))
     234          56 :         ptr++;
     235             : 
     236     4839744 :     if (unlikely(*ptr != '\0'))
     237           8 :         goto invalid_syntax;
     238             : 
     239     4839736 :     if (!neg)
     240             :     {
     241             :         /* could fail if input is most negative number */
     242     4654498 :         if (unlikely(tmp == PG_INT32_MIN))
     243           0 :             goto out_of_range;
     244     4654498 :         tmp = -tmp;
     245             :     }
     246             : 
     247     4839736 :     return tmp;
     248             : 
     249             : out_of_range:
     250           4 :     ereport(ERROR,
     251             :             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     252             :              errmsg("value \"%s\" is out of range for type %s",
     253             :                     s, "integer")));
     254             : 
     255             : invalid_syntax:
     256          84 :     ereport(ERROR,
     257             :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     258             :              errmsg("invalid input syntax for type %s: \"%s\"",
     259             :                     "integer", s)));
     260             : 
     261             :     return 0;                   /* keep compiler quiet */
     262             : }
     263             : 
     264             : /*
     265             :  * pg_itoa: converts a signed 16-bit integer to its string representation
     266             :  *
     267             :  * Caller must ensure that 'a' points to enough memory to hold the result
     268             :  * (at least 7 bytes, counting a leading sign and trailing NUL).
     269             :  *
     270             :  * It doesn't seem worth implementing this separately.
     271             :  */
     272             : void
     273      108074 : pg_itoa(int16 i, char *a)
     274             : {
     275      108074 :     pg_ltoa((int32) i, a);
     276      108074 : }
     277             : 
     278             : /*
     279             :  * pg_ltoa: converts a signed 32-bit integer to its string representation
     280             :  *
     281             :  * Caller must ensure that 'a' points to enough memory to hold the result
     282             :  * (at least 12 bytes, counting a leading sign and trailing NUL).
     283             :  */
     284             : void
     285     5459292 : pg_ltoa(int32 value, char *a)
     286             : {
     287     5459292 :     char       *start = a;
     288     5459292 :     bool        neg = false;
     289             : 
     290             :     /*
     291             :      * Avoid problems with the most negative integer not being representable
     292             :      * as a positive integer.
     293             :      */
     294     5459292 :     if (value == PG_INT32_MIN)
     295             :     {
     296          20 :         memcpy(a, "-2147483648", 12);
     297          20 :         return;
     298             :     }
     299     5459272 :     else if (value < 0)
     300             :     {
     301       69440 :         value = -value;
     302       69440 :         neg = true;
     303             :     }
     304             : 
     305             :     /* Compute the result string backwards. */
     306             :     do
     307             :     {
     308             :         int32       remainder;
     309    14121152 :         int32       oldval = value;
     310             : 
     311    14121152 :         value /= 10;
     312    14121152 :         remainder = oldval - value * 10;
     313    14121152 :         *a++ = '0' + remainder;
     314    14121152 :     } while (value != 0);
     315             : 
     316     5459272 :     if (neg)
     317       69440 :         *a++ = '-';
     318             : 
     319             :     /* Add trailing NUL byte, and back up 'a' to the last character. */
     320     5459272 :     *a-- = '\0';
     321             : 
     322             :     /* Reverse string. */
     323    16601010 :     while (start < a)
     324             :     {
     325     5682466 :         char        swap = *start;
     326             : 
     327     5682466 :         *start++ = *a;
     328     5682466 :         *a-- = swap;
     329             :     }
     330             : }
     331             : 
     332             : /*
     333             :  * pg_lltoa: convert a signed 64-bit integer to its string representation
     334             :  *
     335             :  * Caller must ensure that 'a' points to enough memory to hold the result
     336             :  * (at least MAXINT8LEN+1 bytes, counting a leading sign and trailing NUL).
     337             :  */
     338             : void
     339      124196 : pg_lltoa(int64 value, char *a)
     340             : {
     341      124196 :     char       *start = a;
     342      124196 :     bool        neg = false;
     343             : 
     344             :     /*
     345             :      * Avoid problems with the most negative integer not being representable
     346             :      * as a positive integer.
     347             :      */
     348      124196 :     if (value == PG_INT64_MIN)
     349             :     {
     350          46 :         memcpy(a, "-9223372036854775808", 21);
     351          46 :         return;
     352             :     }
     353      124150 :     else if (value < 0)
     354             :     {
     355        1438 :         value = -value;
     356        1438 :         neg = true;
     357             :     }
     358             : 
     359             :     /* Compute the result string backwards. */
     360             :     do
     361             :     {
     362             :         int64       remainder;
     363      401642 :         int64       oldval = value;
     364             : 
     365      401642 :         value /= 10;
     366      401642 :         remainder = oldval - value * 10;
     367      401642 :         *a++ = '0' + remainder;
     368      401642 :     } while (value != 0);
     369             : 
     370      124150 :     if (neg)
     371        1438 :         *a++ = '-';
     372             : 
     373             :     /* Add trailing NUL byte, and back up 'a' to the last character. */
     374      124150 :     *a-- = '\0';
     375             : 
     376             :     /* Reverse string. */
     377      399536 :     while (start < a)
     378             :     {
     379      151236 :         char        swap = *start;
     380             : 
     381      151236 :         *start++ = *a;
     382      151236 :         *a-- = swap;
     383             :     }
     384             : }
     385             : 
     386             : 
     387             : /*
     388             :  * pg_ltostr_zeropad
     389             :  *      Converts 'value' into a decimal string representation stored at 'str'.
     390             :  *      'minwidth' specifies the minimum width of the result; any extra space
     391             :  *      is filled up by prefixing the number with zeros.
     392             :  *
     393             :  * Returns the ending address of the string result (the last character written
     394             :  * plus 1).  Note that no NUL terminator is written.
     395             :  *
     396             :  * The intended use-case for this function is to build strings that contain
     397             :  * multiple individual numbers, for example:
     398             :  *
     399             :  *  str = pg_ltostr_zeropad(str, hours, 2);
     400             :  *  *str++ = ':';
     401             :  *  str = pg_ltostr_zeropad(str, mins, 2);
     402             :  *  *str++ = ':';
     403             :  *  str = pg_ltostr_zeropad(str, secs, 2);
     404             :  *  *str = '\0';
     405             :  *
     406             :  * Note: Caller must ensure that 'str' points to enough memory to hold the
     407             :  * result.
     408             :  */
     409             : char *
     410      535852 : pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
     411             : {
     412      535852 :     char       *start = str;
     413      535852 :     char       *end = &str[minwidth];
     414      535852 :     int32       num = value;
     415             : 
     416             :     Assert(minwidth > 0);
     417             : 
     418             :     /*
     419             :      * Handle negative numbers in a special way.  We can't just write a '-'
     420             :      * prefix and reverse the sign as that would overflow for INT32_MIN.
     421             :      */
     422      535852 :     if (num < 0)
     423             :     {
     424           0 :         *start++ = '-';
     425           0 :         minwidth--;
     426             : 
     427             :         /*
     428             :          * Build the number starting at the last digit.  Here remainder will
     429             :          * be a negative number, so we must reverse the sign before adding '0'
     430             :          * in order to get the correct ASCII digit.
     431             :          */
     432           0 :         while (minwidth--)
     433             :         {
     434           0 :             int32       oldval = num;
     435             :             int32       remainder;
     436             : 
     437           0 :             num /= 10;
     438           0 :             remainder = oldval - num * 10;
     439           0 :             start[minwidth] = '0' - remainder;
     440             :         }
     441             :     }
     442             :     else
     443             :     {
     444             :         /* Build the number starting at the last digit */
     445     2314640 :         while (minwidth--)
     446             :         {
     447     1242936 :             int32       oldval = num;
     448             :             int32       remainder;
     449             : 
     450     1242936 :             num /= 10;
     451     1242936 :             remainder = oldval - num * 10;
     452     1242936 :             start[minwidth] = '0' + remainder;
     453             :         }
     454             :     }
     455             : 
     456             :     /*
     457             :      * If minwidth was not high enough to fit the number then num won't have
     458             :      * been divided down to zero.  We punt the problem to pg_ltostr(), which
     459             :      * will generate a correct answer in the minimum valid width.
     460             :      */
     461      535852 :     if (num != 0)
     462          48 :         return pg_ltostr(str, value);
     463             : 
     464             :     /* Otherwise, return last output character + 1 */
     465      535804 :     return end;
     466             : }
     467             : 
     468             : /*
     469             :  * pg_ltostr
     470             :  *      Converts 'value' into a decimal string representation stored at 'str'.
     471             :  *
     472             :  * Returns the ending address of the string result (the last character written
     473             :  * plus 1).  Note that no NUL terminator is written.
     474             :  *
     475             :  * The intended use-case for this function is to build strings that contain
     476             :  * multiple individual numbers, for example:
     477             :  *
     478             :  *  str = pg_ltostr(str, a);
     479             :  *  *str++ = ' ';
     480             :  *  str = pg_ltostr(str, b);
     481             :  *  *str = '\0';
     482             :  *
     483             :  * Note: Caller must ensure that 'str' points to enough memory to hold the
     484             :  * result.
     485             :  */
     486             : char *
     487        2168 : pg_ltostr(char *str, int32 value)
     488             : {
     489             :     char       *start;
     490             :     char       *end;
     491             : 
     492             :     /*
     493             :      * Handle negative numbers in a special way.  We can't just write a '-'
     494             :      * prefix and reverse the sign as that would overflow for INT32_MIN.
     495             :      */
     496        2168 :     if (value < 0)
     497             :     {
     498           0 :         *str++ = '-';
     499             : 
     500             :         /* Mark the position we must reverse the string from. */
     501           0 :         start = str;
     502             : 
     503             :         /* Compute the result string backwards. */
     504             :         do
     505             :         {
     506           0 :             int32       oldval = value;
     507             :             int32       remainder;
     508             : 
     509           0 :             value /= 10;
     510           0 :             remainder = oldval - value * 10;
     511             :             /* As above, we expect remainder to be negative. */
     512           0 :             *str++ = '0' - remainder;
     513           0 :         } while (value != 0);
     514             :     }
     515             :     else
     516             :     {
     517             :         /* Mark the position we must reverse the string from. */
     518        2168 :         start = str;
     519             : 
     520             :         /* Compute the result string backwards. */
     521             :         do
     522             :         {
     523        3066 :             int32       oldval = value;
     524             :             int32       remainder;
     525             : 
     526        3066 :             value /= 10;
     527        3066 :             remainder = oldval - value * 10;
     528        3066 :             *str++ = '0' + remainder;
     529        3066 :         } while (value != 0);
     530             :     }
     531             : 
     532             :     /* Remember the end+1 and back up 'str' to the last character. */
     533        2168 :     end = str--;
     534             : 
     535             :     /* Reverse string. */
     536        5134 :     while (start < str)
     537             :     {
     538         798 :         char        swap = *start;
     539             : 
     540         798 :         *start++ = *str;
     541         798 :         *str-- = swap;
     542             :     }
     543             : 
     544        2168 :     return end;
     545             : }
     546             : 
     547             : /*
     548             :  * pg_strtouint64
     549             :  *      Converts 'str' into an unsigned 64-bit integer.
     550             :  *
     551             :  * This has the identical API to strtoul(3), except that it will handle
     552             :  * 64-bit ints even where "long" is narrower than that.
     553             :  *
     554             :  * For the moment it seems sufficient to assume that the platform has
     555             :  * such a function somewhere; let's not roll our own.
     556             :  */
     557             : uint64
     558      242950 : pg_strtouint64(const char *str, char **endptr, int base)
     559             : {
     560             : #ifdef _MSC_VER                 /* MSVC only */
     561             :     return _strtoui64(str, endptr, base);
     562             : #elif defined(HAVE_STRTOULL) && SIZEOF_LONG < 8
     563             :     return strtoull(str, endptr, base);
     564             : #else
     565      242950 :     return strtoul(str, endptr, base);
     566             : #endif
     567             : }

Generated by: LCOV version 1.13