sql_cli/sql/
recursive_parser.rs

1// Keep chrono imports for the parser implementation
2
3// Re-exports for backward compatibility - these serve as both imports and re-exports
4pub use super::parser::ast::{
5    Condition, JoinClause, JoinCondition, JoinOperator, JoinType, LogicalOp, OrderByColumn,
6    SelectItem, SelectStatement, SortDirection, SqlExpression, TableFunction, TableSource,
7    WhenBranch, WhereClause, WindowSpec, CTE,
8};
9pub use super::parser::legacy::{ParseContext, ParseState, Schema, SqlParser, SqlToken, TableInfo};
10pub use super::parser::lexer::{Lexer, Token};
11pub use super::parser::ParserConfig;
12
13// Re-export formatting functions for backward compatibility
14pub use super::parser::formatter::{format_ast_tree, format_sql_pretty, format_sql_pretty_compact};
15
16// New AST-based formatter
17pub use super::parser::ast_formatter::{format_sql_ast, format_sql_ast_with_config, FormatConfig};
18
19// Import the new expression modules
20use super::parser::expressions::arithmetic::{
21    parse_additive as parse_additive_expr, parse_multiplicative as parse_multiplicative_expr,
22    ParseArithmetic,
23};
24use super::parser::expressions::case::{parse_case_expression as parse_case_expr, ParseCase};
25use super::parser::expressions::comparison::{
26    parse_comparison as parse_comparison_expr, parse_in_operator, ParseComparison,
27};
28use super::parser::expressions::logical::{
29    parse_logical_and as parse_logical_and_expr, parse_logical_or as parse_logical_or_expr,
30    ParseLogical,
31};
32use super::parser::expressions::primary::{
33    parse_primary as parse_primary_expr, ParsePrimary, PrimaryExpressionContext,
34};
35pub struct Parser {
36    lexer: Lexer,
37    current_token: Token,
38    in_method_args: bool, // Track if we're parsing method arguments
39    columns: Vec<String>, // Known column names for context-aware parsing
40    paren_depth: i32,     // Track parentheses nesting depth
41    #[allow(dead_code)]
42    config: ParserConfig, // Parser configuration including case sensitivity
43}
44
45impl Parser {
46    #[must_use]
47    pub fn new(input: &str) -> Self {
48        let mut lexer = Lexer::new(input);
49        let current_token = lexer.next_token();
50        Self {
51            lexer,
52            current_token,
53            in_method_args: false,
54            columns: Vec::new(),
55            paren_depth: 0,
56            config: ParserConfig::default(),
57        }
58    }
59
60    #[must_use]
61    pub fn with_config(input: &str, config: ParserConfig) -> Self {
62        let mut lexer = Lexer::new(input);
63        let current_token = lexer.next_token();
64        Self {
65            lexer,
66            current_token,
67            in_method_args: false,
68            columns: Vec::new(),
69            paren_depth: 0,
70            config,
71        }
72    }
73
74    #[must_use]
75    pub fn with_columns(mut self, columns: Vec<String>) -> Self {
76        self.columns = columns;
77        self
78    }
79
80    fn consume(&mut self, expected: Token) -> Result<(), String> {
81        if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
82            // Track parentheses depth
83            match &expected {
84                Token::LeftParen => self.paren_depth += 1,
85                Token::RightParen => {
86                    self.paren_depth -= 1;
87                    // Check for extra closing parenthesis
88                    if self.paren_depth < 0 {
89                        return Err(
90                            "Unexpected closing parenthesis - no matching opening parenthesis"
91                                .to_string(),
92                        );
93                    }
94                }
95                _ => {}
96            }
97
98            self.current_token = self.lexer.next_token();
99            Ok(())
100        } else {
101            // Provide better error messages for common cases
102            let error_msg = match (&expected, &self.current_token) {
103                (Token::RightParen, Token::Eof) if self.paren_depth > 0 => {
104                    format!(
105                        "Unclosed parenthesis - missing {} closing parenthes{}",
106                        self.paren_depth,
107                        if self.paren_depth == 1 { "is" } else { "es" }
108                    )
109                }
110                (Token::RightParen, _) if self.paren_depth > 0 => {
111                    format!(
112                        "Expected closing parenthesis but found {:?} (currently {} unclosed parenthes{})",
113                        self.current_token,
114                        self.paren_depth,
115                        if self.paren_depth == 1 { "is" } else { "es" }
116                    )
117                }
118                _ => format!("Expected {:?}, found {:?}", expected, self.current_token),
119            };
120            Err(error_msg)
121        }
122    }
123
124    fn advance(&mut self) {
125        // Track parentheses depth when advancing
126        match &self.current_token {
127            Token::LeftParen => self.paren_depth += 1,
128            Token::RightParen => {
129                self.paren_depth -= 1;
130                // Note: We don't check for < 0 here because advance() is used
131                // in contexts where we're not necessarily expecting a right paren
132            }
133            _ => {}
134        }
135        self.current_token = self.lexer.next_token();
136    }
137
138    pub fn parse(&mut self) -> Result<SelectStatement, String> {
139        // Check for WITH clause at the beginning
140        if matches!(self.current_token, Token::With) {
141            self.parse_with_clause()
142        } else {
143            self.parse_select_statement()
144        }
145    }
146
147    fn parse_with_clause(&mut self) -> Result<SelectStatement, String> {
148        self.consume(Token::With)?;
149
150        let mut ctes = Vec::new();
151
152        // Parse CTEs
153        loop {
154            // Parse CTE name
155            let name = match &self.current_token {
156                Token::Identifier(name) => name.clone(),
157                _ => return Err("Expected CTE name after WITH".to_string()),
158            };
159            self.advance();
160
161            // Optional column list: WITH t(col1, col2) AS ...
162            let column_list = if matches!(self.current_token, Token::LeftParen) {
163                self.advance();
164                let cols = self.parse_identifier_list()?;
165                self.consume(Token::RightParen)?;
166                Some(cols)
167            } else {
168                None
169            };
170
171            // Expect AS
172            self.consume(Token::As)?;
173
174            // Expect opening parenthesis
175            self.consume(Token::LeftParen)?;
176
177            // Parse the CTE query (inner version that doesn't check parentheses)
178            let query = self.parse_select_statement_inner()?;
179
180            // Expect closing parenthesis
181            self.consume(Token::RightParen)?;
182
183            ctes.push(CTE {
184                name,
185                column_list,
186                query,
187            });
188
189            // Check for more CTEs
190            if !matches!(self.current_token, Token::Comma) {
191                break;
192            }
193            self.advance();
194        }
195
196        // Parse the main SELECT statement (with parenthesis checking)
197        let mut main_query = self.parse_select_statement()?;
198        main_query.ctes = ctes;
199
200        Ok(main_query)
201    }
202
203    fn parse_with_clause_inner(&mut self) -> Result<SelectStatement, String> {
204        self.consume(Token::With)?;
205
206        let mut ctes = Vec::new();
207
208        // Parse CTEs
209        loop {
210            // Parse CTE name
211            let name = match &self.current_token {
212                Token::Identifier(name) => name.clone(),
213                _ => return Err("Expected CTE name after WITH".to_string()),
214            };
215            self.advance();
216
217            // Optional column list: WITH t(col1, col2) AS ...
218            let column_list = if matches!(self.current_token, Token::LeftParen) {
219                self.advance();
220                let cols = self.parse_identifier_list()?;
221                self.consume(Token::RightParen)?;
222                Some(cols)
223            } else {
224                None
225            };
226
227            // Expect AS
228            self.consume(Token::As)?;
229
230            // Expect opening parenthesis
231            self.consume(Token::LeftParen)?;
232
233            // Parse the CTE query (inner version that doesn't check parentheses)
234            let query = self.parse_select_statement_inner()?;
235
236            // Expect closing parenthesis
237            self.consume(Token::RightParen)?;
238
239            ctes.push(CTE {
240                name,
241                column_list,
242                query,
243            });
244
245            // Check for more CTEs
246            if !matches!(self.current_token, Token::Comma) {
247                break;
248            }
249            self.advance();
250        }
251
252        // Parse the main SELECT statement (without parenthesis checking for subqueries)
253        let mut main_query = self.parse_select_statement_inner()?;
254        main_query.ctes = ctes;
255
256        Ok(main_query)
257    }
258
259    fn parse_select_statement(&mut self) -> Result<SelectStatement, String> {
260        let result = self.parse_select_statement_inner()?;
261
262        // Check for balanced parentheses at the end of parsing
263        if self.paren_depth > 0 {
264            return Err(format!(
265                "Unclosed parenthesis - missing {} closing parenthes{}",
266                self.paren_depth,
267                if self.paren_depth == 1 { "is" } else { "es" }
268            ));
269        } else if self.paren_depth < 0 {
270            return Err(
271                "Extra closing parenthesis found - no matching opening parenthesis".to_string(),
272            );
273        }
274
275        Ok(result)
276    }
277
278    fn parse_select_statement_inner(&mut self) -> Result<SelectStatement, String> {
279        self.consume(Token::Select)?;
280
281        // Check for DISTINCT keyword
282        let distinct = if matches!(self.current_token, Token::Distinct) {
283            self.advance();
284            true
285        } else {
286            false
287        };
288
289        // Parse SELECT items (supports computed expressions)
290        let select_items = self.parse_select_items()?;
291
292        // Create legacy columns vector for backward compatibility
293        let columns = select_items
294            .iter()
295            .map(|item| match item {
296                SelectItem::Star => "*".to_string(),
297                SelectItem::Column(name) => name.clone(),
298                SelectItem::Expression { alias, .. } => alias.clone(),
299            })
300            .collect();
301
302        // Parse FROM clause - can be a table name, subquery, or table function
303        let (from_table, from_subquery, from_function, from_alias) =
304            if matches!(self.current_token, Token::From) {
305                self.advance();
306
307                // Check for table function like RANGE()
308                if let Token::Identifier(name) = &self.current_token.clone() {
309                    if name.to_uppercase() == "RANGE" {
310                        self.advance();
311                        // Parse RANGE function
312                        self.consume(Token::LeftParen)?;
313
314                        // Parse start expression
315                        let start = self.parse_expression()?;
316                        self.consume(Token::Comma)?;
317
318                        // Parse end expression
319                        let end = self.parse_expression()?;
320
321                        // Parse optional step
322                        let step = if matches!(self.current_token, Token::Comma) {
323                            self.advance();
324                            Some(self.parse_expression()?)
325                        } else {
326                            None
327                        };
328
329                        self.consume(Token::RightParen)?;
330
331                        // Optional alias
332                        let alias = if matches!(self.current_token, Token::As) {
333                            self.advance();
334                            match &self.current_token {
335                                Token::Identifier(name) => {
336                                    let alias = name.clone();
337                                    self.advance();
338                                    Some(alias)
339                                }
340                                _ => return Err("Expected alias name after AS".to_string()),
341                            }
342                        } else if let Token::Identifier(name) = &self.current_token {
343                            let alias = name.clone();
344                            self.advance();
345                            Some(alias)
346                        } else {
347                            None
348                        };
349
350                        (
351                            None,
352                            None,
353                            Some(TableFunction::Range { start, end, step }),
354                            alias,
355                        )
356                    } else {
357                        // Not a RANGE function, so it's a regular table name
358                        let table_name = name.clone();
359                        self.advance();
360
361                        // Check for optional alias
362                        let alias = if matches!(self.current_token, Token::As) {
363                            self.advance();
364                            match &self.current_token {
365                                Token::Identifier(name) => {
366                                    let alias = name.clone();
367                                    self.advance();
368                                    Some(alias)
369                                }
370                                _ => return Err("Expected alias name after AS".to_string()),
371                            }
372                        } else if let Token::Identifier(name) = &self.current_token {
373                            // AS is optional for table aliases
374                            let alias = name.clone();
375                            self.advance();
376                            Some(alias)
377                        } else {
378                            None
379                        };
380
381                        (Some(table_name), None, None, alias)
382                    }
383                } else if matches!(self.current_token, Token::LeftParen) {
384                    // Check for subquery: FROM (SELECT ...)
385                    self.advance();
386
387                    // Parse the subquery (inner version that doesn't check parentheses)
388                    let subquery = self.parse_select_statement_inner()?;
389
390                    self.consume(Token::RightParen)?;
391
392                    // Subqueries must have an alias
393                    let alias = if matches!(self.current_token, Token::As) {
394                        self.advance();
395                        match &self.current_token {
396                            Token::Identifier(name) => {
397                                let alias = name.clone();
398                                self.advance();
399                                alias
400                            }
401                            _ => return Err("Expected alias name after AS".to_string()),
402                        }
403                    } else {
404                        // AS is optional, but alias is required
405                        match &self.current_token {
406                            Token::Identifier(name) => {
407                                let alias = name.clone();
408                                self.advance();
409                                alias
410                            }
411                            _ => {
412                                return Err(
413                                    "Subquery in FROM must have an alias (e.g., AS t)".to_string()
414                                )
415                            }
416                        }
417                    };
418
419                    (None, Some(Box::new(subquery)), None, Some(alias))
420                } else {
421                    // Regular table name
422                    match &self.current_token {
423                        Token::Identifier(table) => {
424                            let table_name = table.clone();
425                            self.advance();
426
427                            // Check for optional alias
428                            let alias = if matches!(self.current_token, Token::As) {
429                                self.advance();
430                                match &self.current_token {
431                                    Token::Identifier(name) => {
432                                        let alias = name.clone();
433                                        self.advance();
434                                        Some(alias)
435                                    }
436                                    _ => return Err("Expected alias name after AS".to_string()),
437                                }
438                            } else if let Token::Identifier(name) = &self.current_token {
439                                // AS is optional for table aliases
440                                let alias = name.clone();
441                                self.advance();
442                                Some(alias)
443                            } else {
444                                None
445                            };
446
447                            (Some(table_name), None, None, alias)
448                        }
449                        Token::QuotedIdentifier(table) => {
450                            // Handle quoted table names
451                            let table_name = table.clone();
452                            self.advance();
453
454                            // Check for optional alias
455                            let alias = if matches!(self.current_token, Token::As) {
456                                self.advance();
457                                match &self.current_token {
458                                    Token::Identifier(name) => {
459                                        let alias = name.clone();
460                                        self.advance();
461                                        Some(alias)
462                                    }
463                                    _ => return Err("Expected alias name after AS".to_string()),
464                                }
465                            } else if let Token::Identifier(name) = &self.current_token {
466                                // AS is optional for table aliases
467                                let alias = name.clone();
468                                self.advance();
469                                Some(alias)
470                            } else {
471                                None
472                            };
473
474                            (Some(table_name), None, None, alias)
475                        }
476                        _ => return Err("Expected table name or subquery after FROM".to_string()),
477                    }
478                }
479            } else {
480                (None, None, None, None)
481            };
482
483        // Parse JOIN clauses
484        let mut joins = Vec::new();
485        while self.is_join_token() {
486            joins.push(self.parse_join_clause()?);
487        }
488
489        let where_clause = if matches!(self.current_token, Token::Where) {
490            self.advance();
491            Some(self.parse_where_clause()?)
492        } else {
493            None
494        };
495
496        let group_by = if matches!(self.current_token, Token::GroupBy) {
497            self.advance();
498            // Parse expressions instead of just identifiers for GROUP BY
499            // This allows GROUP BY TIME_BUCKET(...), CASE ..., etc.
500            Some(self.parse_expression_list()?)
501        } else {
502            None
503        };
504
505        // Parse HAVING clause (must come after GROUP BY)
506        let having = if matches!(self.current_token, Token::Having) {
507            if group_by.is_none() {
508                return Err("HAVING clause requires GROUP BY".to_string());
509            }
510            self.advance();
511            Some(self.parse_expression()?)
512        } else {
513            None
514        };
515
516        // Parse ORDER BY clause (comes after GROUP BY and HAVING)
517        let order_by = if matches!(self.current_token, Token::OrderBy) {
518            self.advance();
519            Some(self.parse_order_by_list()?)
520        } else if let Token::Identifier(s) = &self.current_token {
521            if s.to_uppercase() == "ORDER" {
522                // Handle ORDER BY as two separate tokens
523                self.advance(); // consume ORDER
524                if matches!(&self.current_token, Token::Identifier(by_token) if by_token.to_uppercase() == "BY")
525                {
526                    self.advance(); // consume BY
527                    Some(self.parse_order_by_list()?)
528                } else {
529                    return Err("Expected BY after ORDER".to_string());
530                }
531            } else {
532                None
533            }
534        } else {
535            None
536        };
537
538        // Parse LIMIT clause
539        let limit = if matches!(self.current_token, Token::Limit) {
540            self.advance();
541            match &self.current_token {
542                Token::NumberLiteral(num) => {
543                    let limit_val = num
544                        .parse::<usize>()
545                        .map_err(|_| format!("Invalid LIMIT value: {num}"))?;
546                    self.advance();
547                    Some(limit_val)
548                }
549                _ => return Err("Expected number after LIMIT".to_string()),
550            }
551        } else {
552            None
553        };
554
555        // Parse OFFSET clause
556        let offset = if matches!(self.current_token, Token::Offset) {
557            self.advance();
558            match &self.current_token {
559                Token::NumberLiteral(num) => {
560                    let offset_val = num
561                        .parse::<usize>()
562                        .map_err(|_| format!("Invalid OFFSET value: {num}"))?;
563                    self.advance();
564                    Some(offset_val)
565                }
566                _ => return Err("Expected number after OFFSET".to_string()),
567            }
568        } else {
569            None
570        };
571
572        Ok(SelectStatement {
573            distinct,
574            columns,
575            select_items,
576            from_table,
577            from_subquery,
578            from_function,
579            from_alias,
580            joins,
581            where_clause,
582            order_by,
583            group_by,
584            having,
585            limit,
586            offset,
587            ctes: Vec::new(), // Will be populated by WITH clause parser
588        })
589    }
590
591    fn parse_select_list(&mut self) -> Result<Vec<String>, String> {
592        let mut columns = Vec::new();
593
594        if matches!(self.current_token, Token::Star) {
595            columns.push("*".to_string());
596            self.advance();
597        } else {
598            loop {
599                match &self.current_token {
600                    Token::Identifier(col) => {
601                        columns.push(col.clone());
602                        self.advance();
603                    }
604                    Token::QuotedIdentifier(col) => {
605                        // Handle quoted column names like "Customer Id"
606                        columns.push(col.clone());
607                        self.advance();
608                    }
609                    _ => return Err("Expected column name".to_string()),
610                }
611
612                if matches!(self.current_token, Token::Comma) {
613                    self.advance();
614                } else {
615                    break;
616                }
617            }
618        }
619
620        Ok(columns)
621    }
622
623    /// Parse SELECT items that support computed expressions with aliases
624    fn parse_select_items(&mut self) -> Result<Vec<SelectItem>, String> {
625        let mut items = Vec::new();
626
627        loop {
628            // Check for * only at the beginning of a select item
629            // After a comma, * could be either SELECT * or part of multiplication
630            if matches!(self.current_token, Token::Star) {
631                // Determine if this is SELECT * or multiplication
632                // SELECT * is only valid:
633                // 1. As the first item in SELECT
634                // 2. Right after a comma (but not if followed by something that makes it multiplication)
635
636                // For now, treat Star as SELECT * only if we're at the start or just after a comma
637                // and the star is not immediately followed by something that would make it multiplication
638                items.push(SelectItem::Star);
639                self.advance();
640            } else {
641                // Parse expression or column
642                let expr = self.parse_comparison()?; // Use comparison to support IS NULL and other comparisons
643
644                // Check for AS alias
645                let alias = if matches!(self.current_token, Token::As) {
646                    self.advance();
647                    match &self.current_token {
648                        Token::Identifier(alias_name) => {
649                            let alias = alias_name.clone();
650                            self.advance();
651                            alias
652                        }
653                        Token::QuotedIdentifier(alias_name) => {
654                            let alias = alias_name.clone();
655                            self.advance();
656                            alias
657                        }
658                        _ => return Err("Expected alias name after AS".to_string()),
659                    }
660                } else {
661                    // Generate default alias based on expression
662                    match &expr {
663                        SqlExpression::Column(col_name) => col_name.clone(),
664                        _ => format!("expr_{}", items.len() + 1), // Default alias for computed expressions
665                    }
666                };
667
668                // Create SelectItem based on expression type
669                let item = match expr {
670                    SqlExpression::Column(col_name) if alias == col_name => {
671                        // Simple column reference without alias
672                        SelectItem::Column(col_name)
673                    }
674                    _ => {
675                        // Computed expression or column with different alias
676                        SelectItem::Expression { expr, alias }
677                    }
678                };
679
680                items.push(item);
681            }
682
683            // Check for comma to continue
684            if matches!(self.current_token, Token::Comma) {
685                self.advance();
686            } else {
687                break;
688            }
689        }
690
691        Ok(items)
692    }
693
694    fn parse_identifier_list(&mut self) -> Result<Vec<String>, String> {
695        let mut identifiers = Vec::new();
696
697        loop {
698            match &self.current_token {
699                Token::Identifier(id) => {
700                    // Check if this is a reserved keyword that should stop identifier parsing
701                    let id_upper = id.to_uppercase();
702                    if matches!(
703                        id_upper.as_str(),
704                        "ORDER" | "HAVING" | "LIMIT" | "OFFSET" | "UNION" | "INTERSECT" | "EXCEPT"
705                    ) {
706                        // Stop parsing identifiers if we hit a reserved keyword
707                        break;
708                    }
709                    identifiers.push(id.clone());
710                    self.advance();
711                }
712                Token::QuotedIdentifier(id) => {
713                    // Handle quoted identifiers like "Customer Id"
714                    identifiers.push(id.clone());
715                    self.advance();
716                }
717                _ => {
718                    // Stop parsing if we hit any other token type
719                    break;
720                }
721            }
722
723            if matches!(self.current_token, Token::Comma) {
724                self.advance();
725            } else {
726                break;
727            }
728        }
729
730        if identifiers.is_empty() {
731            return Err("Expected at least one identifier".to_string());
732        }
733
734        Ok(identifiers)
735    }
736
737    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
738        let mut partition_by = Vec::new();
739        let mut order_by = Vec::new();
740
741        // Check for PARTITION BY
742        if matches!(self.current_token, Token::Partition) {
743            self.advance(); // consume PARTITION
744            if !matches!(self.current_token, Token::By) {
745                return Err("Expected BY after PARTITION".to_string());
746            }
747            self.advance(); // consume BY
748
749            // Parse partition columns
750            partition_by = self.parse_identifier_list()?;
751        }
752
753        // Check for ORDER BY
754        if matches!(self.current_token, Token::OrderBy) {
755            self.advance(); // consume ORDER BY (as single token)
756            order_by = self.parse_order_by_list()?;
757        } else if let Token::Identifier(s) = &self.current_token {
758            if s.to_uppercase() == "ORDER" {
759                // Handle ORDER BY as two tokens
760                self.advance(); // consume ORDER
761                if !matches!(self.current_token, Token::By) {
762                    return Err("Expected BY after ORDER".to_string());
763                }
764                self.advance(); // consume BY
765                order_by = self.parse_order_by_list()?;
766            }
767        }
768
769        Ok(WindowSpec {
770            partition_by,
771            order_by,
772        })
773    }
774
775    fn parse_order_by_list(&mut self) -> Result<Vec<OrderByColumn>, String> {
776        let mut order_columns = Vec::new();
777
778        loop {
779            let column = match &self.current_token {
780                Token::Identifier(id) => {
781                    let col = id.clone();
782                    self.advance();
783                    col
784                }
785                Token::QuotedIdentifier(id) => {
786                    let col = id.clone();
787                    self.advance();
788                    col
789                }
790                Token::NumberLiteral(num) if self.columns.iter().any(|col| col == num) => {
791                    // Support numeric column names like "202204"
792                    let col = num.clone();
793                    self.advance();
794                    col
795                }
796                _ => return Err("Expected column name in ORDER BY".to_string()),
797            };
798
799            // Check for ASC/DESC
800            let direction = match &self.current_token {
801                Token::Asc => {
802                    self.advance();
803                    SortDirection::Asc
804                }
805                Token::Desc => {
806                    self.advance();
807                    SortDirection::Desc
808                }
809                _ => SortDirection::Asc, // Default to ASC if not specified
810            };
811
812            order_columns.push(OrderByColumn { column, direction });
813
814            if matches!(self.current_token, Token::Comma) {
815                self.advance();
816            } else {
817                break;
818            }
819        }
820
821        Ok(order_columns)
822    }
823
824    fn parse_where_clause(&mut self) -> Result<WhereClause, String> {
825        // Parse the entire WHERE clause as a single expression tree
826        // The logical operators (AND/OR) are now handled within parse_expression
827        let expr = self.parse_expression()?;
828
829        // Check for unexpected closing parenthesis
830        if matches!(self.current_token, Token::RightParen) && self.paren_depth <= 0 {
831            return Err(
832                "Unexpected closing parenthesis - no matching opening parenthesis".to_string(),
833            );
834        }
835
836        // Create a single condition with the entire expression
837        let conditions = vec![Condition {
838            expr,
839            connector: None,
840        }];
841
842        Ok(WhereClause { conditions })
843    }
844
845    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
846        // Start with logical OR as the lowest precedence operator
847        // The hierarchy is: OR -> AND -> comparison -> additive -> multiplicative -> primary
848        let mut left = self.parse_logical_or()?;
849
850        // Handle IN operator (not preceded by NOT)
851        // This uses the modular comparison module
852        left = parse_in_operator(self, left)?;
853
854        Ok(left)
855    }
856
857    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
858        // Use the new modular comparison expression parser
859        parse_comparison_expr(self)
860    }
861
862    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
863        // Use the new modular arithmetic expression parser
864        parse_additive_expr(self)
865    }
866
867    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
868        // Use the new modular arithmetic expression parser
869        parse_multiplicative_expr(self)
870    }
871
872    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
873        // Use the new modular logical expression parser
874        parse_logical_or_expr(self)
875    }
876
877    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
878        // Use the new modular logical expression parser
879        parse_logical_and_expr(self)
880    }
881
882    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
883        // Use the new modular CASE expression parser
884        parse_case_expr(self)
885    }
886
887    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
888        // Use the new modular primary expression parser
889        // Clone the necessary data to avoid borrowing issues
890        let columns = self.columns.clone();
891        let in_method_args = self.in_method_args;
892        let ctx = PrimaryExpressionContext {
893            columns: &columns,
894            in_method_args,
895        };
896        parse_primary_expr(self, &ctx)
897    }
898
899    // Keep the old implementation temporarily for reference (will be removed)
900    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
901        let mut args = Vec::new();
902
903        // Set flag to indicate we're parsing method arguments
904        self.in_method_args = true;
905
906        if !matches!(self.current_token, Token::RightParen) {
907            loop {
908                args.push(self.parse_expression()?);
909
910                if matches!(self.current_token, Token::Comma) {
911                    self.advance();
912                } else {
913                    break;
914                }
915            }
916        }
917
918        // Clear the flag
919        self.in_method_args = false;
920
921        Ok(args)
922    }
923
924    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
925        let mut args = Vec::new();
926        let mut has_distinct = false;
927
928        if !matches!(self.current_token, Token::RightParen) {
929            // Check if first argument starts with DISTINCT
930            if matches!(self.current_token, Token::Distinct) {
931                self.advance(); // consume DISTINCT
932                has_distinct = true;
933            }
934
935            // Parse the expression (either after DISTINCT or directly)
936            args.push(self.parse_additive()?);
937
938            // Parse any remaining arguments (DISTINCT only applies to first arg for aggregates)
939            while matches!(self.current_token, Token::Comma) {
940                self.advance();
941                args.push(self.parse_additive()?);
942            }
943        }
944
945        Ok((args, has_distinct))
946    }
947
948    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
949        let mut expressions = Vec::new();
950
951        loop {
952            expressions.push(self.parse_expression()?);
953
954            if matches!(self.current_token, Token::Comma) {
955                self.advance();
956            } else {
957                break;
958            }
959        }
960
961        Ok(expressions)
962    }
963
964    fn get_binary_op(&self) -> Option<String> {
965        match &self.current_token {
966            Token::Equal => Some("=".to_string()),
967            Token::NotEqual => Some("!=".to_string()),
968            Token::LessThan => Some("<".to_string()),
969            Token::GreaterThan => Some(">".to_string()),
970            Token::LessThanOrEqual => Some("<=".to_string()),
971            Token::GreaterThanOrEqual => Some(">=".to_string()),
972            Token::Like => Some("LIKE".to_string()),
973            _ => None,
974        }
975    }
976
977    fn get_arithmetic_op(&self) -> Option<String> {
978        match &self.current_token {
979            Token::Plus => Some("+".to_string()),
980            Token::Minus => Some("-".to_string()),
981            Token::Star => Some("*".to_string()), // Multiplication (context-sensitive)
982            Token::Divide => Some("/".to_string()),
983            Token::Modulo => Some("%".to_string()),
984            _ => None,
985        }
986    }
987
988    #[must_use]
989    pub fn get_position(&self) -> usize {
990        self.lexer.get_position()
991    }
992
993    // Check if current token is a JOIN-related token
994    fn is_join_token(&self) -> bool {
995        matches!(
996            self.current_token,
997            Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
998        )
999    }
1000
1001    // Parse a JOIN clause
1002    fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1003        // Determine join type
1004        let join_type = match &self.current_token {
1005            Token::Join => {
1006                self.advance();
1007                JoinType::Inner // Default JOIN is INNER JOIN
1008            }
1009            Token::Inner => {
1010                self.advance();
1011                if !matches!(self.current_token, Token::Join) {
1012                    return Err("Expected JOIN after INNER".to_string());
1013                }
1014                self.advance();
1015                JoinType::Inner
1016            }
1017            Token::Left => {
1018                self.advance();
1019                // Handle optional OUTER keyword
1020                if matches!(self.current_token, Token::Outer) {
1021                    self.advance();
1022                }
1023                if !matches!(self.current_token, Token::Join) {
1024                    return Err("Expected JOIN after LEFT".to_string());
1025                }
1026                self.advance();
1027                JoinType::Left
1028            }
1029            Token::Right => {
1030                self.advance();
1031                // Handle optional OUTER keyword
1032                if matches!(self.current_token, Token::Outer) {
1033                    self.advance();
1034                }
1035                if !matches!(self.current_token, Token::Join) {
1036                    return Err("Expected JOIN after RIGHT".to_string());
1037                }
1038                self.advance();
1039                JoinType::Right
1040            }
1041            Token::Full => {
1042                self.advance();
1043                // Handle optional OUTER keyword
1044                if matches!(self.current_token, Token::Outer) {
1045                    self.advance();
1046                }
1047                if !matches!(self.current_token, Token::Join) {
1048                    return Err("Expected JOIN after FULL".to_string());
1049                }
1050                self.advance();
1051                JoinType::Full
1052            }
1053            Token::Cross => {
1054                self.advance();
1055                if !matches!(self.current_token, Token::Join) {
1056                    return Err("Expected JOIN after CROSS".to_string());
1057                }
1058                self.advance();
1059                JoinType::Cross
1060            }
1061            _ => return Err("Expected JOIN keyword".to_string()),
1062        };
1063
1064        // Parse the table being joined
1065        let (table, alias) = self.parse_join_table_source()?;
1066
1067        // Parse ON condition (required for all joins except CROSS JOIN)
1068        let condition = if join_type == JoinType::Cross {
1069            // CROSS JOIN doesn't have ON condition
1070            JoinCondition {
1071                left_column: String::new(),
1072                operator: JoinOperator::Equal,
1073                right_column: String::new(),
1074            }
1075        } else {
1076            if !matches!(self.current_token, Token::On) {
1077                return Err("Expected ON keyword after JOIN table".to_string());
1078            }
1079            self.advance();
1080            self.parse_join_condition()?
1081        };
1082
1083        Ok(JoinClause {
1084            join_type,
1085            table,
1086            alias,
1087            condition,
1088        })
1089    }
1090
1091    fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1092        let table = match &self.current_token {
1093            Token::Identifier(name) => {
1094                let table_name = name.clone();
1095                self.advance();
1096                TableSource::Table(table_name)
1097            }
1098            Token::LeftParen => {
1099                // Subquery as table source
1100                self.advance();
1101                let subquery = self.parse_select_statement_inner()?;
1102                if !matches!(self.current_token, Token::RightParen) {
1103                    return Err("Expected ')' after subquery".to_string());
1104                }
1105                self.advance();
1106
1107                // Subqueries must have an alias
1108                let alias = match &self.current_token {
1109                    Token::Identifier(alias_name) => {
1110                        let alias = alias_name.clone();
1111                        self.advance();
1112                        alias
1113                    }
1114                    Token::As => {
1115                        self.advance();
1116                        match &self.current_token {
1117                            Token::Identifier(alias_name) => {
1118                                let alias = alias_name.clone();
1119                                self.advance();
1120                                alias
1121                            }
1122                            _ => return Err("Expected alias after AS keyword".to_string()),
1123                        }
1124                    }
1125                    _ => return Err("Subqueries must have an alias".to_string()),
1126                };
1127
1128                return Ok((
1129                    TableSource::DerivedTable {
1130                        query: Box::new(subquery),
1131                        alias: alias.clone(),
1132                    },
1133                    Some(alias),
1134                ));
1135            }
1136            _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1137        };
1138
1139        // Check for optional alias
1140        let alias = match &self.current_token {
1141            Token::Identifier(alias_name) => {
1142                let alias = alias_name.clone();
1143                self.advance();
1144                Some(alias)
1145            }
1146            Token::As => {
1147                self.advance();
1148                match &self.current_token {
1149                    Token::Identifier(alias_name) => {
1150                        let alias = alias_name.clone();
1151                        self.advance();
1152                        Some(alias)
1153                    }
1154                    _ => return Err("Expected alias after AS keyword".to_string()),
1155                }
1156            }
1157            _ => None,
1158        };
1159
1160        Ok((table, alias))
1161    }
1162
1163    fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1164        // Parse left column (can include table prefix)
1165        let left_column = self.parse_column_reference()?;
1166
1167        // Parse operator
1168        let operator = match &self.current_token {
1169            Token::Equal => JoinOperator::Equal,
1170            Token::NotEqual => JoinOperator::NotEqual,
1171            Token::LessThan => JoinOperator::LessThan,
1172            Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
1173            Token::GreaterThan => JoinOperator::GreaterThan,
1174            Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
1175            _ => return Err("Expected comparison operator in JOIN condition".to_string()),
1176        };
1177        self.advance();
1178
1179        // Parse right column (can include table prefix)
1180        let right_column = self.parse_column_reference()?;
1181
1182        Ok(JoinCondition {
1183            left_column,
1184            operator,
1185            right_column,
1186        })
1187    }
1188
1189    fn parse_column_reference(&mut self) -> Result<String, String> {
1190        match &self.current_token {
1191            Token::Identifier(name) => {
1192                let mut column_ref = name.clone();
1193                self.advance();
1194
1195                // Check for table.column notation
1196                if matches!(self.current_token, Token::Dot) {
1197                    self.advance();
1198                    match &self.current_token {
1199                        Token::Identifier(col_name) => {
1200                            column_ref.push('.');
1201                            column_ref.push_str(col_name);
1202                            self.advance();
1203                        }
1204                        _ => return Err("Expected column name after '.'".to_string()),
1205                    }
1206                }
1207
1208                Ok(column_ref)
1209            }
1210            _ => Err("Expected column reference".to_string()),
1211        }
1212    }
1213}
1214
1215// Context detection for cursor position
1216#[derive(Debug, Clone)]
1217pub enum CursorContext {
1218    SelectClause,
1219    FromClause,
1220    WhereClause,
1221    OrderByClause,
1222    AfterColumn(String),
1223    AfterLogicalOp(LogicalOp),
1224    AfterComparisonOp(String, String), // column_name, operator
1225    InMethodCall(String, String),      // object, method
1226    InExpression,
1227    Unknown,
1228}
1229
1230/// Safe UTF-8 string slicing that ensures we don't slice in the middle of a character
1231fn safe_slice_to(s: &str, pos: usize) -> &str {
1232    if pos >= s.len() {
1233        return s;
1234    }
1235
1236    // Find the nearest valid character boundary at or before pos
1237    let mut safe_pos = pos;
1238    while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
1239        safe_pos -= 1;
1240    }
1241
1242    &s[..safe_pos]
1243}
1244
1245/// Safe UTF-8 string slicing from a position to the end
1246fn safe_slice_from(s: &str, pos: usize) -> &str {
1247    if pos >= s.len() {
1248        return "";
1249    }
1250
1251    // Find the nearest valid character boundary at or after pos
1252    let mut safe_pos = pos;
1253    while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
1254        safe_pos += 1;
1255    }
1256
1257    &s[safe_pos..]
1258}
1259
1260#[must_use]
1261pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1262    let truncated = safe_slice_to(query, cursor_pos);
1263    let mut parser = Parser::new(truncated);
1264
1265    // Try to parse as much as possible
1266    if let Ok(stmt) = parser.parse() {
1267        let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
1268        #[cfg(test)]
1269        println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1270        (ctx, partial)
1271    } else {
1272        // Partial parse - analyze what we have
1273        let (ctx, partial) = analyze_partial(truncated, cursor_pos);
1274        #[cfg(test)]
1275        println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1276        (ctx, partial)
1277    }
1278}
1279
1280#[must_use]
1281pub fn tokenize_query(query: &str) -> Vec<String> {
1282    let mut lexer = Lexer::new(query);
1283    let tokens = lexer.tokenize_all();
1284    tokens.iter().map(|t| format!("{t:?}")).collect()
1285}
1286
1287#[must_use]
1288fn analyze_statement(
1289    stmt: &SelectStatement,
1290    query: &str,
1291    _cursor_pos: usize,
1292) -> (CursorContext, Option<String>) {
1293    // First check for method call context (e.g., "columnName." or "columnName.Con")
1294    let trimmed = query.trim();
1295
1296    // Check if we're after a comparison operator (e.g., "createdDate > ")
1297    let comparison_ops = [" > ", " < ", " >= ", " <= ", " = ", " != "];
1298    for op in &comparison_ops {
1299        if let Some(op_pos) = query.rfind(op) {
1300            let before_op = safe_slice_to(query, op_pos);
1301            let after_op_start = op_pos + op.len();
1302            let after_op = if after_op_start < query.len() {
1303                &query[after_op_start..]
1304            } else {
1305                ""
1306            };
1307
1308            // Check if we have a column name before the operator
1309            if let Some(col_name) = before_op.split_whitespace().last() {
1310                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
1311                    // Check if we're at or near the end of the query
1312                    let after_op_trimmed = after_op.trim();
1313                    if after_op_trimmed.is_empty()
1314                        || (after_op_trimmed
1315                            .chars()
1316                            .all(|c| c.is_alphanumeric() || c == '_')
1317                            && !after_op_trimmed.contains('('))
1318                    {
1319                        let partial = if after_op_trimmed.is_empty() {
1320                            None
1321                        } else {
1322                            Some(after_op_trimmed.to_string())
1323                        };
1324                        return (
1325                            CursorContext::AfterComparisonOp(
1326                                col_name.to_string(),
1327                                op.trim().to_string(),
1328                            ),
1329                            partial,
1330                        );
1331                    }
1332                }
1333            }
1334        }
1335    }
1336
1337    // First check if we're after AND/OR - this takes precedence
1338    if trimmed.to_uppercase().ends_with(" AND")
1339        || trimmed.to_uppercase().ends_with(" OR")
1340        || trimmed.to_uppercase().ends_with(" AND ")
1341        || trimmed.to_uppercase().ends_with(" OR ")
1342    {
1343        // Don't check for method context if we're clearly after a logical operator
1344    } else {
1345        // Look for the last dot in the query
1346        if let Some(dot_pos) = trimmed.rfind('.') {
1347            // Check if we're after a column name and dot
1348            let before_dot = safe_slice_to(trimmed, dot_pos);
1349            let after_dot_start = dot_pos + 1;
1350            let after_dot = if after_dot_start < trimmed.len() {
1351                &trimmed[after_dot_start..]
1352            } else {
1353                ""
1354            };
1355
1356            // Check if the part after dot looks like an incomplete method call
1357            // (not a complete method call like "Contains(...)")
1358            if !after_dot.contains('(') {
1359                // Try to extract the column name - could be quoted or regular
1360                let col_name = if before_dot.ends_with('"') {
1361                    // Handle quoted identifier - search backwards for matching opening quote
1362                    let bytes = before_dot.as_bytes();
1363                    let mut pos = before_dot.len() - 1; // Position of closing quote
1364                    let mut found_start = None;
1365
1366                    // Skip the closing quote and search backwards
1367                    if pos > 0 {
1368                        pos -= 1;
1369                        while pos > 0 {
1370                            if bytes[pos] == b'"' {
1371                                // Check if it's not an escaped quote
1372                                if pos == 0 || bytes[pos - 1] != b'\\' {
1373                                    found_start = Some(pos);
1374                                    break;
1375                                }
1376                            }
1377                            pos -= 1;
1378                        }
1379                        // Check position 0 separately
1380                        if found_start.is_none() && bytes[0] == b'"' {
1381                            found_start = Some(0);
1382                        }
1383                    }
1384
1385                    found_start.map(|start| safe_slice_from(before_dot, start))
1386                } else {
1387                    // Regular identifier - get the last word, handling parentheses
1388                    // Strip all leading parentheses
1389                    before_dot
1390                        .split_whitespace()
1391                        .last()
1392                        .map(|word| word.trim_start_matches('('))
1393                };
1394
1395                if let Some(col_name) = col_name {
1396                    // For quoted identifiers, keep the quotes, for regular identifiers check validity
1397                    let is_valid = if col_name.starts_with('"') && col_name.ends_with('"') {
1398                        // Quoted identifier - always valid
1399                        true
1400                    } else {
1401                        // Regular identifier - check if it's alphanumeric or underscore
1402                        col_name.chars().all(|c| c.is_alphanumeric() || c == '_')
1403                    };
1404
1405                    if is_valid {
1406                        // We're in a method call context
1407                        // Check if there's a partial method name after the dot
1408                        let partial_method = if after_dot.is_empty() {
1409                            None
1410                        } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1411                            Some(after_dot.to_string())
1412                        } else {
1413                            None
1414                        };
1415
1416                        // For AfterColumn context, strip quotes if present for consistency
1417                        let col_name_for_context = if col_name.starts_with('"')
1418                            && col_name.ends_with('"')
1419                            && col_name.len() > 2
1420                        {
1421                            col_name[1..col_name.len() - 1].to_string()
1422                        } else {
1423                            col_name.to_string()
1424                        };
1425
1426                        return (
1427                            CursorContext::AfterColumn(col_name_for_context),
1428                            partial_method,
1429                        );
1430                    }
1431                }
1432            }
1433        }
1434    }
1435
1436    // Check if we're in WHERE clause
1437    if let Some(where_clause) = &stmt.where_clause {
1438        // Check if query ends with AND/OR (with or without trailing space/partial)
1439        if trimmed.to_uppercase().ends_with(" AND") || trimmed.to_uppercase().ends_with(" OR") {
1440            let op = if trimmed.to_uppercase().ends_with(" AND") {
1441                LogicalOp::And
1442            } else {
1443                LogicalOp::Or
1444            };
1445            return (CursorContext::AfterLogicalOp(op), None);
1446        }
1447
1448        // Check if we have AND/OR followed by a partial word
1449        if let Some(and_pos) = query.to_uppercase().rfind(" AND ") {
1450            let after_and = safe_slice_from(query, and_pos + 5);
1451            let partial = extract_partial_at_end(after_and);
1452            if partial.is_some() {
1453                return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
1454            }
1455        }
1456
1457        if let Some(or_pos) = query.to_uppercase().rfind(" OR ") {
1458            let after_or = safe_slice_from(query, or_pos + 4);
1459            let partial = extract_partial_at_end(after_or);
1460            if partial.is_some() {
1461                return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
1462            }
1463        }
1464
1465        if let Some(last_condition) = where_clause.conditions.last() {
1466            if let Some(connector) = &last_condition.connector {
1467                // We're after AND/OR
1468                return (
1469                    CursorContext::AfterLogicalOp(connector.clone()),
1470                    extract_partial_at_end(query),
1471                );
1472            }
1473        }
1474        // We're in WHERE clause but not after AND/OR
1475        return (CursorContext::WhereClause, extract_partial_at_end(query));
1476    }
1477
1478    // Check if we're after ORDER BY
1479    if query.to_uppercase().ends_with(" ORDER BY ") || query.to_uppercase().ends_with(" ORDER BY") {
1480        return (CursorContext::OrderByClause, None);
1481    }
1482
1483    // Check other contexts based on what's in the statement
1484    if stmt.order_by.is_some() {
1485        return (CursorContext::OrderByClause, extract_partial_at_end(query));
1486    }
1487
1488    if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
1489        return (CursorContext::FromClause, extract_partial_at_end(query));
1490    }
1491
1492    if !stmt.columns.is_empty() && stmt.from_table.is_none() {
1493        return (CursorContext::SelectClause, extract_partial_at_end(query));
1494    }
1495
1496    (CursorContext::Unknown, None)
1497}
1498
1499fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1500    let upper = query.to_uppercase();
1501
1502    // Check for method call context first (e.g., "columnName." or "columnName.Con")
1503    let trimmed = query.trim();
1504
1505    #[cfg(test)]
1506    {
1507        if trimmed.contains("\"Last Name\"") {
1508            eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
1509        }
1510    }
1511
1512    // Check if we're after a comparison operator (e.g., "createdDate > ")
1513    let comparison_ops = [" > ", " < ", " >= ", " <= ", " = ", " != "];
1514    for op in &comparison_ops {
1515        if let Some(op_pos) = query.rfind(op) {
1516            let before_op = safe_slice_to(query, op_pos);
1517            let after_op_start = op_pos + op.len();
1518            let after_op = if after_op_start < query.len() {
1519                &query[after_op_start..]
1520            } else {
1521                ""
1522            };
1523
1524            // Check if we have a column name before the operator
1525            if let Some(col_name) = before_op.split_whitespace().last() {
1526                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
1527                    // Check if we're at or near the end of the query (allowing for some whitespace)
1528                    let after_op_trimmed = after_op.trim();
1529                    if after_op_trimmed.is_empty()
1530                        || (after_op_trimmed
1531                            .chars()
1532                            .all(|c| c.is_alphanumeric() || c == '_')
1533                            && !after_op_trimmed.contains('('))
1534                    {
1535                        let partial = if after_op_trimmed.is_empty() {
1536                            None
1537                        } else {
1538                            Some(after_op_trimmed.to_string())
1539                        };
1540                        return (
1541                            CursorContext::AfterComparisonOp(
1542                                col_name.to_string(),
1543                                op.trim().to_string(),
1544                            ),
1545                            partial,
1546                        );
1547                    }
1548                }
1549            }
1550        }
1551    }
1552
1553    // Look for the last dot in the query (method call context) - check this FIRST
1554    // before AND/OR detection to properly handle cases like "AND (Country."
1555    if let Some(dot_pos) = trimmed.rfind('.') {
1556        #[cfg(test)]
1557        {
1558            if trimmed.contains("\"Last Name\"") {
1559                eprintln!("DEBUG: Found dot at position {dot_pos}");
1560            }
1561        }
1562        // Check if we're after a column name and dot
1563        let before_dot = &trimmed[..dot_pos];
1564        let after_dot = &trimmed[dot_pos + 1..];
1565
1566        // Check if the part after dot looks like an incomplete method call
1567        // (not a complete method call like "Contains(...)")
1568        if !after_dot.contains('(') {
1569            // Try to extract the column name before the dot
1570            // It could be a quoted identifier like "Last Name" or a regular identifier
1571            let col_name = if before_dot.ends_with('"') {
1572                // Handle quoted identifier - search backwards for matching opening quote
1573                let bytes = before_dot.as_bytes();
1574                let mut pos = before_dot.len() - 1; // Position of closing quote
1575                let mut found_start = None;
1576
1577                #[cfg(test)]
1578                {
1579                    if trimmed.contains("\"Last Name\"") {
1580                        eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
1581                    }
1582                }
1583
1584                // Skip the closing quote and search backwards
1585                if pos > 0 {
1586                    pos -= 1;
1587                    while pos > 0 {
1588                        if bytes[pos] == b'"' {
1589                            // Check if it's not an escaped quote
1590                            if pos == 0 || bytes[pos - 1] != b'\\' {
1591                                found_start = Some(pos);
1592                                break;
1593                            }
1594                        }
1595                        pos -= 1;
1596                    }
1597                    // Check position 0 separately
1598                    if found_start.is_none() && bytes[0] == b'"' {
1599                        found_start = Some(0);
1600                    }
1601                }
1602
1603                if let Some(start) = found_start {
1604                    // Extract the full quoted identifier including quotes
1605                    let result = safe_slice_from(before_dot, start);
1606                    #[cfg(test)]
1607                    {
1608                        if trimmed.contains("\"Last Name\"") {
1609                            eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
1610                        }
1611                    }
1612                    Some(result)
1613                } else {
1614                    #[cfg(test)]
1615                    {
1616                        if trimmed.contains("\"Last Name\"") {
1617                            eprintln!("DEBUG: No opening quote found!");
1618                        }
1619                    }
1620                    None
1621                }
1622            } else {
1623                // Regular identifier - get the last word, handling parentheses
1624                // Strip all leading parentheses
1625                before_dot
1626                    .split_whitespace()
1627                    .last()
1628                    .map(|word| word.trim_start_matches('('))
1629            };
1630
1631            if let Some(col_name) = col_name {
1632                #[cfg(test)]
1633                {
1634                    if trimmed.contains("\"Last Name\"") {
1635                        eprintln!("DEBUG: col_name = '{col_name}'");
1636                    }
1637                }
1638
1639                // For quoted identifiers, keep the quotes, for regular identifiers check validity
1640                let is_valid = if col_name.starts_with('"') && col_name.ends_with('"') {
1641                    // Quoted identifier - always valid
1642                    true
1643                } else {
1644                    // Regular identifier - check if it's alphanumeric or underscore
1645                    col_name.chars().all(|c| c.is_alphanumeric() || c == '_')
1646                };
1647
1648                #[cfg(test)]
1649                {
1650                    if trimmed.contains("\"Last Name\"") {
1651                        eprintln!("DEBUG: is_valid = {is_valid}");
1652                    }
1653                }
1654
1655                if is_valid {
1656                    // We're in a method call context
1657                    // Check if there's a partial method name after the dot
1658                    let partial_method = if after_dot.is_empty() {
1659                        None
1660                    } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1661                        Some(after_dot.to_string())
1662                    } else {
1663                        None
1664                    };
1665
1666                    // For AfterColumn context, strip quotes if present for consistency
1667                    let col_name_for_context = if col_name.starts_with('"')
1668                        && col_name.ends_with('"')
1669                        && col_name.len() > 2
1670                    {
1671                        col_name[1..col_name.len() - 1].to_string()
1672                    } else {
1673                        col_name.to_string()
1674                    };
1675
1676                    return (
1677                        CursorContext::AfterColumn(col_name_for_context),
1678                        partial_method,
1679                    );
1680                }
1681            }
1682        }
1683    }
1684
1685    // Check if we're after AND/OR - but only after checking for method calls
1686    if let Some(and_pos) = upper.rfind(" AND ") {
1687        // Check if cursor is after AND
1688        if cursor_pos >= and_pos + 5 {
1689            // Extract any partial word after AND
1690            let after_and = safe_slice_from(query, and_pos + 5);
1691            let partial = extract_partial_at_end(after_and);
1692            return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
1693        }
1694    }
1695
1696    if let Some(or_pos) = upper.rfind(" OR ") {
1697        // Check if cursor is after OR
1698        if cursor_pos >= or_pos + 4 {
1699            // Extract any partial word after OR
1700            let after_or = safe_slice_from(query, or_pos + 4);
1701            let partial = extract_partial_at_end(after_or);
1702            return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
1703        }
1704    }
1705
1706    // Handle case where AND/OR is at the very end
1707    if trimmed.to_uppercase().ends_with(" AND") || trimmed.to_uppercase().ends_with(" OR") {
1708        let op = if trimmed.to_uppercase().ends_with(" AND") {
1709            LogicalOp::And
1710        } else {
1711            LogicalOp::Or
1712        };
1713        return (CursorContext::AfterLogicalOp(op), None);
1714    }
1715
1716    // Check if we're after ORDER BY
1717    if upper.ends_with(" ORDER BY ") || upper.ends_with(" ORDER BY") || upper.contains("ORDER BY ")
1718    {
1719        return (CursorContext::OrderByClause, extract_partial_at_end(query));
1720    }
1721
1722    if upper.contains("WHERE") && !upper.contains("ORDER") && !upper.contains("GROUP") {
1723        return (CursorContext::WhereClause, extract_partial_at_end(query));
1724    }
1725
1726    if upper.contains("FROM") && !upper.contains("WHERE") && !upper.contains("ORDER") {
1727        return (CursorContext::FromClause, extract_partial_at_end(query));
1728    }
1729
1730    if upper.contains("SELECT") && !upper.contains("FROM") {
1731        return (CursorContext::SelectClause, extract_partial_at_end(query));
1732    }
1733
1734    (CursorContext::Unknown, None)
1735}
1736
1737fn extract_partial_at_end(query: &str) -> Option<String> {
1738    let trimmed = query.trim();
1739
1740    // First check if the last word itself starts with a quote (unclosed quoted identifier being typed)
1741    if let Some(last_word) = trimmed.split_whitespace().last() {
1742        if last_word.starts_with('"') && !last_word.ends_with('"') {
1743            // This is an unclosed quoted identifier like "Cust
1744            return Some(last_word.to_string());
1745        }
1746    }
1747
1748    // Regular identifier extraction
1749    let last_word = trimmed.split_whitespace().last()?;
1750
1751    // Check if it's a partial identifier (not a keyword or operator)
1752    if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') && !is_sql_keyword(last_word) {
1753        Some(last_word.to_string())
1754    } else {
1755        None
1756    }
1757}
1758
1759// Implement the ParsePrimary trait for Parser to use the modular expression parsing
1760impl ParsePrimary for Parser {
1761    fn current_token(&self) -> &Token {
1762        &self.current_token
1763    }
1764
1765    fn advance(&mut self) {
1766        self.advance();
1767    }
1768
1769    fn consume(&mut self, expected: Token) -> Result<(), String> {
1770        self.consume(expected)
1771    }
1772
1773    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1774        self.parse_case_expression()
1775    }
1776
1777    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1778        self.parse_function_args()
1779    }
1780
1781    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
1782        self.parse_window_spec()
1783    }
1784
1785    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1786        self.parse_logical_or()
1787    }
1788
1789    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1790        self.parse_comparison()
1791    }
1792
1793    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1794        self.parse_expression_list()
1795    }
1796
1797    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
1798        // Parse subquery without parenthesis balance validation
1799        if matches!(self.current_token, Token::With) {
1800            self.parse_with_clause_inner()
1801        } else {
1802            self.parse_select_statement_inner()
1803        }
1804    }
1805}
1806
1807// Implement the ParseArithmetic trait for Parser to use the modular arithmetic parsing
1808impl ParseArithmetic for Parser {
1809    fn current_token(&self) -> &Token {
1810        &self.current_token
1811    }
1812
1813    fn advance(&mut self) {
1814        self.advance();
1815    }
1816
1817    fn consume(&mut self, expected: Token) -> Result<(), String> {
1818        self.consume(expected)
1819    }
1820
1821    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1822        self.parse_primary()
1823    }
1824
1825    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1826        self.parse_multiplicative()
1827    }
1828
1829    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1830        self.parse_method_args()
1831    }
1832}
1833
1834// Implement the ParseComparison trait for Parser to use the modular comparison parsing
1835impl ParseComparison for Parser {
1836    fn current_token(&self) -> &Token {
1837        &self.current_token
1838    }
1839
1840    fn advance(&mut self) {
1841        self.advance();
1842    }
1843
1844    fn consume(&mut self, expected: Token) -> Result<(), String> {
1845        self.consume(expected)
1846    }
1847
1848    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1849        self.parse_primary()
1850    }
1851
1852    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1853        self.parse_additive()
1854    }
1855
1856    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1857        self.parse_expression_list()
1858    }
1859
1860    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
1861        // Parse subquery without parenthesis balance validation
1862        if matches!(self.current_token, Token::With) {
1863            self.parse_with_clause_inner()
1864        } else {
1865            self.parse_select_statement_inner()
1866        }
1867    }
1868}
1869
1870// Implement the ParseLogical trait for Parser to use the modular logical parsing
1871impl ParseLogical for Parser {
1872    fn current_token(&self) -> &Token {
1873        &self.current_token
1874    }
1875
1876    fn advance(&mut self) {
1877        self.advance();
1878    }
1879
1880    fn consume(&mut self, expected: Token) -> Result<(), String> {
1881        self.consume(expected)
1882    }
1883
1884    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1885        self.parse_logical_and()
1886    }
1887
1888    fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
1889        // This is the base for logical AND - it should parse comparison expressions
1890        // to avoid infinite recursion with parse_expression
1891        self.parse_comparison()
1892    }
1893
1894    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1895        self.parse_comparison()
1896    }
1897
1898    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1899        self.parse_expression_list()
1900    }
1901}
1902
1903// Implement the ParseCase trait for Parser to use the modular CASE parsing
1904impl ParseCase for Parser {
1905    fn current_token(&self) -> &Token {
1906        &self.current_token
1907    }
1908
1909    fn advance(&mut self) {
1910        self.advance();
1911    }
1912
1913    fn consume(&mut self, expected: Token) -> Result<(), String> {
1914        self.consume(expected)
1915    }
1916
1917    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
1918        self.parse_expression()
1919    }
1920}
1921
1922fn is_sql_keyword(word: &str) -> bool {
1923    matches!(
1924        word.to_uppercase().as_str(),
1925        "SELECT"
1926            | "FROM"
1927            | "WHERE"
1928            | "AND"
1929            | "OR"
1930            | "IN"
1931            | "ORDER"
1932            | "BY"
1933            | "GROUP"
1934            | "HAVING"
1935            | "ASC"
1936            | "DESC"
1937            | "DISTINCT"
1938    )
1939}