1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-16 06:01:02 +03:00

Reject trailing junk after numeric literals

After this, the PostgreSQL lexers no longer accept numeric literals
with trailing non-digits, such as 123abc, which would be scanned as
two tokens: 123 and abc.  This is undocumented and surprising, and it
might also interfere with some extended numeric literal syntax being
contemplated for the future.

Reviewed-by: John Naylor <john.naylor@enterprisedb.com>
Discussion: https://www.postgresql.org/message-id/flat/b239564c-cad0-b23e-c57e-166d883cb97d@enterprisedb.com
This commit is contained in:
Peter Eisentraut
2022-02-16 10:32:36 +01:00
parent 70e81861fa
commit 2549f0661b
5 changed files with 96 additions and 86 deletions

View File

@ -387,7 +387,7 @@ operator {op_chars}+
* *
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10. * {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
* *
* {realfail1} and {realfail2} are added to prevent the need for scanner * {realfail} is added to prevent the need for scanner
* backup when the {real} rule fails to match completely. * backup when the {real} rule fails to match completely.
*/ */
digit [0-9] digit [0-9]
@ -396,10 +396,14 @@ integer {digit}+
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
decimalfail {digit}+\.\. decimalfail {digit}+\.\.
real ({integer}|{decimal})[Ee][-+]?{digit}+ real ({integer}|{decimal})[Ee][-+]?{digit}+
realfail1 ({integer}|{decimal})[Ee] realfail ({integer}|{decimal})[Ee][-+]
realfail2 ({integer}|{decimal})[Ee][-+]
integer_junk {integer}{ident_start}
decimal_junk {decimal}{ident_start}
real_junk {real}{ident_start}
param \${integer} param \${integer}
param_junk \${integer}{ident_start}
other . other .
@ -974,6 +978,10 @@ other .
yylval->ival = atol(yytext + 1); yylval->ival = atol(yytext + 1);
return PARAM; return PARAM;
} }
{param_junk} {
SET_YYLLOC();
yyerror("trailing junk after parameter");
}
{integer} { {integer} {
SET_YYLLOC(); SET_YYLLOC();
@ -995,20 +1003,21 @@ other .
yylval->str = pstrdup(yytext); yylval->str = pstrdup(yytext);
return FCONST; return FCONST;
} }
{realfail1} { {realfail} {
/*
* throw back the [Ee], and figure out whether what
* remains is an {integer} or {decimal}.
*/
yyless(yyleng - 1);
SET_YYLLOC(); SET_YYLLOC();
return process_integer_literal(yytext, yylval); yyerror("trailing junk after numeric literal");
} }
{realfail2} { {integer_junk} {
/* throw back the [Ee][+-], and proceed as above */
yyless(yyleng - 2);
SET_YYLLOC(); SET_YYLLOC();
return process_integer_literal(yytext, yylval); yyerror("trailing junk after numeric literal");
}
{decimal_junk} {
SET_YYLLOC();
yyerror("trailing junk after numeric literal");
}
{real_junk} {
SET_YYLLOC();
yyerror("trailing junk after numeric literal");
} }

View File

@ -325,7 +325,7 @@ operator {op_chars}+
* *
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10. * {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
* *
* {realfail1} and {realfail2} are added to prevent the need for scanner * {realfail} is added to prevent the need for scanner
* backup when the {real} rule fails to match completely. * backup when the {real} rule fails to match completely.
*/ */
digit [0-9] digit [0-9]
@ -334,10 +334,14 @@ integer {digit}+
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
decimalfail {digit}+\.\. decimalfail {digit}+\.\.
real ({integer}|{decimal})[Ee][-+]?{digit}+ real ({integer}|{decimal})[Ee][-+]?{digit}+
realfail1 ({integer}|{decimal})[Ee] realfail ({integer}|{decimal})[Ee][-+]
realfail2 ({integer}|{decimal})[Ee][-+]
integer_junk {integer}{ident_start}
decimal_junk {decimal}{ident_start}
real_junk {real}{ident_start}
param \${integer} param \${integer}
param_junk \${integer}{ident_start}
/* psql-specific: characters allowed in variable names */ /* psql-specific: characters allowed in variable names */
variable_char [A-Za-z\200-\377_0-9] variable_char [A-Za-z\200-\377_0-9]
@ -839,6 +843,9 @@ other .
{param} { {param} {
ECHO; ECHO;
} }
{param_junk} {
ECHO;
}
{integer} { {integer} {
ECHO; ECHO;
@ -854,18 +861,16 @@ other .
{real} { {real} {
ECHO; ECHO;
} }
{realfail1} { {realfail} {
/*
* throw back the [Ee], and figure out whether what
* remains is an {integer} or {decimal}.
* (in psql, we don't actually care...)
*/
yyless(yyleng - 1);
ECHO; ECHO;
} }
{realfail2} { {integer_junk} {
/* throw back the [Ee][+-], and proceed as above */ ECHO;
yyless(yyleng - 2); }
{decimal_junk} {
ECHO;
}
{real_junk} {
ECHO; ECHO;
} }

View File

@ -353,7 +353,7 @@ operator {op_chars}+
* *
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10. * {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
* *
* {realfail1} and {realfail2} are added to prevent the need for scanner * {realfail} is added to prevent the need for scanner
* backup when the {real} rule fails to match completely. * backup when the {real} rule fails to match completely.
*/ */
digit [0-9] digit [0-9]
@ -362,10 +362,14 @@ integer {digit}+
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
decimalfail {digit}+\.\. decimalfail {digit}+\.\.
real ({integer}|{decimal})[Ee][-+]?{digit}+ real ({integer}|{decimal})[Ee][-+]?{digit}+
realfail1 ({integer}|{decimal})[Ee] realfail ({integer}|{decimal})[Ee][-+]
realfail2 ({integer}|{decimal})[Ee][-+]
integer_junk {integer}{ident_start}
decimal_junk {decimal}{ident_start}
real_junk {real}{ident_start}
param \${integer} param \${integer}
param_junk \${integer}{ident_start}
/* special characters for other dbms */ /* special characters for other dbms */
/* we have to react differently in compat mode */ /* we have to react differently in compat mode */
@ -917,6 +921,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
base_yylval.ival = atol(yytext+1); base_yylval.ival = atol(yytext+1);
return PARAM; return PARAM;
} }
{param_junk} {
mmfatal(PARSE_ERROR, "trailing junk after parameter");
}
{ip} { {ip} {
base_yylval.str = mm_strdup(yytext); base_yylval.str = mm_strdup(yytext);
@ -941,22 +948,31 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
base_yylval.str = mm_strdup(yytext); base_yylval.str = mm_strdup(yytext);
return FCONST; return FCONST;
} }
{realfail1} { {realfail} {
/* /*
* throw back the [Ee], and figure out whether what * throw back the [Ee][+-], and figure out whether what
* remains is an {integer} or {decimal}. * remains is an {integer} or {decimal}.
*/ */
yyless(yyleng - 1);
return process_integer_literal(yytext, &base_yylval);
}
{realfail2} {
/* throw back the [Ee][+-], and proceed as above */
yyless(yyleng - 2); yyless(yyleng - 2);
return process_integer_literal(yytext, &base_yylval); return process_integer_literal(yytext, &base_yylval);
} }
} /* <C,SQL> */ } /* <C,SQL> */
<SQL>{ <SQL>{
/*
* Note that some trailing junk is valid in C (such as 100LL), so we
* contain this to SQL mode.
*/
{integer_junk} {
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
}
{decimal_junk} {
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
}
{real_junk} {
mmfatal(PARSE_ERROR, "trailing junk after numeric literal");
}
:{identifier}((("->"|\.){identifier})|(\[{array}\]))* { :{identifier}((("->"|\.){identifier})|(\[{array}\]))* {
base_yylval.str = mm_strdup(yytext+1); base_yylval.str = mm_strdup(yytext+1);
return CVARIABLE; return CVARIABLE;

View File

@ -6,64 +6,45 @@
-- Trailing junk in numeric literals -- Trailing junk in numeric literals
-- --
SELECT 123abc; SELECT 123abc;
abc ERROR: trailing junk after numeric literal at or near "123a"
----- LINE 1: SELECT 123abc;
123 ^
(1 row)
SELECT 0x0o; SELECT 0x0o;
x0o ERROR: trailing junk after numeric literal at or near "0x"
----- LINE 1: SELECT 0x0o;
0 ^
(1 row)
SELECT 1_2_3; SELECT 1_2_3;
_2_3 ERROR: trailing junk after numeric literal at or near "1_"
------ LINE 1: SELECT 1_2_3;
1 ^
(1 row)
SELECT 0.a; SELECT 0.a;
a ERROR: trailing junk after numeric literal at or near "0.a"
--- LINE 1: SELECT 0.a;
0 ^
(1 row)
SELECT 0.0a; SELECT 0.0a;
a ERROR: trailing junk after numeric literal at or near "0.0a"
----- LINE 1: SELECT 0.0a;
0.0 ^
(1 row)
SELECT .0a; SELECT .0a;
a ERROR: trailing junk after numeric literal at or near ".0a"
----- LINE 1: SELECT .0a;
0.0 ^
(1 row)
SELECT 0.0e1a; SELECT 0.0e1a;
a ERROR: trailing junk after numeric literal at or near "0.0e1a"
--- LINE 1: SELECT 0.0e1a;
0 ^
(1 row)
SELECT 0.0e; SELECT 0.0e;
e ERROR: trailing junk after numeric literal at or near "0.0e"
----- LINE 1: SELECT 0.0e;
0.0 ^
(1 row)
SELECT 0.0e+a; SELECT 0.0e+a;
ERROR: syntax error at or near "+" ERROR: trailing junk after numeric literal at or near "0.0e+"
LINE 1: SELECT 0.0e+a; LINE 1: SELECT 0.0e+a;
^ ^
PREPARE p1 AS SELECT $1a; PREPARE p1 AS SELECT $1a;
EXECUTE p1(1); ERROR: trailing junk after parameter at or near "$1a"
a LINE 1: PREPARE p1 AS SELECT $1a;
--- ^
1
(1 row)
-- --
-- Test implicit type conversions -- Test implicit type conversions
-- This fails for Postgres v6.1 (and earlier?) -- This fails for Postgres v6.1 (and earlier?)

View File

@ -17,7 +17,6 @@ SELECT 0.0e1a;
SELECT 0.0e; SELECT 0.0e;
SELECT 0.0e+a; SELECT 0.0e+a;
PREPARE p1 AS SELECT $1a; PREPARE p1 AS SELECT $1a;
EXECUTE p1(1);
-- --
-- Test implicit type conversions -- Test implicit type conversions