Fix tokenization of qualified identifiers with numeric prefix. (#1803)

Co-authored-by: Roman Borschel <roman@cluvio.com>
This commit is contained in:
Roman Borschel 2025-04-11 20:58:43 +02:00 committed by GitHub
parent d090ad4ccf
commit bbc80d7537
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 185 additions and 11 deletions

View file

@ -1926,6 +1926,128 @@ fn parse_select_with_numeric_prefix_column_name() {
}
}
#[test]
fn parse_qualified_identifiers_with_numeric_prefix() {
// Case 1: Qualified column name that starts with digits.
match mysql().verified_stmt("SELECT t.15to29 FROM my_table AS t") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
assert_eq!(&[Ident::new("t"), Ident::new("15to29")], &parts[..]);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 2: Qualified column name that starts with digits and on its own represents a number.
match mysql().verified_stmt("SELECT t.15e29 FROM my_table AS t") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
assert_eq!(&[Ident::new("t"), Ident::new("15e29")], &parts[..]);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 3: Unqualified, the same token is parsed as a number.
match mysql()
.parse_sql_statements("SELECT 15e29 FROM my_table")
.unwrap()
.pop()
{
Some(Statement::Query(q)) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::Value(ValueWithSpan { value, .. }))) => {
assert_eq!(&number("15e29"), value);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 4: Quoted simple identifier.
match mysql().verified_stmt("SELECT `15e29` FROM my_table") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::Identifier(name))) => {
assert_eq!(&Ident::with_quote('`', "15e29"), name);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 5: Quoted compound identifier.
match mysql().verified_stmt("SELECT t.`15e29` FROM my_table AS t") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
assert_eq!(
&[Ident::new("t"), Ident::with_quote('`', "15e29")],
&parts[..]
);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 6: Multi-level compound identifiers.
match mysql().verified_stmt("SELECT 1db.1table.1column") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
assert_eq!(
&[
Ident::new("1db"),
Ident::new("1table"),
Ident::new("1column")
],
&parts[..]
);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
// Case 7: Multi-level compound quoted identifiers.
match mysql().verified_stmt("SELECT `1`.`2`.`3`") {
Statement::Query(q) => match *q.body {
SetExpr::Select(s) => match s.projection.last() {
Some(SelectItem::UnnamedExpr(Expr::CompoundIdentifier(parts))) => {
assert_eq!(
&[
Ident::with_quote('`', "1"),
Ident::with_quote('`', "2"),
Ident::with_quote('`', "3")
],
&parts[..]
);
}
proj => panic!("Unexpected projection: {:?}", proj),
},
body => panic!("Unexpected statement body: {:?}", body),
},
stmt => panic!("Unexpected statement: {:?}", stmt),
}
}
// Don't run with bigdecimal as it fails like this on rust beta:
//
// 'parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column'