File tree Expand file tree Collapse file tree 3 files changed +72
-3
lines changed Expand file tree Collapse file tree 3 files changed +72
-3
lines changed Original file line number Diff line number Diff line change @@ -18,8 +18,8 @@ pub struct MySqlDialect {}
18
18
impl Dialect for MySqlDialect {
19
19
fn is_identifier_start ( & self , ch : char ) -> bool {
20
20
// See https://dev.mysql.com/doc/refman/8.0/en/identifiers.html.
21
- // We don't yet support identifiers beginning with numbers, as that
22
- // makes it hard to distinguish numeric literals.
21
+ // Identifiers which begin with a digit are recognized while tokenizing numbers,
22
+ // so they can be distinguished from exponent numeric literals.
23
23
ch. is_alphabetic ( )
24
24
|| ch == '_'
25
25
|| ch == '$'
Original file line number Diff line number Diff line change @@ -673,10 +673,10 @@ impl<'a> Tokenizer<'a> {
673
673
return Ok ( Some ( Token :: Period ) ) ;
674
674
}
675
675
676
+ let mut exponent_part = String :: new ( ) ;
676
677
// Parse exponent as number
677
678
if chars. peek ( ) == Some ( & 'e' ) || chars. peek ( ) == Some ( & 'E' ) {
678
679
let mut char_clone = chars. peekable . clone ( ) ;
679
- let mut exponent_part = String :: new ( ) ;
680
680
exponent_part. push ( char_clone. next ( ) . unwrap ( ) ) ;
681
681
682
682
// Optional sign
@@ -703,6 +703,18 @@ impl<'a> Tokenizer<'a> {
703
703
}
704
704
}
705
705
706
+ // mysql dialect supports identifiers that start with a numeric prefix,
707
+ // as long as they aren't an exponent number.
708
+ if dialect_of ! ( self is MySqlDialect ) && exponent_part. is_empty ( ) {
709
+ let word =
710
+ peeking_take_while ( chars, |ch| self . dialect . is_identifier_part ( ch) ) ;
711
+
712
+ if !word. is_empty ( ) {
713
+ s += word. as_str ( ) ;
714
+ return Ok ( Some ( Token :: make_word ( s. as_str ( ) , None ) ) ) ;
715
+ }
716
+ }
717
+
706
718
let long = if chars. peek ( ) == Some ( & 'L' ) {
707
719
chars. next ( ) ;
708
720
true
Original file line number Diff line number Diff line change @@ -849,6 +849,63 @@ fn parse_insert_with_on_duplicate_update() {
849
849
}
850
850
}
851
851
852
+ #[ test]
853
+ fn parse_select_with_numeric_prefix_column_name ( ) {
854
+ let sql = "SELECT 123col_$@123abc FROM \" table\" " ;
855
+ match mysql ( ) . verified_stmt ( sql) {
856
+ Statement :: Query ( q) => {
857
+ assert_eq ! (
858
+ q. body,
859
+ Box :: new( SetExpr :: Select ( Box :: new( Select {
860
+ distinct: false ,
861
+ top: None ,
862
+ projection: vec![ SelectItem :: UnnamedExpr ( Expr :: Identifier ( Ident :: new(
863
+ "123col_$@123abc"
864
+ ) ) ) ] ,
865
+ into: None ,
866
+ from: vec![ TableWithJoins {
867
+ relation: TableFactor :: Table {
868
+ name: ObjectName ( vec![ Ident :: with_quote( '"' , "table" ) ] ) ,
869
+ alias: None ,
870
+ args: None ,
871
+ with_hints: vec![ ] ,
872
+ } ,
873
+ joins: vec![ ]
874
+ } ] ,
875
+ lateral_views: vec![ ] ,
876
+ selection: None ,
877
+ group_by: vec![ ] ,
878
+ cluster_by: vec![ ] ,
879
+ distribute_by: vec![ ] ,
880
+ sort_by: vec![ ] ,
881
+ having: None ,
882
+ qualify: None ,
883
+ } ) ) )
884
+ ) ;
885
+ }
886
+ _ => unreachable ! ( ) ,
887
+ }
888
+ }
889
+
890
+ #[ test]
891
+ fn parse_insert_with_numeric_prefix_column_name ( ) {
892
+ let sql = "INSERT INTO s1.t1 (123col_$@length123) VALUES (67.654)" ;
893
+ match mysql ( ) . verified_stmt ( sql) {
894
+ Statement :: Insert {
895
+ table_name,
896
+ columns,
897
+ ..
898
+ } => {
899
+ assert_eq ! (
900
+ ObjectName ( vec![ Ident :: new( "s1" ) , Ident :: new( "t1" ) ] ) ,
901
+ table_name
902
+ ) ;
903
+ assert_eq ! ( vec![ Ident :: new( "123col_$@length123" ) ] , columns) ;
904
+ }
905
+ _ => unreachable ! ( ) ,
906
+ }
907
+ }
908
+
852
909
#[ test]
853
910
fn parse_update_with_joins ( ) {
854
911
let sql = "UPDATE orders AS o JOIN customers AS c ON o.customer_id = c.id SET o.completed = true WHERE c.firstname = 'Peter'" ;
You can’t perform that action at this time.
0 commit comments