1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

Allow underscores in integer and numeric constants.

This allows underscores to be used in integer and numeric literals,
and their corresponding type input functions, for visual grouping.
For example:

    1_500_000_000
    3.14159_26535_89793
    0xffff_ffff
    0b_1001_0001

A single underscore is allowed between any 2 digits, or immediately
after the base prefix indicator of non-decimal integers, per SQL:202x
draft.

Peter Eisentraut and Dean Rasheed

Discussion: https://postgr.es/m/84aae844-dc55-a4be-86d9-4f0fa405cc97%40enterprisedb.com
This commit is contained in:
Dean Rasheed
2023-02-04 09:48:51 +00:00
parent 1b6f632a35
commit faff8f8e47
22 changed files with 712 additions and 172 deletions

View File

@ -6968,10 +6968,7 @@ set_var_from_str(const char *str, const char *cp,
}
if (!isdigit((unsigned char) *cp))
ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"numeric", str)));
goto invalid_syntax;
decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2);
@ -6992,12 +6989,19 @@ set_var_from_str(const char *str, const char *cp,
else if (*cp == '.')
{
if (have_dp)
ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"numeric", str)));
goto invalid_syntax;
have_dp = true;
cp++;
/* decimal point must not be followed by underscore */
if (*cp == '_')
goto invalid_syntax;
}
else if (*cp == '_')
{
/* underscore must be followed by more digits */
cp++;
if (!isdigit((unsigned char) *cp))
goto invalid_syntax;
}
else
break;
@ -7010,17 +7014,8 @@ set_var_from_str(const char *str, const char *cp,
/* Handle exponent, if any */
if (*cp == 'e' || *cp == 'E')
{
long exponent;
char *endptr;
cp++;
exponent = strtol(cp, &endptr, 10);
if (endptr == cp)
ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"numeric", str)));
cp = endptr;
int64 exponent = 0;
bool neg = false;
/*
* At this point, dweight and dscale can't be more than about
@ -7030,10 +7025,43 @@ set_var_from_str(const char *str, const char *cp,
* fit in storage format, make_result() will complain about it later;
* for consistency use the same ereport errcode/text as make_result().
*/
if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
ereturn(escontext, false,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
/* exponent sign */
cp++;
if (*cp == '+')
cp++;
else if (*cp == '-')
{
neg = true;
cp++;
}
/* exponent digits */
if (!isdigit((unsigned char) *cp))
goto invalid_syntax;
while (*cp)
{
if (isdigit((unsigned char) *cp))
{
exponent = exponent * 10 + (*cp++ - '0');
if (exponent > PG_INT32_MAX / 2)
goto out_of_range;
}
else if (*cp == '_')
{
/* underscore must be followed by more digits */
cp++;
if (!isdigit((unsigned char) *cp))
goto invalid_syntax;
}
else
break;
}
if (neg)
exponent = -exponent;
dweight += (int) exponent;
dscale -= (int) exponent;
if (dscale < 0)
@ -7085,6 +7113,17 @@ set_var_from_str(const char *str, const char *cp,
*endptr = cp;
return true;
out_of_range:
ereturn(escontext, false,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
invalid_syntax:
ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"numeric", str)));
}
@ -7167,6 +7206,13 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign,
tmp = tmp * 16 + xdigit_value(*cp++);
mul = mul * 16;
}
else if (*cp == '_')
{
/* Underscore must be followed by more digits */
cp++;
if (!isxdigit((unsigned char) *cp))
goto invalid_syntax;
}
else
break;
}
@ -7197,6 +7243,13 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign,
tmp = tmp * 8 + (*cp++ - '0');
mul = mul * 8;
}
else if (*cp == '_')
{
/* Underscore must be followed by more digits */
cp++;
if (*cp < '0' || *cp > '7')
goto invalid_syntax;
}
else
break;
}
@ -7227,6 +7280,13 @@ set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign,
tmp = tmp * 2 + (*cp++ - '0');
mul = mul * 2;
}
else if (*cp == '_')
{
/* Underscore must be followed by more digits */
cp++;
if (*cp < '0' || *cp > '1')
goto invalid_syntax;
}
else
break;
}