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