aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r--src/backend/utils/adt/arrayutils.c3
-rw-r--r--src/backend/utils/adt/int.c4
-rw-r--r--src/backend/utils/adt/int8.c1
-rw-r--r--src/backend/utils/adt/numutils.c149
-rw-r--r--src/backend/utils/adt/varlena.c4
5 files changed, 155 insertions, 6 deletions
diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c
index c0d719e98cc..5b98efe76bc 100644
--- a/src/backend/utils/adt/arrayutils.c
+++ b/src/backend/utils/adt/arrayutils.c
@@ -226,8 +226,7 @@ ArrayGetIntegerTypmods(ArrayType *arr, int *n)
result = (int32 *) palloc(*n * sizeof(int32));
for (i = 0; i < *n; i++)
- result[i] = pg_atoi(DatumGetCString(elem_values[i]),
- sizeof(int32), '\0');
+ result[i] = pg_strtoint32(DatumGetCString(elem_values[i]));
pfree(elem_values);
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 02783d8d6fe..8149dc1369b 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -60,7 +60,7 @@ int2in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
- PG_RETURN_INT16(pg_atoi(num, sizeof(int16), '\0'));
+ PG_RETURN_INT16(pg_strtoint16(num));
}
/*
@@ -265,7 +265,7 @@ int4in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
- PG_RETURN_INT32(pg_atoi(num, sizeof(int32), '\0'));
+ PG_RETURN_INT32(pg_strtoint32(num));
}
/*
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 49f32a8b3dd..3c595e800a4 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -101,6 +101,7 @@ scanint8(const char *str, bool errorOK, int64 *result)
if (!neg)
{
+ /* could fail if input is most negative number */
if (unlikely(tmp == PG_INT64_MIN))
goto out_of_range;
tmp = -tmp;
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index fb46f692e3a..49055d519cb 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -18,6 +18,7 @@
#include <limits.h>
#include <ctype.h>
+#include "common/int.h"
#include "utils/builtins.h"
/*
@@ -109,6 +110,154 @@ pg_atoi(const char *s, int size, int c)
}
/*
+ * Convert input string to a signed 16 bit integer.
+ *
+ * Allows any number of leading or trailing whitespace characters. Will throw
+ * ereport() upon bad input format or overflow.
+ *
+ * NB: Accumulate input as a negative number, to deal with two's complement
+ * representation of the most negative number, which can't be represented as a
+ * positive number.
+ */
+int16
+pg_strtoint16(const char *s)
+{
+ const char *ptr = s;
+ int16 tmp = 0;
+ bool neg = false;
+
+ /* skip leading spaces */
+ while (likely(*ptr) && isspace((unsigned char) *ptr))
+ ptr++;
+
+ /* handle sign */
+ if (*ptr == '-')
+ {
+ ptr++;
+ neg = true;
+ }
+ else if (*ptr == '+')
+ ptr++;
+
+ /* require at least one digit */
+ if (unlikely(!isdigit((unsigned char) *ptr)))
+ goto invalid_syntax;
+
+ /* process digits */
+ while (*ptr && isdigit((unsigned char) *ptr))
+ {
+ int8 digit = (*ptr++ - '0');
+
+ if (unlikely(pg_mul_s16_overflow(tmp, 10, &tmp)) ||
+ unlikely(pg_sub_s16_overflow(tmp, digit, &tmp)))
+ goto out_of_range;
+ }
+
+ /* allow trailing whitespace, but not other trailing chars */
+ while (*ptr != '\0' && isspace((unsigned char) *ptr))
+ ptr++;
+
+ if (unlikely(*ptr != '\0'))
+ goto invalid_syntax;
+
+ if (!neg)
+ {
+ /* could fail if input is most negative number */
+ if (unlikely(tmp == PG_INT16_MIN))
+ goto out_of_range;
+ tmp = -tmp;
+ }
+
+ return tmp;
+
+out_of_range:
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ s, "smallint")));
+
+invalid_syntax:
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "smallint", s)));
+}
+
+/*
+ * Convert input string to a signed 32 bit integer.
+ *
+ * Allows any number of leading or trailing whitespace characters. Will throw
+ * ereport() upon bad input format or overflow.
+ *
+ * NB: Accumulate input as a negative number, to deal with two's complement
+ * representation of the most negative number, which can't be represented as a
+ * positive number.
+ */
+int32
+pg_strtoint32(const char *s)
+{
+ const char *ptr = s;
+ int32 tmp = 0;
+ bool neg = false;
+
+ /* skip leading spaces */
+ while (likely(*ptr) && isspace((unsigned char) *ptr))
+ ptr++;
+
+ /* handle sign */
+ if (*ptr == '-')
+ {
+ ptr++;
+ neg = true;
+ }
+ else if (*ptr == '+')
+ ptr++;
+
+ /* require at least one digit */
+ if (unlikely(!isdigit((unsigned char) *ptr)))
+ goto invalid_syntax;
+
+ /* process digits */
+ while (*ptr && isdigit((unsigned char) *ptr))
+ {
+ int8 digit = (*ptr++ - '0');
+
+ if (unlikely(pg_mul_s32_overflow(tmp, 10, &tmp)) ||
+ unlikely(pg_sub_s32_overflow(tmp, digit, &tmp)))
+ goto out_of_range;
+ }
+
+ /* allow trailing whitespace, but not other trailing chars */
+ while (*ptr != '\0' && isspace((unsigned char) *ptr))
+ ptr++;
+
+ if (unlikely(*ptr != '\0'))
+ goto invalid_syntax;
+
+ if (!neg)
+ {
+ /* could fail if input is most negative number */
+ if (unlikely(tmp == PG_INT32_MIN))
+ goto out_of_range;
+ tmp = -tmp;
+ }
+
+ return tmp;
+
+out_of_range:
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ s, "integer")));
+
+invalid_syntax:
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ "integer", s)));
+}
+
+/*
* pg_itoa: converts a signed 16-bit integer to its string representation
*
* Caller must ensure that 'a' points to enough memory to hold the result
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index e8500b274dc..31eaa92c3b7 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -5155,8 +5155,8 @@ text_format(PG_FUNCTION_ARGS)
str = OutputFunctionCall(&typoutputinfo_width, value);
- /* pg_atoi will complain about bad data or overflow */
- width = pg_atoi(str, sizeof(int), '\0');
+ /* pg_strtoint32 will complain about bad data or overflow */
+ width = pg_strtoint32(str);
pfree(str);
}