PostgreSQL Source Code  git master
numutils.c
Go to the documentation of this file.
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 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  if (s == NULL)
48  elog(ERROR, "NULL pointer");
49  if (*s == 0)
50  ereport(ERROR,
51  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
52  errmsg("invalid input syntax for type %s: \"%s\"",
53  "integer", s)));
54 
55  errno = 0;
56  l = strtol(s, &badp, 10);
57 
58  /* We made no progress parsing the string, so bail out */
59  if (s == badp)
60  ereport(ERROR,
61  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
62  errmsg("invalid input syntax for type %s: \"%s\"",
63  "integer", s)));
64 
65  switch (size)
66  {
67  case sizeof(int32):
68  if (errno == ERANGE
69 #if defined(HAVE_LONG_INT_64)
70  /* won't get ERANGE on these with 64-bit longs... */
71  || l < INT_MIN || l > INT_MAX
72 #endif
73  )
74  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  break;
79  case sizeof(int16):
80  if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
81  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  break;
86  case sizeof(int8):
87  if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
88  ereport(ERROR,
89  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
90  errmsg("value \"%s\" is out of range for 8-bit integer", s)));
91  break;
92  default:
93  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  while (*badp && *badp != c && isspace((unsigned char) *badp))
101  badp++;
102 
103  if (*badp && *badp != c)
104  ereport(ERROR,
105  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
106  errmsg("invalid input syntax for type %s: \"%s\"",
107  "integer", s)));
108 
109  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 pg_strtoint16(const char *s)
124 {
125  const char *ptr = s;
126  int16 tmp = 0;
127  bool neg = false;
128 
129  /* skip leading spaces */
130  while (likely(*ptr) && isspace((unsigned char) *ptr))
131  ptr++;
132 
133  /* handle sign */
134  if (*ptr == '-')
135  {
136  ptr++;
137  neg = true;
138  }
139  else if (*ptr == '+')
140  ptr++;
141 
142  /* require at least one digit */
143  if (unlikely(!isdigit((unsigned char) *ptr)))
144  goto invalid_syntax;
145 
146  /* process digits */
147  while (*ptr && isdigit((unsigned char) *ptr))
148  {
149  int8 digit = (*ptr++ - '0');
150 
151  if (unlikely(pg_mul_s16_overflow(tmp, 10, &tmp)) ||
152  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  while (*ptr != '\0' && isspace((unsigned char) *ptr))
158  ptr++;
159 
160  if (unlikely(*ptr != '\0'))
161  goto invalid_syntax;
162 
163  if (!neg)
164  {
165  /* could fail if input is most negative number */
166  if (unlikely(tmp == PG_INT16_MIN))
167  goto out_of_range;
168  tmp = -tmp;
169  }
170 
171  return tmp;
172 
173 out_of_range:
174  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  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 pg_strtoint32(const char *s)
200 {
201  const char *ptr = s;
202  int32 tmp = 0;
203  bool neg = false;
204 
205  /* skip leading spaces */
206  while (likely(*ptr) && isspace((unsigned char) *ptr))
207  ptr++;
208 
209  /* handle sign */
210  if (*ptr == '-')
211  {
212  ptr++;
213  neg = true;
214  }
215  else if (*ptr == '+')
216  ptr++;
217 
218  /* require at least one digit */
219  if (unlikely(!isdigit((unsigned char) *ptr)))
220  goto invalid_syntax;
221 
222  /* process digits */
223  while (*ptr && isdigit((unsigned char) *ptr))
224  {
225  int8 digit = (*ptr++ - '0');
226 
227  if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||
228  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  while (*ptr != '\0' && isspace((unsigned char) *ptr))
234  ptr++;
235 
236  if (unlikely(*ptr != '\0'))
237  goto invalid_syntax;
238 
239  if (!neg)
240  {
241  /* could fail if input is most negative number */
242  if (unlikely(tmp == PG_INT32_MIN))
243  goto out_of_range;
244  tmp = -tmp;
245  }
246 
247  return tmp;
248 
249 out_of_range:
250  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  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 pg_itoa(int16 i, char *a)
274 {
275  pg_ltoa((int32) i, a);
276 }
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 pg_ltoa(int32 value, char *a)
286 {
287  char *start = a;
288  bool neg = false;
289 
290  /*
291  * Avoid problems with the most negative integer not being representable
292  * as a positive integer.
293  */
294  if (value == PG_INT32_MIN)
295  {
296  memcpy(a, "-2147483648", 12);
297  return;
298  }
299  else if (value < 0)
300  {
301  value = -value;
302  neg = true;
303  }
304 
305  /* Compute the result string backwards. */
306  do
307  {
308  int32 remainder;
309  int32 oldval = value;
310 
311  value /= 10;
312  remainder = oldval - value * 10;
313  *a++ = '0' + remainder;
314  } while (value != 0);
315 
316  if (neg)
317  *a++ = '-';
318 
319  /* Add trailing NUL byte, and back up 'a' to the last character. */
320  *a-- = '\0';
321 
322  /* Reverse string. */
323  while (start < a)
324  {
325  char swap = *start;
326 
327  *start++ = *a;
328  *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 pg_lltoa(int64 value, char *a)
340 {
341  char *start = a;
342  bool neg = false;
343 
344  /*
345  * Avoid problems with the most negative integer not being representable
346  * as a positive integer.
347  */
348  if (value == PG_INT64_MIN)
349  {
350  memcpy(a, "-9223372036854775808", 21);
351  return;
352  }
353  else if (value < 0)
354  {
355  value = -value;
356  neg = true;
357  }
358 
359  /* Compute the result string backwards. */
360  do
361  {
362  int64 remainder;
363  int64 oldval = value;
364 
365  value /= 10;
366  remainder = oldval - value * 10;
367  *a++ = '0' + remainder;
368  } while (value != 0);
369 
370  if (neg)
371  *a++ = '-';
372 
373  /* Add trailing NUL byte, and back up 'a' to the last character. */
374  *a-- = '\0';
375 
376  /* Reverse string. */
377  while (start < a)
378  {
379  char swap = *start;
380 
381  *start++ = *a;
382  *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 *
411 {
412  char *start = str;
413  char *end = &str[minwidth];
414  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  if (num < 0)
423  {
424  *start++ = '-';
425  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  while (minwidth--)
433  {
434  int32 oldval = num;
435  int32 remainder;
436 
437  num /= 10;
438  remainder = oldval - num * 10;
439  start[minwidth] = '0' - remainder;
440  }
441  }
442  else
443  {
444  /* Build the number starting at the last digit */
445  while (minwidth--)
446  {
447  int32 oldval = num;
448  int32 remainder;
449 
450  num /= 10;
451  remainder = oldval - num * 10;
452  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  if (num != 0)
462  return pg_ltostr(str, value);
463 
464  /* Otherwise, return last output character + 1 */
465  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 *
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  if (value < 0)
497  {
498  *str++ = '-';
499 
500  /* Mark the position we must reverse the string from. */
501  start = str;
502 
503  /* Compute the result string backwards. */
504  do
505  {
506  int32 oldval = value;
507  int32 remainder;
508 
509  value /= 10;
510  remainder = oldval - value * 10;
511  /* As above, we expect remainder to be negative. */
512  *str++ = '0' - remainder;
513  } while (value != 0);
514  }
515  else
516  {
517  /* Mark the position we must reverse the string from. */
518  start = str;
519 
520  /* Compute the result string backwards. */
521  do
522  {
523  int32 oldval = value;
524  int32 remainder;
525 
526  value /= 10;
527  remainder = oldval - value * 10;
528  *str++ = '0' + remainder;
529  } while (value != 0);
530  }
531 
532  /* Remember the end+1 and back up 'str' to the last character. */
533  end = str--;
534 
535  /* Reverse string. */
536  while (start < str)
537  {
538  char swap = *start;
539 
540  *start++ = *str;
541  *str-- = swap;
542  }
543 
544  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 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  return strtoul(str, endptr, base);
566 #endif
567 }
signed short int16
Definition: c.h:345
#define swap(a, b)
Definition: qsort.c:94
#define likely(x)
Definition: c.h:207
static bool pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:140
static struct @144 value
int errcode(int sqlerrcode)
Definition: elog.c:570
static bool pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:83
signed int int32
Definition: c.h:346
#define ERROR
Definition: elog.h:43
char * c
#define PG_INT64_MIN
Definition: c.h:443
int16 pg_strtoint16(const char *s)
Definition: numutils.c:123
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:122
#define PG_INT16_MIN
Definition: c.h:437
#define PG_INT32_MIN
Definition: c.h:440
#define ereport(elevel, rest)
Definition: elog.h:141
void pg_itoa(int16 i, char *a)
Definition: numutils.c:273
signed char int8
Definition: c.h:344
uint64 pg_strtouint64(const char *str, char **endptr, int base)
Definition: numutils.c:558
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:410
char * pg_ltostr(char *str, int32 value)
Definition: numutils.c:487
#define Assert(condition)
Definition: c.h:732
static bool pg_sub_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:65
int32 pg_strtoint32(const char *s)
Definition: numutils.c:199
void pg_lltoa(int64 value, char *a)
Definition: numutils.c:339
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
#define unlikely(x)
Definition: c.h:208
void pg_ltoa(int32 value, char *a)
Definition: numutils.c:285
int32 pg_atoi(const char *s, int size, int c)
Definition: numutils.c:38