diff options
author | Peter Eisentraut <peter@eisentraut.org> | 2022-12-14 05:40:38 +0100 |
---|---|---|
committer | Peter Eisentraut <peter@eisentraut.org> | 2022-12-14 06:17:07 +0100 |
commit | 6fcda9aba83449082124825b6d375c0a61e21c42 (patch) | |
tree | d2e23f5322bf6879e0ee328593fbc7b3f6f71702 /src/backend/utils/adt/numutils.c | |
parent | 60684dd834a222fefedd49b19d1f0a6189c1632e (diff) | |
download | postgresql-6fcda9aba83449082124825b6d375c0a61e21c42.tar.gz postgresql-6fcda9aba83449082124825b6d375c0a61e21c42.zip |
Non-decimal integer literals
Add support for hexadecimal, octal, and binary integer literals:
0x42F
0o273
0b100101
per SQL:202x draft.
This adds support in the lexer as well as in the integer type input
functions.
Reviewed-by: John Naylor <john.naylor@enterprisedb.com>
Reviewed-by: Zhihong Yu <zyu@yugabyte.com>
Reviewed-by: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/b239564c-cad0-b23e-c57e-166d883cb97d@enterprisedb.com
Diffstat (limited to 'src/backend/utils/adt/numutils.c')
-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)) |