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:
parent
60684dd834
commit
6fcda9aba8
@ -694,6 +694,40 @@ $function$
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Additionally, non-decimal integer constants can be used in these forms:
|
||||
<synopsis>
|
||||
0x<replaceable>hexdigits</replaceable>
|
||||
0o<replaceable>octdigits</replaceable>
|
||||
0b<replaceable>bindigits</replaceable>
|
||||
</synopsis>
|
||||
<replaceable>hexdigits</replaceable> is one or more hexadecimal digits
|
||||
(0-9, A-F), <replaceable>octdigits</replaceable> is one or more octal
|
||||
digits (0-7), <replaceable>bindigits</replaceable> is one or more binary
|
||||
digits (0 or 1). Hexadecimal digits and the radix prefixes can be in
|
||||
upper or lower case. Note that only integers can have non-decimal forms,
|
||||
not numbers with fractional parts.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These are some examples of this:
|
||||
<literallayout>0b100101
|
||||
0B10011001
|
||||
0o273
|
||||
0O755
|
||||
0x42f
|
||||
0XFFFF
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Nondecimal integer constants are currently only supported in the range
|
||||
of the <type>bigint</type> type (see <xref
|
||||
linkend="datatype-numeric-table"/>).
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
<indexterm><primary>integer</primary></indexterm>
|
||||
<indexterm><primary>bigint</primary></indexterm>
|
||||
|
@ -119,7 +119,7 @@ RETURN
|
||||
WHEN 1700 /*numeric*/ THEN
|
||||
CASE WHEN $2 = -1
|
||||
THEN null
|
||||
ELSE (($2 - 4) >> 16) & 65535
|
||||
ELSE (($2 - 4) >> 16) & 0xFFFF
|
||||
END
|
||||
WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/
|
||||
WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/
|
||||
@ -147,7 +147,7 @@ RETURN
|
||||
WHEN $1 IN (1700) THEN
|
||||
CASE WHEN $2 = -1
|
||||
THEN null
|
||||
ELSE ($2 - 4) & 65535
|
||||
ELSE ($2 - 4) & 0xFFFF
|
||||
END
|
||||
ELSE null
|
||||
END;
|
||||
@ -163,7 +163,7 @@ RETURN
|
||||
WHEN $1 IN (1083, 1114, 1184, 1266) /* time, timestamp, same + tz */
|
||||
THEN CASE WHEN $2 < 0 THEN 6 ELSE $2 END
|
||||
WHEN $1 IN (1186) /* interval */
|
||||
THEN CASE WHEN $2 < 0 OR $2 & 65535 = 65535 THEN 6 ELSE $2 & 65535 END
|
||||
THEN CASE WHEN $2 < 0 OR $2 & 0xFFFF = 0xFFFF THEN 6 ELSE $2 & 0xFFFF END
|
||||
ELSE null
|
||||
END;
|
||||
|
||||
|
@ -527,6 +527,7 @@ T652 SQL-dynamic statements in SQL routines NO
|
||||
T653 SQL-schema statements in external routines YES
|
||||
T654 SQL-dynamic statements in external routines NO
|
||||
T655 Cyclically dependent routines YES
|
||||
T661 Non-decimal integer literals YES SQL:202x draft
|
||||
T811 Basic SQL/JSON constructor functions NO
|
||||
T812 SQL/JSON: JSON_OBJECTAGG NO
|
||||
T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY NO
|
||||
|
@ -385,11 +385,46 @@ make_const(ParseState *pstate, A_Const *aconst)
|
||||
{
|
||||
/* could be an oversize integer as well as a float ... */
|
||||
|
||||
int base = 10;
|
||||
char *startptr;
|
||||
int sign;
|
||||
char *testvalue;
|
||||
int64 val64;
|
||||
char *endptr;
|
||||
|
||||
startptr = aconst->val.fval.fval;
|
||||
if (startptr[0] == '-')
|
||||
{
|
||||
sign = -1;
|
||||
startptr++;
|
||||
}
|
||||
else
|
||||
sign = +1;
|
||||
if (startptr[0] == '0')
|
||||
{
|
||||
if (startptr[1] == 'b' || startptr[1] == 'B')
|
||||
{
|
||||
base = 2;
|
||||
startptr += 2;
|
||||
}
|
||||
else if (startptr[1] == 'o' || startptr[1] == 'O')
|
||||
{
|
||||
base = 8;
|
||||
startptr += 2;
|
||||
}
|
||||
if (startptr[1] == 'x' || startptr[1] == 'X')
|
||||
{
|
||||
base = 16;
|
||||
startptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign == +1)
|
||||
testvalue = startptr;
|
||||
else
|
||||
testvalue = psprintf("-%s", startptr);
|
||||
errno = 0;
|
||||
val64 = strtoi64(aconst->val.fval.fval, &endptr, 10);
|
||||
val64 = strtoi64(testvalue, &endptr, base);
|
||||
if (errno == 0 && *endptr == '\0')
|
||||
{
|
||||
/*
|
||||
|
@ -124,7 +124,7 @@ static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner);
|
||||
static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner);
|
||||
static char *litbufdup(core_yyscan_t yyscanner);
|
||||
static unsigned char unescape_single_char(unsigned char c, core_yyscan_t yyscanner);
|
||||
static int process_integer_literal(const char *token, YYSTYPE *lval);
|
||||
static int process_integer_literal(const char *token, YYSTYPE *lval, int base);
|
||||
static void addunicode(pg_wchar c, yyscan_t yyscanner);
|
||||
|
||||
#define yyerror(msg) scanner_yyerror(msg, yyscanner)
|
||||
@ -385,25 +385,40 @@ operator {op_chars}+
|
||||
* Unary minus is not part of a number here. Instead we pass it separately to
|
||||
* the parser, and there it gets coerced via doNegate().
|
||||
*
|
||||
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
* {numericfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
*
|
||||
* {realfail} is added to prevent the need for scanner
|
||||
* backup when the {real} rule fails to match completely.
|
||||
*/
|
||||
digit [0-9]
|
||||
decdigit [0-9]
|
||||
hexdigit [0-9A-Fa-f]
|
||||
octdigit [0-7]
|
||||
bindigit [0-1]
|
||||
|
||||
integer {digit}+
|
||||
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
|
||||
decimalfail {digit}+\.\.
|
||||
real ({integer}|{decimal})[Ee][-+]?{digit}+
|
||||
realfail ({integer}|{decimal})[Ee][-+]
|
||||
decinteger {decdigit}+
|
||||
hexinteger 0[xX]{hexdigit}+
|
||||
octinteger 0[oO]{octdigit}+
|
||||
bininteger 0[bB]{bindigit}+
|
||||
|
||||
integer_junk {integer}{ident_start}
|
||||
decimal_junk {decimal}{ident_start}
|
||||
hexfail 0[xX]
|
||||
octfail 0[oO]
|
||||
binfail 0[bB]
|
||||
|
||||
numeric (({decinteger}\.{decinteger}?)|(\.{decinteger}))
|
||||
numericfail {decdigit}+\.\.
|
||||
|
||||
real ({decinteger}|{numeric})[Ee][-+]?{decdigit}+
|
||||
realfail ({decinteger}|{numeric})[Ee][-+]
|
||||
|
||||
decinteger_junk {decinteger}{ident_start}
|
||||
hexinteger_junk {hexinteger}{ident_start}
|
||||
octinteger_junk {octinteger}{ident_start}
|
||||
bininteger_junk {bininteger}{ident_start}
|
||||
numeric_junk {numeric}{ident_start}
|
||||
real_junk {real}{ident_start}
|
||||
|
||||
param \${integer}
|
||||
param_junk \${integer}{ident_start}
|
||||
param \${decinteger}
|
||||
param_junk \${decinteger}{ident_start}
|
||||
|
||||
other .
|
||||
|
||||
@ -983,20 +998,44 @@ other .
|
||||
yyerror("trailing junk after parameter");
|
||||
}
|
||||
|
||||
{integer} {
|
||||
{decinteger} {
|
||||
SET_YYLLOC();
|
||||
return process_integer_literal(yytext, yylval);
|
||||
return process_integer_literal(yytext, yylval, 10);
|
||||
}
|
||||
{decimal} {
|
||||
{hexinteger} {
|
||||
SET_YYLLOC();
|
||||
return process_integer_literal(yytext, yylval, 16);
|
||||
}
|
||||
{octinteger} {
|
||||
SET_YYLLOC();
|
||||
return process_integer_literal(yytext, yylval, 8);
|
||||
}
|
||||
{bininteger} {
|
||||
SET_YYLLOC();
|
||||
return process_integer_literal(yytext, yylval, 2);
|
||||
}
|
||||
{hexfail} {
|
||||
SET_YYLLOC();
|
||||
yyerror("invalid hexadecimal integer");
|
||||
}
|
||||
{octfail} {
|
||||
SET_YYLLOC();
|
||||
yyerror("invalid octal integer");
|
||||
}
|
||||
{binfail} {
|
||||
SET_YYLLOC();
|
||||
yyerror("invalid binary integer");
|
||||
}
|
||||
{numeric} {
|
||||
SET_YYLLOC();
|
||||
yylval->str = pstrdup(yytext);
|
||||
return FCONST;
|
||||
}
|
||||
{decimalfail} {
|
||||
{numericfail} {
|
||||
/* throw back the .., and treat as integer */
|
||||
yyless(yyleng - 2);
|
||||
SET_YYLLOC();
|
||||
return process_integer_literal(yytext, yylval);
|
||||
return process_integer_literal(yytext, yylval, 10);
|
||||
}
|
||||
{real} {
|
||||
SET_YYLLOC();
|
||||
@ -1007,11 +1046,23 @@ other .
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
{integer_junk} {
|
||||
{decinteger_junk} {
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
{decimal_junk} {
|
||||
{hexinteger_junk} {
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
{octinteger_junk} {
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
{bininteger_junk} {
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
{numeric_junk} {
|
||||
SET_YYLLOC();
|
||||
yyerror("trailing junk after numeric literal");
|
||||
}
|
||||
@ -1307,17 +1358,17 @@ litbufdup(core_yyscan_t yyscanner)
|
||||
}
|
||||
|
||||
/*
|
||||
* Process {integer}. Note this will also do the right thing with {decimal},
|
||||
* ie digits and a decimal point.
|
||||
* Process {decinteger}, {hexinteger}, etc. Note this will also do the right
|
||||
* thing with {numeric}, ie digits and a decimal point.
|
||||
*/
|
||||
static int
|
||||
process_integer_literal(const char *token, YYSTYPE *lval)
|
||||
process_integer_literal(const char *token, YYSTYPE *lval, int base)
|
||||
{
|
||||
int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoint(token, &endptr, 10);
|
||||
val = strtoint(base == 10 ? token : token + 2, &endptr, base);
|
||||
if (*endptr != '\0' || errno == ERANGE)
|
||||
{
|
||||
/* integer too large (or contains decimal pt), treat it as a float */
|
||||
|
@ -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))
|
||||
|
@ -323,25 +323,40 @@ operator {op_chars}+
|
||||
* Unary minus is not part of a number here. Instead we pass it separately to
|
||||
* the parser, and there it gets coerced via doNegate().
|
||||
*
|
||||
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
* {numericfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
*
|
||||
* {realfail} is added to prevent the need for scanner
|
||||
* backup when the {real} rule fails to match completely.
|
||||
*/
|
||||
digit [0-9]
|
||||
decdigit [0-9]
|
||||
hexdigit [0-9A-Fa-f]
|
||||
octdigit [0-7]
|
||||
bindigit [0-1]
|
||||
|
||||
integer {digit}+
|
||||
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
|
||||
decimalfail {digit}+\.\.
|
||||
real ({integer}|{decimal})[Ee][-+]?{digit}+
|
||||
realfail ({integer}|{decimal})[Ee][-+]
|
||||
decinteger {decdigit}+
|
||||
hexinteger 0[xX]{hexdigit}+
|
||||
octinteger 0[oO]{octdigit}+
|
||||
bininteger 0[bB]{bindigit}+
|
||||
|
||||
integer_junk {integer}{ident_start}
|
||||
decimal_junk {decimal}{ident_start}
|
||||
hexfail 0[xX]
|
||||
octfail 0[oO]
|
||||
binfail 0[bB]
|
||||
|
||||
numeric (({decinteger}\.{decinteger}?)|(\.{decinteger}))
|
||||
numericfail {decdigit}+\.\.
|
||||
|
||||
real ({decinteger}|{numeric})[Ee][-+]?{decdigit}+
|
||||
realfail ({decinteger}|{numeric})[Ee][-+]
|
||||
|
||||
decinteger_junk {decinteger}{ident_start}
|
||||
hexinteger_junk {hexinteger}{ident_start}
|
||||
octinteger_junk {octinteger}{ident_start}
|
||||
bininteger_junk {bininteger}{ident_start}
|
||||
numeric_junk {numeric}{ident_start}
|
||||
real_junk {real}{ident_start}
|
||||
|
||||
param \${integer}
|
||||
param_junk \${integer}{ident_start}
|
||||
param \${decinteger}
|
||||
param_junk \${decinteger}{ident_start}
|
||||
|
||||
/* psql-specific: characters allowed in variable names */
|
||||
variable_char [A-Za-z\200-\377_0-9]
|
||||
@ -847,13 +862,31 @@ other .
|
||||
ECHO;
|
||||
}
|
||||
|
||||
{integer} {
|
||||
{decinteger} {
|
||||
ECHO;
|
||||
}
|
||||
{decimal} {
|
||||
{hexinteger} {
|
||||
ECHO;
|
||||
}
|
||||
{decimalfail} {
|
||||
{octinteger} {
|
||||
ECHO;
|
||||
}
|
||||
{bininteger} {
|
||||
ECHO;
|
||||
}
|
||||
{hexfail} {
|
||||
ECHO;
|
||||
}
|
||||
{octfail} {
|
||||
ECHO;
|
||||
}
|
||||
{binfail} {
|
||||
ECHO;
|
||||
}
|
||||
{numeric} {
|
||||
ECHO;
|
||||
}
|
||||
{numericfail} {
|
||||
/* throw back the .., and treat as integer */
|
||||
yyless(yyleng - 2);
|
||||
ECHO;
|
||||
@ -864,10 +897,19 @@ other .
|
||||
{realfail} {
|
||||
ECHO;
|
||||
}
|
||||
{integer_junk} {
|
||||
{decinteger_junk} {
|
||||
ECHO;
|
||||
}
|
||||
{decimal_junk} {
|
||||
{hexinteger_junk} {
|
||||
ECHO;
|
||||
}
|
||||
{octinteger_junk} {
|
||||
ECHO;
|
||||
}
|
||||
{bininteger_junk} {
|
||||
ECHO;
|
||||
}
|
||||
{numeric_junk} {
|
||||
ECHO;
|
||||
}
|
||||
{real_junk} {
|
||||
|
@ -57,7 +57,7 @@ static bool include_next;
|
||||
#define startlit() (literalbuf[0] = '\0', literallen = 0)
|
||||
static void addlit(char *ytext, int yleng);
|
||||
static void addlitchar(unsigned char ychar);
|
||||
static int process_integer_literal(const char *token, YYSTYPE *lval);
|
||||
static int process_integer_literal(const char *token, YYSTYPE *lval, int base);
|
||||
static void parse_include(void);
|
||||
static bool ecpg_isspace(char ch);
|
||||
static bool isdefine(void);
|
||||
@ -351,25 +351,40 @@ operator {op_chars}+
|
||||
* Unary minus is not part of a number here. Instead we pass it separately to
|
||||
* the parser, and there it gets coerced via doNegate().
|
||||
*
|
||||
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
* {numericfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
|
||||
*
|
||||
* {realfail} is added to prevent the need for scanner
|
||||
* backup when the {real} rule fails to match completely.
|
||||
*/
|
||||
digit [0-9]
|
||||
decdigit [0-9]
|
||||
hexdigit [0-9A-Fa-f]
|
||||
octdigit [0-7]
|
||||
bindigit [0-1]
|
||||
|
||||
integer {digit}+
|
||||
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
|
||||
decimalfail {digit}+\.\.
|
||||
real ({integer}|{decimal})[Ee][-+]?{digit}+
|
||||
realfail ({integer}|{decimal})[Ee][-+]
|
||||
decinteger {decdigit}+
|
||||
hexinteger 0[xX]{hexdigit}+
|
||||
octinteger 0[oO]{octdigit}+
|
||||
bininteger 0[bB]{bindigit}+
|
||||
|
||||
integer_junk {integer}{ident_start}
|
||||
decimal_junk {decimal}{ident_start}
|
||||
hexfail 0[xX]
|
||||
octfail 0[oO]
|
||||
binfail 0[bB]
|
||||
|
||||
numeric (({decinteger}\.{decinteger}?)|(\.{decinteger}))
|
||||
numericfail {decdigit}+\.\.
|
||||
|
||||
real ({decinteger}|{numeric})[Ee][-+]?{decdigit}+
|
||||
realfail ({decinteger}|{numeric})[Ee][-+]
|
||||
|
||||
decinteger_junk {decinteger}{ident_start}
|
||||
hexinteger_junk {hexinteger}{ident_start}
|
||||
octinteger_junk {octinteger}{ident_start}
|
||||
bininteger_junk {bininteger}{ident_start}
|
||||
numeric_junk {numeric}{ident_start}
|
||||
real_junk {real}{ident_start}
|
||||
|
||||
param \${integer}
|
||||
param_junk \${integer}{ident_start}
|
||||
param \${decinteger}
|
||||
param_junk \${decinteger}{ident_start}
|
||||
|
||||
/* special characters for other dbms */
|
||||
/* we have to react differently in compat mode */
|
||||
@ -399,9 +414,6 @@ include_next [iI][nN][cC][lL][uU][dD][eE]_[nN][eE][xX][tT]
|
||||
import [iI][mM][pP][oO][rR][tT]
|
||||
undef [uU][nN][dD][eE][fF]
|
||||
|
||||
/* C version of hex number */
|
||||
xch 0[xX][0-9A-Fa-f]*
|
||||
|
||||
ccomment "//".*\n
|
||||
|
||||
if [iI][fF]
|
||||
@ -414,7 +426,7 @@ endif [eE][nN][dD][iI][fF]
|
||||
struct [sS][tT][rR][uU][cC][tT]
|
||||
|
||||
exec_sql {exec}{space}*{sql}{space}*
|
||||
ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
|
||||
ipdigit ({decdigit}|{decdigit}{decdigit}|{decdigit}{decdigit}{decdigit})
|
||||
ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
|
||||
|
||||
/* we might want to parse all cpp include files */
|
||||
@ -932,17 +944,20 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
||||
} /* <SQL> */
|
||||
|
||||
<C,SQL>{
|
||||
{integer} {
|
||||
return process_integer_literal(yytext, &base_yylval);
|
||||
{decinteger} {
|
||||
return process_integer_literal(yytext, &base_yylval, 10);
|
||||
}
|
||||
{decimal} {
|
||||
{hexinteger} {
|
||||
return process_integer_literal(yytext, &base_yylval, 16);
|
||||
}
|
||||
{numeric} {
|
||||
base_yylval.str = mm_strdup(yytext);
|
||||
return FCONST;
|
||||
}
|
||||
{decimalfail} {
|
||||
{numericfail} {
|
||||
/* throw back the .., and treat as integer */
|
||||
yyless(yyleng - 2);
|
||||
return process_integer_literal(yytext, &base_yylval);
|
||||
return process_integer_literal(yytext, &base_yylval, 10);
|
||||
}
|
||||
{real} {
|
||||
base_yylval.str = mm_strdup(yytext);
|
||||
@ -951,22 +966,38 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
||||
{realfail} {
|
||||
/*
|
||||
* throw back the [Ee][+-], and figure out whether what
|
||||
* remains is an {integer} or {decimal}.
|
||||
* remains is an {decinteger} or {numeric}.
|
||||
*/
|
||||
yyless(yyleng - 2);
|
||||
return process_integer_literal(yytext, &base_yylval);
|
||||
return process_integer_literal(yytext, &base_yylval, 10);
|
||||
}
|
||||
} /* <C,SQL> */
|
||||
|
||||
<SQL>{
|
||||
{octinteger} {
|
||||
return process_integer_literal(yytext, &base_yylval, 8);
|
||||
}
|
||||
{bininteger} {
|
||||
return process_integer_literal(yytext, &base_yylval, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that some trailing junk is valid in C (such as 100LL), so we
|
||||
* contain this to SQL mode.
|
||||
*/
|
||||
{integer_junk} {
|
||||
{decinteger_junk} {
|
||||
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
|
||||
}
|
||||
{decimal_junk} {
|
||||
{hexinteger_junk} {
|
||||
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
|
||||
}
|
||||
{octinteger_junk} {
|
||||
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
|
||||
}
|
||||
{bininteger_junk} {
|
||||
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
|
||||
}
|
||||
{numeric_junk} {
|
||||
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
|
||||
}
|
||||
{real_junk} {
|
||||
@ -1036,19 +1067,6 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
|
||||
return S_ANYTHING;
|
||||
}
|
||||
<C>{ccomment} { ECHO; }
|
||||
<C>{xch} {
|
||||
char* endptr;
|
||||
|
||||
errno = 0;
|
||||
base_yylval.ival = strtoul((char *) yytext, &endptr, 16);
|
||||
if (*endptr != '\0' || errno == ERANGE)
|
||||
{
|
||||
errno = 0;
|
||||
base_yylval.str = mm_strdup(yytext);
|
||||
return SCONST;
|
||||
}
|
||||
return ICONST;
|
||||
}
|
||||
<C>{cppinclude} {
|
||||
if (system_includes)
|
||||
{
|
||||
@ -1573,17 +1591,17 @@ addlitchar(unsigned char ychar)
|
||||
}
|
||||
|
||||
/*
|
||||
* Process {integer}. Note this will also do the right thing with {decimal},
|
||||
* ie digits and a decimal point.
|
||||
* Process {decinteger}, {hexinteger}, etc. Note this will also do the right
|
||||
* thing with {numeric}, ie digits and a decimal point.
|
||||
*/
|
||||
static int
|
||||
process_integer_literal(const char *token, YYSTYPE *lval)
|
||||
process_integer_literal(const char *token, YYSTYPE *lval, int base)
|
||||
{
|
||||
int val;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
val = strtoint(token, &endptr, 10);
|
||||
val = strtoint(base == 10 ? token : token + 2, &endptr, base);
|
||||
if (*endptr != '\0' || errno == ERANGE)
|
||||
{
|
||||
/* integer too large (or contains decimal pt), treat it as a float */
|
||||
|
@ -329,3 +329,95 @@ FROM (VALUES (-2.5::numeric),
|
||||
2.5 | 3
|
||||
(7 rows)
|
||||
|
||||
-- non-decimal literals
|
||||
SELECT int2 '0b100101';
|
||||
int2
|
||||
------
|
||||
37
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0o273';
|
||||
int2
|
||||
------
|
||||
187
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0x42F';
|
||||
int2
|
||||
------
|
||||
1071
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0b';
|
||||
ERROR: invalid input syntax for type smallint: "0b"
|
||||
LINE 1: SELECT int2 '0b';
|
||||
^
|
||||
SELECT int2 '0o';
|
||||
ERROR: invalid input syntax for type smallint: "0o"
|
||||
LINE 1: SELECT int2 '0o';
|
||||
^
|
||||
SELECT int2 '0x';
|
||||
ERROR: invalid input syntax for type smallint: "0x"
|
||||
LINE 1: SELECT int2 '0x';
|
||||
^
|
||||
-- cases near overflow
|
||||
SELECT int2 '0b111111111111111';
|
||||
int2
|
||||
-------
|
||||
32767
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0b1000000000000000';
|
||||
ERROR: value "0b1000000000000000" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '0b1000000000000000';
|
||||
^
|
||||
SELECT int2 '0o77777';
|
||||
int2
|
||||
-------
|
||||
32767
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0o100000';
|
||||
ERROR: value "0o100000" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '0o100000';
|
||||
^
|
||||
SELECT int2 '0x7FFF';
|
||||
int2
|
||||
-------
|
||||
32767
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '0x8000';
|
||||
ERROR: value "0x8000" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '0x8000';
|
||||
^
|
||||
SELECT int2 '-0b1000000000000000';
|
||||
int2
|
||||
--------
|
||||
-32768
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '-0b1000000000000001';
|
||||
ERROR: value "-0b1000000000000001" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '-0b1000000000000001';
|
||||
^
|
||||
SELECT int2 '-0o100000';
|
||||
int2
|
||||
--------
|
||||
-32768
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '-0o100001';
|
||||
ERROR: value "-0o100001" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '-0o100001';
|
||||
^
|
||||
SELECT int2 '-0x8000';
|
||||
int2
|
||||
--------
|
||||
-32768
|
||||
(1 row)
|
||||
|
||||
SELECT int2 '-0x8001';
|
||||
ERROR: value "-0x8001" is out of range for type smallint
|
||||
LINE 1: SELECT int2 '-0x8001';
|
||||
^
|
||||
|
@ -456,3 +456,95 @@ SELECT lcm((-2147483648)::int4, 1::int4); -- overflow
|
||||
ERROR: integer out of range
|
||||
SELECT lcm(2147483647::int4, 2147483646::int4); -- overflow
|
||||
ERROR: integer out of range
|
||||
-- non-decimal literals
|
||||
SELECT int4 '0b100101';
|
||||
int4
|
||||
------
|
||||
37
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0o273';
|
||||
int4
|
||||
------
|
||||
187
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0x42F';
|
||||
int4
|
||||
------
|
||||
1071
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0b';
|
||||
ERROR: invalid input syntax for type integer: "0b"
|
||||
LINE 1: SELECT int4 '0b';
|
||||
^
|
||||
SELECT int4 '0o';
|
||||
ERROR: invalid input syntax for type integer: "0o"
|
||||
LINE 1: SELECT int4 '0o';
|
||||
^
|
||||
SELECT int4 '0x';
|
||||
ERROR: invalid input syntax for type integer: "0x"
|
||||
LINE 1: SELECT int4 '0x';
|
||||
^
|
||||
-- cases near overflow
|
||||
SELECT int4 '0b1111111111111111111111111111111';
|
||||
int4
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0b10000000000000000000000000000000';
|
||||
ERROR: value "0b10000000000000000000000000000000" is out of range for type integer
|
||||
LINE 1: SELECT int4 '0b10000000000000000000000000000000';
|
||||
^
|
||||
SELECT int4 '0o17777777777';
|
||||
int4
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0o20000000000';
|
||||
ERROR: value "0o20000000000" is out of range for type integer
|
||||
LINE 1: SELECT int4 '0o20000000000';
|
||||
^
|
||||
SELECT int4 '0x7FFFFFFF';
|
||||
int4
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '0x80000000';
|
||||
ERROR: value "0x80000000" is out of range for type integer
|
||||
LINE 1: SELECT int4 '0x80000000';
|
||||
^
|
||||
SELECT int4 '-0b10000000000000000000000000000000';
|
||||
int4
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '-0b10000000000000000000000000000001';
|
||||
ERROR: value "-0b10000000000000000000000000000001" is out of range for type integer
|
||||
LINE 1: SELECT int4 '-0b10000000000000000000000000000001';
|
||||
^
|
||||
SELECT int4 '-0o20000000000';
|
||||
int4
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '-0o20000000001';
|
||||
ERROR: value "-0o20000000001" is out of range for type integer
|
||||
LINE 1: SELECT int4 '-0o20000000001';
|
||||
^
|
||||
SELECT int4 '-0x80000000';
|
||||
int4
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT int4 '-0x80000001';
|
||||
ERROR: value "-0x80000001" is out of range for type integer
|
||||
LINE 1: SELECT int4 '-0x80000001';
|
||||
^
|
||||
|
@ -952,3 +952,95 @@ SELECT lcm((-9223372036854775808)::int8, 1::int8); -- overflow
|
||||
ERROR: bigint out of range
|
||||
SELECT lcm(9223372036854775807::int8, 9223372036854775806::int8); -- overflow
|
||||
ERROR: bigint out of range
|
||||
-- non-decimal literals
|
||||
SELECT int8 '0b100101';
|
||||
int8
|
||||
------
|
||||
37
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0o273';
|
||||
int8
|
||||
------
|
||||
187
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0x42F';
|
||||
int8
|
||||
------
|
||||
1071
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0b';
|
||||
ERROR: invalid input syntax for type bigint: "0b"
|
||||
LINE 1: SELECT int8 '0b';
|
||||
^
|
||||
SELECT int8 '0o';
|
||||
ERROR: invalid input syntax for type bigint: "0o"
|
||||
LINE 1: SELECT int8 '0o';
|
||||
^
|
||||
SELECT int8 '0x';
|
||||
ERROR: invalid input syntax for type bigint: "0x"
|
||||
LINE 1: SELECT int8 '0x';
|
||||
^
|
||||
-- cases near overflow
|
||||
SELECT int8 '0b111111111111111111111111111111111111111111111111111111111111111';
|
||||
int8
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0b1000000000000000000000000000000000000000000000000000000000000000';
|
||||
ERROR: value "0b1000000000000000000000000000000000000000000000000000000000000000" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '0b100000000000000000000000000000000000000000000...
|
||||
^
|
||||
SELECT int8 '0o777777777777777777777';
|
||||
int8
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0o1000000000000000000000';
|
||||
ERROR: value "0o1000000000000000000000" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '0o1000000000000000000000';
|
||||
^
|
||||
SELECT int8 '0x7FFFFFFFFFFFFFFF';
|
||||
int8
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '0x8000000000000000';
|
||||
ERROR: value "0x8000000000000000" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '0x8000000000000000';
|
||||
^
|
||||
SELECT int8 '-0b1000000000000000000000000000000000000000000000000000000000000000';
|
||||
int8
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '-0b1000000000000000000000000000000000000000000000000000000000000001';
|
||||
ERROR: value "-0b1000000000000000000000000000000000000000000000000000000000000001" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '-0b10000000000000000000000000000000000000000000...
|
||||
^
|
||||
SELECT int8 '-0o1000000000000000000000';
|
||||
int8
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '-0o1000000000000000000001';
|
||||
ERROR: value "-0o1000000000000000000001" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '-0o1000000000000000000001';
|
||||
^
|
||||
SELECT int8 '-0x8000000000000000';
|
||||
int8
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT int8 '-0x8000000000000001';
|
||||
ERROR: value "-0x8000000000000001" is out of range for type bigint
|
||||
LINE 1: SELECT int8 '-0x8000000000000001';
|
||||
^
|
||||
|
@ -3,14 +3,167 @@
|
||||
-- Test various combinations of numeric types and functions.
|
||||
--
|
||||
--
|
||||
-- Trailing junk in numeric literals
|
||||
-- numeric literals
|
||||
--
|
||||
SELECT 0b100101;
|
||||
?column?
|
||||
----------
|
||||
37
|
||||
(1 row)
|
||||
|
||||
SELECT 0o273;
|
||||
?column?
|
||||
----------
|
||||
187
|
||||
(1 row)
|
||||
|
||||
SELECT 0x42F;
|
||||
?column?
|
||||
----------
|
||||
1071
|
||||
(1 row)
|
||||
|
||||
-- cases near int4 overflow
|
||||
SELECT 0b1111111111111111111111111111111;
|
||||
?column?
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT 0b10000000000000000000000000000000;
|
||||
?column?
|
||||
------------
|
||||
2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT 0o17777777777;
|
||||
?column?
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT 0o20000000000;
|
||||
?column?
|
||||
------------
|
||||
2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT 0x7FFFFFFF;
|
||||
?column?
|
||||
------------
|
||||
2147483647
|
||||
(1 row)
|
||||
|
||||
SELECT 0x80000000;
|
||||
?column?
|
||||
------------
|
||||
2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT -0b10000000000000000000000000000000;
|
||||
?column?
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT -0b10000000000000000000000000000001;
|
||||
?column?
|
||||
-------------
|
||||
-2147483649
|
||||
(1 row)
|
||||
|
||||
SELECT -0o20000000000;
|
||||
?column?
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT -0o20000000001;
|
||||
?column?
|
||||
-------------
|
||||
-2147483649
|
||||
(1 row)
|
||||
|
||||
SELECT -0x80000000;
|
||||
?column?
|
||||
-------------
|
||||
-2147483648
|
||||
(1 row)
|
||||
|
||||
SELECT -0x80000001;
|
||||
?column?
|
||||
-------------
|
||||
-2147483649
|
||||
(1 row)
|
||||
|
||||
-- cases near int8 overflow
|
||||
SELECT 0b111111111111111111111111111111111111111111111111111111111111111;
|
||||
?column?
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT 0b1000000000000000000000000000000000000000000000000000000000000000;
|
||||
ERROR: invalid input syntax for type numeric: "0b1000000000000000000000000000000000000000000000000000000000000000"
|
||||
LINE 1: SELECT 0b100000000000000000000000000000000000000000000000000...
|
||||
^
|
||||
SELECT 0o777777777777777777777;
|
||||
?column?
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT 0o1000000000000000000000;
|
||||
ERROR: invalid input syntax for type numeric: "0o1000000000000000000000"
|
||||
LINE 1: SELECT 0o1000000000000000000000;
|
||||
^
|
||||
SELECT 0x7FFFFFFFFFFFFFFF;
|
||||
?column?
|
||||
---------------------
|
||||
9223372036854775807
|
||||
(1 row)
|
||||
|
||||
SELECT 0x8000000000000000;
|
||||
ERROR: invalid input syntax for type numeric: "0x8000000000000000"
|
||||
LINE 1: SELECT 0x8000000000000000;
|
||||
^
|
||||
SELECT -0b1000000000000000000000000000000000000000000000000000000000000000;
|
||||
?column?
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT -0b1000000000000000000000000000000000000000000000000000000000000001;
|
||||
ERROR: invalid input syntax for type numeric: "-0b1000000000000000000000000000000000000000000000000000000000000001"
|
||||
LINE 1: SELECT -0b10000000000000000000000000000000000000000000000000...
|
||||
^
|
||||
SELECT -0o1000000000000000000000;
|
||||
?column?
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT -0o1000000000000000000001;
|
||||
ERROR: invalid input syntax for type numeric: "-0o1000000000000000000001"
|
||||
LINE 1: SELECT -0o1000000000000000000001;
|
||||
^
|
||||
SELECT -0x8000000000000000;
|
||||
?column?
|
||||
----------------------
|
||||
-9223372036854775808
|
||||
(1 row)
|
||||
|
||||
SELECT -0x8000000000000001;
|
||||
ERROR: invalid input syntax for type numeric: "-0x8000000000000001"
|
||||
LINE 1: SELECT -0x8000000000000001;
|
||||
^
|
||||
-- error cases
|
||||
SELECT 123abc;
|
||||
ERROR: trailing junk after numeric literal at or near "123a"
|
||||
LINE 1: SELECT 123abc;
|
||||
^
|
||||
SELECT 0x0o;
|
||||
ERROR: trailing junk after numeric literal at or near "0x"
|
||||
ERROR: trailing junk after numeric literal at or near "0x0o"
|
||||
LINE 1: SELECT 0x0o;
|
||||
^
|
||||
SELECT 1_2_3;
|
||||
@ -45,6 +198,42 @@ PREPARE p1 AS SELECT $1a;
|
||||
ERROR: trailing junk after parameter at or near "$1a"
|
||||
LINE 1: PREPARE p1 AS SELECT $1a;
|
||||
^
|
||||
SELECT 0b;
|
||||
ERROR: invalid binary integer at or near "0b"
|
||||
LINE 1: SELECT 0b;
|
||||
^
|
||||
SELECT 1b;
|
||||
ERROR: trailing junk after numeric literal at or near "1b"
|
||||
LINE 1: SELECT 1b;
|
||||
^
|
||||
SELECT 0b0x;
|
||||
ERROR: trailing junk after numeric literal at or near "0b0x"
|
||||
LINE 1: SELECT 0b0x;
|
||||
^
|
||||
SELECT 0o;
|
||||
ERROR: invalid octal integer at or near "0o"
|
||||
LINE 1: SELECT 0o;
|
||||
^
|
||||
SELECT 1o;
|
||||
ERROR: trailing junk after numeric literal at or near "1o"
|
||||
LINE 1: SELECT 1o;
|
||||
^
|
||||
SELECT 0o0x;
|
||||
ERROR: trailing junk after numeric literal at or near "0o0x"
|
||||
LINE 1: SELECT 0o0x;
|
||||
^
|
||||
SELECT 0x;
|
||||
ERROR: invalid hexadecimal integer at or near "0x"
|
||||
LINE 1: SELECT 0x;
|
||||
^
|
||||
SELECT 1x;
|
||||
ERROR: trailing junk after numeric literal at or near "1x"
|
||||
LINE 1: SELECT 1x;
|
||||
^
|
||||
SELECT 0x0y;
|
||||
ERROR: trailing junk after numeric literal at or near "0x0y"
|
||||
LINE 1: SELECT 0x0y;
|
||||
^
|
||||
--
|
||||
-- Test implicit type conversions
|
||||
-- This fails for Postgres v6.1 (and earlier?)
|
||||
|
@ -110,3 +110,29 @@ FROM (VALUES (-2.5::numeric),
|
||||
(0.5::numeric),
|
||||
(1.5::numeric),
|
||||
(2.5::numeric)) t(x);
|
||||
|
||||
|
||||
-- non-decimal literals
|
||||
|
||||
SELECT int2 '0b100101';
|
||||
SELECT int2 '0o273';
|
||||
SELECT int2 '0x42F';
|
||||
|
||||
SELECT int2 '0b';
|
||||
SELECT int2 '0o';
|
||||
SELECT int2 '0x';
|
||||
|
||||
-- cases near overflow
|
||||
SELECT int2 '0b111111111111111';
|
||||
SELECT int2 '0b1000000000000000';
|
||||
SELECT int2 '0o77777';
|
||||
SELECT int2 '0o100000';
|
||||
SELECT int2 '0x7FFF';
|
||||
SELECT int2 '0x8000';
|
||||
|
||||
SELECT int2 '-0b1000000000000000';
|
||||
SELECT int2 '-0b1000000000000001';
|
||||
SELECT int2 '-0o100000';
|
||||
SELECT int2 '-0o100001';
|
||||
SELECT int2 '-0x8000';
|
||||
SELECT int2 '-0x8001';
|
||||
|
@ -170,3 +170,29 @@ FROM (VALUES (0::int4, 0::int4),
|
||||
|
||||
SELECT lcm((-2147483648)::int4, 1::int4); -- overflow
|
||||
SELECT lcm(2147483647::int4, 2147483646::int4); -- overflow
|
||||
|
||||
|
||||
-- non-decimal literals
|
||||
|
||||
SELECT int4 '0b100101';
|
||||
SELECT int4 '0o273';
|
||||
SELECT int4 '0x42F';
|
||||
|
||||
SELECT int4 '0b';
|
||||
SELECT int4 '0o';
|
||||
SELECT int4 '0x';
|
||||
|
||||
-- cases near overflow
|
||||
SELECT int4 '0b1111111111111111111111111111111';
|
||||
SELECT int4 '0b10000000000000000000000000000000';
|
||||
SELECT int4 '0o17777777777';
|
||||
SELECT int4 '0o20000000000';
|
||||
SELECT int4 '0x7FFFFFFF';
|
||||
SELECT int4 '0x80000000';
|
||||
|
||||
SELECT int4 '-0b10000000000000000000000000000000';
|
||||
SELECT int4 '-0b10000000000000000000000000000001';
|
||||
SELECT int4 '-0o20000000000';
|
||||
SELECT int4 '-0o20000000001';
|
||||
SELECT int4 '-0x80000000';
|
||||
SELECT int4 '-0x80000001';
|
||||
|
@ -251,3 +251,29 @@ FROM (VALUES (0::int8, 0::int8),
|
||||
|
||||
SELECT lcm((-9223372036854775808)::int8, 1::int8); -- overflow
|
||||
SELECT lcm(9223372036854775807::int8, 9223372036854775806::int8); -- overflow
|
||||
|
||||
|
||||
-- non-decimal literals
|
||||
|
||||
SELECT int8 '0b100101';
|
||||
SELECT int8 '0o273';
|
||||
SELECT int8 '0x42F';
|
||||
|
||||
SELECT int8 '0b';
|
||||
SELECT int8 '0o';
|
||||
SELECT int8 '0x';
|
||||
|
||||
-- cases near overflow
|
||||
SELECT int8 '0b111111111111111111111111111111111111111111111111111111111111111';
|
||||
SELECT int8 '0b1000000000000000000000000000000000000000000000000000000000000000';
|
||||
SELECT int8 '0o777777777777777777777';
|
||||
SELECT int8 '0o1000000000000000000000';
|
||||
SELECT int8 '0x7FFFFFFFFFFFFFFF';
|
||||
SELECT int8 '0x8000000000000000';
|
||||
|
||||
SELECT int8 '-0b1000000000000000000000000000000000000000000000000000000000000000';
|
||||
SELECT int8 '-0b1000000000000000000000000000000000000000000000000000000000000001';
|
||||
SELECT int8 '-0o1000000000000000000000';
|
||||
SELECT int8 '-0o1000000000000000000001';
|
||||
SELECT int8 '-0x8000000000000000';
|
||||
SELECT int8 '-0x8000000000000001';
|
||||
|
@ -3,10 +3,46 @@
|
||||
-- Test various combinations of numeric types and functions.
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Trailing junk in numeric literals
|
||||
-- numeric literals
|
||||
--
|
||||
|
||||
SELECT 0b100101;
|
||||
SELECT 0o273;
|
||||
SELECT 0x42F;
|
||||
|
||||
-- cases near int4 overflow
|
||||
SELECT 0b1111111111111111111111111111111;
|
||||
SELECT 0b10000000000000000000000000000000;
|
||||
SELECT 0o17777777777;
|
||||
SELECT 0o20000000000;
|
||||
SELECT 0x7FFFFFFF;
|
||||
SELECT 0x80000000;
|
||||
|
||||
SELECT -0b10000000000000000000000000000000;
|
||||
SELECT -0b10000000000000000000000000000001;
|
||||
SELECT -0o20000000000;
|
||||
SELECT -0o20000000001;
|
||||
SELECT -0x80000000;
|
||||
SELECT -0x80000001;
|
||||
|
||||
-- cases near int8 overflow
|
||||
SELECT 0b111111111111111111111111111111111111111111111111111111111111111;
|
||||
SELECT 0b1000000000000000000000000000000000000000000000000000000000000000;
|
||||
SELECT 0o777777777777777777777;
|
||||
SELECT 0o1000000000000000000000;
|
||||
SELECT 0x7FFFFFFFFFFFFFFF;
|
||||
SELECT 0x8000000000000000;
|
||||
|
||||
SELECT -0b1000000000000000000000000000000000000000000000000000000000000000;
|
||||
SELECT -0b1000000000000000000000000000000000000000000000000000000000000001;
|
||||
SELECT -0o1000000000000000000000;
|
||||
SELECT -0o1000000000000000000001;
|
||||
SELECT -0x8000000000000000;
|
||||
SELECT -0x8000000000000001;
|
||||
|
||||
-- error cases
|
||||
SELECT 123abc;
|
||||
SELECT 0x0o;
|
||||
SELECT 1_2_3;
|
||||
@ -18,6 +54,19 @@ SELECT 0.0e;
|
||||
SELECT 0.0e+a;
|
||||
PREPARE p1 AS SELECT $1a;
|
||||
|
||||
SELECT 0b;
|
||||
SELECT 1b;
|
||||
SELECT 0b0x;
|
||||
|
||||
SELECT 0o;
|
||||
SELECT 1o;
|
||||
SELECT 0o0x;
|
||||
|
||||
SELECT 0x;
|
||||
SELECT 1x;
|
||||
SELECT 0x0y;
|
||||
|
||||
|
||||
--
|
||||
-- Test implicit type conversions
|
||||
-- This fails for Postgres v6.1 (and earlier?)
|
||||
|
Loading…
x
Reference in New Issue
Block a user