diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/int8.c | 90 | ||||
-rw-r--r-- | src/backend/utils/adt/numutils.c | 84 |
2 files changed, 86 insertions, 88 deletions
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index ad19d154ffc..4a87114a4f4 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -24,7 +24,6 @@ #include "nodes/supportnodes.h" #include "optimizer/optimizer.h" #include "utils/builtins.h" -#include "utils/int8.h" typedef struct @@ -45,99 +44,14 @@ typedef struct * Formatting and conversion routines. *---------------------------------------------------------*/ -/* - * scanint8 --- try to parse a string into an int8. - * - * If errorOK is false, ereport a useful error message if the string is bad. - * If errorOK is true, just return "false" for bad input. - */ -bool -scanint8(const char *str, bool errorOK, int64 *result) -{ - const char *ptr = str; - int64 tmp = 0; - bool neg = false; - - /* - * Do our own scan, rather than relying on sscanf which might be broken - * for long long. - * - * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate - * value as a negative number. - */ - - /* skip leading spaces */ - while (*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_s64_overflow(tmp, 10, &tmp)) || - unlikely(pg_sub_s64_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_INT64_MIN)) - goto out_of_range; - tmp = -tmp; - } - - *result = tmp; - return true; - -out_of_range: - if (!errorOK) - ereport(ERROR, - (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), - errmsg("value \"%s\" is out of range for type %s", - str, "bigint"))); - return false; - -invalid_syntax: - if (!errorOK) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type %s: \"%s\"", - "bigint", str))); - return false; -} - /* int8in() */ Datum int8in(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); - int64 result; + char *num = PG_GETARG_CSTRING(0); - (void) scanint8(str, false, &result); - PG_RETURN_INT64(result); + PG_RETURN_INT64(pg_strtoint64(num)); } diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c index 898a9e3f9a1..e82d23a325e 100644 --- a/src/backend/utils/adt/numutils.c +++ b/src/backend/utils/adt/numutils.c @@ -326,6 +326,90 @@ invalid_syntax: } /* + * Convert input string to a signed 64 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. + */ +int64 +pg_strtoint64(const char *s) +{ + const char *ptr = s; + int64 tmp = 0; + bool neg = false; + + /* + * Do our own scan, rather than relying on sscanf which might be broken + * for long long. + * + * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate + * value as a negative number. + */ + + /* skip leading spaces */ + while (*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_s64_overflow(tmp, 10, &tmp)) || + unlikely(pg_sub_s64_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_INT64_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, "bigint"))); + +invalid_syntax: + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for type %s: \"%s\"", + "bigint", s))); + + return 0; /* keep compiler quiet */ +} + +/* * pg_itoa: converts a signed 16-bit integer to its string representation * and returns strlen(a). * |