LCOV - code coverage report
Current view: top level - src/backend/utils/adt - numutils.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 95 114 83.3 %
Date: 2017-09-29 13:40:31 Functions: 7 7 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-2017, 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 "utils/builtins.h"
      22             : 
      23             : /*
      24             :  * pg_atoi: convert string to integer
      25             :  *
      26             :  * allows any number of leading or trailing whitespace characters.
      27             :  *
      28             :  * 'size' is the sizeof() the desired integral result (1, 2, or 4 bytes).
      29             :  *
      30             :  * c, if not 0, is a terminator character that may appear after the
      31             :  * integer (plus whitespace).  If 0, the string must end after the integer.
      32             :  *
      33             :  * Unlike plain atoi(), this will throw ereport() upon bad input format or
      34             :  * overflow.
      35             :  */
      36             : int32
      37      300371 : pg_atoi(const char *s, int size, int c)
      38             : {
      39             :     long        l;
      40             :     char       *badp;
      41             : 
      42             :     /*
      43             :      * Some versions of strtol treat the empty string as an error, but some
      44             :      * seem not to.  Make an explicit test to be sure we catch it.
      45             :      */
      46      300371 :     if (s == NULL)
      47           0 :         elog(ERROR, "NULL pointer");
      48      300371 :     if (*s == 0)
      49           3 :         ereport(ERROR,
      50             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      51             :                  errmsg("invalid input syntax for %s: \"%s\"",
      52             :                         "integer", s)));
      53             : 
      54      300368 :     errno = 0;
      55      300368 :     l = strtol(s, &badp, 10);
      56             : 
      57             :     /* We made no progress parsing the string, so bail out */
      58      300368 :     if (s == badp)
      59          12 :         ereport(ERROR,
      60             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
      61             :                  errmsg("invalid input syntax for %s: \"%s\"",
      62             :                         "integer", s)));
      63             : 
      64      300356 :     switch (size)
      65             :     {
      66             :         case sizeof(int32):
      67      292761 :             if (errno == ERANGE
      68             : #if defined(HAVE_LONG_INT_64)
      69             :             /* won't get ERANGE on these with 64-bit longs... */
      70             :                 || l < INT_MIN || l > INT_MAX
      71             : #endif
      72             :                 )
      73           1 :                 ereport(ERROR,
      74             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      75             :                          errmsg("value \"%s\" is out of range for type %s", s,
      76             :                                 "integer")));
      77      292760 :             break;
      78             :         case sizeof(int16):
      79        7595 :             if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
      80           1 :                 ereport(ERROR,
      81             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      82             :                          errmsg("value \"%s\" is out of range for type %s", s,
      83             :                                 "smallint")));
      84        7594 :             break;
      85             :         case sizeof(int8):
      86           0 :             if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
      87           0 :                 ereport(ERROR,
      88             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      89             :                          errmsg("value \"%s\" is out of range for 8-bit integer", s)));
      90           0 :             break;
      91             :         default:
      92           0 :             elog(ERROR, "unsupported result size: %d", size);
      93             :     }
      94             : 
      95             :     /*
      96             :      * Skip any trailing whitespace; if anything but whitespace remains before
      97             :      * the terminating character, bail out
      98             :      */
      99      600728 :     while (*badp && *badp != c && isspace((unsigned char) *badp))
     100          20 :         badp++;
     101             : 
     102      300354 :     if (*badp && *badp != c)
     103           5 :         ereport(ERROR,
     104             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     105             :                  errmsg("invalid input syntax for %s: \"%s\"",
     106             :                         "integer", s)));
     107             : 
     108      300349 :     return (int32) l;
     109             : }
     110             : 
     111             : /*
     112             :  * pg_itoa: converts a signed 16-bit integer to its string representation
     113             :  *
     114             :  * Caller must ensure that 'a' points to enough memory to hold the result
     115             :  * (at least 7 bytes, counting a leading sign and trailing NUL).
     116             :  *
     117             :  * It doesn't seem worth implementing this separately.
     118             :  */
     119             : void
     120        1543 : pg_itoa(int16 i, char *a)
     121             : {
     122        1543 :     pg_ltoa((int32) i, a);
     123        1543 : }
     124             : 
     125             : /*
     126             :  * pg_ltoa: converts a signed 32-bit integer to its string representation
     127             :  *
     128             :  * Caller must ensure that 'a' points to enough memory to hold the result
     129             :  * (at least 12 bytes, counting a leading sign and trailing NUL).
     130             :  */
     131             : void
     132      151235 : pg_ltoa(int32 value, char *a)
     133             : {
     134      151235 :     char       *start = a;
     135      151235 :     bool        neg = false;
     136             : 
     137             :     /*
     138             :      * Avoid problems with the most negative integer not being representable
     139             :      * as a positive integer.
     140             :      */
     141      151235 :     if (value == PG_INT32_MIN)
     142             :     {
     143           3 :         memcpy(a, "-2147483648", 12);
     144      151238 :         return;
     145             :     }
     146      151232 :     else if (value < 0)
     147             :     {
     148        1733 :         value = -value;
     149        1733 :         neg = true;
     150             :     }
     151             : 
     152             :     /* Compute the result string backwards. */
     153             :     do
     154             :     {
     155             :         int32       remainder;
     156      397002 :         int32       oldval = value;
     157             : 
     158      397002 :         value /= 10;
     159      397002 :         remainder = oldval - value * 10;
     160      397002 :         *a++ = '0' + remainder;
     161      397002 :     } while (value != 0);
     162             : 
     163      151232 :     if (neg)
     164        1733 :         *a++ = '-';
     165             : 
     166             :     /* Add trailing NUL byte, and back up 'a' to the last character. */
     167      151232 :     *a-- = '\0';
     168             : 
     169             :     /* Reverse string. */
     170      469100 :     while (start < a)
     171             :     {
     172      166636 :         char        swap = *start;
     173             : 
     174      166636 :         *start++ = *a;
     175      166636 :         *a-- = swap;
     176             :     }
     177             : }
     178             : 
     179             : /*
     180             :  * pg_lltoa: convert a signed 64-bit integer to its string representation
     181             :  *
     182             :  * Caller must ensure that 'a' points to enough memory to hold the result
     183             :  * (at least MAXINT8LEN+1 bytes, counting a leading sign and trailing NUL).
     184             :  */
     185             : void
     186        5306 : pg_lltoa(int64 value, char *a)
     187             : {
     188        5306 :     char       *start = a;
     189        5306 :     bool        neg = false;
     190             : 
     191             :     /*
     192             :      * Avoid problems with the most negative integer not being representable
     193             :      * as a positive integer.
     194             :      */
     195        5306 :     if (value == PG_INT64_MIN)
     196             :     {
     197           7 :         memcpy(a, "-9223372036854775808", 21);
     198        5313 :         return;
     199             :     }
     200        5299 :     else if (value < 0)
     201             :     {
     202         269 :         value = -value;
     203         269 :         neg = true;
     204             :     }
     205             : 
     206             :     /* Compute the result string backwards. */
     207             :     do
     208             :     {
     209             :         int64       remainder;
     210       28741 :         int64       oldval = value;
     211             : 
     212       28741 :         value /= 10;
     213       28741 :         remainder = oldval - value * 10;
     214       28741 :         *a++ = '0' + remainder;
     215       28741 :     } while (value != 0);
     216             : 
     217        5299 :     if (neg)
     218         269 :         *a++ = '-';
     219             : 
     220             :     /* Add trailing NUL byte, and back up 'a' to the last character. */
     221        5299 :     *a-- = '\0';
     222             : 
     223             :     /* Reverse string. */
     224       23423 :     while (start < a)
     225             :     {
     226       12825 :         char        swap = *start;
     227             : 
     228       12825 :         *start++ = *a;
     229       12825 :         *a-- = swap;
     230             :     }
     231             : }
     232             : 
     233             : 
     234             : /*
     235             :  * pg_ltostr_zeropad
     236             :  *      Converts 'value' into a decimal string representation stored at 'str'.
     237             :  *      'minwidth' specifies the minimum width of the result; any extra space
     238             :  *      is filled up by prefixing the number with zeros.
     239             :  *
     240             :  * Returns the ending address of the string result (the last character written
     241             :  * plus 1).  Note that no NUL terminator is written.
     242             :  *
     243             :  * The intended use-case for this function is to build strings that contain
     244             :  * multiple individual numbers, for example:
     245             :  *
     246             :  *  str = pg_ltostr_zeropad(str, hours, 2);
     247             :  *  *str++ = ':';
     248             :  *  str = pg_ltostr_zeropad(str, mins, 2);
     249             :  *  *str++ = ':';
     250             :  *  str = pg_ltostr_zeropad(str, secs, 2);
     251             :  *  *str = '\0';
     252             :  *
     253             :  * Note: Caller must ensure that 'str' points to enough memory to hold the
     254             :  * result.
     255             :  */
     256             : char *
     257       22250 : pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
     258             : {
     259       22250 :     char       *start = str;
     260       22250 :     char       *end = &str[minwidth];
     261       22250 :     int32       num = value;
     262             : 
     263       22250 :     Assert(minwidth > 0);
     264             : 
     265             :     /*
     266             :      * Handle negative numbers in a special way.  We can't just write a '-'
     267             :      * prefix and reverse the sign as that would overflow for INT32_MIN.
     268             :      */
     269       22250 :     if (num < 0)
     270             :     {
     271           0 :         *start++ = '-';
     272           0 :         minwidth--;
     273             : 
     274             :         /*
     275             :          * Build the number starting at the last digit.  Here remainder will
     276             :          * be a negative number, so we must reverse the sign before adding '0'
     277             :          * in order to get the correct ASCII digit.
     278             :          */
     279           0 :         while (minwidth--)
     280             :         {
     281           0 :             int32       oldval = num;
     282             :             int32       remainder;
     283             : 
     284           0 :             num /= 10;
     285           0 :             remainder = oldval - num * 10;
     286           0 :             start[minwidth] = '0' - remainder;
     287             :         }
     288             :     }
     289             :     else
     290             :     {
     291             :         /* Build the number starting at the last digit */
     292       96806 :         while (minwidth--)
     293             :         {
     294       52306 :             int32       oldval = num;
     295             :             int32       remainder;
     296             : 
     297       52306 :             num /= 10;
     298       52306 :             remainder = oldval - num * 10;
     299       52306 :             start[minwidth] = '0' + remainder;
     300             :         }
     301             :     }
     302             : 
     303             :     /*
     304             :      * If minwidth was not high enough to fit the number then num won't have
     305             :      * been divided down to zero.  We punt the problem to pg_ltostr(), which
     306             :      * will generate a correct answer in the minimum valid width.
     307             :      */
     308       22250 :     if (num != 0)
     309          12 :         return pg_ltostr(str, value);
     310             : 
     311             :     /* Otherwise, return last output character + 1 */
     312       22238 :     return end;
     313             : }
     314             : 
     315             : /*
     316             :  * pg_ltostr
     317             :  *      Converts 'value' into a decimal string representation stored at 'str'.
     318             :  *
     319             :  * Returns the ending address of the string result (the last character written
     320             :  * plus 1).  Note that no NUL terminator is written.
     321             :  *
     322             :  * The intended use-case for this function is to build strings that contain
     323             :  * multiple individual numbers, for example:
     324             :  *
     325             :  *  str = pg_ltostr(str, a);
     326             :  *  *str++ = ' ';
     327             :  *  str = pg_ltostr(str, b);
     328             :  *  *str = '\0';
     329             :  *
     330             :  * Note: Caller must ensure that 'str' points to enough memory to hold the
     331             :  * result.
     332             :  */
     333             : char *
     334         538 : pg_ltostr(char *str, int32 value)
     335             : {
     336             :     char       *start;
     337             :     char       *end;
     338             : 
     339             :     /*
     340             :      * Handle negative numbers in a special way.  We can't just write a '-'
     341             :      * prefix and reverse the sign as that would overflow for INT32_MIN.
     342             :      */
     343         538 :     if (value < 0)
     344             :     {
     345           0 :         *str++ = '-';
     346             : 
     347             :         /* Mark the position we must reverse the string from. */
     348           0 :         start = str;
     349             : 
     350             :         /* Compute the result string backwards. */
     351             :         do
     352             :         {
     353           0 :             int32       oldval = value;
     354             :             int32       remainder;
     355             : 
     356           0 :             value /= 10;
     357           0 :             remainder = oldval - value * 10;
     358             :             /* As above, we expect remainder to be negative. */
     359           0 :             *str++ = '0' - remainder;
     360           0 :         } while (value != 0);
     361             :     }
     362             :     else
     363             :     {
     364             :         /* Mark the position we must reverse the string from. */
     365         538 :         start = str;
     366             : 
     367             :         /* Compute the result string backwards. */
     368             :         do
     369             :         {
     370         764 :             int32       oldval = value;
     371             :             int32       remainder;
     372             : 
     373         764 :             value /= 10;
     374         764 :             remainder = oldval - value * 10;
     375         764 :             *str++ = '0' + remainder;
     376         764 :         } while (value != 0);
     377             :     }
     378             : 
     379             :     /* Remember the end+1 and back up 'str' to the last character. */
     380         538 :     end = str--;
     381             : 
     382             :     /* Reverse string. */
     383        1277 :     while (start < str)
     384             :     {
     385         201 :         char        swap = *start;
     386             : 
     387         201 :         *start++ = *str;
     388         201 :         *str-- = swap;
     389             :     }
     390             : 
     391         538 :     return end;
     392             : }
     393             : 
     394             : /*
     395             :  * pg_strtouint64
     396             :  *      Converts 'str' into an unsigned 64-bit integer.
     397             :  *
     398             :  * This has the identical API to strtoul(3), except that it will handle
     399             :  * 64-bit ints even where "long" is narrower than that.
     400             :  *
     401             :  * For the moment it seems sufficient to assume that the platform has
     402             :  * such a function somewhere; let's not roll our own.
     403             :  */
     404             : uint64
     405           8 : pg_strtouint64(const char *str, char **endptr, int base)
     406             : {
     407             : #ifdef _MSC_VER                 /* MSVC only */
     408             :     return _strtoui64(str, endptr, base);
     409             : #elif defined(HAVE_STRTOULL) && SIZEOF_LONG < 8
     410           8 :     return strtoull(str, endptr, base);
     411             : #else
     412             :     return strtoul(str, endptr, base);
     413             : #endif
     414             : }

Generated by: LCOV version 1.11