@@ -1530,12 +1530,13 @@ impl<'a> Tokenizer<'a> {
15301530 }
15311531 Some ( '<' ) => self . consume_for_binop ( chars, "<<" , Token :: ShiftLeft ) ,
15321532 Some ( '-' ) if self . dialect . supports_geometric_types ( ) => {
1533- chars. next ( ) ; // consume
1534- match chars. peek ( ) {
1535- Some ( '>' ) => {
1536- self . consume_for_binop ( chars, "<->" , Token :: TwoWayArrow )
1537- }
1538- _ => self . start_binop_opt ( chars, "<-" , None ) ,
1533+ // `<->` is a geometric operator, but `<-123` means `< -123`.
1534+ // If the sequence is not `<->`, keep `-` unconsumed so it can be tokenized as a unary minus.
1535+ if chars. peekable . clone ( ) . nth ( 1 ) == Some ( '>' ) {
1536+ chars. next ( ) ; // consume '-'
1537+ self . consume_for_binop ( chars, "<->" , Token :: TwoWayArrow )
1538+ } else {
1539+ self . start_binop ( chars, "<" , Token :: Lt )
15391540 }
15401541 }
15411542 Some ( '^' ) if self . dialect . supports_geometric_types ( ) => {
@@ -2495,7 +2496,8 @@ fn take_char_from_hex_digits(
24952496mod tests {
24962497 use super :: * ;
24972498 use crate :: dialect:: {
2498- BigQueryDialect , ClickHouseDialect , HiveDialect , MsSqlDialect , MySqlDialect , SQLiteDialect ,
2499+ BigQueryDialect , ClickHouseDialect , HiveDialect , MsSqlDialect , MySqlDialect ,
2500+ RedshiftSqlDialect , SQLiteDialect ,
24992501 } ;
25002502 use crate :: test_utils:: { all_dialects_except, all_dialects_where} ;
25012503 use core:: fmt:: Debug ;
@@ -4152,4 +4154,38 @@ mod tests {
41524154 ] ,
41534155 ) ;
41544156 }
4157+
4158+ #[ test]
4159+ fn tokenize_lt_followed_by_negative_number ( ) {
4160+ let sql = "SELECT a <-4000" ;
4161+ let dialect = RedshiftSqlDialect { } ;
4162+ let tokens = Tokenizer :: new ( & dialect, sql) . tokenize ( ) . unwrap ( ) ;
4163+ compare (
4164+ vec ! [
4165+ Token :: make_keyword( "SELECT" ) ,
4166+ Token :: Whitespace ( Whitespace :: Space ) ,
4167+ Token :: make_word( "a" , None ) ,
4168+ Token :: Whitespace ( Whitespace :: Space ) ,
4169+ Token :: Lt ,
4170+ Token :: Minus ,
4171+ Token :: Number ( "4000" . to_string( ) , false ) ,
4172+ ] ,
4173+ tokens,
4174+ ) ;
4175+
4176+ // Ensure geometric `<->` is still recognized.
4177+ let tokens = Tokenizer :: new ( & dialect, "SELECT a <-> b" ) . tokenize ( ) . unwrap ( ) ;
4178+ compare (
4179+ vec ! [
4180+ Token :: make_keyword( "SELECT" ) ,
4181+ Token :: Whitespace ( Whitespace :: Space ) ,
4182+ Token :: make_word( "a" , None ) ,
4183+ Token :: Whitespace ( Whitespace :: Space ) ,
4184+ Token :: TwoWayArrow ,
4185+ Token :: Whitespace ( Whitespace :: Space ) ,
4186+ Token :: make_word( "b" , None ) ,
4187+ ] ,
4188+ tokens,
4189+ ) ;
4190+ }
41554191}
0 commit comments