PostgreSQL Source Code  git master
numutils.c File Reference
#include "postgres.h"
#include <math.h>
#include <limits.h>
#include <ctype.h>
#include "common/int.h"
#include "utils/builtins.h"
Include dependency graph for numutils.c:

Go to the source code of this file.

Functions

int32 pg_atoi (const char *s, int size, int c)
 
int16 pg_strtoint16 (const char *s)
 
int32 pg_strtoint32 (const char *s)
 
void pg_itoa (int16 i, char *a)
 
void pg_ltoa (int32 value, char *a)
 
void pg_lltoa (int64 value, char *a)
 
char * pg_ltostr_zeropad (char *str, int32 value, int32 minwidth)
 
char * pg_ltostr (char *str, int32 value)
 
uint64 pg_strtouint64 (const char *str, char **endptr, int base)
 

Function Documentation

◆ pg_atoi()

int32 pg_atoi ( const char *  s,
int  size,
int  c 
)

Definition at line 38 of file numutils.c.

References elog, ereport, errcode(), errmsg(), and ERROR.

Referenced by int2vectorin().

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 }
signed short int16
Definition: c.h:345
int errcode(int sqlerrcode)
Definition: elog.c:570
signed int int32
Definition: c.h:346
#define ERROR
Definition: elog.h:43
char * c
#define ereport(elevel, rest)
Definition: elog.h:141
signed char int8
Definition: c.h:344
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226

◆ pg_itoa()

void pg_itoa ( int16  i,
char *  a 
)

Definition at line 273 of file numutils.c.

References pg_ltoa().

Referenced by int2out(), int2vectorout(), LogicalTapeSetCreate(), and ltsConcatWorkerTapes().

274 {
275  pg_ltoa((int32) i, a);
276 }
signed int int32
Definition: c.h:346
int i
void pg_ltoa(int32 value, char *a)
Definition: numutils.c:285

◆ pg_lltoa()

void pg_lltoa ( int64  value,
char *  a 
)

Definition at line 339 of file numutils.c.

References PG_INT64_MIN, swap, and value.

Referenced by int8out(), and printsimple().

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 }
#define swap(a, b)
Definition: qsort.c:94
static struct @130 value
#define PG_INT64_MIN
Definition: c.h:443

◆ pg_ltoa()

void pg_ltoa ( int32  value,
char *  a 
)

Definition at line 285 of file numutils.c.

References PG_INT32_MIN, swap, and value.

Referenced by int4out(), pg_itoa(), and printsimple().

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 }
#define swap(a, b)
Definition: qsort.c:94
static struct @130 value
signed int int32
Definition: c.h:346
#define PG_INT32_MIN
Definition: c.h:440

◆ pg_ltostr()

char* pg_ltostr ( char *  str,
int32  value 
)

Definition at line 487 of file numutils.c.

References generate_unaccent_rules::str, swap, and value.

Referenced by AppendSeconds(), and pg_ltostr_zeropad().

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 }
#define swap(a, b)
Definition: qsort.c:94
static struct @130 value
signed int int32
Definition: c.h:346

◆ pg_ltostr_zeropad()

char* pg_ltostr_zeropad ( char *  str,
int32  value,
int32  minwidth 
)

Definition at line 410 of file numutils.c.

References Assert, pg_ltostr(), generate_unaccent_rules::str, and value.

Referenced by AppendSeconds(), EncodeDateOnly(), EncodeDateTime(), EncodeTimeOnly(), and EncodeTimezone().

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 }
static struct @130 value
signed int int32
Definition: c.h:346
char * pg_ltostr(char *str, int32 value)
Definition: numutils.c:487
#define Assert(condition)
Definition: c.h:732

◆ pg_strtoint16()

int16 pg_strtoint16 ( const char *  s)

Definition at line 123 of file numutils.c.

References ereport, errcode(), errmsg(), ERROR, likely, PG_INT16_MIN, pg_mul_s16_overflow(), pg_sub_s16_overflow(), and unlikely.

Referenced by int2in().

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 }
signed short int16
Definition: c.h:345
#define likely(x)
Definition: c.h:207
int errcode(int sqlerrcode)
Definition: elog.c:570
static bool pg_mul_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:75
#define ERROR
Definition: elog.h:43
#define PG_INT16_MIN
Definition: c.h:437
#define ereport(elevel, rest)
Definition: elog.h:141
signed char int8
Definition: c.h:344
static bool pg_sub_s16_overflow(int16 a, int16 b, int16 *result)
Definition: int.h:52
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define unlikely(x)
Definition: c.h:208

◆ pg_strtoint32()

int32 pg_strtoint32 ( const char *  s)

Definition at line 199 of file numutils.c.

References ereport, errcode(), errmsg(), ERROR, likely, PG_INT32_MIN, pg_mul_s32_overflow(), pg_sub_s32_overflow(), and unlikely.

Referenced by ArrayGetIntegerTypmods(), check_foreign_key(), int4in(), libpqrcv_endstreaming(), libpqrcv_identify_system(), pq_parse_errornotice(), prsd_headline(), and text_format().

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 }
#define likely(x)
Definition: c.h:207
static bool pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:144
int errcode(int sqlerrcode)
Definition: elog.c:570
signed int int32
Definition: c.h:346
#define ERROR
Definition: elog.h:43
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:121
#define PG_INT32_MIN
Definition: c.h:440
#define ereport(elevel, rest)
Definition: elog.h:141
signed char int8
Definition: c.h:344
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define unlikely(x)
Definition: c.h:208

◆ pg_strtouint64()

uint64 pg_strtouint64 ( const char *  str,
char **  endptr,
int  base 
)

Definition at line 558 of file numutils.c.

Referenced by _SPI_execute_plan(), and pgss_ProcessUtility().

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 }