Skip to main content

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, Comment, Condition, DataFormat, FileCTESpec, FrameBound, FrameUnit, HttpMethod,
6    IntoTable, JoinClause, JoinCondition, JoinOperator, JoinType, LogicalOp, OrderByColumn,
7    OrderByItem, PivotAggregate, SelectItem, SelectStatement, SetOperation, SingleJoinCondition,
8    SortDirection, SqlExpression, TableFunction, TableSource, WebCTESpec, WhenBranch, WhereClause,
9    WindowFrame, WindowSpec, CTE,
10};
11pub use super::parser::legacy::{ParseContext, ParseState, Schema, SqlParser, SqlToken, TableInfo};
12pub use super::parser::lexer::{Lexer, LexerMode, Token};
13pub use super::parser::ParserConfig;
14
15// Re-export formatting functions for backward compatibility
16pub use super::parser::formatter::{format_ast_tree, format_sql_pretty, format_sql_pretty_compact};
17
18// New AST-based formatter
19pub use super::parser::ast_formatter::{format_sql_ast, format_sql_ast_with_config, FormatConfig};
20
21// Import the new expression modules
22use super::parser::expressions::arithmetic::{
23    parse_additive as parse_additive_expr, parse_multiplicative as parse_multiplicative_expr,
24    ParseArithmetic,
25};
26use super::parser::expressions::case::{parse_case_expression as parse_case_expr, ParseCase};
27use super::parser::expressions::comparison::{
28    parse_comparison as parse_comparison_expr, parse_in_operator, ParseComparison,
29};
30use super::parser::expressions::logical::{
31    parse_logical_and as parse_logical_and_expr, parse_logical_or as parse_logical_or_expr,
32    ParseLogical,
33};
34use super::parser::expressions::primary::{
35    parse_primary as parse_primary_expr, ParsePrimary, PrimaryExpressionContext,
36};
37use super::parser::expressions::ExpressionParser;
38
39// Import function registry to check for function existence
40use crate::sql::functions::{FunctionCategory, FunctionRegistry};
41use crate::sql::generators::GeneratorRegistry;
42use std::sync::Arc;
43
44// Import Web CTE parser
45use super::parser::file_cte_parser::FileCteParser;
46use super::parser::web_cte_parser::WebCteParser;
47
48/// Parser mode - controls whether comments are preserved in AST
49#[derive(Debug, Clone, Copy, PartialEq)]
50pub enum ParserMode {
51    /// Standard parsing - skip comments (current behavior, backward compatible)
52    Standard,
53    /// Preserve comments in AST (opt-in for formatters)
54    PreserveComments,
55}
56
57impl Default for ParserMode {
58    fn default() -> Self {
59        ParserMode::Standard
60    }
61}
62
63pub struct Parser {
64    lexer: Lexer,
65    pub current_token: Token,    // Made public for web_cte_parser access
66    in_method_args: bool,        // Track if we're parsing method arguments
67    columns: Vec<String>,        // Known column names for context-aware parsing
68    paren_depth: i32,            // Track parentheses nesting depth
69    paren_depth_stack: Vec<i32>, // Stack to save/restore paren depth for nested contexts
70    _config: ParserConfig,       // Parser configuration including case sensitivity
71    debug_trace: bool,           // Enable detailed token-by-token trace
72    trace_depth: usize,          // Track recursion depth for indented trace
73    function_registry: Arc<FunctionRegistry>, // Function registry for validation
74    generator_registry: Arc<GeneratorRegistry>, // Generator registry for table functions
75    mode: ParserMode,            // Parser mode for comment preservation
76}
77
78impl Parser {
79    #[must_use]
80    pub fn new(input: &str) -> Self {
81        Self::with_mode(input, ParserMode::default())
82    }
83
84    /// Create a new parser with explicit mode for comment preservation
85    #[must_use]
86    pub fn with_mode(input: &str, mode: ParserMode) -> Self {
87        // Choose lexer mode based on parser mode
88        let lexer_mode = match mode {
89            ParserMode::Standard => LexerMode::SkipComments,
90            ParserMode::PreserveComments => LexerMode::PreserveComments,
91        };
92
93        let mut lexer = Lexer::with_mode(input, lexer_mode);
94        let current_token = lexer.next_token();
95        Self {
96            lexer,
97            current_token,
98            in_method_args: false,
99            columns: Vec::new(),
100            paren_depth: 0,
101            paren_depth_stack: Vec::new(),
102            _config: ParserConfig::default(),
103            debug_trace: false,
104            trace_depth: 0,
105            function_registry: Arc::new(FunctionRegistry::new()),
106            generator_registry: Arc::new(GeneratorRegistry::new()),
107            mode,
108        }
109    }
110
111    #[must_use]
112    pub fn with_config(input: &str, config: ParserConfig) -> Self {
113        let mut lexer = Lexer::new(input);
114        let current_token = lexer.next_token();
115        Self {
116            lexer,
117            current_token,
118            in_method_args: false,
119            columns: Vec::new(),
120            paren_depth: 0,
121            paren_depth_stack: Vec::new(),
122            _config: config,
123            debug_trace: false,
124            trace_depth: 0,
125            function_registry: Arc::new(FunctionRegistry::new()),
126            generator_registry: Arc::new(GeneratorRegistry::new()),
127            mode: ParserMode::default(),
128        }
129    }
130
131    #[must_use]
132    pub fn with_columns(mut self, columns: Vec<String>) -> Self {
133        self.columns = columns;
134        self
135    }
136
137    #[must_use]
138    pub fn with_debug_trace(mut self, enabled: bool) -> Self {
139        self.debug_trace = enabled;
140        self
141    }
142
143    #[must_use]
144    pub fn with_function_registry(mut self, registry: Arc<FunctionRegistry>) -> Self {
145        self.function_registry = registry;
146        self
147    }
148
149    #[must_use]
150    pub fn with_generator_registry(mut self, registry: Arc<GeneratorRegistry>) -> Self {
151        self.generator_registry = registry;
152        self
153    }
154
155    fn trace_enter(&mut self, context: &str) {
156        if self.debug_trace {
157            let indent = "  ".repeat(self.trace_depth);
158            eprintln!("{}→ {} | Token: {:?}", indent, context, self.current_token);
159            self.trace_depth += 1;
160        }
161    }
162
163    fn trace_exit(&mut self, context: &str, result: &Result<impl std::fmt::Debug, String>) {
164        if self.debug_trace {
165            self.trace_depth = self.trace_depth.saturating_sub(1);
166            let indent = "  ".repeat(self.trace_depth);
167            match result {
168                Ok(val) => eprintln!("{}← {} ✓ | Result: {:?}", indent, context, val),
169                Err(e) => eprintln!("{}← {} ✗ | Error: {}", indent, context, e),
170            }
171        }
172    }
173
174    fn trace_token(&self, action: &str) {
175        if self.debug_trace {
176            let indent = "  ".repeat(self.trace_depth);
177            eprintln!("{}  {} | Token: {:?}", indent, action, self.current_token);
178        }
179    }
180
181    #[allow(dead_code)]
182    fn peek_token(&self) -> Option<Token> {
183        // Alternative peek that returns owned token
184        let mut temp_lexer = self.lexer.clone();
185        let next_token = temp_lexer.next_token();
186        if matches!(next_token, Token::Eof) {
187            None
188        } else {
189            Some(next_token)
190        }
191    }
192
193    /// Check if current token is one of the reserved keywords that should stop parsing
194    /// Check if an identifier string is a reserved keyword (for backward compatibility)
195    /// This is used when the lexer hasn't properly tokenized keywords and they come through
196    /// as Token::Identifier instead of their proper token types
197    fn is_identifier_reserved(id: &str) -> bool {
198        let id_upper = id.to_uppercase();
199        matches!(
200            id_upper.as_str(),
201            "ORDER" | "HAVING" | "LIMIT" | "OFFSET" | "UNION" | "INTERSECT" | "EXCEPT"
202        )
203    }
204
205    /// Get comparison operator string representation (for autocomplete context)
206    const COMPARISON_OPERATORS: [&'static str; 6] = [" > ", " < ", " >= ", " <= ", " = ", " != "];
207
208    pub fn consume(&mut self, expected: Token) -> Result<(), String> {
209        self.trace_token(&format!("Consuming expected {:?}", expected));
210        if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
211            // Track parentheses depth
212            self.update_paren_depth(&expected)?;
213
214            self.current_token = self.lexer.next_token();
215            Ok(())
216        } else {
217            // Provide better error messages for common cases
218            let error_msg = match (&expected, &self.current_token) {
219                (Token::RightParen, Token::Eof) if self.paren_depth > 0 => {
220                    format!(
221                        "Unclosed parenthesis - missing {} closing parenthes{}",
222                        self.paren_depth,
223                        if self.paren_depth == 1 { "is" } else { "es" }
224                    )
225                }
226                (Token::RightParen, _) if self.paren_depth > 0 => {
227                    format!(
228                        "Expected closing parenthesis but found {:?} (currently {} unclosed parenthes{})",
229                        self.current_token,
230                        self.paren_depth,
231                        if self.paren_depth == 1 { "is" } else { "es" }
232                    )
233                }
234                _ => format!("Expected {:?}, found {:?}", expected, self.current_token),
235            };
236            Err(error_msg)
237        }
238    }
239
240    pub fn advance(&mut self) {
241        // Track parentheses depth when advancing
242        match &self.current_token {
243            Token::LeftParen => self.paren_depth += 1,
244            Token::RightParen => {
245                self.paren_depth -= 1;
246                // Note: We don't check for < 0 here because advance() is used
247                // in contexts where we're not necessarily expecting a right paren
248            }
249            _ => {}
250        }
251        let old_token = self.current_token.clone();
252        self.current_token = self.lexer.next_token();
253        if self.debug_trace {
254            let indent = "  ".repeat(self.trace_depth);
255            eprintln!(
256                "{}  Advanced: {:?} → {:?}",
257                indent, old_token, self.current_token
258            );
259        }
260    }
261
262    /// Collect all leading comments before a SQL construct
263    /// This consumes comment tokens and returns them as a Vec<Comment>
264    fn collect_leading_comments(&mut self) -> Vec<Comment> {
265        let mut comments = Vec::new();
266        loop {
267            match &self.current_token {
268                Token::LineComment(text) => {
269                    comments.push(Comment::line(text.clone()));
270                    self.advance();
271                }
272                Token::BlockComment(text) => {
273                    comments.push(Comment::block(text.clone()));
274                    self.advance();
275                }
276                _ => break,
277            }
278        }
279        comments
280    }
281
282    /// Collect a trailing inline comment (on the same line)
283    /// This consumes a single comment token if present
284    fn collect_trailing_comment(&mut self) -> Option<Comment> {
285        match &self.current_token {
286            Token::LineComment(text) => {
287                let comment = Some(Comment::line(text.clone()));
288                self.advance();
289                comment
290            }
291            Token::BlockComment(text) => {
292                let comment = Some(Comment::block(text.clone()));
293                self.advance();
294                comment
295            }
296            _ => None,
297        }
298    }
299
300    fn push_paren_depth(&mut self) {
301        self.paren_depth_stack.push(self.paren_depth);
302        self.paren_depth = 0;
303    }
304
305    fn pop_paren_depth(&mut self) {
306        if let Some(depth) = self.paren_depth_stack.pop() {
307            // Ignore the internal depth - just restore the saved value
308            self.paren_depth = depth;
309        }
310    }
311
312    pub fn parse(&mut self) -> Result<SelectStatement, String> {
313        self.trace_enter("parse");
314
315        // Collect leading comments FIRST (before checking for WITH or SELECT)
316        // This allows comments before WITH clauses to be preserved
317        let leading_comments = if self.mode == ParserMode::PreserveComments {
318            self.collect_leading_comments()
319        } else {
320            vec![]
321        };
322
323        // Now check for WITH clause (after consuming comments)
324        let result = if matches!(self.current_token, Token::With) {
325            let mut stmt = self.parse_with_clause()?;
326            // Attach the leading comments we collected
327            stmt.leading_comments = leading_comments;
328            stmt
329        } else {
330            // For SELECT without WITH, pass comments to inner parser
331            let stmt = self.parse_select_statement_with_comments_public(leading_comments)?;
332            self.check_balanced_parentheses()?;
333            stmt
334        };
335
336        self.expect_end_of_statement()?;
337
338        self.trace_exit("parse", &Ok(&result));
339        Ok(result)
340    }
341
342    /// Require that the whole input was consumed.
343    ///
344    /// Without this the parser stops at the first token it cannot place and
345    /// **silently ignores the rest of the statement** — so `ORDER BY x FROBNICATE
346    /// LIMIT 3` ran clean and dropped the LIMIT, and any typo or unsupported
347    /// clause quietly became a different query that succeeded (P13).
348    ///
349    /// A single trailing `;` is accepted: it terminates a statement rather than
350    /// being part of one. Script batches are already split on `GO` and have their
351    /// `;` stripped before reaching here, so this is for the `-q` path and for
352    /// anyone who ends a query out of habit.
353    fn expect_end_of_statement(&mut self) -> Result<(), String> {
354        if matches!(self.current_token, Token::Semicolon) {
355            self.advance();
356        }
357
358        // Trailing comments are content, not leftovers.
359        while matches!(
360            self.current_token,
361            Token::LineComment(_) | Token::BlockComment(_)
362        ) {
363            self.advance();
364        }
365
366        if matches!(self.current_token, Token::Eof) {
367            return Ok(());
368        }
369
370        Err(format!(
371            "Unexpected {} after end of statement (at position {}). \
372             The rest of the query would be ignored.",
373            describe_token(&self.current_token),
374            self.get_position()
375        ))
376    }
377
378    /// Public wrapper that accepts pre-collected comments and checks parens
379    fn parse_select_statement_with_comments_public(
380        &mut self,
381        comments: Vec<Comment>,
382    ) -> Result<SelectStatement, String> {
383        self.parse_select_statement_with_comments(comments)
384    }
385
386    fn parse_with_clause(&mut self) -> Result<SelectStatement, String> {
387        self.consume(Token::With)?;
388        let ctes = self.parse_cte_list()?;
389
390        // Parse the main SELECT statement - use inner version since we're already tracking parens
391        let mut main_query = self.parse_select_statement_inner_no_comments()?;
392        main_query.ctes = ctes;
393
394        // Check for balanced parentheses at the end of parsing
395        self.check_balanced_parentheses()?;
396
397        Ok(main_query)
398    }
399
400    fn parse_with_clause_inner(&mut self) -> Result<SelectStatement, String> {
401        self.consume(Token::With)?;
402        let ctes = self.parse_cte_list()?;
403
404        // Parse the main SELECT statement (without parenthesis checking for subqueries)
405        let mut main_query = self.parse_select_statement_inner()?;
406        main_query.ctes = ctes;
407
408        Ok(main_query)
409    }
410
411    // Helper function to parse CTE list - eliminates duplication
412    fn parse_cte_list(&mut self) -> Result<Vec<CTE>, String> {
413        let mut ctes = Vec::new();
414
415        // Parse CTEs
416        loop {
417            // Check for WEB keyword before the CTE name (WEB uses an outer marker).
418            // FILE CTEs are detected *inside* the parens after AS, since the design
419            // doc uses `WITH name AS (FILE PATH '...')` rather than `WITH FILE name ...`.
420            let is_web = if matches!(&self.current_token, Token::Web) {
421                self.trace_token("Found WEB keyword for CTE");
422                self.advance();
423                true
424            } else {
425                false
426            };
427
428            // Parse CTE name - allow keywords as CTE names since they're valid identifiers in this context
429            let name = match &self.current_token {
430                Token::Identifier(name) => name.clone(),
431                token => {
432                    // Check if this is a keyword that can be used as an identifier
433                    if let Some(keyword) = token.as_keyword_str() {
434                        // Allow keywords as CTE names (they're valid in this context)
435                        keyword.to_lowercase()
436                    } else {
437                        return Err(format!(
438                            "Expected CTE name after {}",
439                            if is_web { "WEB" } else { "WITH or comma" }
440                        ));
441                    }
442                }
443            };
444            self.advance();
445
446            // Optional column list: WITH t(col1, col2) AS ...
447            let column_list = if matches!(self.current_token, Token::LeftParen) {
448                self.advance();
449                let cols = self.parse_identifier_list()?;
450                self.consume(Token::RightParen)?;
451                Some(cols)
452            } else {
453                None
454            };
455
456            // Expect AS
457            self.consume(Token::As)?;
458
459            let cte_type = if is_web {
460                // Expect opening parenthesis for WEB CTE
461                self.consume(Token::LeftParen)?;
462                // Parse WEB CTE specification using dedicated parser
463                let web_spec = WebCteParser::parse(self)?;
464                // Consume closing parenthesis for WEB CTE
465                self.consume(Token::RightParen)?;
466                CTEType::Web(web_spec)
467            } else {
468                // Push depth BEFORE consuming the opening paren, matching the
469                // original standard-CTE flow. This keeps the `(`...`)` pair
470                // balanced inside the inner context.
471                self.push_paren_depth();
472                self.consume(Token::LeftParen)?;
473
474                let result = if matches!(&self.current_token, Token::File) {
475                    self.trace_token("Found FILE keyword inside CTE parens");
476                    self.advance();
477                    let file_spec = FileCteParser::parse(self)?;
478                    CTEType::File(file_spec)
479                } else {
480                    let query = self.parse_select_statement_inner()?;
481                    CTEType::Standard(query)
482                };
483
484                // Expect closing parenthesis while still in CTE context
485                self.consume(Token::RightParen)?;
486                // Now pop to restore outer depth after consuming both parens
487                self.pop_paren_depth();
488                result
489            };
490
491            ctes.push(CTE {
492                name,
493                column_list,
494                cte_type,
495            });
496
497            // Check for more CTEs
498            if !matches!(self.current_token, Token::Comma) {
499                break;
500            }
501            self.advance();
502        }
503
504        Ok(ctes)
505    }
506
507    /// Helper function to parse an optional table alias (with or without AS keyword)
508    fn parse_optional_alias(&mut self) -> Result<Option<String>, String> {
509        if matches!(self.current_token, Token::As) {
510            self.advance();
511            match &self.current_token {
512                Token::Identifier(name) => {
513                    let alias = name.clone();
514                    self.advance();
515                    Ok(Some(alias))
516                }
517                token => {
518                    // Check if it's a reserved keyword - provide helpful error
519                    if let Some(keyword) = token.as_keyword_str() {
520                        Err(format!(
521                            "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
522                            keyword,
523                            keyword.to_lowercase()
524                        ))
525                    } else {
526                        Err("Expected alias name after AS".to_string())
527                    }
528                }
529            }
530        } else if let Token::Identifier(name) = &self.current_token {
531            // AS is optional for table aliases
532            let alias = name.clone();
533            self.advance();
534            Ok(Some(alias))
535        } else {
536            Ok(None)
537        }
538    }
539
540    /// Helper function to check if an identifier is valid (quoted or regular)
541    fn is_valid_identifier(name: &str) -> bool {
542        if name.starts_with('"') && name.ends_with('"') {
543            // Quoted identifier - always valid
544            true
545        } else {
546            // Regular identifier - check if it's alphanumeric or underscore
547            name.chars().all(|c| c.is_alphanumeric() || c == '_')
548        }
549    }
550
551    /// Helper function to update parentheses depth tracking
552    fn update_paren_depth(&mut self, token: &Token) -> Result<(), String> {
553        match token {
554            Token::LeftParen => self.paren_depth += 1,
555            Token::RightParen => {
556                self.paren_depth -= 1;
557                // Check for extra closing parenthesis
558                if self.paren_depth < 0 {
559                    return Err(
560                        "Unexpected closing parenthesis - no matching opening parenthesis"
561                            .to_string(),
562                    );
563                }
564            }
565            _ => {}
566        }
567        Ok(())
568    }
569
570    /// Helper function to parse comma-separated argument list
571    fn parse_argument_list(&mut self) -> Result<Vec<SqlExpression>, String> {
572        let mut args = Vec::new();
573
574        if !matches!(self.current_token, Token::RightParen) {
575            loop {
576                args.push(self.parse_expression()?);
577
578                if matches!(self.current_token, Token::Comma) {
579                    self.advance();
580                } else {
581                    break;
582                }
583            }
584        }
585
586        Ok(args)
587    }
588
589    /// Helper function to check for balanced parentheses at the end of parsing
590    fn check_balanced_parentheses(&self) -> Result<(), String> {
591        if self.paren_depth > 0 {
592            Err(format!(
593                "Unclosed parenthesis - missing {} closing parenthes{}",
594                self.paren_depth,
595                if self.paren_depth == 1 { "is" } else { "es" }
596            ))
597        } else if self.paren_depth < 0 {
598            Err("Extra closing parenthesis found - no matching opening parenthesis".to_string())
599        } else {
600            Ok(())
601        }
602    }
603
604    /// Check if an expression contains aggregate functions (COUNT, SUM, AVG, etc.)
605    /// This is used to detect unsupported patterns in HAVING clause
606    fn contains_aggregate_function(expr: &SqlExpression) -> bool {
607        match expr {
608            SqlExpression::FunctionCall { name, args, .. } => {
609                // Check if this is an aggregate function
610                let upper_name = name.to_uppercase();
611                let is_aggregate = matches!(
612                    upper_name.as_str(),
613                    "COUNT" | "SUM" | "AVG" | "MIN" | "MAX" | "GROUP_CONCAT" | "STRING_AGG"
614                );
615
616                // If this is an aggregate, return true
617                // Otherwise, recursively check arguments
618                is_aggregate || args.iter().any(Self::contains_aggregate_function)
619            }
620            // Recursively check nested expressions
621            SqlExpression::BinaryOp { left, right, .. } => {
622                Self::contains_aggregate_function(left) || Self::contains_aggregate_function(right)
623            }
624            SqlExpression::Not { expr } => Self::contains_aggregate_function(expr),
625            SqlExpression::MethodCall { args, .. } => {
626                args.iter().any(Self::contains_aggregate_function)
627            }
628            SqlExpression::ChainedMethodCall { base, args, .. } => {
629                Self::contains_aggregate_function(base)
630                    || args.iter().any(Self::contains_aggregate_function)
631            }
632            SqlExpression::CaseExpression {
633                when_branches,
634                else_branch,
635            } => {
636                when_branches.iter().any(|branch| {
637                    Self::contains_aggregate_function(&branch.condition)
638                        || Self::contains_aggregate_function(&branch.result)
639                }) || else_branch
640                    .as_ref()
641                    .map_or(false, |e| Self::contains_aggregate_function(e))
642            }
643            SqlExpression::SimpleCaseExpression {
644                expr,
645                when_branches,
646                else_branch,
647            } => {
648                Self::contains_aggregate_function(expr)
649                    || when_branches.iter().any(|branch| {
650                        Self::contains_aggregate_function(&branch.value)
651                            || Self::contains_aggregate_function(&branch.result)
652                    })
653                    || else_branch
654                        .as_ref()
655                        .map_or(false, |e| Self::contains_aggregate_function(e))
656            }
657            SqlExpression::ScalarSubquery { query } => {
658                // Subqueries can have their own aggregates, but that's fine
659                // We're only checking the outer HAVING clause
660                query
661                    .having
662                    .as_ref()
663                    .map_or(false, |h| Self::contains_aggregate_function(h))
664            }
665            // Leaf nodes - no aggregates
666            SqlExpression::Column(_)
667            | SqlExpression::StringLiteral(_)
668            | SqlExpression::NumberLiteral(_)
669            | SqlExpression::BooleanLiteral(_)
670            | SqlExpression::Null
671            | SqlExpression::DateTimeConstructor { .. }
672            | SqlExpression::DateTimeToday { .. } => false,
673
674            // Window functions contain aggregates by definition
675            SqlExpression::WindowFunction { .. } => true,
676
677            // Between has three parts to check
678            SqlExpression::Between { expr, lower, upper } => {
679                Self::contains_aggregate_function(expr)
680                    || Self::contains_aggregate_function(lower)
681                    || Self::contains_aggregate_function(upper)
682            }
683
684            // IN list - check expr and all values
685            SqlExpression::InList { expr, values } | SqlExpression::NotInList { expr, values } => {
686                Self::contains_aggregate_function(expr)
687                    || values.iter().any(Self::contains_aggregate_function)
688            }
689
690            // IN subquery - check expr and subquery
691            SqlExpression::InSubquery { expr, subquery }
692            | SqlExpression::NotInSubquery { expr, subquery } => {
693                Self::contains_aggregate_function(expr)
694                    || subquery
695                        .having
696                        .as_ref()
697                        .map_or(false, |h| Self::contains_aggregate_function(h))
698            }
699
700            // Tuple IN/NOT IN subquery - check each expr and subquery
701            SqlExpression::InSubqueryTuple { exprs, subquery }
702            | SqlExpression::NotInSubqueryTuple { exprs, subquery } => {
703                exprs.iter().any(Self::contains_aggregate_function)
704                    || subquery
705                        .having
706                        .as_ref()
707                        .map_or(false, |h| Self::contains_aggregate_function(h))
708            }
709
710            // UNNEST - check column expression
711            SqlExpression::Unnest { column, .. } => Self::contains_aggregate_function(column),
712        }
713    }
714
715    fn parse_select_statement(&mut self) -> Result<SelectStatement, String> {
716        self.trace_enter("parse_select_statement");
717        let result = self.parse_select_statement_inner()?;
718
719        // Check for balanced parentheses at the end of parsing
720        self.check_balanced_parentheses()?;
721
722        Ok(result)
723    }
724
725    fn parse_select_statement_inner(&mut self) -> Result<SelectStatement, String> {
726        // Collect leading comments ONLY in PreserveComments mode
727        let leading_comments = if self.mode == ParserMode::PreserveComments {
728            self.collect_leading_comments()
729        } else {
730            vec![]
731        };
732
733        self.parse_select_statement_with_comments(leading_comments)
734    }
735
736    /// Parse SELECT statement without collecting leading comments
737    /// Used when comments were already collected (e.g., before WITH clause)
738    fn parse_select_statement_inner_no_comments(&mut self) -> Result<SelectStatement, String> {
739        self.parse_select_statement_with_comments(vec![])
740    }
741
742    /// Core SELECT parsing logic - takes pre-collected comments
743    fn parse_select_statement_with_comments(
744        &mut self,
745        leading_comments: Vec<Comment>,
746    ) -> Result<SelectStatement, String> {
747        self.consume(Token::Select)?;
748
749        // Check for DISTINCT keyword
750        let distinct = if matches!(self.current_token, Token::Distinct) {
751            self.advance();
752            true
753        } else {
754            false
755        };
756
757        // Parse SELECT items (supports computed expressions)
758        let select_items = self.parse_select_items()?;
759
760        // Create legacy columns vector for backward compatibility
761        let columns = select_items
762            .iter()
763            .map(|item| match item {
764                SelectItem::Star { .. } => "*".to_string(),
765                SelectItem::StarExclude { .. } => "*".to_string(), // Treated as * in legacy columns
766                SelectItem::Column {
767                    column: col_ref, ..
768                } => col_ref.name.clone(),
769                SelectItem::Expression { alias, .. } => alias.clone(),
770            })
771            .collect();
772
773        // Parse INTO clause (for temporary tables) - comes immediately after SELECT items
774        let into_table = if matches!(self.current_token, Token::Into) {
775            self.advance();
776            Some(self.parse_into_clause()?)
777        } else {
778            None
779        };
780
781        // Parse FROM clause - can be a table name, subquery, or table function
782        let (from_table, from_subquery, from_function, from_alias) = if matches!(
783            self.current_token,
784            Token::From
785        ) {
786            self.advance();
787
788            // Check for table function like RANGE()
789            // Also handle keywords that could be table/CTE names
790            let table_or_function_name = match &self.current_token {
791                Token::Identifier(name) => Some(name.clone()),
792                token => {
793                    // Check if it's a keyword that can be used as table/CTE name
794                    token.as_keyword_str().map(|k| k.to_lowercase())
795                }
796            };
797
798            if let Some(name) = table_or_function_name {
799                // Check if this is a table function by consulting the registry
800                // We need to lookahead to see if there's a parenthesis to distinguish
801                // between a function call and a table with the same name
802                let has_paren = self.peek_token() == Some(Token::LeftParen);
803                if self.debug_trace {
804                    eprintln!(
805                        "  Checking {} for table function, has_paren={}",
806                        name, has_paren
807                    );
808                }
809
810                // Check if it's a known table function or generator
811                // In FROM clause context, prioritize generators over scalar functions
812                let is_table_function = if has_paren {
813                    // First check generator registry (for FROM clause context)
814                    if self.debug_trace {
815                        eprintln!("  Checking generator registry for {}", name.to_uppercase());
816                    }
817                    if let Some(_gen) = self.generator_registry.get(&name.to_uppercase()) {
818                        if self.debug_trace {
819                            eprintln!("  Found {} in generator registry", name);
820                        }
821                        self.trace_token(&format!("Found generator: {}", name));
822                        true
823                    } else {
824                        // Then check if it's a table function in the function registry
825                        if let Some(func) = self.function_registry.get(&name.to_uppercase()) {
826                            let sig = func.signature();
827                            let is_table_fn = sig.category == FunctionCategory::TableFunction;
828                            if self.debug_trace {
829                                eprintln!(
830                                    "  Found {} in function registry, is_table_function={}",
831                                    name, is_table_fn
832                                );
833                            }
834                            if is_table_fn {
835                                self.trace_token(&format!(
836                                    "Found table function in function registry: {}",
837                                    name
838                                ));
839                            }
840                            is_table_fn
841                        } else {
842                            if self.debug_trace {
843                                eprintln!("  {} not found in either registry", name);
844                                self.trace_token(&format!(
845                                    "Not found as generator or table function: {}",
846                                    name
847                                ));
848                            }
849                            // `name(` in a FROM clause is unambiguously a table
850                            // function call (table/CTE names are never followed
851                            // by parens). If we don't recognise it, erroring here
852                            // beats silently treating `name` as a missing table
853                            // and degrading to the DUAL placeholder row.
854                            return Err(format!(
855                                "Unknown table function '{}'. Run --list-functions to see available table functions (e.g. READ_CSV, READ_JSON, READ_JSONL, RANGE).",
856                                name
857                            ));
858                        }
859                    }
860                } else {
861                    if self.debug_trace {
862                        eprintln!("  No parenthesis after {}, treating as table", name);
863                    }
864                    false
865                };
866
867                if is_table_function {
868                    // Parse table function
869                    let function_name = name.clone();
870                    self.advance(); // Skip function name
871
872                    // Parse arguments
873                    self.consume(Token::LeftParen)?;
874                    let args = self.parse_argument_list()?;
875                    self.consume(Token::RightParen)?;
876
877                    // Optional alias
878                    let alias = if matches!(self.current_token, Token::As) {
879                        self.advance();
880                        match &self.current_token {
881                            Token::Identifier(name) => {
882                                let alias = name.clone();
883                                self.advance();
884                                Some(alias)
885                            }
886                            token => {
887                                if let Some(keyword) = token.as_keyword_str() {
888                                    return Err(format!(
889                                            "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
890                                            keyword,
891                                            keyword.to_lowercase()
892                                        ));
893                                } else {
894                                    return Err("Expected alias name after AS".to_string());
895                                }
896                            }
897                        }
898                    } else if let Token::Identifier(name) = &self.current_token {
899                        let alias = name.clone();
900                        self.advance();
901                        Some(alias)
902                    } else {
903                        None
904                    };
905
906                    (
907                        None,
908                        None,
909                        Some(TableFunction::Generator {
910                            name: function_name,
911                            args,
912                        }),
913                        alias,
914                    )
915                } else {
916                    // Not a RANGE, SPLIT, or generator function, so it's a regular table name
917                    let table_name = name.clone();
918                    self.advance();
919
920                    // Check for optional alias
921                    let alias = self.parse_optional_alias()?;
922
923                    (Some(table_name), None, None, alias)
924                }
925            } else if matches!(self.current_token, Token::LeftParen) {
926                // Check for subquery: FROM (SELECT ...) or FROM (WITH ... SELECT ...)
927                self.advance();
928
929                // Parse the subquery - it might start with WITH
930                let subquery = if matches!(self.current_token, Token::With) {
931                    self.parse_with_clause_inner()?
932                } else {
933                    self.parse_select_statement_inner()?
934                };
935
936                self.consume(Token::RightParen)?;
937
938                // Subqueries must have an alias
939                let alias = if matches!(self.current_token, Token::As) {
940                    self.advance();
941                    match &self.current_token {
942                        Token::Identifier(name) => {
943                            let alias = name.clone();
944                            self.advance();
945                            alias
946                        }
947                        token => {
948                            if let Some(keyword) = token.as_keyword_str() {
949                                return Err(format!(
950                                        "Reserved keyword '{}' cannot be used as subquery alias. Use a different name or quote it with double quotes: \"{}\"",
951                                        keyword,
952                                        keyword.to_lowercase()
953                                    ));
954                            } else {
955                                return Err("Expected alias name after AS".to_string());
956                            }
957                        }
958                    }
959                } else {
960                    // AS is optional, but alias is required
961                    match &self.current_token {
962                        Token::Identifier(name) => {
963                            let alias = name.clone();
964                            self.advance();
965                            alias
966                        }
967                        _ => {
968                            return Err(
969                                "Subquery in FROM must have an alias (e.g., AS t)".to_string()
970                            )
971                        }
972                    }
973                };
974
975                (None, Some(Box::new(subquery)), None, Some(alias))
976            } else {
977                // Regular table name - handle identifiers and keywords
978                let table_name = match &self.current_token {
979                    Token::Identifier(table) => table.clone(),
980                    Token::QuotedIdentifier(table) => table.clone(),
981                    token => {
982                        // Check if it's a keyword that can be used as table/CTE name
983                        if let Some(keyword) = token.as_keyword_str() {
984                            keyword.to_lowercase()
985                        } else {
986                            return Err("Expected table name or subquery after FROM".to_string());
987                        }
988                    }
989                };
990
991                self.advance();
992
993                // Check for optional alias
994                let alias = self.parse_optional_alias()?;
995
996                (Some(table_name), None, None, alias)
997            }
998        } else {
999            (None, None, None, None)
1000        };
1001
1002        // Check for PIVOT after FROM table source
1003        // PIVOT wraps the FROM table/subquery before JOINs are processed
1004        // This creates a PIVOT TableSource that will be processed by PivotExpander transformer
1005        let pivot_source = if matches!(self.current_token, Token::Pivot) {
1006            // Build a TableSource from the current FROM clause
1007            let source = if let Some(ref table_name) = from_table {
1008                TableSource::Table(table_name.clone())
1009            } else if let Some(ref subquery) = from_subquery {
1010                TableSource::DerivedTable {
1011                    query: subquery.clone(),
1012                    alias: from_alias.clone().unwrap_or_default(),
1013                }
1014            } else {
1015                return Err("PIVOT requires a table or subquery source".to_string());
1016            };
1017
1018            // Parse the PIVOT clause - this wraps the source in a Pivot TableSource
1019            let pivoted = self.parse_pivot_clause(source)?;
1020            Some(pivoted)
1021        } else {
1022            None
1023        };
1024
1025        // Parse JOIN clauses
1026        let mut joins = Vec::new();
1027        while self.is_join_token() {
1028            joins.push(self.parse_join_clause()?);
1029        }
1030
1031        let where_clause = if matches!(self.current_token, Token::Where) {
1032            self.advance();
1033            Some(self.parse_where_clause()?)
1034        } else {
1035            None
1036        };
1037
1038        let group_by = if matches!(self.current_token, Token::GroupBy) {
1039            self.advance();
1040            // Parse expressions instead of just identifiers for GROUP BY
1041            // This allows GROUP BY TIME_BUCKET(...), CASE ..., etc.
1042            Some(self.parse_expression_list()?)
1043        } else {
1044            None
1045        };
1046
1047        // Parse HAVING clause (must come after GROUP BY)
1048        let having = if matches!(self.current_token, Token::Having) {
1049            if group_by.is_none() {
1050                return Err("HAVING clause requires GROUP BY".to_string());
1051            }
1052            self.advance();
1053            let having_expr = self.parse_expression()?;
1054
1055            // Note: Aggregate functions in HAVING are now supported via the
1056            // HavingAliasTransformer preprocessing step, which automatically
1057            // adds aliases and rewrites the HAVING clause to use them.
1058
1059            Some(having_expr)
1060        } else {
1061            None
1062        };
1063
1064        // Parse QUALIFY clause (Snowflake-style window function filtering)
1065        // QUALIFY filters on window function results without needing a subquery
1066        // Example: SELECT *, ROW_NUMBER() OVER (...) AS rn FROM t QUALIFY rn <= 3
1067        let qualify = if matches!(self.current_token, Token::Qualify) {
1068            self.advance();
1069            let qualify_expr = self.parse_expression()?;
1070
1071            // Note: QUALIFY is handled by the QualifyToWhereTransformer preprocessing step
1072            // which converts it to WHERE after window functions are lifted to CTEs
1073
1074            Some(qualify_expr)
1075        } else {
1076            None
1077        };
1078
1079        // Parse ORDER BY clause (comes after GROUP BY, HAVING, and QUALIFY)
1080        let order_by = if matches!(self.current_token, Token::OrderBy) {
1081            self.trace_token("Found OrderBy token");
1082            self.advance();
1083            Some(self.parse_order_by_list()?)
1084        } else if let Token::Identifier(s) = &self.current_token {
1085            // This shouldn't happen if the lexer properly tokenizes ORDER BY
1086            // But keeping as fallback for compatibility
1087            if Self::is_identifier_reserved(s) && s.to_uppercase() == "ORDER" {
1088                self.trace_token("Warning: ORDER as identifier instead of OrderBy token");
1089                self.advance(); // consume ORDER
1090                if matches!(&self.current_token, Token::By) {
1091                    self.advance(); // consume BY
1092                    Some(self.parse_order_by_list()?)
1093                } else {
1094                    return Err("Expected BY after ORDER".to_string());
1095                }
1096            } else {
1097                None
1098            }
1099        } else {
1100            None
1101        };
1102
1103        // Parse LIMIT clause
1104        let limit = if matches!(self.current_token, Token::Limit) {
1105            self.advance();
1106            match &self.current_token {
1107                Token::NumberLiteral(num) => {
1108                    let limit_val = num
1109                        .parse::<usize>()
1110                        .map_err(|_| format!("Invalid LIMIT value: {num}"))?;
1111                    self.advance();
1112                    Some(limit_val)
1113                }
1114                _ => return Err("Expected number after LIMIT".to_string()),
1115            }
1116        } else {
1117            None
1118        };
1119
1120        // Parse OFFSET clause
1121        let offset = if matches!(self.current_token, Token::Offset) {
1122            self.advance();
1123            match &self.current_token {
1124                Token::NumberLiteral(num) => {
1125                    let offset_val = num
1126                        .parse::<usize>()
1127                        .map_err(|_| format!("Invalid OFFSET value: {num}"))?;
1128                    self.advance();
1129                    Some(offset_val)
1130                }
1131                _ => return Err("Expected number after OFFSET".to_string()),
1132            }
1133        } else {
1134            None
1135        };
1136
1137        // Parse INTO clause (alternative position - SQL Server also supports INTO after all clauses)
1138        // This handles: SELECT * FROM table WHERE x > 5 INTO #temp
1139        // If INTO was already parsed after SELECT, this will be None (can't have two INTOs)
1140        let into_table = if into_table.is_none() && matches!(self.current_token, Token::Into) {
1141            self.advance();
1142            Some(self.parse_into_clause()?)
1143        } else {
1144            into_table // Keep the one from after SELECT if it exists
1145        };
1146
1147        // Parse UNION/INTERSECT/EXCEPT operations
1148        let set_operations = self.parse_set_operations()?;
1149
1150        // Collect trailing comment ONLY in PreserveComments mode
1151        let trailing_comment = if self.mode == ParserMode::PreserveComments {
1152            self.collect_trailing_comment()
1153        } else {
1154            None
1155        };
1156
1157        // Build unified from_source from parsed components
1158        // PIVOT takes precedence if it exists (it already wraps the base source)
1159        let from_source = if let Some(pivot) = pivot_source {
1160            Some(pivot)
1161        } else if let Some(ref table_name) = from_table {
1162            Some(TableSource::Table(table_name.clone()))
1163        } else if let Some(ref subquery) = from_subquery {
1164            Some(TableSource::DerivedTable {
1165                query: subquery.clone(),
1166                alias: from_alias.clone().unwrap_or_default(),
1167            })
1168        } else if let Some(ref _func) = from_function {
1169            // Table functions don't use TableSource yet, keep as None for now
1170            // TODO: Add TableFunction variant to TableSource
1171            None
1172        } else {
1173            None
1174        };
1175
1176        Ok(SelectStatement {
1177            distinct,
1178            columns,
1179            select_items,
1180            from_source,
1181            #[allow(deprecated)]
1182            from_table,
1183            #[allow(deprecated)]
1184            from_subquery,
1185            #[allow(deprecated)]
1186            from_function,
1187            #[allow(deprecated)]
1188            from_alias,
1189            joins,
1190            where_clause,
1191            order_by,
1192            group_by,
1193            having,
1194            qualify,
1195            limit,
1196            offset,
1197            ctes: Vec::new(), // Will be populated by WITH clause parser
1198            into_table,
1199            set_operations,
1200            leading_comments,
1201            trailing_comment,
1202        })
1203    }
1204
1205    /// Parse UNION/INTERSECT/EXCEPT operations
1206    /// Returns a vector of (operation, select_statement) pairs
1207    fn parse_set_operations(
1208        &mut self,
1209    ) -> Result<Vec<(SetOperation, Box<SelectStatement>)>, String> {
1210        let mut operations = Vec::new();
1211
1212        while matches!(
1213            self.current_token,
1214            Token::Union | Token::Intersect | Token::Except
1215        ) {
1216            // Determine the operation type
1217            let operation = match &self.current_token {
1218                Token::Union => {
1219                    self.advance();
1220                    // Check for ALL keyword
1221                    if let Token::Identifier(id) = &self.current_token {
1222                        if id.to_uppercase() == "ALL" {
1223                            self.advance();
1224                            SetOperation::UnionAll
1225                        } else {
1226                            SetOperation::Union
1227                        }
1228                    } else {
1229                        SetOperation::Union
1230                    }
1231                }
1232                Token::Intersect => {
1233                    self.advance();
1234                    SetOperation::Intersect
1235                }
1236                Token::Except => {
1237                    self.advance();
1238                    SetOperation::Except
1239                }
1240                _ => unreachable!(),
1241            };
1242
1243            // Parse the next SELECT statement
1244            let next_select = self.parse_select_statement_inner()?;
1245
1246            operations.push((operation, Box::new(next_select)));
1247        }
1248
1249        Ok(operations)
1250    }
1251
1252    /// Parse SELECT items that support computed expressions with aliases
1253    fn parse_select_items(&mut self) -> Result<Vec<SelectItem>, String> {
1254        let mut items = Vec::new();
1255
1256        loop {
1257            // Check for qualified star (table.*) or unqualified star (*)
1258            // First check if we have identifier.* pattern
1259            if let Token::Identifier(name) = &self.current_token.clone() {
1260                // Peek ahead to check for .* pattern
1261                let saved_pos = self.lexer.clone();
1262                let saved_token = self.current_token.clone();
1263                let table_name = name.clone();
1264
1265                self.advance();
1266
1267                if matches!(self.current_token, Token::Dot) {
1268                    self.advance();
1269                    if matches!(self.current_token, Token::Star) {
1270                        // This is table.* pattern
1271                        items.push(SelectItem::Star {
1272                            table_prefix: Some(table_name),
1273                            leading_comments: vec![],
1274                            trailing_comment: None,
1275                        });
1276                        self.advance();
1277
1278                        // Continue to next item or end
1279                        if matches!(self.current_token, Token::Comma) {
1280                            self.advance();
1281                            continue;
1282                        } else {
1283                            break;
1284                        }
1285                    }
1286                }
1287
1288                // Not table.*, restore position and continue with normal parsing
1289                self.lexer = saved_pos;
1290                self.current_token = saved_token;
1291            }
1292
1293            // Check for unqualified *
1294            if matches!(self.current_token, Token::Star) {
1295                self.advance(); // consume *
1296
1297                // Check for EXCLUDE clause
1298                if matches!(self.current_token, Token::Exclude) {
1299                    self.advance(); // consume EXCLUDE
1300
1301                    // Expect opening paren
1302                    if !matches!(self.current_token, Token::LeftParen) {
1303                        return Err("Expected '(' after EXCLUDE".to_string());
1304                    }
1305                    self.advance(); // consume (
1306
1307                    // Parse column list
1308                    let mut excluded_columns = Vec::new();
1309                    loop {
1310                        match &self.current_token {
1311                            Token::Identifier(col_name) | Token::QuotedIdentifier(col_name) => {
1312                                excluded_columns.push(col_name.clone());
1313                                self.advance();
1314                            }
1315                            _ => return Err("Expected column name in EXCLUDE list".to_string()),
1316                        }
1317
1318                        // Check for comma or closing paren
1319                        if matches!(self.current_token, Token::Comma) {
1320                            self.advance();
1321                        } else if matches!(self.current_token, Token::RightParen) {
1322                            self.advance(); // consume )
1323                            break;
1324                        } else {
1325                            return Err("Expected ',' or ')' in EXCLUDE list".to_string());
1326                        }
1327                    }
1328
1329                    if excluded_columns.is_empty() {
1330                        return Err("EXCLUDE list cannot be empty".to_string());
1331                    }
1332
1333                    items.push(SelectItem::StarExclude {
1334                        table_prefix: None,
1335                        excluded_columns,
1336                        leading_comments: vec![],
1337                        trailing_comment: None,
1338                    });
1339                } else {
1340                    // Regular * without EXCLUDE
1341                    items.push(SelectItem::Star {
1342                        table_prefix: None,
1343                        leading_comments: vec![],
1344                        trailing_comment: None,
1345                    });
1346                }
1347            } else {
1348                // Parse expression or column
1349                let expr = self.parse_comparison()?; // Use comparison to support IS NULL and other comparisons
1350
1351                // Check for AS alias
1352                let alias = if matches!(self.current_token, Token::As) {
1353                    self.advance();
1354                    match &self.current_token {
1355                        Token::Identifier(alias_name) => {
1356                            let alias = alias_name.clone();
1357                            self.advance();
1358                            alias
1359                        }
1360                        Token::QuotedIdentifier(alias_name) => {
1361                            let alias = alias_name.clone();
1362                            self.advance();
1363                            alias
1364                        }
1365                        token => {
1366                            if let Some(keyword) = token.as_keyword_str() {
1367                                return Err(format!(
1368                                    "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
1369                                    keyword,
1370                                    keyword.to_lowercase()
1371                                ));
1372                            } else {
1373                                return Err("Expected alias name after AS".to_string());
1374                            }
1375                        }
1376                    }
1377                } else {
1378                    // Generate default alias based on expression
1379                    match &expr {
1380                        SqlExpression::Column(col_ref) => col_ref.name.clone(),
1381                        _ => format!("expr_{}", items.len() + 1), // Default alias for computed expressions
1382                    }
1383                };
1384
1385                // Create SelectItem based on expression type
1386                let item = match expr {
1387                    SqlExpression::Column(col_ref) if alias == col_ref.name => {
1388                        // Simple column reference without alias
1389                        SelectItem::Column {
1390                            column: col_ref,
1391                            leading_comments: vec![],
1392                            trailing_comment: None,
1393                        }
1394                    }
1395                    _ => {
1396                        // Computed expression or column with different alias
1397                        SelectItem::Expression {
1398                            expr,
1399                            alias,
1400                            leading_comments: vec![],
1401                            trailing_comment: None,
1402                        }
1403                    }
1404                };
1405
1406                items.push(item);
1407            }
1408
1409            // Check for comma to continue
1410            if matches!(self.current_token, Token::Comma) {
1411                self.advance();
1412            } else {
1413                break;
1414            }
1415        }
1416
1417        Ok(items)
1418    }
1419
1420    fn parse_identifier_list(&mut self) -> Result<Vec<String>, String> {
1421        let mut identifiers = Vec::new();
1422
1423        loop {
1424            match &self.current_token {
1425                Token::Identifier(id) => {
1426                    // Check if this is a reserved keyword that should stop identifier parsing
1427                    if Self::is_identifier_reserved(id) {
1428                        // Stop parsing identifiers if we hit a reserved keyword
1429                        break;
1430                    }
1431                    let mut name = id.clone();
1432                    self.advance();
1433
1434                    // Handle qualified names (table.column)
1435                    if matches!(self.current_token, Token::Dot) {
1436                        self.advance(); // consume dot
1437                        match &self.current_token {
1438                            Token::Identifier(col) => {
1439                                name = format!("{}.{}", name, col);
1440                                self.advance();
1441                            }
1442                            Token::QuotedIdentifier(col) => {
1443                                name = format!("{}.{}", name, col);
1444                                self.advance();
1445                            }
1446                            _ => {
1447                                return Err("Expected identifier after '.'".to_string());
1448                            }
1449                        }
1450                    }
1451
1452                    identifiers.push(name);
1453                }
1454                Token::QuotedIdentifier(id) => {
1455                    // Handle quoted identifiers like "Customer Id"
1456                    identifiers.push(id.clone());
1457                    self.advance();
1458                }
1459                _ => {
1460                    // Stop parsing if we hit any other token type
1461                    break;
1462                }
1463            }
1464
1465            if matches!(self.current_token, Token::Comma) {
1466                self.advance();
1467            } else {
1468                break;
1469            }
1470        }
1471
1472        if identifiers.is_empty() {
1473            return Err("Expected at least one identifier".to_string());
1474        }
1475
1476        Ok(identifiers)
1477    }
1478
1479    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
1480        let mut partition_by = Vec::new();
1481        let mut order_by = Vec::new();
1482
1483        // Check for PARTITION BY
1484        if matches!(self.current_token, Token::Partition) {
1485            self.advance(); // consume PARTITION
1486            if !matches!(self.current_token, Token::By) {
1487                return Err("Expected BY after PARTITION".to_string());
1488            }
1489            self.advance(); // consume BY
1490
1491            // Parse partition columns
1492            partition_by = self.parse_identifier_list()?;
1493        }
1494
1495        // Check for ORDER BY
1496        if matches!(self.current_token, Token::OrderBy) {
1497            self.advance(); // consume ORDER BY (as single token)
1498            order_by = self.parse_order_by_list()?;
1499        } else if let Token::Identifier(s) = &self.current_token {
1500            if Self::is_identifier_reserved(s) && s.to_uppercase() == "ORDER" {
1501                // Handle ORDER BY as two tokens
1502                self.advance(); // consume ORDER
1503                if !matches!(self.current_token, Token::By) {
1504                    return Err("Expected BY after ORDER".to_string());
1505                }
1506                self.advance(); // consume BY
1507                order_by = self.parse_order_by_list()?;
1508            }
1509        }
1510
1511        // Parse optional window frame (ROWS/RANGE BETWEEN ... AND ...)
1512        let mut frame = self.parse_window_frame()?;
1513
1514        // SQL Standard: If ORDER BY is present but no frame is specified,
1515        // default to RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
1516        // This matches behavior of PostgreSQL, MySQL, SQL Server, etc.
1517        if !order_by.is_empty() && frame.is_none() {
1518            frame = Some(WindowFrame {
1519                unit: FrameUnit::Range,
1520                start: FrameBound::UnboundedPreceding,
1521                end: Some(FrameBound::CurrentRow),
1522            });
1523        }
1524
1525        Ok(WindowSpec {
1526            partition_by,
1527            order_by,
1528            frame,
1529        })
1530    }
1531
1532    fn parse_order_by_list(&mut self) -> Result<Vec<OrderByItem>, String> {
1533        let mut order_items = Vec::new();
1534
1535        loop {
1536            // Parse ANY expression (not just column names)
1537            // This supports:
1538            // - Simple columns: region
1539            // - Qualified columns: table.column
1540            // - Aggregate functions: SUM(sales_amount)
1541            // - Arithmetic: sales_amount * 1.1
1542            // - CASE expressions: CASE WHEN ... END
1543            let expr = self.parse_expression()?;
1544
1545            // Check for ASC/DESC
1546            let direction = match &self.current_token {
1547                Token::Asc => {
1548                    self.advance();
1549                    SortDirection::Asc
1550                }
1551                Token::Desc => {
1552                    self.advance();
1553                    SortDirection::Desc
1554                }
1555                _ => SortDirection::Asc, // Default to ASC if not specified
1556            };
1557
1558            order_items.push(OrderByItem { expr, direction });
1559
1560            if matches!(self.current_token, Token::Comma) {
1561                self.advance();
1562            } else {
1563                break;
1564            }
1565        }
1566
1567        Ok(order_items)
1568    }
1569
1570    /// Parse INTO clause for temporary tables
1571    /// Syntax: INTO #table_name
1572    fn parse_into_clause(&mut self) -> Result<IntoTable, String> {
1573        // Expect an identifier starting with #
1574        let name = match &self.current_token {
1575            Token::Identifier(id) if id.starts_with('#') => {
1576                let table_name = id.clone();
1577                self.advance();
1578                table_name
1579            }
1580            Token::Identifier(id) => {
1581                return Err(format!(
1582                    "Temporary table name must start with #, got: {}",
1583                    id
1584                ));
1585            }
1586            _ => {
1587                return Err(
1588                    "Expected temporary table name (starting with #) after INTO".to_string()
1589                );
1590            }
1591        };
1592
1593        Ok(IntoTable { name })
1594    }
1595
1596    fn parse_window_frame(&mut self) -> Result<Option<WindowFrame>, String> {
1597        // Check for ROWS or RANGE keyword
1598        let unit = match &self.current_token {
1599            Token::Rows => {
1600                self.advance();
1601                FrameUnit::Rows
1602            }
1603            Token::Identifier(id) if id.to_uppercase() == "RANGE" => {
1604                // RANGE as window frame unit
1605                self.advance();
1606                FrameUnit::Range
1607            }
1608            _ => return Ok(None), // No window frame specified
1609        };
1610
1611        // Check for BETWEEN or just a single bound
1612        let (start, end) = if let Token::Between = &self.current_token {
1613            self.advance(); // consume BETWEEN
1614                            // Parse start bound
1615            let start = self.parse_frame_bound()?;
1616
1617            // Expect AND
1618            if !matches!(&self.current_token, Token::And) {
1619                return Err("Expected AND after window frame start bound".to_string());
1620            }
1621            self.advance();
1622
1623            // Parse end bound
1624            let end = self.parse_frame_bound()?;
1625            (start, Some(end))
1626        } else {
1627            // Single bound (e.g., "ROWS 5 PRECEDING")
1628            let bound = self.parse_frame_bound()?;
1629            (bound, None)
1630        };
1631
1632        Ok(Some(WindowFrame { unit, start, end }))
1633    }
1634
1635    fn parse_frame_bound(&mut self) -> Result<FrameBound, String> {
1636        match &self.current_token {
1637            Token::Unbounded => {
1638                self.advance();
1639                match &self.current_token {
1640                    Token::Preceding => {
1641                        self.advance();
1642                        Ok(FrameBound::UnboundedPreceding)
1643                    }
1644                    Token::Following => {
1645                        self.advance();
1646                        Ok(FrameBound::UnboundedFollowing)
1647                    }
1648                    _ => Err("Expected PRECEDING or FOLLOWING after UNBOUNDED".to_string()),
1649                }
1650            }
1651            Token::Current => {
1652                self.advance();
1653                if matches!(&self.current_token, Token::Row) {
1654                    self.advance();
1655                    return Ok(FrameBound::CurrentRow);
1656                }
1657                Err("Expected ROW after CURRENT".to_string())
1658            }
1659            Token::NumberLiteral(num) => {
1660                let n: i64 = num
1661                    .parse()
1662                    .map_err(|_| "Invalid number in window frame".to_string())?;
1663                self.advance();
1664                match &self.current_token {
1665                    Token::Preceding => {
1666                        self.advance();
1667                        Ok(FrameBound::Preceding(n))
1668                    }
1669                    Token::Following => {
1670                        self.advance();
1671                        Ok(FrameBound::Following(n))
1672                    }
1673                    _ => Err("Expected PRECEDING or FOLLOWING after number".to_string()),
1674                }
1675            }
1676            _ => Err("Invalid window frame bound".to_string()),
1677        }
1678    }
1679
1680    fn parse_where_clause(&mut self) -> Result<WhereClause, String> {
1681        // Parse the entire WHERE clause as a single expression tree
1682        // The logical operators (AND/OR) are now handled within parse_expression
1683        let expr = self.parse_expression()?;
1684
1685        // Check for unexpected closing parenthesis
1686        if matches!(self.current_token, Token::RightParen) && self.paren_depth <= 0 {
1687            return Err(
1688                "Unexpected closing parenthesis - no matching opening parenthesis".to_string(),
1689            );
1690        }
1691
1692        // Create a single condition with the entire expression
1693        let conditions = vec![Condition {
1694            expr,
1695            connector: None,
1696        }];
1697
1698        Ok(WhereClause { conditions })
1699    }
1700
1701    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
1702        self.trace_enter("parse_expression");
1703        // Start with logical OR as the lowest precedence operator
1704        // The hierarchy is: OR -> AND -> comparison -> additive -> multiplicative -> primary
1705        let mut left = self.parse_logical_or()?;
1706
1707        // Handle IN operator (not preceded by NOT)
1708        // This uses the modular comparison module
1709        left = parse_in_operator(self, left)?;
1710
1711        let result = Ok(left);
1712        self.trace_exit("parse_expression", &result);
1713        result
1714    }
1715
1716    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1717        // Use the new modular comparison expression parser
1718        parse_comparison_expr(self)
1719    }
1720
1721    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1722        // Use the new modular arithmetic expression parser
1723        parse_additive_expr(self)
1724    }
1725
1726    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1727        // Use the new modular arithmetic expression parser
1728        parse_multiplicative_expr(self)
1729    }
1730
1731    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1732        // Use the new modular logical expression parser
1733        parse_logical_or_expr(self)
1734    }
1735
1736    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1737        // Use the new modular logical expression parser
1738        parse_logical_and_expr(self)
1739    }
1740
1741    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1742        // Use the new modular CASE expression parser
1743        parse_case_expr(self)
1744    }
1745
1746    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1747        // Use the new modular primary expression parser
1748        // Clone the necessary data to avoid borrowing issues
1749        let columns = self.columns.clone();
1750        let in_method_args = self.in_method_args;
1751        let ctx = PrimaryExpressionContext {
1752            columns: &columns,
1753            in_method_args,
1754        };
1755        parse_primary_expr(self, &ctx)
1756    }
1757
1758    // Keep the old implementation temporarily for reference (will be removed)
1759    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1760        // Set flag to indicate we're parsing method arguments
1761        self.in_method_args = true;
1762
1763        let args = self.parse_argument_list()?;
1764
1765        // Clear the flag
1766        self.in_method_args = false;
1767
1768        Ok(args)
1769    }
1770
1771    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1772        let mut args = Vec::new();
1773        let mut has_distinct = false;
1774
1775        if !matches!(self.current_token, Token::RightParen) {
1776            // Check if first argument starts with DISTINCT
1777            if matches!(self.current_token, Token::Distinct) {
1778                self.advance(); // consume DISTINCT
1779                has_distinct = true;
1780            }
1781
1782            // Parse full expressions as arguments — this allows comparisons and
1783            // boolean logic inside function calls, e.g. AVG(x > 5), SUM(a = 'b')
1784            args.push(self.parse_logical_or()?);
1785
1786            // Parse any remaining arguments (DISTINCT only applies to first arg for aggregates)
1787            while matches!(self.current_token, Token::Comma) {
1788                self.advance();
1789                args.push(self.parse_logical_or()?);
1790            }
1791        }
1792
1793        Ok((args, has_distinct))
1794    }
1795
1796    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1797        let mut expressions = Vec::new();
1798
1799        loop {
1800            expressions.push(self.parse_expression()?);
1801
1802            if matches!(self.current_token, Token::Comma) {
1803                self.advance();
1804            } else {
1805                break;
1806            }
1807        }
1808
1809        Ok(expressions)
1810    }
1811
1812    #[must_use]
1813    pub fn get_position(&self) -> usize {
1814        self.lexer.get_position()
1815    }
1816
1817    // Check if current token is a JOIN-related token
1818    fn is_join_token(&self) -> bool {
1819        matches!(
1820            self.current_token,
1821            Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
1822        )
1823    }
1824
1825    // Parse a JOIN clause
1826    fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1827        // Determine join type
1828        let join_type = match &self.current_token {
1829            Token::Join => {
1830                self.advance();
1831                JoinType::Inner // Default JOIN is INNER JOIN
1832            }
1833            Token::Inner => {
1834                self.advance();
1835                if !matches!(self.current_token, Token::Join) {
1836                    return Err("Expected JOIN after INNER".to_string());
1837                }
1838                self.advance();
1839                JoinType::Inner
1840            }
1841            Token::Left => {
1842                self.advance();
1843                // Handle optional OUTER keyword
1844                if matches!(self.current_token, Token::Outer) {
1845                    self.advance();
1846                }
1847                if !matches!(self.current_token, Token::Join) {
1848                    return Err("Expected JOIN after LEFT".to_string());
1849                }
1850                self.advance();
1851                JoinType::Left
1852            }
1853            Token::Right => {
1854                self.advance();
1855                // Handle optional OUTER keyword
1856                if matches!(self.current_token, Token::Outer) {
1857                    self.advance();
1858                }
1859                if !matches!(self.current_token, Token::Join) {
1860                    return Err("Expected JOIN after RIGHT".to_string());
1861                }
1862                self.advance();
1863                JoinType::Right
1864            }
1865            Token::Full => {
1866                self.advance();
1867                // Handle optional OUTER keyword
1868                if matches!(self.current_token, Token::Outer) {
1869                    self.advance();
1870                }
1871                if !matches!(self.current_token, Token::Join) {
1872                    return Err("Expected JOIN after FULL".to_string());
1873                }
1874                self.advance();
1875                JoinType::Full
1876            }
1877            Token::Cross => {
1878                self.advance();
1879                if !matches!(self.current_token, Token::Join) {
1880                    return Err("Expected JOIN after CROSS".to_string());
1881                }
1882                self.advance();
1883                JoinType::Cross
1884            }
1885            _ => return Err("Expected JOIN keyword".to_string()),
1886        };
1887
1888        // Parse the table being joined
1889        let (table, alias) = self.parse_join_table_source()?;
1890
1891        // Parse ON condition (required for all joins except CROSS JOIN)
1892        let condition = if join_type == JoinType::Cross {
1893            // CROSS JOIN doesn't have ON condition - create empty condition
1894            JoinCondition { conditions: vec![] }
1895        } else {
1896            if !matches!(self.current_token, Token::On) {
1897                return Err("Expected ON keyword after JOIN table".to_string());
1898            }
1899            self.advance();
1900            self.parse_join_condition()?
1901        };
1902
1903        Ok(JoinClause {
1904            join_type,
1905            table,
1906            alias,
1907            condition,
1908        })
1909    }
1910
1911    fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1912        let table = match &self.current_token {
1913            Token::Identifier(name) => {
1914                let table_name = name.clone();
1915                self.advance();
1916                TableSource::Table(table_name)
1917            }
1918            Token::LeftParen => {
1919                // Subquery as table source
1920                self.advance();
1921                let subquery = self.parse_select_statement_inner()?;
1922                if !matches!(self.current_token, Token::RightParen) {
1923                    return Err("Expected ')' after subquery".to_string());
1924                }
1925                self.advance();
1926
1927                // Subqueries must have an alias
1928                let alias = match &self.current_token {
1929                    Token::Identifier(alias_name) => {
1930                        let alias = alias_name.clone();
1931                        self.advance();
1932                        alias
1933                    }
1934                    Token::As => {
1935                        self.advance();
1936                        match &self.current_token {
1937                            Token::Identifier(alias_name) => {
1938                                let alias = alias_name.clone();
1939                                self.advance();
1940                                alias
1941                            }
1942                            _ => return Err("Expected alias after AS keyword".to_string()),
1943                        }
1944                    }
1945                    _ => return Err("Subqueries must have an alias".to_string()),
1946                };
1947
1948                return Ok((
1949                    TableSource::DerivedTable {
1950                        query: Box::new(subquery),
1951                        alias: alias.clone(),
1952                    },
1953                    Some(alias),
1954                ));
1955            }
1956            _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1957        };
1958
1959        // Check for optional alias
1960        let alias = match &self.current_token {
1961            Token::Identifier(alias_name) => {
1962                let alias = alias_name.clone();
1963                self.advance();
1964                Some(alias)
1965            }
1966            Token::As => {
1967                self.advance();
1968                match &self.current_token {
1969                    Token::Identifier(alias_name) => {
1970                        let alias = alias_name.clone();
1971                        self.advance();
1972                        Some(alias)
1973                    }
1974                    _ => return Err("Expected alias after AS keyword".to_string()),
1975                }
1976            }
1977            _ => None,
1978        };
1979
1980        Ok((table, alias))
1981    }
1982
1983    fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1984        let mut conditions = Vec::new();
1985
1986        // Parse first condition
1987        conditions.push(self.parse_single_join_condition()?);
1988
1989        // Parse additional conditions connected by AND
1990        while matches!(self.current_token, Token::And) {
1991            self.advance(); // consume AND
1992            conditions.push(self.parse_single_join_condition()?);
1993        }
1994
1995        Ok(JoinCondition { conditions })
1996    }
1997
1998    fn parse_single_join_condition(&mut self) -> Result<SingleJoinCondition, String> {
1999        // Parse left side as additive expression (stops before comparison operators)
2000        // This allows the comparison operator to be explicitly parsed by this function
2001        let left_expr = self.parse_additive()?;
2002
2003        // Parse operator
2004        let operator = match &self.current_token {
2005            Token::Equal => JoinOperator::Equal,
2006            Token::NotEqual => JoinOperator::NotEqual,
2007            Token::LessThan => JoinOperator::LessThan,
2008            Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
2009            Token::GreaterThan => JoinOperator::GreaterThan,
2010            Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
2011            _ => return Err("Expected comparison operator in JOIN condition".to_string()),
2012        };
2013        self.advance();
2014
2015        // Parse right side as additive expression (stops before comparison operators)
2016        let right_expr = self.parse_additive()?;
2017
2018        Ok(SingleJoinCondition {
2019            left_expr,
2020            operator,
2021            right_expr,
2022        })
2023    }
2024
2025    fn parse_column_reference(&mut self) -> Result<String, String> {
2026        match &self.current_token {
2027            Token::Identifier(name) => {
2028                let mut column_ref = name.clone();
2029                self.advance();
2030
2031                // Check for table.column notation
2032                if matches!(self.current_token, Token::Dot) {
2033                    self.advance();
2034                    match &self.current_token {
2035                        Token::Identifier(col_name) => {
2036                            column_ref.push('.');
2037                            column_ref.push_str(col_name);
2038                            self.advance();
2039                        }
2040                        _ => return Err("Expected column name after '.'".to_string()),
2041                    }
2042                }
2043
2044                Ok(column_ref)
2045            }
2046            _ => Err("Expected column reference".to_string()),
2047        }
2048    }
2049
2050    // ===== PIVOT Parsing =====
2051
2052    /// Parse a PIVOT clause after a table source
2053    /// Syntax: PIVOT (aggregate_function FOR pivot_column IN (value1, value2, ...))
2054    fn parse_pivot_clause(&mut self, source: TableSource) -> Result<TableSource, String> {
2055        // Consume PIVOT keyword
2056        self.consume(Token::Pivot)?;
2057
2058        // Consume opening parenthesis
2059        self.consume(Token::LeftParen)?;
2060
2061        // Parse aggregate function (e.g., MAX(AmountEaten))
2062        let aggregate = self.parse_pivot_aggregate()?;
2063
2064        // Parse FOR keyword
2065        self.consume(Token::For)?;
2066
2067        // Parse pivot column name
2068        let pivot_column = match &self.current_token {
2069            Token::Identifier(col) => {
2070                let column = col.clone();
2071                self.advance();
2072                column
2073            }
2074            Token::QuotedIdentifier(col) => {
2075                let column = col.clone();
2076                self.advance();
2077                column
2078            }
2079            _ => return Err("Expected column name after FOR in PIVOT".to_string()),
2080        };
2081
2082        // Parse IN keyword
2083        if !matches!(self.current_token, Token::In) {
2084            return Err("Expected IN keyword in PIVOT clause".to_string());
2085        }
2086        self.advance();
2087
2088        // Parse pivot values
2089        let pivot_values = self.parse_pivot_in_clause()?;
2090
2091        // Consume closing parenthesis for PIVOT
2092        self.consume(Token::RightParen)?;
2093
2094        // Check for optional alias
2095        let alias = self.parse_optional_alias()?;
2096
2097        Ok(TableSource::Pivot {
2098            source: Box::new(source),
2099            aggregate,
2100            pivot_column,
2101            pivot_values,
2102            alias,
2103        })
2104    }
2105
2106    /// Parse the aggregate function specification in PIVOT
2107    /// Example: MAX(AmountEaten), SUM(sales), COUNT(*)
2108    fn parse_pivot_aggregate(&mut self) -> Result<PivotAggregate, String> {
2109        // Parse aggregate function name
2110        let function = match &self.current_token {
2111            Token::Identifier(name) => {
2112                let func_name = name.to_uppercase();
2113                // Validate it's an aggregate function
2114                match func_name.as_str() {
2115                    "MAX" | "MIN" | "SUM" | "AVG" | "COUNT" => {
2116                        self.advance();
2117                        func_name
2118                    }
2119                    _ => {
2120                        return Err(format!(
2121                            "Expected aggregate function (MAX, MIN, SUM, AVG, COUNT), got {}",
2122                            func_name
2123                        ))
2124                    }
2125                }
2126            }
2127            _ => return Err("Expected aggregate function in PIVOT".to_string()),
2128        };
2129
2130        // Consume opening parenthesis
2131        self.consume(Token::LeftParen)?;
2132
2133        // Parse column name (or * for COUNT)
2134        let column = match &self.current_token {
2135            Token::Identifier(col) => {
2136                let column = col.clone();
2137                self.advance();
2138                column
2139            }
2140            Token::QuotedIdentifier(col) => {
2141                let column = col.clone();
2142                self.advance();
2143                column
2144            }
2145            Token::Star => {
2146                // COUNT(*) is allowed
2147                if function == "COUNT" {
2148                    self.advance();
2149                    "*".to_string()
2150                } else {
2151                    return Err(format!("Only COUNT can use *, not {}", function));
2152                }
2153            }
2154            _ => return Err("Expected column name in aggregate function".to_string()),
2155        };
2156
2157        // Consume closing parenthesis
2158        self.consume(Token::RightParen)?;
2159
2160        Ok(PivotAggregate { function, column })
2161    }
2162
2163    /// Parse the IN clause values in PIVOT
2164    /// Example: IN ('Sammich', 'Pickle', 'Apple')
2165    /// Returns vector of pivot values
2166    fn parse_pivot_in_clause(&mut self) -> Result<Vec<String>, String> {
2167        // Consume opening parenthesis
2168        self.consume(Token::LeftParen)?;
2169
2170        let mut values = Vec::new();
2171
2172        // Parse first value
2173        match &self.current_token {
2174            Token::StringLiteral(val) => {
2175                values.push(val.clone());
2176                self.advance();
2177            }
2178            Token::Identifier(val) => {
2179                // Allow unquoted identifiers as well
2180                values.push(val.clone());
2181                self.advance();
2182            }
2183            Token::NumberLiteral(val) => {
2184                // Allow numeric values
2185                values.push(val.clone());
2186                self.advance();
2187            }
2188            _ => return Err("Expected value in PIVOT IN clause".to_string()),
2189        }
2190
2191        // Parse additional values separated by commas
2192        while matches!(self.current_token, Token::Comma) {
2193            self.advance(); // consume comma
2194
2195            match &self.current_token {
2196                Token::StringLiteral(val) => {
2197                    values.push(val.clone());
2198                    self.advance();
2199                }
2200                Token::Identifier(val) => {
2201                    values.push(val.clone());
2202                    self.advance();
2203                }
2204                Token::NumberLiteral(val) => {
2205                    values.push(val.clone());
2206                    self.advance();
2207                }
2208                _ => return Err("Expected value after comma in PIVOT IN clause".to_string()),
2209            }
2210        }
2211
2212        // Consume closing parenthesis
2213        self.consume(Token::RightParen)?;
2214
2215        if values.is_empty() {
2216            return Err("PIVOT IN clause must have at least one value".to_string());
2217        }
2218
2219        Ok(values)
2220    }
2221}
2222
2223// Context detection for cursor position
2224#[derive(Debug, Clone)]
2225pub enum CursorContext {
2226    SelectClause,
2227    FromClause,
2228    WhereClause,
2229    OrderByClause,
2230    AfterColumn(String),
2231    AfterLogicalOp(LogicalOp),
2232    AfterComparisonOp(String, String), // column_name, operator
2233    InMethodCall(String, String),      // object, method
2234    InExpression,
2235    Unknown,
2236}
2237
2238/// Safe UTF-8 string slicing that ensures we don't slice in the middle of a character
2239fn safe_slice_to(s: &str, pos: usize) -> &str {
2240    if pos >= s.len() {
2241        return s;
2242    }
2243
2244    // Find the nearest valid character boundary at or before pos
2245    let mut safe_pos = pos;
2246    while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
2247        safe_pos -= 1;
2248    }
2249
2250    &s[..safe_pos]
2251}
2252
2253/// Safe UTF-8 string slicing from a position to the end
2254fn safe_slice_from(s: &str, pos: usize) -> &str {
2255    if pos >= s.len() {
2256        return "";
2257    }
2258
2259    // Find the nearest valid character boundary at or after pos
2260    let mut safe_pos = pos;
2261    while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
2262        safe_pos += 1;
2263    }
2264
2265    &s[safe_pos..]
2266}
2267
2268#[must_use]
2269pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2270    let truncated = safe_slice_to(query, cursor_pos);
2271    let mut parser = Parser::new(truncated);
2272
2273    // Try to parse as much as possible
2274    if let Ok(stmt) = parser.parse() {
2275        let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
2276        #[cfg(test)]
2277        println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2278        (ctx, partial)
2279    } else {
2280        // Partial parse - analyze what we have
2281        let (ctx, partial) = analyze_partial(truncated, cursor_pos);
2282        #[cfg(test)]
2283        println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2284        (ctx, partial)
2285    }
2286}
2287
2288#[must_use]
2289pub fn tokenize_query(query: &str) -> Vec<String> {
2290    let mut lexer = Lexer::new(query);
2291    let tokens = lexer.tokenize_all();
2292    tokens.iter().map(|t| format!("{t:?}")).collect()
2293}
2294
2295#[must_use]
2296/// Helper function to find the start of a quoted string searching backwards
2297fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
2298    // Skip the closing quote and search backwards
2299    if pos > 0 {
2300        pos -= 1;
2301        while pos > 0 {
2302            if bytes[pos] == b'"' {
2303                // Check if it's not an escaped quote
2304                if pos == 0 || bytes[pos - 1] != b'\\' {
2305                    return Some(pos);
2306                }
2307            }
2308            pos -= 1;
2309        }
2310        // Check position 0 separately
2311        if bytes[0] == b'"' {
2312            return Some(0);
2313        }
2314    }
2315    None
2316}
2317
2318/// Helper function to handle method call context after validation
2319fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
2320    // Check if there's a partial method name after the dot
2321    let partial_method = if after_dot.is_empty() {
2322        None
2323    } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
2324        Some(after_dot.to_string())
2325    } else {
2326        None
2327    };
2328
2329    // For AfterColumn context, strip quotes if present for consistency
2330    let col_name_for_context =
2331        if col_name.starts_with('"') && col_name.ends_with('"') && col_name.len() > 2 {
2332            col_name[1..col_name.len() - 1].to_string()
2333        } else {
2334            col_name.to_string()
2335        };
2336
2337    (
2338        CursorContext::AfterColumn(col_name_for_context),
2339        partial_method,
2340    )
2341}
2342
2343/// Helper function to check if we're after a comparison operator
2344fn check_after_comparison_operator(query: &str) -> Option<(CursorContext, Option<String>)> {
2345    for op in &Parser::COMPARISON_OPERATORS {
2346        if let Some(op_pos) = query.rfind(op) {
2347            let before_op = safe_slice_to(query, op_pos);
2348            let after_op_start = op_pos + op.len();
2349            let after_op = if after_op_start < query.len() {
2350                &query[after_op_start..]
2351            } else {
2352                ""
2353            };
2354
2355            // Check if we have a column name before the operator
2356            if let Some(col_name) = before_op.split_whitespace().last() {
2357                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2358                    // Check if we're at or near the end of the query
2359                    let after_op_trimmed = after_op.trim();
2360                    if after_op_trimmed.is_empty()
2361                        || (after_op_trimmed
2362                            .chars()
2363                            .all(|c| c.is_alphanumeric() || c == '_')
2364                            && !after_op_trimmed.contains('('))
2365                    {
2366                        let partial = if after_op_trimmed.is_empty() {
2367                            None
2368                        } else {
2369                            Some(after_op_trimmed.to_string())
2370                        };
2371                        return Some((
2372                            CursorContext::AfterComparisonOp(
2373                                col_name.to_string(),
2374                                op.trim().to_string(),
2375                            ),
2376                            partial,
2377                        ));
2378                    }
2379                }
2380            }
2381        }
2382    }
2383    None
2384}
2385
2386fn analyze_statement(
2387    stmt: &SelectStatement,
2388    query: &str,
2389    _cursor_pos: usize,
2390) -> (CursorContext, Option<String>) {
2391    // First check for method call context (e.g., "columnName." or "columnName.Con")
2392    let trimmed = query.trim();
2393
2394    // Check if we're after a comparison operator (e.g., "createdDate > ")
2395    if let Some(result) = check_after_comparison_operator(query) {
2396        return result;
2397    }
2398
2399    // First check if we're after AND/OR - this takes precedence
2400    // Helper function to check if string ends with a logical operator
2401    let ends_with_logical_op = |s: &str| -> bool {
2402        let s_upper = s.to_uppercase();
2403        s_upper.ends_with(" AND") || s_upper.ends_with(" OR")
2404    };
2405
2406    if ends_with_logical_op(trimmed) {
2407        // Don't check for method context if we're clearly after a logical operator
2408    } else {
2409        // Look for the last dot in the query
2410        if let Some(dot_pos) = trimmed.rfind('.') {
2411            // Check if we're after a column name and dot
2412            let before_dot = safe_slice_to(trimmed, dot_pos);
2413            let after_dot_start = dot_pos + 1;
2414            let after_dot = if after_dot_start < trimmed.len() {
2415                &trimmed[after_dot_start..]
2416            } else {
2417                ""
2418            };
2419
2420            // Check if the part after dot looks like an incomplete method call
2421            // (not a complete method call like "Contains(...)")
2422            if !after_dot.contains('(') {
2423                // Try to extract the column name - could be quoted or regular
2424                let col_name = if before_dot.ends_with('"') {
2425                    // Handle quoted identifier - search backwards for matching opening quote
2426                    let bytes = before_dot.as_bytes();
2427                    let pos = before_dot.len() - 1; // Position of closing quote
2428
2429                    find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2430                } else {
2431                    // Regular identifier - get the last word, handling parentheses
2432                    // Strip all leading parentheses
2433                    before_dot
2434                        .split_whitespace()
2435                        .last()
2436                        .map(|word| word.trim_start_matches('('))
2437                };
2438
2439                if let Some(col_name) = col_name {
2440                    // For quoted identifiers, keep the quotes, for regular identifiers check validity
2441                    let is_valid = Parser::is_valid_identifier(col_name);
2442
2443                    if is_valid {
2444                        return handle_method_call_context(col_name, after_dot);
2445                    }
2446                }
2447            }
2448        }
2449    }
2450
2451    // Check if we're in WHERE clause
2452    if let Some(where_clause) = &stmt.where_clause {
2453        // Check if query ends with AND/OR (with or without trailing space/partial)
2454        let trimmed_upper = trimmed.to_uppercase();
2455        if trimmed_upper.ends_with(" AND") || trimmed_upper.ends_with(" OR") {
2456            let op = if trimmed_upper.ends_with(" AND") {
2457                LogicalOp::And
2458            } else {
2459                LogicalOp::Or
2460            };
2461            return (CursorContext::AfterLogicalOp(op), None);
2462        }
2463
2464        // Check if we have AND/OR followed by a partial word
2465        let query_upper = query.to_uppercase();
2466        if let Some(and_pos) = query_upper.rfind(" AND ") {
2467            let after_and = safe_slice_from(query, and_pos + 5);
2468            let partial = extract_partial_at_end(after_and);
2469            if partial.is_some() {
2470                return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
2471            }
2472        }
2473
2474        if let Some(or_pos) = query_upper.rfind(" OR ") {
2475            let after_or = safe_slice_from(query, or_pos + 4);
2476            let partial = extract_partial_at_end(after_or);
2477            if partial.is_some() {
2478                return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
2479            }
2480        }
2481
2482        if let Some(last_condition) = where_clause.conditions.last() {
2483            if let Some(connector) = &last_condition.connector {
2484                // We're after AND/OR
2485                return (
2486                    CursorContext::AfterLogicalOp(connector.clone()),
2487                    extract_partial_at_end(query),
2488                );
2489            }
2490        }
2491        // We're in WHERE clause but not after AND/OR
2492        return (CursorContext::WhereClause, extract_partial_at_end(query));
2493    }
2494
2495    // Check if we're after ORDER BY
2496    let query_upper = query.to_uppercase();
2497    if query_upper.ends_with(" ORDER BY") {
2498        return (CursorContext::OrderByClause, None);
2499    }
2500
2501    // Check other contexts based on what's in the statement
2502    if stmt.order_by.is_some() {
2503        return (CursorContext::OrderByClause, extract_partial_at_end(query));
2504    }
2505
2506    if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
2507        return (CursorContext::FromClause, extract_partial_at_end(query));
2508    }
2509
2510    if !stmt.columns.is_empty() && stmt.from_table.is_none() {
2511        return (CursorContext::SelectClause, extract_partial_at_end(query));
2512    }
2513
2514    (CursorContext::Unknown, None)
2515}
2516
2517/// Render a token for an error message: the literal text where we have it, so the
2518/// user sees what they typed rather than an internal variant name.
2519fn describe_token(token: &Token) -> String {
2520    if let Some(kw) = token.as_keyword_str() {
2521        return format!("keyword '{kw}'");
2522    }
2523    match token {
2524        Token::Identifier(s) | Token::QuotedIdentifier(s) => format!("'{s}'"),
2525        Token::StringLiteral(s) => format!("string literal '{s}'"),
2526        Token::NumberLiteral(s) => format!("number '{s}'"),
2527        Token::Comma => "','".to_string(),
2528        Token::Semicolon => "';'".to_string(),
2529        Token::LeftParen => "'('".to_string(),
2530        Token::RightParen => "')'".to_string(),
2531        Token::Star => "'*'".to_string(),
2532        Token::Dot => "'.'".to_string(),
2533        Token::Eof => "end of input".to_string(),
2534        other => format!("{other:?}"),
2535    }
2536}
2537
2538/// Helper function to find the last occurrence of a token type in the token stream
2539fn find_last_token(tokens: &[(usize, usize, Token)], target: &Token) -> Option<usize> {
2540    tokens
2541        .iter()
2542        .rposition(|(_, _, t)| t == target)
2543        .map(|idx| tokens[idx].0)
2544}
2545
2546/// Helper function to find the last occurrence of any matching token
2547fn find_last_matching_token<F>(
2548    tokens: &[(usize, usize, Token)],
2549    predicate: F,
2550) -> Option<(usize, &Token)>
2551where
2552    F: Fn(&Token) -> bool,
2553{
2554    tokens
2555        .iter()
2556        .rposition(|(_, _, t)| predicate(t))
2557        .map(|idx| (tokens[idx].0, &tokens[idx].2))
2558}
2559
2560/// Helper function to check if we're in a specific clause based on tokens
2561fn is_in_clause(
2562    tokens: &[(usize, usize, Token)],
2563    clause_token: Token,
2564    exclude_tokens: &[Token],
2565) -> bool {
2566    // Find the last occurrence of the clause token
2567    if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2568        // Check if any exclude tokens appear after it
2569        for (pos, _, token) in tokens.iter() {
2570            if *pos > clause_pos && exclude_tokens.contains(token) {
2571                return false;
2572            }
2573        }
2574        return true;
2575    }
2576    false
2577}
2578
2579fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2580    // Tokenize the query up to cursor position
2581    let mut lexer = Lexer::new(query);
2582    let tokens = lexer.tokenize_all_with_positions();
2583
2584    let trimmed = query.trim();
2585
2586    #[cfg(test)]
2587    {
2588        if trimmed.contains("\"Last Name\"") {
2589            eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
2590        }
2591    }
2592
2593    // Check if we're after a comparison operator (e.g., "createdDate > ")
2594    if let Some(result) = check_after_comparison_operator(query) {
2595        return result;
2596    }
2597
2598    // Look for the last dot in the query (method call context) - check this FIRST
2599    // before AND/OR detection to properly handle cases like "AND (Country."
2600    if let Some(dot_pos) = trimmed.rfind('.') {
2601        #[cfg(test)]
2602        {
2603            if trimmed.contains("\"Last Name\"") {
2604                eprintln!("DEBUG: Found dot at position {dot_pos}");
2605            }
2606        }
2607        // Check if we're after a column name and dot
2608        let before_dot = &trimmed[..dot_pos];
2609        let after_dot = &trimmed[dot_pos + 1..];
2610
2611        // Check if the part after dot looks like an incomplete method call
2612        // (not a complete method call like "Contains(...)")
2613        if !after_dot.contains('(') {
2614            // Try to extract the column name before the dot
2615            // It could be a quoted identifier like "Last Name" or a regular identifier
2616            let col_name = if before_dot.ends_with('"') {
2617                // Handle quoted identifier - search backwards for matching opening quote
2618                let bytes = before_dot.as_bytes();
2619                let pos = before_dot.len() - 1; // Position of closing quote
2620
2621                #[cfg(test)]
2622                {
2623                    if trimmed.contains("\"Last Name\"") {
2624                        eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
2625                    }
2626                }
2627
2628                let found_start = find_quote_start(bytes, pos);
2629
2630                if let Some(start) = found_start {
2631                    // Extract the full quoted identifier including quotes
2632                    let result = safe_slice_from(before_dot, start);
2633                    #[cfg(test)]
2634                    {
2635                        if trimmed.contains("\"Last Name\"") {
2636                            eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
2637                        }
2638                    }
2639                    Some(result)
2640                } else {
2641                    #[cfg(test)]
2642                    {
2643                        if trimmed.contains("\"Last Name\"") {
2644                            eprintln!("DEBUG: No opening quote found!");
2645                        }
2646                    }
2647                    None
2648                }
2649            } else {
2650                // Regular identifier - get the last word, handling parentheses
2651                // Strip all leading parentheses
2652                before_dot
2653                    .split_whitespace()
2654                    .last()
2655                    .map(|word| word.trim_start_matches('('))
2656            };
2657
2658            if let Some(col_name) = col_name {
2659                #[cfg(test)]
2660                {
2661                    if trimmed.contains("\"Last Name\"") {
2662                        eprintln!("DEBUG: col_name = '{col_name}'");
2663                    }
2664                }
2665
2666                // For quoted identifiers, keep the quotes, for regular identifiers check validity
2667                let is_valid = Parser::is_valid_identifier(col_name);
2668
2669                #[cfg(test)]
2670                {
2671                    if trimmed.contains("\"Last Name\"") {
2672                        eprintln!("DEBUG: is_valid = {is_valid}");
2673                    }
2674                }
2675
2676                if is_valid {
2677                    return handle_method_call_context(col_name, after_dot);
2678                }
2679            }
2680        }
2681    }
2682
2683    // Check if we're after AND/OR using tokens - but only after checking for method calls
2684    if let Some((pos, token)) =
2685        find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2686    {
2687        // Check if cursor is after the logical operator
2688        let token_end_pos = if matches!(token, Token::And) {
2689            pos + 3 // "AND" is 3 characters
2690        } else {
2691            pos + 2 // "OR" is 2 characters
2692        };
2693
2694        if cursor_pos > token_end_pos {
2695            // Extract any partial word after the operator
2696            let after_op = safe_slice_from(query, token_end_pos + 1); // +1 for the space
2697            let partial = extract_partial_at_end(after_op);
2698            let op = if matches!(token, Token::And) {
2699                LogicalOp::And
2700            } else {
2701                LogicalOp::Or
2702            };
2703            return (CursorContext::AfterLogicalOp(op), partial);
2704        }
2705    }
2706
2707    // Check if the last token is AND or OR (handles case where it's at the very end)
2708    if let Some((_, _, last_token)) = tokens.last() {
2709        if matches!(last_token, Token::And | Token::Or) {
2710            let op = if matches!(last_token, Token::And) {
2711                LogicalOp::And
2712            } else {
2713                LogicalOp::Or
2714            };
2715            return (CursorContext::AfterLogicalOp(op), None);
2716        }
2717    }
2718
2719    // Check if we're in ORDER BY clause using tokens
2720    if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2721        // Check if there's a BY token after ORDER
2722        let has_by = tokens
2723            .iter()
2724            .any(|(pos, _, t)| *pos > order_pos && matches!(t, Token::By));
2725        if has_by
2726            || tokens
2727                .last()
2728                .map_or(false, |(_, _, t)| matches!(t, Token::OrderBy))
2729        {
2730            return (CursorContext::OrderByClause, extract_partial_at_end(query));
2731        }
2732    }
2733
2734    // Check if we're in WHERE clause using tokens
2735    if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2736        return (CursorContext::WhereClause, extract_partial_at_end(query));
2737    }
2738
2739    // Check if we're in FROM clause using tokens
2740    if is_in_clause(
2741        &tokens,
2742        Token::From,
2743        &[Token::Where, Token::OrderBy, Token::GroupBy],
2744    ) {
2745        return (CursorContext::FromClause, extract_partial_at_end(query));
2746    }
2747
2748    // Check if we're in SELECT clause using tokens
2749    if find_last_token(&tokens, &Token::Select).is_some()
2750        && find_last_token(&tokens, &Token::From).is_none()
2751    {
2752        return (CursorContext::SelectClause, extract_partial_at_end(query));
2753    }
2754
2755    (CursorContext::Unknown, None)
2756}
2757
2758fn extract_partial_at_end(query: &str) -> Option<String> {
2759    let trimmed = query.trim();
2760
2761    // First check if the last word itself starts with a quote (unclosed quoted identifier being typed)
2762    if let Some(last_word) = trimmed.split_whitespace().last() {
2763        if last_word.starts_with('"') && !last_word.ends_with('"') {
2764            // This is an unclosed quoted identifier like "Cust
2765            return Some(last_word.to_string());
2766        }
2767    }
2768
2769    // Regular identifier extraction
2770    let last_word = trimmed.split_whitespace().last()?;
2771
2772    // Check if it's a partial identifier (not a keyword or operator)
2773    // First check if it's alphanumeric (potential identifier)
2774    if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2775        // Use lexer to determine if it's a keyword or identifier
2776        if !is_sql_keyword(last_word) {
2777            Some(last_word.to_string())
2778        } else {
2779            None
2780        }
2781    } else {
2782        None
2783    }
2784}
2785
2786// Implement the ParsePrimary trait for Parser to use the modular expression parsing
2787impl ParsePrimary for Parser {
2788    fn current_token(&self) -> &Token {
2789        &self.current_token
2790    }
2791
2792    fn advance(&mut self) {
2793        self.advance();
2794    }
2795
2796    fn consume(&mut self, expected: Token) -> Result<(), String> {
2797        self.consume(expected)
2798    }
2799
2800    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2801        self.parse_case_expression()
2802    }
2803
2804    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2805        self.parse_function_args()
2806    }
2807
2808    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2809        self.parse_window_spec()
2810    }
2811
2812    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2813        self.parse_logical_or()
2814    }
2815
2816    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2817        self.parse_comparison()
2818    }
2819
2820    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2821        self.parse_expression_list()
2822    }
2823
2824    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2825        // Parse subquery without parenthesis balance validation
2826        if matches!(self.current_token, Token::With) {
2827            self.parse_with_clause_inner()
2828        } else {
2829            self.parse_select_statement_inner()
2830        }
2831    }
2832}
2833
2834// Implement the ExpressionParser trait for Parser to use the modular expression parsing
2835impl ExpressionParser for Parser {
2836    fn current_token(&self) -> &Token {
2837        &self.current_token
2838    }
2839
2840    fn advance(&mut self) {
2841        // Call the main advance method directly to avoid recursion
2842        match &self.current_token {
2843            Token::LeftParen => self.paren_depth += 1,
2844            Token::RightParen => {
2845                self.paren_depth -= 1;
2846            }
2847            _ => {}
2848        }
2849        self.current_token = self.lexer.next_token();
2850    }
2851
2852    fn peek(&self) -> Option<&Token> {
2853        // We can't return a reference to a token from a temporary lexer,
2854        // so we need a different approach. For now, let's use a workaround
2855        // that checks the next token type without consuming it.
2856        // This is a limitation of the current design.
2857        // A proper fix would be to store the peeked token in the Parser struct.
2858        None // TODO: Implement proper lookahead
2859    }
2860
2861    fn is_at_end(&self) -> bool {
2862        matches!(self.current_token, Token::Eof)
2863    }
2864
2865    fn consume(&mut self, expected: Token) -> Result<(), String> {
2866        // Call the main consume method to avoid recursion
2867        if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
2868            self.update_paren_depth(&expected)?;
2869            self.current_token = self.lexer.next_token();
2870            Ok(())
2871        } else {
2872            Err(format!(
2873                "Expected {:?}, found {:?}",
2874                expected, self.current_token
2875            ))
2876        }
2877    }
2878
2879    fn parse_identifier(&mut self) -> Result<String, String> {
2880        if let Token::Identifier(id) = &self.current_token {
2881            let id = id.clone();
2882            self.advance();
2883            Ok(id)
2884        } else {
2885            Err(format!(
2886                "Expected identifier, found {:?}",
2887                self.current_token
2888            ))
2889        }
2890    }
2891}
2892
2893// Implement the ParseArithmetic trait for Parser to use the modular arithmetic parsing
2894impl ParseArithmetic for Parser {
2895    fn current_token(&self) -> &Token {
2896        &self.current_token
2897    }
2898
2899    fn advance(&mut self) {
2900        self.advance();
2901    }
2902
2903    fn consume(&mut self, expected: Token) -> Result<(), String> {
2904        self.consume(expected)
2905    }
2906
2907    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2908        self.parse_primary()
2909    }
2910
2911    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2912        self.parse_multiplicative()
2913    }
2914
2915    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2916        self.parse_method_args()
2917    }
2918}
2919
2920// Implement the ParseComparison trait for Parser to use the modular comparison parsing
2921impl ParseComparison for Parser {
2922    fn current_token(&self) -> &Token {
2923        &self.current_token
2924    }
2925
2926    fn advance(&mut self) {
2927        self.advance();
2928    }
2929
2930    fn consume(&mut self, expected: Token) -> Result<(), String> {
2931        self.consume(expected)
2932    }
2933
2934    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2935        self.parse_primary()
2936    }
2937
2938    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2939        self.parse_additive()
2940    }
2941
2942    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2943        self.parse_expression_list()
2944    }
2945
2946    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2947        // Parse subquery without parenthesis balance validation
2948        if matches!(self.current_token, Token::With) {
2949            self.parse_with_clause_inner()
2950        } else {
2951            self.parse_select_statement_inner()
2952        }
2953    }
2954}
2955
2956// Implement the ParseLogical trait for Parser to use the modular logical parsing
2957impl ParseLogical for Parser {
2958    fn current_token(&self) -> &Token {
2959        &self.current_token
2960    }
2961
2962    fn advance(&mut self) {
2963        self.advance();
2964    }
2965
2966    fn consume(&mut self, expected: Token) -> Result<(), String> {
2967        self.consume(expected)
2968    }
2969
2970    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2971        self.parse_logical_and()
2972    }
2973
2974    fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2975        // This is the base for logical AND - it should parse comparison expressions
2976        // to avoid infinite recursion with parse_expression
2977        self.parse_comparison()
2978    }
2979
2980    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2981        self.parse_comparison()
2982    }
2983
2984    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2985        self.parse_expression_list()
2986    }
2987}
2988
2989// Implement the ParseCase trait for Parser to use the modular CASE parsing
2990impl ParseCase for Parser {
2991    fn current_token(&self) -> &Token {
2992        &self.current_token
2993    }
2994
2995    fn advance(&mut self) {
2996        self.advance();
2997    }
2998
2999    fn consume(&mut self, expected: Token) -> Result<(), String> {
3000        self.consume(expected)
3001    }
3002
3003    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
3004        self.parse_expression()
3005    }
3006}
3007
3008fn is_sql_keyword(word: &str) -> bool {
3009    // Use the lexer to check if this word produces a keyword token
3010    let mut lexer = Lexer::new(word);
3011    let token = lexer.next_token();
3012
3013    // Check if it's a keyword token (not an identifier)
3014    !matches!(token, Token::Identifier(_) | Token::Eof)
3015}
3016
3017#[cfg(test)]
3018mod tests {
3019    use super::*;
3020
3021    /// Test that Parser::new() defaults to Standard mode (backward compatible)
3022    #[test]
3023    fn test_parser_mode_default_is_standard() {
3024        let sql = "-- Leading comment\nSELECT * FROM users";
3025        let mut parser = Parser::new(sql);
3026        let stmt = parser.parse().unwrap();
3027
3028        // In Standard mode, comments should be empty
3029        assert!(stmt.leading_comments.is_empty());
3030        assert!(stmt.trailing_comment.is_none());
3031    }
3032
3033    /// Test that PreserveComments mode collects leading comments
3034    #[test]
3035    fn test_parser_mode_preserve_leading_comments() {
3036        let sql = "-- Important query\n-- Author: Alice\nSELECT id, name FROM users";
3037        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3038        let stmt = parser.parse().unwrap();
3039
3040        // Should have 2 leading comments
3041        assert_eq!(stmt.leading_comments.len(), 2);
3042        assert!(stmt.leading_comments[0].is_line_comment);
3043        assert!(stmt.leading_comments[0].text.contains("Important query"));
3044        assert!(stmt.leading_comments[1].text.contains("Author: Alice"));
3045    }
3046
3047    /// Test that PreserveComments mode collects trailing comments
3048    #[test]
3049    fn test_parser_mode_preserve_trailing_comment() {
3050        let sql = "SELECT * FROM users -- Fetch all users";
3051        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3052        let stmt = parser.parse().unwrap();
3053
3054        // Should have trailing comment
3055        assert!(stmt.trailing_comment.is_some());
3056        let comment = stmt.trailing_comment.unwrap();
3057        assert!(comment.is_line_comment);
3058        assert!(comment.text.contains("Fetch all users"));
3059    }
3060
3061    /// Test that PreserveComments mode handles block comments
3062    #[test]
3063    fn test_parser_mode_preserve_block_comments() {
3064        let sql = "/* Query explanation */\nSELECT * FROM users";
3065        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3066        let stmt = parser.parse().unwrap();
3067
3068        // Should have leading block comment
3069        assert_eq!(stmt.leading_comments.len(), 1);
3070        assert!(!stmt.leading_comments[0].is_line_comment); // It's a block comment
3071        assert!(stmt.leading_comments[0].text.contains("Query explanation"));
3072    }
3073
3074    /// Test that PreserveComments mode collects both leading and trailing
3075    #[test]
3076    fn test_parser_mode_preserve_both_comments() {
3077        let sql = "-- Leading\nSELECT * FROM users -- Trailing";
3078        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3079        let stmt = parser.parse().unwrap();
3080
3081        // Should have both
3082        assert_eq!(stmt.leading_comments.len(), 1);
3083        assert!(stmt.leading_comments[0].text.contains("Leading"));
3084        assert!(stmt.trailing_comment.is_some());
3085        assert!(stmt.trailing_comment.unwrap().text.contains("Trailing"));
3086    }
3087
3088    /// Test that Standard mode has zero performance overhead (no comment parsing)
3089    #[test]
3090    fn test_parser_mode_standard_ignores_comments() {
3091        let sql = "-- Comment 1\n/* Comment 2 */\nSELECT * FROM users -- Comment 3";
3092        let mut parser = Parser::with_mode(sql, ParserMode::Standard);
3093        let stmt = parser.parse().unwrap();
3094
3095        // Comments should be completely ignored
3096        assert!(stmt.leading_comments.is_empty());
3097        assert!(stmt.trailing_comment.is_none());
3098
3099        // But query should still parse correctly
3100        assert_eq!(stmt.select_items.len(), 1);
3101        assert_eq!(stmt.from_table, Some("users".to_string()));
3102    }
3103
3104    /// Test backward compatibility - existing code using Parser::new() unchanged
3105    #[test]
3106    fn test_parser_backward_compatibility() {
3107        let sql = "SELECT id, name FROM users WHERE active = true";
3108
3109        // Old way (still works, defaults to Standard mode)
3110        let mut parser1 = Parser::new(sql);
3111        let stmt1 = parser1.parse().unwrap();
3112
3113        // Explicit Standard mode (same behavior)
3114        let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
3115        let stmt2 = parser2.parse().unwrap();
3116
3117        // Both should produce identical ASTs (comments are empty in both)
3118        assert_eq!(stmt1.select_items.len(), stmt2.select_items.len());
3119        assert_eq!(stmt1.from_table, stmt2.from_table);
3120        assert_eq!(stmt1.where_clause.is_some(), stmt2.where_clause.is_some());
3121        assert!(stmt1.leading_comments.is_empty());
3122        assert!(stmt2.leading_comments.is_empty());
3123    }
3124
3125    /// Test PIVOT parsing - currently returns error as execution is not implemented
3126    #[test]
3127    fn test_pivot_parsing_not_yet_supported() {
3128        let sql = "SELECT * FROM food_eaten PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle', 'Apple'))";
3129        let mut parser = Parser::new(sql);
3130        let result = parser.parse();
3131
3132        // PIVOT is now fully supported! Verify parsing succeeds
3133        assert!(result.is_ok());
3134        let stmt = result.unwrap();
3135
3136        // Verify from_source contains a PIVOT
3137        assert!(stmt.from_source.is_some());
3138        if let Some(crate::sql::parser::ast::TableSource::Pivot { .. }) = stmt.from_source {
3139            // Success!
3140        } else {
3141            panic!("Expected from_source to be a Pivot variant");
3142        }
3143    }
3144
3145    /// Test PIVOT syntax with different aggregate functions
3146    #[test]
3147    fn test_pivot_aggregate_functions() {
3148        // Test with SUM - PIVOT is now fully supported!
3149        let sql = "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb', 'Mar'))";
3150        let mut parser = Parser::new(sql);
3151        let result = parser.parse();
3152        assert!(result.is_ok());
3153
3154        // Test with COUNT
3155        let sql2 = "SELECT * FROM sales PIVOT (COUNT(*) FOR month IN ('Jan', 'Feb'))";
3156        let mut parser2 = Parser::new(sql2);
3157        let result2 = parser2.parse();
3158        assert!(result2.is_ok());
3159
3160        // Test with AVG
3161        let sql3 = "SELECT * FROM sales PIVOT (AVG(price) FOR category IN ('A', 'B'))";
3162        let mut parser3 = Parser::new(sql3);
3163        let result3 = parser3.parse();
3164        assert!(result3.is_ok());
3165    }
3166
3167    /// Test PIVOT with subquery source
3168    #[test]
3169    fn test_pivot_with_subquery() {
3170        let sql = "SELECT * FROM (SELECT * FROM food_eaten WHERE Id > 5) AS t \
3171                   PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle'))";
3172        let mut parser = Parser::new(sql);
3173        let result = parser.parse();
3174
3175        // PIVOT with subquery is now fully supported!
3176        assert!(result.is_ok());
3177        let stmt = result.unwrap();
3178        assert!(stmt.from_source.is_some());
3179    }
3180
3181    /// Test PIVOT with alias
3182    #[test]
3183    fn test_pivot_with_alias() {
3184        let sql =
3185            "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb')) AS pivot_table";
3186        let mut parser = Parser::new(sql);
3187        let result = parser.parse();
3188
3189        // PIVOT with alias is now fully supported!
3190        assert!(result.is_ok());
3191        let stmt = result.unwrap();
3192        assert!(stmt.from_source.is_some());
3193    }
3194
3195    /// Pull the WebCTESpec out of a parsed top-level statement that uses a
3196    /// single WEB CTE. Test helper.
3197    fn extract_web_spec(
3198        stmt: &crate::sql::parser::ast::SelectStatement,
3199    ) -> &crate::sql::parser::ast::WebCTESpec {
3200        use crate::sql::parser::ast::CTEType;
3201        assert!(!stmt.ctes.is_empty(), "statement should have CTEs");
3202        match &stmt.ctes[0].cte_type {
3203            CTEType::Web(spec) => spec,
3204            other => panic!("expected Web CTE, got {:?}", other),
3205        }
3206    }
3207
3208    #[test]
3209    fn test_web_cte_delimiter_pipe() {
3210        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '|') \
3211                   SELECT * FROM foo";
3212        let mut parser = Parser::new(sql);
3213        let stmt = parser.parse().expect("parse failed");
3214        let spec = extract_web_spec(&stmt);
3215        assert_eq!(spec.delimiter, Some(b'|'));
3216    }
3217
3218    #[test]
3219    fn test_web_cte_delimiter_tab_via_escape() {
3220        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '\\t') \
3221                   SELECT * FROM foo";
3222        let mut parser = Parser::new(sql);
3223        let stmt = parser.parse().expect("parse failed");
3224        let spec = extract_web_spec(&stmt);
3225        assert_eq!(spec.delimiter, Some(b'\t'));
3226    }
3227
3228    #[test]
3229    fn test_web_cte_no_delimiter_defaults_to_none() {
3230        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV) SELECT * FROM foo";
3231        let mut parser = Parser::new(sql);
3232        let stmt = parser.parse().expect("parse failed");
3233        let spec = extract_web_spec(&stmt);
3234        assert!(spec.delimiter.is_none());
3235    }
3236
3237    #[test]
3238    fn test_web_cte_delimiter_rejects_multi_char() {
3239        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '||') \
3240                   SELECT * FROM foo";
3241        let mut parser = Parser::new(sql);
3242        let err = parser.parse().unwrap_err();
3243        let msg = err.to_string();
3244        assert!(
3245            msg.contains("DELIMITER") || msg.contains("single ASCII"),
3246            "should reject multi-char delimiter: {}",
3247            msg
3248        );
3249    }
3250}