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, FrameBound, FrameUnit, JoinClause, JoinCondition, JoinOperator,
6    JoinType, LogicalOp, OrderByColumn, SelectItem, SelectStatement, SortDirection, SqlExpression,
7    TableFunction, TableSource, WebCTESpec, WhenBranch, WhereClause, WindowFrame, 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        // Parse optional window frame (ROWS/RANGE BETWEEN ... AND ...)
948        let frame = self.parse_window_frame()?;
949
950        Ok(WindowSpec {
951            partition_by,
952            order_by,
953            frame,
954        })
955    }
956
957    fn parse_order_by_list(&mut self) -> Result<Vec<OrderByColumn>, String> {
958        let mut order_columns = Vec::new();
959
960        loop {
961            let column = match &self.current_token {
962                Token::Identifier(id) => {
963                    let col = id.clone();
964                    self.advance();
965                    col
966                }
967                Token::QuotedIdentifier(id) => {
968                    let col = id.clone();
969                    self.advance();
970                    col
971                }
972                Token::NumberLiteral(num) if self.columns.iter().any(|col| col == num) => {
973                    // Support numeric column names like "202204"
974                    let col = num.clone();
975                    self.advance();
976                    col
977                }
978                _ => return Err("Expected column name in ORDER BY".to_string()),
979            };
980
981            // Check for ASC/DESC
982            let direction = match &self.current_token {
983                Token::Asc => {
984                    self.advance();
985                    SortDirection::Asc
986                }
987                Token::Desc => {
988                    self.advance();
989                    SortDirection::Desc
990                }
991                _ => SortDirection::Asc, // Default to ASC if not specified
992            };
993
994            order_columns.push(OrderByColumn { column, direction });
995
996            if matches!(self.current_token, Token::Comma) {
997                self.advance();
998            } else {
999                break;
1000            }
1001        }
1002
1003        Ok(order_columns)
1004    }
1005
1006    fn parse_window_frame(&mut self) -> Result<Option<WindowFrame>, String> {
1007        // Check for ROWS or RANGE keyword
1008        let unit = match &self.current_token {
1009            Token::Identifier(id) if id.to_uppercase() == "ROWS" => {
1010                self.advance();
1011                FrameUnit::Rows
1012            }
1013            Token::Identifier(id) if id.to_uppercase() == "RANGE" => {
1014                self.advance();
1015                FrameUnit::Range
1016            }
1017            _ => return Ok(None), // No window frame specified
1018        };
1019
1020        // Check for BETWEEN or just a single bound
1021        let (start, end) = if let Token::Between = &self.current_token {
1022            self.advance(); // consume BETWEEN
1023                            // Parse start bound
1024            let start = self.parse_frame_bound()?;
1025
1026            // Expect AND
1027            if !matches!(&self.current_token, Token::And) {
1028                return Err("Expected AND after window frame start bound".to_string());
1029            }
1030            self.advance();
1031
1032            // Parse end bound
1033            let end = self.parse_frame_bound()?;
1034            (start, Some(end))
1035        } else {
1036            // Single bound (e.g., "ROWS 5 PRECEDING")
1037            let bound = self.parse_frame_bound()?;
1038            (bound, None)
1039        };
1040
1041        Ok(Some(WindowFrame { unit, start, end }))
1042    }
1043
1044    fn parse_frame_bound(&mut self) -> Result<FrameBound, String> {
1045        match &self.current_token {
1046            Token::Identifier(id) if id.to_uppercase() == "UNBOUNDED" => {
1047                self.advance();
1048                match &self.current_token {
1049                    Token::Identifier(id) if id.to_uppercase() == "PRECEDING" => {
1050                        self.advance();
1051                        Ok(FrameBound::UnboundedPreceding)
1052                    }
1053                    Token::Identifier(id) if id.to_uppercase() == "FOLLOWING" => {
1054                        self.advance();
1055                        Ok(FrameBound::UnboundedFollowing)
1056                    }
1057                    _ => Err("Expected PRECEDING or FOLLOWING after UNBOUNDED".to_string()),
1058                }
1059            }
1060            Token::Identifier(id) if id.to_uppercase() == "CURRENT" => {
1061                self.advance();
1062                if let Token::Identifier(id) = &self.current_token {
1063                    if id.to_uppercase() == "ROW" {
1064                        self.advance();
1065                        return Ok(FrameBound::CurrentRow);
1066                    }
1067                }
1068                Err("Expected ROW after CURRENT".to_string())
1069            }
1070            Token::NumberLiteral(num) => {
1071                let n: i64 = num
1072                    .parse()
1073                    .map_err(|_| "Invalid number in window frame".to_string())?;
1074                self.advance();
1075                match &self.current_token {
1076                    Token::Identifier(id) if id.to_uppercase() == "PRECEDING" => {
1077                        self.advance();
1078                        Ok(FrameBound::Preceding(n))
1079                    }
1080                    Token::Identifier(id) if id.to_uppercase() == "FOLLOWING" => {
1081                        self.advance();
1082                        Ok(FrameBound::Following(n))
1083                    }
1084                    _ => Err("Expected PRECEDING or FOLLOWING after number".to_string()),
1085                }
1086            }
1087            _ => Err("Invalid window frame bound".to_string()),
1088        }
1089    }
1090
1091    fn parse_where_clause(&mut self) -> Result<WhereClause, String> {
1092        // Parse the entire WHERE clause as a single expression tree
1093        // The logical operators (AND/OR) are now handled within parse_expression
1094        let expr = self.parse_expression()?;
1095
1096        // Check for unexpected closing parenthesis
1097        if matches!(self.current_token, Token::RightParen) && self.paren_depth <= 0 {
1098            return Err(
1099                "Unexpected closing parenthesis - no matching opening parenthesis".to_string(),
1100            );
1101        }
1102
1103        // Create a single condition with the entire expression
1104        let conditions = vec![Condition {
1105            expr,
1106            connector: None,
1107        }];
1108
1109        Ok(WhereClause { conditions })
1110    }
1111
1112    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
1113        // Start with logical OR as the lowest precedence operator
1114        // The hierarchy is: OR -> AND -> comparison -> additive -> multiplicative -> primary
1115        let mut left = self.parse_logical_or()?;
1116
1117        // Handle IN operator (not preceded by NOT)
1118        // This uses the modular comparison module
1119        left = parse_in_operator(self, left)?;
1120
1121        Ok(left)
1122    }
1123
1124    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1125        // Use the new modular comparison expression parser
1126        parse_comparison_expr(self)
1127    }
1128
1129    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1130        // Use the new modular arithmetic expression parser
1131        parse_additive_expr(self)
1132    }
1133
1134    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1135        // Use the new modular arithmetic expression parser
1136        parse_multiplicative_expr(self)
1137    }
1138
1139    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1140        // Use the new modular logical expression parser
1141        parse_logical_or_expr(self)
1142    }
1143
1144    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1145        // Use the new modular logical expression parser
1146        parse_logical_and_expr(self)
1147    }
1148
1149    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1150        // Use the new modular CASE expression parser
1151        parse_case_expr(self)
1152    }
1153
1154    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1155        // Use the new modular primary expression parser
1156        // Clone the necessary data to avoid borrowing issues
1157        let columns = self.columns.clone();
1158        let in_method_args = self.in_method_args;
1159        let ctx = PrimaryExpressionContext {
1160            columns: &columns,
1161            in_method_args,
1162        };
1163        parse_primary_expr(self, &ctx)
1164    }
1165
1166    // Keep the old implementation temporarily for reference (will be removed)
1167    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1168        let mut args = Vec::new();
1169
1170        // Set flag to indicate we're parsing method arguments
1171        self.in_method_args = true;
1172
1173        if !matches!(self.current_token, Token::RightParen) {
1174            loop {
1175                args.push(self.parse_expression()?);
1176
1177                if matches!(self.current_token, Token::Comma) {
1178                    self.advance();
1179                } else {
1180                    break;
1181                }
1182            }
1183        }
1184
1185        // Clear the flag
1186        self.in_method_args = false;
1187
1188        Ok(args)
1189    }
1190
1191    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1192        let mut args = Vec::new();
1193        let mut has_distinct = false;
1194
1195        if !matches!(self.current_token, Token::RightParen) {
1196            // Check if first argument starts with DISTINCT
1197            if matches!(self.current_token, Token::Distinct) {
1198                self.advance(); // consume DISTINCT
1199                has_distinct = true;
1200            }
1201
1202            // Parse the expression (either after DISTINCT or directly)
1203            args.push(self.parse_additive()?);
1204
1205            // Parse any remaining arguments (DISTINCT only applies to first arg for aggregates)
1206            while matches!(self.current_token, Token::Comma) {
1207                self.advance();
1208                args.push(self.parse_additive()?);
1209            }
1210        }
1211
1212        Ok((args, has_distinct))
1213    }
1214
1215    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1216        let mut expressions = Vec::new();
1217
1218        loop {
1219            expressions.push(self.parse_expression()?);
1220
1221            if matches!(self.current_token, Token::Comma) {
1222                self.advance();
1223            } else {
1224                break;
1225            }
1226        }
1227
1228        Ok(expressions)
1229    }
1230
1231    fn get_binary_op(&self) -> Option<String> {
1232        match &self.current_token {
1233            Token::Equal => Some("=".to_string()),
1234            Token::NotEqual => Some("!=".to_string()),
1235            Token::LessThan => Some("<".to_string()),
1236            Token::GreaterThan => Some(">".to_string()),
1237            Token::LessThanOrEqual => Some("<=".to_string()),
1238            Token::GreaterThanOrEqual => Some(">=".to_string()),
1239            Token::Like => Some("LIKE".to_string()),
1240            _ => None,
1241        }
1242    }
1243
1244    fn get_arithmetic_op(&self) -> Option<String> {
1245        match &self.current_token {
1246            Token::Plus => Some("+".to_string()),
1247            Token::Minus => Some("-".to_string()),
1248            Token::Star => Some("*".to_string()), // Multiplication (context-sensitive)
1249            Token::Divide => Some("/".to_string()),
1250            Token::Modulo => Some("%".to_string()),
1251            _ => None,
1252        }
1253    }
1254
1255    #[must_use]
1256    pub fn get_position(&self) -> usize {
1257        self.lexer.get_position()
1258    }
1259
1260    // Check if current token is a JOIN-related token
1261    fn is_join_token(&self) -> bool {
1262        matches!(
1263            self.current_token,
1264            Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
1265        )
1266    }
1267
1268    // Parse a JOIN clause
1269    fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1270        // Determine join type
1271        let join_type = match &self.current_token {
1272            Token::Join => {
1273                self.advance();
1274                JoinType::Inner // Default JOIN is INNER JOIN
1275            }
1276            Token::Inner => {
1277                self.advance();
1278                if !matches!(self.current_token, Token::Join) {
1279                    return Err("Expected JOIN after INNER".to_string());
1280                }
1281                self.advance();
1282                JoinType::Inner
1283            }
1284            Token::Left => {
1285                self.advance();
1286                // Handle optional OUTER keyword
1287                if matches!(self.current_token, Token::Outer) {
1288                    self.advance();
1289                }
1290                if !matches!(self.current_token, Token::Join) {
1291                    return Err("Expected JOIN after LEFT".to_string());
1292                }
1293                self.advance();
1294                JoinType::Left
1295            }
1296            Token::Right => {
1297                self.advance();
1298                // Handle optional OUTER keyword
1299                if matches!(self.current_token, Token::Outer) {
1300                    self.advance();
1301                }
1302                if !matches!(self.current_token, Token::Join) {
1303                    return Err("Expected JOIN after RIGHT".to_string());
1304                }
1305                self.advance();
1306                JoinType::Right
1307            }
1308            Token::Full => {
1309                self.advance();
1310                // Handle optional OUTER keyword
1311                if matches!(self.current_token, Token::Outer) {
1312                    self.advance();
1313                }
1314                if !matches!(self.current_token, Token::Join) {
1315                    return Err("Expected JOIN after FULL".to_string());
1316                }
1317                self.advance();
1318                JoinType::Full
1319            }
1320            Token::Cross => {
1321                self.advance();
1322                if !matches!(self.current_token, Token::Join) {
1323                    return Err("Expected JOIN after CROSS".to_string());
1324                }
1325                self.advance();
1326                JoinType::Cross
1327            }
1328            _ => return Err("Expected JOIN keyword".to_string()),
1329        };
1330
1331        // Parse the table being joined
1332        let (table, alias) = self.parse_join_table_source()?;
1333
1334        // Parse ON condition (required for all joins except CROSS JOIN)
1335        let condition = if join_type == JoinType::Cross {
1336            // CROSS JOIN doesn't have ON condition
1337            JoinCondition {
1338                left_column: String::new(),
1339                operator: JoinOperator::Equal,
1340                right_column: String::new(),
1341            }
1342        } else {
1343            if !matches!(self.current_token, Token::On) {
1344                return Err("Expected ON keyword after JOIN table".to_string());
1345            }
1346            self.advance();
1347            self.parse_join_condition()?
1348        };
1349
1350        Ok(JoinClause {
1351            join_type,
1352            table,
1353            alias,
1354            condition,
1355        })
1356    }
1357
1358    fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1359        let table = match &self.current_token {
1360            Token::Identifier(name) => {
1361                let table_name = name.clone();
1362                self.advance();
1363                TableSource::Table(table_name)
1364            }
1365            Token::LeftParen => {
1366                // Subquery as table source
1367                self.advance();
1368                let subquery = self.parse_select_statement_inner()?;
1369                if !matches!(self.current_token, Token::RightParen) {
1370                    return Err("Expected ')' after subquery".to_string());
1371                }
1372                self.advance();
1373
1374                // Subqueries must have an alias
1375                let alias = match &self.current_token {
1376                    Token::Identifier(alias_name) => {
1377                        let alias = alias_name.clone();
1378                        self.advance();
1379                        alias
1380                    }
1381                    Token::As => {
1382                        self.advance();
1383                        match &self.current_token {
1384                            Token::Identifier(alias_name) => {
1385                                let alias = alias_name.clone();
1386                                self.advance();
1387                                alias
1388                            }
1389                            _ => return Err("Expected alias after AS keyword".to_string()),
1390                        }
1391                    }
1392                    _ => return Err("Subqueries must have an alias".to_string()),
1393                };
1394
1395                return Ok((
1396                    TableSource::DerivedTable {
1397                        query: Box::new(subquery),
1398                        alias: alias.clone(),
1399                    },
1400                    Some(alias),
1401                ));
1402            }
1403            _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1404        };
1405
1406        // Check for optional alias
1407        let alias = match &self.current_token {
1408            Token::Identifier(alias_name) => {
1409                let alias = alias_name.clone();
1410                self.advance();
1411                Some(alias)
1412            }
1413            Token::As => {
1414                self.advance();
1415                match &self.current_token {
1416                    Token::Identifier(alias_name) => {
1417                        let alias = alias_name.clone();
1418                        self.advance();
1419                        Some(alias)
1420                    }
1421                    _ => return Err("Expected alias after AS keyword".to_string()),
1422                }
1423            }
1424            _ => None,
1425        };
1426
1427        Ok((table, alias))
1428    }
1429
1430    fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1431        // Parse left column (can include table prefix)
1432        let left_column = self.parse_column_reference()?;
1433
1434        // Parse operator
1435        let operator = match &self.current_token {
1436            Token::Equal => JoinOperator::Equal,
1437            Token::NotEqual => JoinOperator::NotEqual,
1438            Token::LessThan => JoinOperator::LessThan,
1439            Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
1440            Token::GreaterThan => JoinOperator::GreaterThan,
1441            Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
1442            _ => return Err("Expected comparison operator in JOIN condition".to_string()),
1443        };
1444        self.advance();
1445
1446        // Parse right column (can include table prefix)
1447        let right_column = self.parse_column_reference()?;
1448
1449        Ok(JoinCondition {
1450            left_column,
1451            operator,
1452            right_column,
1453        })
1454    }
1455
1456    fn parse_column_reference(&mut self) -> Result<String, String> {
1457        match &self.current_token {
1458            Token::Identifier(name) => {
1459                let mut column_ref = name.clone();
1460                self.advance();
1461
1462                // Check for table.column notation
1463                if matches!(self.current_token, Token::Dot) {
1464                    self.advance();
1465                    match &self.current_token {
1466                        Token::Identifier(col_name) => {
1467                            column_ref.push('.');
1468                            column_ref.push_str(col_name);
1469                            self.advance();
1470                        }
1471                        _ => return Err("Expected column name after '.'".to_string()),
1472                    }
1473                }
1474
1475                Ok(column_ref)
1476            }
1477            _ => Err("Expected column reference".to_string()),
1478        }
1479    }
1480}
1481
1482// Context detection for cursor position
1483#[derive(Debug, Clone)]
1484pub enum CursorContext {
1485    SelectClause,
1486    FromClause,
1487    WhereClause,
1488    OrderByClause,
1489    AfterColumn(String),
1490    AfterLogicalOp(LogicalOp),
1491    AfterComparisonOp(String, String), // column_name, operator
1492    InMethodCall(String, String),      // object, method
1493    InExpression,
1494    Unknown,
1495}
1496
1497/// Safe UTF-8 string slicing that ensures we don't slice in the middle of a character
1498fn safe_slice_to(s: &str, pos: usize) -> &str {
1499    if pos >= s.len() {
1500        return s;
1501    }
1502
1503    // Find the nearest valid character boundary at or before pos
1504    let mut safe_pos = pos;
1505    while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
1506        safe_pos -= 1;
1507    }
1508
1509    &s[..safe_pos]
1510}
1511
1512/// Safe UTF-8 string slicing from a position to the end
1513fn safe_slice_from(s: &str, pos: usize) -> &str {
1514    if pos >= s.len() {
1515        return "";
1516    }
1517
1518    // Find the nearest valid character boundary at or after pos
1519    let mut safe_pos = pos;
1520    while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
1521        safe_pos += 1;
1522    }
1523
1524    &s[safe_pos..]
1525}
1526
1527#[must_use]
1528pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1529    let truncated = safe_slice_to(query, cursor_pos);
1530    let mut parser = Parser::new(truncated);
1531
1532    // Try to parse as much as possible
1533    if let Ok(stmt) = parser.parse() {
1534        let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
1535        #[cfg(test)]
1536        println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1537        (ctx, partial)
1538    } else {
1539        // Partial parse - analyze what we have
1540        let (ctx, partial) = analyze_partial(truncated, cursor_pos);
1541        #[cfg(test)]
1542        println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1543        (ctx, partial)
1544    }
1545}
1546
1547#[must_use]
1548pub fn tokenize_query(query: &str) -> Vec<String> {
1549    let mut lexer = Lexer::new(query);
1550    let tokens = lexer.tokenize_all();
1551    tokens.iter().map(|t| format!("{t:?}")).collect()
1552}
1553
1554#[must_use]
1555fn analyze_statement(
1556    stmt: &SelectStatement,
1557    query: &str,
1558    _cursor_pos: usize,
1559) -> (CursorContext, Option<String>) {
1560    // First check for method call context (e.g., "columnName." or "columnName.Con")
1561    let trimmed = query.trim();
1562
1563    // Check if we're after a comparison operator (e.g., "createdDate > ")
1564    let comparison_ops = [" > ", " < ", " >= ", " <= ", " = ", " != "];
1565    for op in &comparison_ops {
1566        if let Some(op_pos) = query.rfind(op) {
1567            let before_op = safe_slice_to(query, op_pos);
1568            let after_op_start = op_pos + op.len();
1569            let after_op = if after_op_start < query.len() {
1570                &query[after_op_start..]
1571            } else {
1572                ""
1573            };
1574
1575            // Check if we have a column name before the operator
1576            if let Some(col_name) = before_op.split_whitespace().last() {
1577                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
1578                    // Check if we're at or near the end of the query
1579                    let after_op_trimmed = after_op.trim();
1580                    if after_op_trimmed.is_empty()
1581                        || (after_op_trimmed
1582                            .chars()
1583                            .all(|c| c.is_alphanumeric() || c == '_')
1584                            && !after_op_trimmed.contains('('))
1585                    {
1586                        let partial = if after_op_trimmed.is_empty() {
1587                            None
1588                        } else {
1589                            Some(after_op_trimmed.to_string())
1590                        };
1591                        return (
1592                            CursorContext::AfterComparisonOp(
1593                                col_name.to_string(),
1594                                op.trim().to_string(),
1595                            ),
1596                            partial,
1597                        );
1598                    }
1599                }
1600            }
1601        }
1602    }
1603
1604    // First check if we're after AND/OR - this takes precedence
1605    if trimmed.to_uppercase().ends_with(" AND")
1606        || trimmed.to_uppercase().ends_with(" OR")
1607        || trimmed.to_uppercase().ends_with(" AND ")
1608        || trimmed.to_uppercase().ends_with(" OR ")
1609    {
1610        // Don't check for method context if we're clearly after a logical operator
1611    } else {
1612        // Look for the last dot in the query
1613        if let Some(dot_pos) = trimmed.rfind('.') {
1614            // Check if we're after a column name and dot
1615            let before_dot = safe_slice_to(trimmed, dot_pos);
1616            let after_dot_start = dot_pos + 1;
1617            let after_dot = if after_dot_start < trimmed.len() {
1618                &trimmed[after_dot_start..]
1619            } else {
1620                ""
1621            };
1622
1623            // Check if the part after dot looks like an incomplete method call
1624            // (not a complete method call like "Contains(...)")
1625            if !after_dot.contains('(') {
1626                // Try to extract the column name - could be quoted or regular
1627                let col_name = if before_dot.ends_with('"') {
1628                    // Handle quoted identifier - search backwards for matching opening quote
1629                    let bytes = before_dot.as_bytes();
1630                    let mut pos = before_dot.len() - 1; // Position of closing quote
1631                    let mut found_start = None;
1632
1633                    // Skip the closing quote and search backwards
1634                    if pos > 0 {
1635                        pos -= 1;
1636                        while pos > 0 {
1637                            if bytes[pos] == b'"' {
1638                                // Check if it's not an escaped quote
1639                                if pos == 0 || bytes[pos - 1] != b'\\' {
1640                                    found_start = Some(pos);
1641                                    break;
1642                                }
1643                            }
1644                            pos -= 1;
1645                        }
1646                        // Check position 0 separately
1647                        if found_start.is_none() && bytes[0] == b'"' {
1648                            found_start = Some(0);
1649                        }
1650                    }
1651
1652                    found_start.map(|start| safe_slice_from(before_dot, start))
1653                } else {
1654                    // Regular identifier - get the last word, handling parentheses
1655                    // Strip all leading parentheses
1656                    before_dot
1657                        .split_whitespace()
1658                        .last()
1659                        .map(|word| word.trim_start_matches('('))
1660                };
1661
1662                if let Some(col_name) = col_name {
1663                    // For quoted identifiers, keep the quotes, for regular identifiers check validity
1664                    let is_valid = if col_name.starts_with('"') && col_name.ends_with('"') {
1665                        // Quoted identifier - always valid
1666                        true
1667                    } else {
1668                        // Regular identifier - check if it's alphanumeric or underscore
1669                        col_name.chars().all(|c| c.is_alphanumeric() || c == '_')
1670                    };
1671
1672                    if is_valid {
1673                        // We're in a method call context
1674                        // Check if there's a partial method name after the dot
1675                        let partial_method = if after_dot.is_empty() {
1676                            None
1677                        } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1678                            Some(after_dot.to_string())
1679                        } else {
1680                            None
1681                        };
1682
1683                        // For AfterColumn context, strip quotes if present for consistency
1684                        let col_name_for_context = if col_name.starts_with('"')
1685                            && col_name.ends_with('"')
1686                            && col_name.len() > 2
1687                        {
1688                            col_name[1..col_name.len() - 1].to_string()
1689                        } else {
1690                            col_name.to_string()
1691                        };
1692
1693                        return (
1694                            CursorContext::AfterColumn(col_name_for_context),
1695                            partial_method,
1696                        );
1697                    }
1698                }
1699            }
1700        }
1701    }
1702
1703    // Check if we're in WHERE clause
1704    if let Some(where_clause) = &stmt.where_clause {
1705        // Check if query ends with AND/OR (with or without trailing space/partial)
1706        if trimmed.to_uppercase().ends_with(" AND") || trimmed.to_uppercase().ends_with(" OR") {
1707            let op = if trimmed.to_uppercase().ends_with(" AND") {
1708                LogicalOp::And
1709            } else {
1710                LogicalOp::Or
1711            };
1712            return (CursorContext::AfterLogicalOp(op), None);
1713        }
1714
1715        // Check if we have AND/OR followed by a partial word
1716        if let Some(and_pos) = query.to_uppercase().rfind(" AND ") {
1717            let after_and = safe_slice_from(query, and_pos + 5);
1718            let partial = extract_partial_at_end(after_and);
1719            if partial.is_some() {
1720                return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
1721            }
1722        }
1723
1724        if let Some(or_pos) = query.to_uppercase().rfind(" OR ") {
1725            let after_or = safe_slice_from(query, or_pos + 4);
1726            let partial = extract_partial_at_end(after_or);
1727            if partial.is_some() {
1728                return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
1729            }
1730        }
1731
1732        if let Some(last_condition) = where_clause.conditions.last() {
1733            if let Some(connector) = &last_condition.connector {
1734                // We're after AND/OR
1735                return (
1736                    CursorContext::AfterLogicalOp(connector.clone()),
1737                    extract_partial_at_end(query),
1738                );
1739            }
1740        }
1741        // We're in WHERE clause but not after AND/OR
1742        return (CursorContext::WhereClause, extract_partial_at_end(query));
1743    }
1744
1745    // Check if we're after ORDER BY
1746    if query.to_uppercase().ends_with(" ORDER BY ") || query.to_uppercase().ends_with(" ORDER BY") {
1747        return (CursorContext::OrderByClause, None);
1748    }
1749
1750    // Check other contexts based on what's in the statement
1751    if stmt.order_by.is_some() {
1752        return (CursorContext::OrderByClause, extract_partial_at_end(query));
1753    }
1754
1755    if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
1756        return (CursorContext::FromClause, extract_partial_at_end(query));
1757    }
1758
1759    if !stmt.columns.is_empty() && stmt.from_table.is_none() {
1760        return (CursorContext::SelectClause, extract_partial_at_end(query));
1761    }
1762
1763    (CursorContext::Unknown, None)
1764}
1765
1766fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1767    let upper = query.to_uppercase();
1768
1769    // Check for method call context first (e.g., "columnName." or "columnName.Con")
1770    let trimmed = query.trim();
1771
1772    #[cfg(test)]
1773    {
1774        if trimmed.contains("\"Last Name\"") {
1775            eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
1776        }
1777    }
1778
1779    // Check if we're after a comparison operator (e.g., "createdDate > ")
1780    let comparison_ops = [" > ", " < ", " >= ", " <= ", " = ", " != "];
1781    for op in &comparison_ops {
1782        if let Some(op_pos) = query.rfind(op) {
1783            let before_op = safe_slice_to(query, op_pos);
1784            let after_op_start = op_pos + op.len();
1785            let after_op = if after_op_start < query.len() {
1786                &query[after_op_start..]
1787            } else {
1788                ""
1789            };
1790
1791            // Check if we have a column name before the operator
1792            if let Some(col_name) = before_op.split_whitespace().last() {
1793                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
1794                    // Check if we're at or near the end of the query (allowing for some whitespace)
1795                    let after_op_trimmed = after_op.trim();
1796                    if after_op_trimmed.is_empty()
1797                        || (after_op_trimmed
1798                            .chars()
1799                            .all(|c| c.is_alphanumeric() || c == '_')
1800                            && !after_op_trimmed.contains('('))
1801                    {
1802                        let partial = if after_op_trimmed.is_empty() {
1803                            None
1804                        } else {
1805                            Some(after_op_trimmed.to_string())
1806                        };
1807                        return (
1808                            CursorContext::AfterComparisonOp(
1809                                col_name.to_string(),
1810                                op.trim().to_string(),
1811                            ),
1812                            partial,
1813                        );
1814                    }
1815                }
1816            }
1817        }
1818    }
1819
1820    // Look for the last dot in the query (method call context) - check this FIRST
1821    // before AND/OR detection to properly handle cases like "AND (Country."
1822    if let Some(dot_pos) = trimmed.rfind('.') {
1823        #[cfg(test)]
1824        {
1825            if trimmed.contains("\"Last Name\"") {
1826                eprintln!("DEBUG: Found dot at position {dot_pos}");
1827            }
1828        }
1829        // Check if we're after a column name and dot
1830        let before_dot = &trimmed[..dot_pos];
1831        let after_dot = &trimmed[dot_pos + 1..];
1832
1833        // Check if the part after dot looks like an incomplete method call
1834        // (not a complete method call like "Contains(...)")
1835        if !after_dot.contains('(') {
1836            // Try to extract the column name before the dot
1837            // It could be a quoted identifier like "Last Name" or a regular identifier
1838            let col_name = if before_dot.ends_with('"') {
1839                // Handle quoted identifier - search backwards for matching opening quote
1840                let bytes = before_dot.as_bytes();
1841                let mut pos = before_dot.len() - 1; // Position of closing quote
1842                let mut found_start = None;
1843
1844                #[cfg(test)]
1845                {
1846                    if trimmed.contains("\"Last Name\"") {
1847                        eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
1848                    }
1849                }
1850
1851                // Skip the closing quote and search backwards
1852                if pos > 0 {
1853                    pos -= 1;
1854                    while pos > 0 {
1855                        if bytes[pos] == b'"' {
1856                            // Check if it's not an escaped quote
1857                            if pos == 0 || bytes[pos - 1] != b'\\' {
1858                                found_start = Some(pos);
1859                                break;
1860                            }
1861                        }
1862                        pos -= 1;
1863                    }
1864                    // Check position 0 separately
1865                    if found_start.is_none() && bytes[0] == b'"' {
1866                        found_start = Some(0);
1867                    }
1868                }
1869
1870                if let Some(start) = found_start {
1871                    // Extract the full quoted identifier including quotes
1872                    let result = safe_slice_from(before_dot, start);
1873                    #[cfg(test)]
1874                    {
1875                        if trimmed.contains("\"Last Name\"") {
1876                            eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
1877                        }
1878                    }
1879                    Some(result)
1880                } else {
1881                    #[cfg(test)]
1882                    {
1883                        if trimmed.contains("\"Last Name\"") {
1884                            eprintln!("DEBUG: No opening quote found!");
1885                        }
1886                    }
1887                    None
1888                }
1889            } else {
1890                // Regular identifier - get the last word, handling parentheses
1891                // Strip all leading parentheses
1892                before_dot
1893                    .split_whitespace()
1894                    .last()
1895                    .map(|word| word.trim_start_matches('('))
1896            };
1897
1898            if let Some(col_name) = col_name {
1899                #[cfg(test)]
1900                {
1901                    if trimmed.contains("\"Last Name\"") {
1902                        eprintln!("DEBUG: col_name = '{col_name}'");
1903                    }
1904                }
1905
1906                // For quoted identifiers, keep the quotes, for regular identifiers check validity
1907                let is_valid = if col_name.starts_with('"') && col_name.ends_with('"') {
1908                    // Quoted identifier - always valid
1909                    true
1910                } else {
1911                    // Regular identifier - check if it's alphanumeric or underscore
1912                    col_name.chars().all(|c| c.is_alphanumeric() || c == '_')
1913                };
1914
1915                #[cfg(test)]
1916                {
1917                    if trimmed.contains("\"Last Name\"") {
1918                        eprintln!("DEBUG: is_valid = {is_valid}");
1919                    }
1920                }
1921
1922                if is_valid {
1923                    // We're in a method call context
1924                    // Check if there's a partial method name after the dot
1925                    let partial_method = if after_dot.is_empty() {
1926                        None
1927                    } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1928                        Some(after_dot.to_string())
1929                    } else {
1930                        None
1931                    };
1932
1933                    // For AfterColumn context, strip quotes if present for consistency
1934                    let col_name_for_context = if col_name.starts_with('"')
1935                        && col_name.ends_with('"')
1936                        && col_name.len() > 2
1937                    {
1938                        col_name[1..col_name.len() - 1].to_string()
1939                    } else {
1940                        col_name.to_string()
1941                    };
1942
1943                    return (
1944                        CursorContext::AfterColumn(col_name_for_context),
1945                        partial_method,
1946                    );
1947                }
1948            }
1949        }
1950    }
1951
1952    // Check if we're after AND/OR - but only after checking for method calls
1953    if let Some(and_pos) = upper.rfind(" AND ") {
1954        // Check if cursor is after AND
1955        if cursor_pos >= and_pos + 5 {
1956            // Extract any partial word after AND
1957            let after_and = safe_slice_from(query, and_pos + 5);
1958            let partial = extract_partial_at_end(after_and);
1959            return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
1960        }
1961    }
1962
1963    if let Some(or_pos) = upper.rfind(" OR ") {
1964        // Check if cursor is after OR
1965        if cursor_pos >= or_pos + 4 {
1966            // Extract any partial word after OR
1967            let after_or = safe_slice_from(query, or_pos + 4);
1968            let partial = extract_partial_at_end(after_or);
1969            return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
1970        }
1971    }
1972
1973    // Handle case where AND/OR is at the very end
1974    if trimmed.to_uppercase().ends_with(" AND") || trimmed.to_uppercase().ends_with(" OR") {
1975        let op = if trimmed.to_uppercase().ends_with(" AND") {
1976            LogicalOp::And
1977        } else {
1978            LogicalOp::Or
1979        };
1980        return (CursorContext::AfterLogicalOp(op), None);
1981    }
1982
1983    // Check if we're after ORDER BY
1984    if upper.ends_with(" ORDER BY ") || upper.ends_with(" ORDER BY") || upper.contains("ORDER BY ")
1985    {
1986        return (CursorContext::OrderByClause, extract_partial_at_end(query));
1987    }
1988
1989    if upper.contains("WHERE") && !upper.contains("ORDER") && !upper.contains("GROUP") {
1990        return (CursorContext::WhereClause, extract_partial_at_end(query));
1991    }
1992
1993    if upper.contains("FROM") && !upper.contains("WHERE") && !upper.contains("ORDER") {
1994        return (CursorContext::FromClause, extract_partial_at_end(query));
1995    }
1996
1997    if upper.contains("SELECT") && !upper.contains("FROM") {
1998        return (CursorContext::SelectClause, extract_partial_at_end(query));
1999    }
2000
2001    (CursorContext::Unknown, None)
2002}
2003
2004fn extract_partial_at_end(query: &str) -> Option<String> {
2005    let trimmed = query.trim();
2006
2007    // First check if the last word itself starts with a quote (unclosed quoted identifier being typed)
2008    if let Some(last_word) = trimmed.split_whitespace().last() {
2009        if last_word.starts_with('"') && !last_word.ends_with('"') {
2010            // This is an unclosed quoted identifier like "Cust
2011            return Some(last_word.to_string());
2012        }
2013    }
2014
2015    // Regular identifier extraction
2016    let last_word = trimmed.split_whitespace().last()?;
2017
2018    // Check if it's a partial identifier (not a keyword or operator)
2019    if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') && !is_sql_keyword(last_word) {
2020        Some(last_word.to_string())
2021    } else {
2022        None
2023    }
2024}
2025
2026// Implement the ParsePrimary trait for Parser to use the modular expression parsing
2027impl ParsePrimary for Parser {
2028    fn current_token(&self) -> &Token {
2029        &self.current_token
2030    }
2031
2032    fn advance(&mut self) {
2033        self.advance();
2034    }
2035
2036    fn consume(&mut self, expected: Token) -> Result<(), String> {
2037        self.consume(expected)
2038    }
2039
2040    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2041        self.parse_case_expression()
2042    }
2043
2044    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2045        self.parse_function_args()
2046    }
2047
2048    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2049        self.parse_window_spec()
2050    }
2051
2052    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2053        self.parse_logical_or()
2054    }
2055
2056    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2057        self.parse_comparison()
2058    }
2059
2060    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2061        self.parse_expression_list()
2062    }
2063
2064    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2065        // Parse subquery without parenthesis balance validation
2066        if matches!(self.current_token, Token::With) {
2067            self.parse_with_clause_inner()
2068        } else {
2069            self.parse_select_statement_inner()
2070        }
2071    }
2072}
2073
2074// Implement the ParseArithmetic trait for Parser to use the modular arithmetic parsing
2075impl ParseArithmetic for Parser {
2076    fn current_token(&self) -> &Token {
2077        &self.current_token
2078    }
2079
2080    fn advance(&mut self) {
2081        self.advance();
2082    }
2083
2084    fn consume(&mut self, expected: Token) -> Result<(), String> {
2085        self.consume(expected)
2086    }
2087
2088    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2089        self.parse_primary()
2090    }
2091
2092    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2093        self.parse_multiplicative()
2094    }
2095
2096    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2097        self.parse_method_args()
2098    }
2099}
2100
2101// Implement the ParseComparison trait for Parser to use the modular comparison parsing
2102impl ParseComparison for Parser {
2103    fn current_token(&self) -> &Token {
2104        &self.current_token
2105    }
2106
2107    fn advance(&mut self) {
2108        self.advance();
2109    }
2110
2111    fn consume(&mut self, expected: Token) -> Result<(), String> {
2112        self.consume(expected)
2113    }
2114
2115    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2116        self.parse_primary()
2117    }
2118
2119    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2120        self.parse_additive()
2121    }
2122
2123    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2124        self.parse_expression_list()
2125    }
2126
2127    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2128        // Parse subquery without parenthesis balance validation
2129        if matches!(self.current_token, Token::With) {
2130            self.parse_with_clause_inner()
2131        } else {
2132            self.parse_select_statement_inner()
2133        }
2134    }
2135}
2136
2137// Implement the ParseLogical trait for Parser to use the modular logical parsing
2138impl ParseLogical for Parser {
2139    fn current_token(&self) -> &Token {
2140        &self.current_token
2141    }
2142
2143    fn advance(&mut self) {
2144        self.advance();
2145    }
2146
2147    fn consume(&mut self, expected: Token) -> Result<(), String> {
2148        self.consume(expected)
2149    }
2150
2151    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2152        self.parse_logical_and()
2153    }
2154
2155    fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2156        // This is the base for logical AND - it should parse comparison expressions
2157        // to avoid infinite recursion with parse_expression
2158        self.parse_comparison()
2159    }
2160
2161    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2162        self.parse_comparison()
2163    }
2164
2165    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2166        self.parse_expression_list()
2167    }
2168}
2169
2170// Implement the ParseCase trait for Parser to use the modular CASE parsing
2171impl ParseCase for Parser {
2172    fn current_token(&self) -> &Token {
2173        &self.current_token
2174    }
2175
2176    fn advance(&mut self) {
2177        self.advance();
2178    }
2179
2180    fn consume(&mut self, expected: Token) -> Result<(), String> {
2181        self.consume(expected)
2182    }
2183
2184    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
2185        self.parse_expression()
2186    }
2187}
2188
2189fn is_sql_keyword(word: &str) -> bool {
2190    matches!(
2191        word.to_uppercase().as_str(),
2192        "SELECT"
2193            | "FROM"
2194            | "WHERE"
2195            | "AND"
2196            | "OR"
2197            | "IN"
2198            | "ORDER"
2199            | "BY"
2200            | "GROUP"
2201            | "HAVING"
2202            | "ASC"
2203            | "DESC"
2204            | "DISTINCT"
2205    )
2206}