diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/numutils.c | 185 |
1 files changed, 161 insertions, 24 deletions
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c index ab1564f22da..7cded73e6e6 100644 --- a/src/backend/utils/adt/numutils.c +++ b/src/backend/utils/adt/numutils.c @@ -85,6 +85,17 @@ decimalLength64(const uint64 v) return t + (v >= PowersOfTen[t]); } +static const int8 hexlookup[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + /* * Convert input string to a signed 16 bit integer. * @@ -108,6 +119,7 @@ int16 pg_strtoint16_safe(const char *s, Node *escontext) { const char *ptr = s; + const char *firstdigit; uint16 tmp = 0; bool neg = false; @@ -124,19 +136,60 @@ pg_strtoint16_safe(const char *s, Node *escontext) 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)) + if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { - if (unlikely(tmp > -(PG_INT16_MIN / 10))) - goto out_of_range; + firstdigit = ptr += 2; + + while (*ptr && isxdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT16_MIN / 16))) + goto out_of_range; + + tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++]; + } + } + else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '7')) + { + if (unlikely(tmp > -(PG_INT16_MIN / 8))) + goto out_of_range; + + tmp = tmp * 8 + (*ptr++ - '0'); + } + } + else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '1')) + { + if (unlikely(tmp > -(PG_INT16_MIN / 2))) + goto out_of_range; + + tmp = tmp * 2 + (*ptr++ - '0'); + } + } + else + { + firstdigit = ptr; - tmp = tmp * 10 + (*ptr++ - '0'); + while (*ptr && isdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT16_MIN / 10))) + goto out_of_range; + + tmp = tmp * 10 + (*ptr++ - '0'); + } } + /* require at least one digit */ + if (unlikely(ptr == firstdigit)) + goto invalid_syntax; + /* allow trailing whitespace, but not other trailing chars */ while (*ptr != '\0' && isspace((unsigned char) *ptr)) ptr++; @@ -193,6 +246,7 @@ int32 pg_strtoint32_safe(const char *s, Node *escontext) { const char *ptr = s; + const char *firstdigit; uint32 tmp = 0; bool neg = false; @@ -209,19 +263,60 @@ pg_strtoint32_safe(const char *s, Node *escontext) 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)) + if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { - if (unlikely(tmp > -(PG_INT32_MIN / 10))) - goto out_of_range; + firstdigit = ptr += 2; + + while (*ptr && isxdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT32_MIN / 16))) + goto out_of_range; + + tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++]; + } + } + else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '7')) + { + if (unlikely(tmp > -(PG_INT32_MIN / 8))) + goto out_of_range; + + tmp = tmp * 8 + (*ptr++ - '0'); + } + } + else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '1')) + { + if (unlikely(tmp > -(PG_INT32_MIN / 2))) + goto out_of_range; + + tmp = tmp * 2 + (*ptr++ - '0'); + } + } + else + { + firstdigit = ptr; + + while (*ptr && isdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT32_MIN / 10))) + goto out_of_range; - tmp = tmp * 10 + (*ptr++ - '0'); + tmp = tmp * 10 + (*ptr++ - '0'); + } } + /* require at least one digit */ + if (unlikely(ptr == firstdigit)) + goto invalid_syntax; + /* allow trailing whitespace, but not other trailing chars */ while (*ptr != '\0' && isspace((unsigned char) *ptr)) ptr++; @@ -278,6 +373,7 @@ int64 pg_strtoint64_safe(const char *s, Node *escontext) { const char *ptr = s; + const char *firstdigit; uint64 tmp = 0; bool neg = false; @@ -294,18 +390,59 @@ pg_strtoint64_safe(const char *s, Node *escontext) 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)) + if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { - if (unlikely(tmp > -(PG_INT64_MIN / 10))) - goto out_of_range; + firstdigit = ptr += 2; + + while (*ptr && isxdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT64_MIN / 16))) + goto out_of_range; - tmp = tmp * 10 + (*ptr++ - '0'); + tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++]; + } } + else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '7')) + { + if (unlikely(tmp > -(PG_INT64_MIN / 8))) + goto out_of_range; + + tmp = tmp * 8 + (*ptr++ - '0'); + } + } + else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) + { + firstdigit = ptr += 2; + + while (*ptr && (*ptr >= '0' && *ptr <= '1')) + { + if (unlikely(tmp > -(PG_INT64_MIN / 2))) + goto out_of_range; + + tmp = tmp * 2 + (*ptr++ - '0'); + } + } + else + { + firstdigit = ptr; + + while (*ptr && isdigit((unsigned char) *ptr)) + { + if (unlikely(tmp > -(PG_INT64_MIN / 10))) + goto out_of_range; + + tmp = tmp * 10 + (*ptr++ - '0'); + } + } + + /* require at least one digit */ + if (unlikely(ptr == firstdigit)) + goto invalid_syntax; /* allow trailing whitespace, but not other trailing chars */ while (*ptr != '\0' && isspace((unsigned char) *ptr)) |