1
0
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:
Peter Eisentraut
2022-12-14 05:40:38 +01:00
parent 60684dd834
commit 6fcda9aba8
16 changed files with 1022 additions and 112 deletions

View File

@@ -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))