mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
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
This commit is contained in:
@@ -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,18 +136,59 @@ 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;
|
||||
|
||||
tmp = tmp * 10 + (*ptr++ - '0');
|
||||
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;
|
||||
|
||||
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))
|
||||
@@ -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,18 +263,59 @@ 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;
|
||||
|
||||
tmp = tmp * 10 + (*ptr++ - '0');
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
/* 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))
|
||||
@@ -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;
|
||||
|
||||
tmp = tmp * 10 + (*ptr++ - '0');
|
||||
while (*ptr && isxdigit((unsigned char) *ptr))
|
||||
{
|
||||
if (unlikely(tmp > -(PG_INT64_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_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))
|
||||
|
||||
Reference in New Issue
Block a user