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