mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-17 20:50:16 +00:00
Support identifiers beginning with digits in MySQL (#856)
This commit is contained in:
parent
6b2b3f1f6c
commit
3e92ad349f
3 changed files with 115 additions and 3 deletions
|
@ -18,8 +18,8 @@ pub struct MySqlDialect {}
|
||||||
impl Dialect for MySqlDialect {
|
impl Dialect for MySqlDialect {
|
||||||
fn is_identifier_start(&self, ch: char) -> bool {
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
// See https://dev.mysql.com/doc/refman/8.0/en/identifiers.html.
|
// See https://dev.mysql.com/doc/refman/8.0/en/identifiers.html.
|
||||||
// We don't yet support identifiers beginning with numbers, as that
|
// Identifiers which begin with a digit are recognized while tokenizing numbers,
|
||||||
// makes it hard to distinguish numeric literals.
|
// so they can be distinguished from exponent numeric literals.
|
||||||
ch.is_alphabetic()
|
ch.is_alphabetic()
|
||||||
|| ch == '_'
|
|| ch == '_'
|
||||||
|| ch == '$'
|
|| ch == '$'
|
||||||
|
|
|
@ -673,10 +673,10 @@ impl<'a> Tokenizer<'a> {
|
||||||
return Ok(Some(Token::Period));
|
return Ok(Some(Token::Period));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut exponent_part = String::new();
|
||||||
// Parse exponent as number
|
// Parse exponent as number
|
||||||
if chars.peek() == Some(&'e') || chars.peek() == Some(&'E') {
|
if chars.peek() == Some(&'e') || chars.peek() == Some(&'E') {
|
||||||
let mut char_clone = chars.peekable.clone();
|
let mut char_clone = chars.peekable.clone();
|
||||||
let mut exponent_part = String::new();
|
|
||||||
exponent_part.push(char_clone.next().unwrap());
|
exponent_part.push(char_clone.next().unwrap());
|
||||||
|
|
||||||
// Optional sign
|
// Optional sign
|
||||||
|
@ -703,6 +703,18 @@ impl<'a> Tokenizer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mysql dialect supports identifiers that start with a numeric prefix,
|
||||||
|
// as long as they aren't an exponent number.
|
||||||
|
if dialect_of!(self is MySqlDialect) && exponent_part.is_empty() {
|
||||||
|
let word =
|
||||||
|
peeking_take_while(chars, |ch| self.dialect.is_identifier_part(ch));
|
||||||
|
|
||||||
|
if !word.is_empty() {
|
||||||
|
s += word.as_str();
|
||||||
|
return Ok(Some(Token::make_word(s.as_str(), None)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let long = if chars.peek() == Some(&'L') {
|
let long = if chars.peek() == Some(&'L') {
|
||||||
chars.next();
|
chars.next();
|
||||||
true
|
true
|
||||||
|
|
|
@ -849,6 +849,106 @@ fn parse_insert_with_on_duplicate_update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_select_with_numeric_prefix_column_name() {
|
||||||
|
let sql = "SELECT 123col_$@123abc FROM \"table\"";
|
||||||
|
match mysql().verified_stmt(sql) {
|
||||||
|
Statement::Query(q) => {
|
||||||
|
assert_eq!(
|
||||||
|
q.body,
|
||||||
|
Box::new(SetExpr::Select(Box::new(Select {
|
||||||
|
distinct: false,
|
||||||
|
top: None,
|
||||||
|
projection: vec![SelectItem::UnnamedExpr(Expr::Identifier(Ident::new(
|
||||||
|
"123col_$@123abc"
|
||||||
|
)))],
|
||||||
|
into: None,
|
||||||
|
from: vec![TableWithJoins {
|
||||||
|
relation: TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::with_quote('"', "table")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
joins: vec![]
|
||||||
|
}],
|
||||||
|
lateral_views: vec![],
|
||||||
|
selection: None,
|
||||||
|
group_by: vec![],
|
||||||
|
cluster_by: vec![],
|
||||||
|
distribute_by: vec![],
|
||||||
|
sort_by: vec![],
|
||||||
|
having: None,
|
||||||
|
qualify: None,
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "bigdecimal"))]
|
||||||
|
#[test]
|
||||||
|
fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
|
||||||
|
let sql = "SELECT 123e4, 123col_$@123abc FROM \"table\"";
|
||||||
|
match mysql().verified_stmt(sql) {
|
||||||
|
Statement::Query(q) => {
|
||||||
|
assert_eq!(
|
||||||
|
q.body,
|
||||||
|
Box::new(SetExpr::Select(Box::new(Select {
|
||||||
|
distinct: false,
|
||||||
|
top: None,
|
||||||
|
projection: vec![
|
||||||
|
SelectItem::UnnamedExpr(Expr::Value(Value::Number(
|
||||||
|
"123e4".to_string(),
|
||||||
|
false
|
||||||
|
))),
|
||||||
|
SelectItem::UnnamedExpr(Expr::Identifier(Ident::new("123col_$@123abc")))
|
||||||
|
],
|
||||||
|
into: None,
|
||||||
|
from: vec![TableWithJoins {
|
||||||
|
relation: TableFactor::Table {
|
||||||
|
name: ObjectName(vec![Ident::with_quote('"', "table")]),
|
||||||
|
alias: None,
|
||||||
|
args: None,
|
||||||
|
with_hints: vec![],
|
||||||
|
},
|
||||||
|
joins: vec![]
|
||||||
|
}],
|
||||||
|
lateral_views: vec![],
|
||||||
|
selection: None,
|
||||||
|
group_by: vec![],
|
||||||
|
cluster_by: vec![],
|
||||||
|
distribute_by: vec![],
|
||||||
|
sort_by: vec![],
|
||||||
|
having: None,
|
||||||
|
qualify: None,
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_insert_with_numeric_prefix_column_name() {
|
||||||
|
let sql = "INSERT INTO s1.t1 (123col_$@length123) VALUES (67.654)";
|
||||||
|
match mysql().verified_stmt(sql) {
|
||||||
|
Statement::Insert {
|
||||||
|
table_name,
|
||||||
|
columns,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
assert_eq!(
|
||||||
|
ObjectName(vec![Ident::new("s1"), Ident::new("t1")]),
|
||||||
|
table_name
|
||||||
|
);
|
||||||
|
assert_eq!(vec![Ident::new("123col_$@length123")], columns);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_update_with_joins() {
|
fn parse_update_with_joins() {
|
||||||
let sql = "UPDATE orders AS o JOIN customers AS c ON o.customer_id = c.id SET o.completed = true WHERE c.firstname = 'Peter'";
|
let sql = "UPDATE orders AS o JOIN customers AS c ON o.customer_id = c.id SET o.completed = true WHERE c.firstname = 'Peter'";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue