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, 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        // IN is handled down in parse_comparison, alongside NOT IN — applying it
1706        // here (outside the OR/AND hierarchy) was P29/P30.
1707        let left = self.parse_logical_or()?;
1708
1709        let result = Ok(left);
1710        self.trace_exit("parse_expression", &result);
1711        result
1712    }
1713
1714    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1715        // Use the new modular comparison expression parser
1716        parse_comparison_expr(self)
1717    }
1718
1719    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1720        // Use the new modular arithmetic expression parser
1721        parse_additive_expr(self)
1722    }
1723
1724    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1725        // Use the new modular arithmetic expression parser
1726        parse_multiplicative_expr(self)
1727    }
1728
1729    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1730        // Use the new modular logical expression parser
1731        parse_logical_or_expr(self)
1732    }
1733
1734    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1735        // Use the new modular logical expression parser
1736        parse_logical_and_expr(self)
1737    }
1738
1739    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1740        // Use the new modular CASE expression parser
1741        parse_case_expr(self)
1742    }
1743
1744    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1745        // Use the new modular primary expression parser
1746        // Clone the necessary data to avoid borrowing issues
1747        let columns = self.columns.clone();
1748        let in_method_args = self.in_method_args;
1749        let ctx = PrimaryExpressionContext {
1750            columns: &columns,
1751            in_method_args,
1752        };
1753        parse_primary_expr(self, &ctx)
1754    }
1755
1756    // Keep the old implementation temporarily for reference (will be removed)
1757    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1758        // Set flag to indicate we're parsing method arguments
1759        self.in_method_args = true;
1760
1761        let args = self.parse_argument_list()?;
1762
1763        // Clear the flag
1764        self.in_method_args = false;
1765
1766        Ok(args)
1767    }
1768
1769    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1770        let mut args = Vec::new();
1771        let mut has_distinct = false;
1772
1773        if !matches!(self.current_token, Token::RightParen) {
1774            // Check if first argument starts with DISTINCT
1775            if matches!(self.current_token, Token::Distinct) {
1776                self.advance(); // consume DISTINCT
1777                has_distinct = true;
1778            }
1779
1780            // Parse full expressions as arguments — this allows comparisons and
1781            // boolean logic inside function calls, e.g. AVG(x > 5), SUM(a = 'b')
1782            args.push(self.parse_logical_or()?);
1783
1784            // Parse any remaining arguments (DISTINCT only applies to first arg for aggregates)
1785            while matches!(self.current_token, Token::Comma) {
1786                self.advance();
1787                args.push(self.parse_logical_or()?);
1788            }
1789        }
1790
1791        Ok((args, has_distinct))
1792    }
1793
1794    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1795        let mut expressions = Vec::new();
1796
1797        loop {
1798            expressions.push(self.parse_expression()?);
1799
1800            if matches!(self.current_token, Token::Comma) {
1801                self.advance();
1802            } else {
1803                break;
1804            }
1805        }
1806
1807        Ok(expressions)
1808    }
1809
1810    #[must_use]
1811    pub fn get_position(&self) -> usize {
1812        self.lexer.get_position()
1813    }
1814
1815    // Check if current token is a JOIN-related token
1816    fn is_join_token(&self) -> bool {
1817        matches!(
1818            self.current_token,
1819            Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
1820        )
1821    }
1822
1823    // Parse a JOIN clause
1824    fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1825        // Determine join type
1826        let join_type = match &self.current_token {
1827            Token::Join => {
1828                self.advance();
1829                JoinType::Inner // Default JOIN is INNER JOIN
1830            }
1831            Token::Inner => {
1832                self.advance();
1833                if !matches!(self.current_token, Token::Join) {
1834                    return Err("Expected JOIN after INNER".to_string());
1835                }
1836                self.advance();
1837                JoinType::Inner
1838            }
1839            Token::Left => {
1840                self.advance();
1841                // Handle optional OUTER keyword
1842                if matches!(self.current_token, Token::Outer) {
1843                    self.advance();
1844                }
1845                if !matches!(self.current_token, Token::Join) {
1846                    return Err("Expected JOIN after LEFT".to_string());
1847                }
1848                self.advance();
1849                JoinType::Left
1850            }
1851            Token::Right => {
1852                self.advance();
1853                // Handle optional OUTER keyword
1854                if matches!(self.current_token, Token::Outer) {
1855                    self.advance();
1856                }
1857                if !matches!(self.current_token, Token::Join) {
1858                    return Err("Expected JOIN after RIGHT".to_string());
1859                }
1860                self.advance();
1861                JoinType::Right
1862            }
1863            Token::Full => {
1864                self.advance();
1865                // Handle optional OUTER keyword
1866                if matches!(self.current_token, Token::Outer) {
1867                    self.advance();
1868                }
1869                if !matches!(self.current_token, Token::Join) {
1870                    return Err("Expected JOIN after FULL".to_string());
1871                }
1872                self.advance();
1873                JoinType::Full
1874            }
1875            Token::Cross => {
1876                self.advance();
1877                if !matches!(self.current_token, Token::Join) {
1878                    return Err("Expected JOIN after CROSS".to_string());
1879                }
1880                self.advance();
1881                JoinType::Cross
1882            }
1883            _ => return Err("Expected JOIN keyword".to_string()),
1884        };
1885
1886        // Parse the table being joined
1887        let (table, alias) = self.parse_join_table_source()?;
1888
1889        // Parse ON condition (required for all joins except CROSS JOIN)
1890        let condition = if join_type == JoinType::Cross {
1891            // CROSS JOIN doesn't have ON condition - create empty condition
1892            JoinCondition { conditions: vec![] }
1893        } else {
1894            if !matches!(self.current_token, Token::On) {
1895                return Err("Expected ON keyword after JOIN table".to_string());
1896            }
1897            self.advance();
1898            self.parse_join_condition()?
1899        };
1900
1901        Ok(JoinClause {
1902            join_type,
1903            table,
1904            alias,
1905            condition,
1906        })
1907    }
1908
1909    fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1910        let table = match &self.current_token {
1911            Token::Identifier(name) => {
1912                let table_name = name.clone();
1913                self.advance();
1914                TableSource::Table(table_name)
1915            }
1916            Token::LeftParen => {
1917                // Subquery as table source
1918                self.advance();
1919                let subquery = self.parse_select_statement_inner()?;
1920                if !matches!(self.current_token, Token::RightParen) {
1921                    return Err("Expected ')' after subquery".to_string());
1922                }
1923                self.advance();
1924
1925                // Subqueries must have an alias
1926                let alias = match &self.current_token {
1927                    Token::Identifier(alias_name) => {
1928                        let alias = alias_name.clone();
1929                        self.advance();
1930                        alias
1931                    }
1932                    Token::As => {
1933                        self.advance();
1934                        match &self.current_token {
1935                            Token::Identifier(alias_name) => {
1936                                let alias = alias_name.clone();
1937                                self.advance();
1938                                alias
1939                            }
1940                            _ => return Err("Expected alias after AS keyword".to_string()),
1941                        }
1942                    }
1943                    _ => return Err("Subqueries must have an alias".to_string()),
1944                };
1945
1946                return Ok((
1947                    TableSource::DerivedTable {
1948                        query: Box::new(subquery),
1949                        alias: alias.clone(),
1950                    },
1951                    Some(alias),
1952                ));
1953            }
1954            _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1955        };
1956
1957        // Check for optional alias
1958        let alias = match &self.current_token {
1959            Token::Identifier(alias_name) => {
1960                let alias = alias_name.clone();
1961                self.advance();
1962                Some(alias)
1963            }
1964            Token::As => {
1965                self.advance();
1966                match &self.current_token {
1967                    Token::Identifier(alias_name) => {
1968                        let alias = alias_name.clone();
1969                        self.advance();
1970                        Some(alias)
1971                    }
1972                    _ => return Err("Expected alias after AS keyword".to_string()),
1973                }
1974            }
1975            _ => None,
1976        };
1977
1978        Ok((table, alias))
1979    }
1980
1981    fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1982        let mut conditions = Vec::new();
1983
1984        // Parse first condition
1985        conditions.push(self.parse_single_join_condition()?);
1986
1987        // Parse additional conditions connected by AND
1988        while matches!(self.current_token, Token::And) {
1989            self.advance(); // consume AND
1990            conditions.push(self.parse_single_join_condition()?);
1991        }
1992
1993        Ok(JoinCondition { conditions })
1994    }
1995
1996    fn parse_single_join_condition(&mut self) -> Result<SingleJoinCondition, String> {
1997        // Parse left side as additive expression (stops before comparison operators)
1998        // This allows the comparison operator to be explicitly parsed by this function
1999        let left_expr = self.parse_additive()?;
2000
2001        // Parse operator
2002        let operator = match &self.current_token {
2003            Token::Equal => JoinOperator::Equal,
2004            Token::NotEqual => JoinOperator::NotEqual,
2005            Token::LessThan => JoinOperator::LessThan,
2006            Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
2007            Token::GreaterThan => JoinOperator::GreaterThan,
2008            Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
2009            _ => return Err("Expected comparison operator in JOIN condition".to_string()),
2010        };
2011        self.advance();
2012
2013        // Parse right side as additive expression (stops before comparison operators)
2014        let right_expr = self.parse_additive()?;
2015
2016        Ok(SingleJoinCondition {
2017            left_expr,
2018            operator,
2019            right_expr,
2020        })
2021    }
2022
2023    fn parse_column_reference(&mut self) -> Result<String, String> {
2024        match &self.current_token {
2025            Token::Identifier(name) => {
2026                let mut column_ref = name.clone();
2027                self.advance();
2028
2029                // Check for table.column notation
2030                if matches!(self.current_token, Token::Dot) {
2031                    self.advance();
2032                    match &self.current_token {
2033                        Token::Identifier(col_name) => {
2034                            column_ref.push('.');
2035                            column_ref.push_str(col_name);
2036                            self.advance();
2037                        }
2038                        _ => return Err("Expected column name after '.'".to_string()),
2039                    }
2040                }
2041
2042                Ok(column_ref)
2043            }
2044            _ => Err("Expected column reference".to_string()),
2045        }
2046    }
2047
2048    // ===== PIVOT Parsing =====
2049
2050    /// Parse a PIVOT clause after a table source
2051    /// Syntax: PIVOT (aggregate_function FOR pivot_column IN (value1, value2, ...))
2052    fn parse_pivot_clause(&mut self, source: TableSource) -> Result<TableSource, String> {
2053        // Consume PIVOT keyword
2054        self.consume(Token::Pivot)?;
2055
2056        // Consume opening parenthesis
2057        self.consume(Token::LeftParen)?;
2058
2059        // Parse aggregate function (e.g., MAX(AmountEaten))
2060        let aggregate = self.parse_pivot_aggregate()?;
2061
2062        // Parse FOR keyword
2063        self.consume(Token::For)?;
2064
2065        // Parse pivot column name
2066        let pivot_column = match &self.current_token {
2067            Token::Identifier(col) => {
2068                let column = col.clone();
2069                self.advance();
2070                column
2071            }
2072            Token::QuotedIdentifier(col) => {
2073                let column = col.clone();
2074                self.advance();
2075                column
2076            }
2077            _ => return Err("Expected column name after FOR in PIVOT".to_string()),
2078        };
2079
2080        // Parse IN keyword
2081        if !matches!(self.current_token, Token::In) {
2082            return Err("Expected IN keyword in PIVOT clause".to_string());
2083        }
2084        self.advance();
2085
2086        // Parse pivot values
2087        let pivot_values = self.parse_pivot_in_clause()?;
2088
2089        // Consume closing parenthesis for PIVOT
2090        self.consume(Token::RightParen)?;
2091
2092        // Check for optional alias
2093        let alias = self.parse_optional_alias()?;
2094
2095        Ok(TableSource::Pivot {
2096            source: Box::new(source),
2097            aggregate,
2098            pivot_column,
2099            pivot_values,
2100            alias,
2101        })
2102    }
2103
2104    /// Parse the aggregate function specification in PIVOT
2105    /// Example: MAX(AmountEaten), SUM(sales), COUNT(*)
2106    fn parse_pivot_aggregate(&mut self) -> Result<PivotAggregate, String> {
2107        // Parse aggregate function name
2108        let function = match &self.current_token {
2109            Token::Identifier(name) => {
2110                let func_name = name.to_uppercase();
2111                // Validate it's an aggregate function
2112                match func_name.as_str() {
2113                    "MAX" | "MIN" | "SUM" | "AVG" | "COUNT" => {
2114                        self.advance();
2115                        func_name
2116                    }
2117                    _ => {
2118                        return Err(format!(
2119                            "Expected aggregate function (MAX, MIN, SUM, AVG, COUNT), got {}",
2120                            func_name
2121                        ))
2122                    }
2123                }
2124            }
2125            _ => return Err("Expected aggregate function in PIVOT".to_string()),
2126        };
2127
2128        // Consume opening parenthesis
2129        self.consume(Token::LeftParen)?;
2130
2131        // Parse column name (or * for COUNT)
2132        let column = match &self.current_token {
2133            Token::Identifier(col) => {
2134                let column = col.clone();
2135                self.advance();
2136                column
2137            }
2138            Token::QuotedIdentifier(col) => {
2139                let column = col.clone();
2140                self.advance();
2141                column
2142            }
2143            Token::Star => {
2144                // COUNT(*) is allowed
2145                if function == "COUNT" {
2146                    self.advance();
2147                    "*".to_string()
2148                } else {
2149                    return Err(format!("Only COUNT can use *, not {}", function));
2150                }
2151            }
2152            _ => return Err("Expected column name in aggregate function".to_string()),
2153        };
2154
2155        // Consume closing parenthesis
2156        self.consume(Token::RightParen)?;
2157
2158        Ok(PivotAggregate { function, column })
2159    }
2160
2161    /// Parse the IN clause values in PIVOT
2162    /// Example: IN ('Sammich', 'Pickle', 'Apple')
2163    /// Returns vector of pivot values
2164    fn parse_pivot_in_clause(&mut self) -> Result<Vec<String>, String> {
2165        // Consume opening parenthesis
2166        self.consume(Token::LeftParen)?;
2167
2168        let mut values = Vec::new();
2169
2170        // Parse first value
2171        match &self.current_token {
2172            Token::StringLiteral(val) => {
2173                values.push(val.clone());
2174                self.advance();
2175            }
2176            Token::Identifier(val) => {
2177                // Allow unquoted identifiers as well
2178                values.push(val.clone());
2179                self.advance();
2180            }
2181            Token::NumberLiteral(val) => {
2182                // Allow numeric values
2183                values.push(val.clone());
2184                self.advance();
2185            }
2186            _ => return Err("Expected value in PIVOT IN clause".to_string()),
2187        }
2188
2189        // Parse additional values separated by commas
2190        while matches!(self.current_token, Token::Comma) {
2191            self.advance(); // consume comma
2192
2193            match &self.current_token {
2194                Token::StringLiteral(val) => {
2195                    values.push(val.clone());
2196                    self.advance();
2197                }
2198                Token::Identifier(val) => {
2199                    values.push(val.clone());
2200                    self.advance();
2201                }
2202                Token::NumberLiteral(val) => {
2203                    values.push(val.clone());
2204                    self.advance();
2205                }
2206                _ => return Err("Expected value after comma in PIVOT IN clause".to_string()),
2207            }
2208        }
2209
2210        // Consume closing parenthesis
2211        self.consume(Token::RightParen)?;
2212
2213        if values.is_empty() {
2214            return Err("PIVOT IN clause must have at least one value".to_string());
2215        }
2216
2217        Ok(values)
2218    }
2219}
2220
2221// Context detection for cursor position
2222#[derive(Debug, Clone)]
2223pub enum CursorContext {
2224    SelectClause,
2225    FromClause,
2226    WhereClause,
2227    OrderByClause,
2228    AfterColumn(String),
2229    AfterLogicalOp(LogicalOp),
2230    AfterComparisonOp(String, String), // column_name, operator
2231    InMethodCall(String, String),      // object, method
2232    InExpression,
2233    Unknown,
2234}
2235
2236/// Safe UTF-8 string slicing that ensures we don't slice in the middle of a character
2237fn safe_slice_to(s: &str, pos: usize) -> &str {
2238    if pos >= s.len() {
2239        return s;
2240    }
2241
2242    // Find the nearest valid character boundary at or before pos
2243    let mut safe_pos = pos;
2244    while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
2245        safe_pos -= 1;
2246    }
2247
2248    &s[..safe_pos]
2249}
2250
2251/// Safe UTF-8 string slicing from a position to the end
2252fn safe_slice_from(s: &str, pos: usize) -> &str {
2253    if pos >= s.len() {
2254        return "";
2255    }
2256
2257    // Find the nearest valid character boundary at or after pos
2258    let mut safe_pos = pos;
2259    while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
2260        safe_pos += 1;
2261    }
2262
2263    &s[safe_pos..]
2264}
2265
2266#[must_use]
2267pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2268    let truncated = safe_slice_to(query, cursor_pos);
2269    let mut parser = Parser::new(truncated);
2270
2271    // Try to parse as much as possible
2272    if let Ok(stmt) = parser.parse() {
2273        let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
2274        #[cfg(test)]
2275        println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2276        (ctx, partial)
2277    } else {
2278        // Partial parse - analyze what we have
2279        let (ctx, partial) = analyze_partial(truncated, cursor_pos);
2280        #[cfg(test)]
2281        println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2282        (ctx, partial)
2283    }
2284}
2285
2286#[must_use]
2287pub fn tokenize_query(query: &str) -> Vec<String> {
2288    let mut lexer = Lexer::new(query);
2289    let tokens = lexer.tokenize_all();
2290    tokens.iter().map(|t| format!("{t:?}")).collect()
2291}
2292
2293#[must_use]
2294/// Helper function to find the start of a quoted string searching backwards
2295fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
2296    // Skip the closing quote and search backwards
2297    if pos > 0 {
2298        pos -= 1;
2299        while pos > 0 {
2300            if bytes[pos] == b'"' {
2301                // Check if it's not an escaped quote
2302                if pos == 0 || bytes[pos - 1] != b'\\' {
2303                    return Some(pos);
2304                }
2305            }
2306            pos -= 1;
2307        }
2308        // Check position 0 separately
2309        if bytes[0] == b'"' {
2310            return Some(0);
2311        }
2312    }
2313    None
2314}
2315
2316/// Helper function to handle method call context after validation
2317fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
2318    // Check if there's a partial method name after the dot
2319    let partial_method = if after_dot.is_empty() {
2320        None
2321    } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
2322        Some(after_dot.to_string())
2323    } else {
2324        None
2325    };
2326
2327    // For AfterColumn context, strip quotes if present for consistency
2328    let col_name_for_context =
2329        if col_name.starts_with('"') && col_name.ends_with('"') && col_name.len() > 2 {
2330            col_name[1..col_name.len() - 1].to_string()
2331        } else {
2332            col_name.to_string()
2333        };
2334
2335    (
2336        CursorContext::AfterColumn(col_name_for_context),
2337        partial_method,
2338    )
2339}
2340
2341/// Helper function to check if we're after a comparison operator
2342fn check_after_comparison_operator(query: &str) -> Option<(CursorContext, Option<String>)> {
2343    for op in &Parser::COMPARISON_OPERATORS {
2344        if let Some(op_pos) = query.rfind(op) {
2345            let before_op = safe_slice_to(query, op_pos);
2346            let after_op_start = op_pos + op.len();
2347            let after_op = if after_op_start < query.len() {
2348                &query[after_op_start..]
2349            } else {
2350                ""
2351            };
2352
2353            // Check if we have a column name before the operator
2354            if let Some(col_name) = before_op.split_whitespace().last() {
2355                if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2356                    // Check if we're at or near the end of the query
2357                    let after_op_trimmed = after_op.trim();
2358                    if after_op_trimmed.is_empty()
2359                        || (after_op_trimmed
2360                            .chars()
2361                            .all(|c| c.is_alphanumeric() || c == '_')
2362                            && !after_op_trimmed.contains('('))
2363                    {
2364                        let partial = if after_op_trimmed.is_empty() {
2365                            None
2366                        } else {
2367                            Some(after_op_trimmed.to_string())
2368                        };
2369                        return Some((
2370                            CursorContext::AfterComparisonOp(
2371                                col_name.to_string(),
2372                                op.trim().to_string(),
2373                            ),
2374                            partial,
2375                        ));
2376                    }
2377                }
2378            }
2379        }
2380    }
2381    None
2382}
2383
2384fn analyze_statement(
2385    stmt: &SelectStatement,
2386    query: &str,
2387    _cursor_pos: usize,
2388) -> (CursorContext, Option<String>) {
2389    // First check for method call context (e.g., "columnName." or "columnName.Con")
2390    let trimmed = query.trim();
2391
2392    // Check if we're after a comparison operator (e.g., "createdDate > ")
2393    if let Some(result) = check_after_comparison_operator(query) {
2394        return result;
2395    }
2396
2397    // First check if we're after AND/OR - this takes precedence
2398    // Helper function to check if string ends with a logical operator
2399    let ends_with_logical_op = |s: &str| -> bool {
2400        let s_upper = s.to_uppercase();
2401        s_upper.ends_with(" AND") || s_upper.ends_with(" OR")
2402    };
2403
2404    if ends_with_logical_op(trimmed) {
2405        // Don't check for method context if we're clearly after a logical operator
2406    } else {
2407        // Look for the last dot in the query
2408        if let Some(dot_pos) = trimmed.rfind('.') {
2409            // Check if we're after a column name and dot
2410            let before_dot = safe_slice_to(trimmed, dot_pos);
2411            let after_dot_start = dot_pos + 1;
2412            let after_dot = if after_dot_start < trimmed.len() {
2413                &trimmed[after_dot_start..]
2414            } else {
2415                ""
2416            };
2417
2418            // Check if the part after dot looks like an incomplete method call
2419            // (not a complete method call like "Contains(...)")
2420            if !after_dot.contains('(') {
2421                // Try to extract the column name - could be quoted or regular
2422                let col_name = if before_dot.ends_with('"') {
2423                    // Handle quoted identifier - search backwards for matching opening quote
2424                    let bytes = before_dot.as_bytes();
2425                    let pos = before_dot.len() - 1; // Position of closing quote
2426
2427                    find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2428                } else {
2429                    // Regular identifier - get the last word, handling parentheses
2430                    // Strip all leading parentheses
2431                    before_dot
2432                        .split_whitespace()
2433                        .last()
2434                        .map(|word| word.trim_start_matches('('))
2435                };
2436
2437                if let Some(col_name) = col_name {
2438                    // For quoted identifiers, keep the quotes, for regular identifiers check validity
2439                    let is_valid = Parser::is_valid_identifier(col_name);
2440
2441                    if is_valid {
2442                        return handle_method_call_context(col_name, after_dot);
2443                    }
2444                }
2445            }
2446        }
2447    }
2448
2449    // Check if we're in WHERE clause
2450    if let Some(where_clause) = &stmt.where_clause {
2451        // Check if query ends with AND/OR (with or without trailing space/partial)
2452        let trimmed_upper = trimmed.to_uppercase();
2453        if trimmed_upper.ends_with(" AND") || trimmed_upper.ends_with(" OR") {
2454            let op = if trimmed_upper.ends_with(" AND") {
2455                LogicalOp::And
2456            } else {
2457                LogicalOp::Or
2458            };
2459            return (CursorContext::AfterLogicalOp(op), None);
2460        }
2461
2462        // Check if we have AND/OR followed by a partial word
2463        let query_upper = query.to_uppercase();
2464        if let Some(and_pos) = query_upper.rfind(" AND ") {
2465            let after_and = safe_slice_from(query, and_pos + 5);
2466            let partial = extract_partial_at_end(after_and);
2467            if partial.is_some() {
2468                return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
2469            }
2470        }
2471
2472        if let Some(or_pos) = query_upper.rfind(" OR ") {
2473            let after_or = safe_slice_from(query, or_pos + 4);
2474            let partial = extract_partial_at_end(after_or);
2475            if partial.is_some() {
2476                return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
2477            }
2478        }
2479
2480        if let Some(last_condition) = where_clause.conditions.last() {
2481            if let Some(connector) = &last_condition.connector {
2482                // We're after AND/OR
2483                return (
2484                    CursorContext::AfterLogicalOp(connector.clone()),
2485                    extract_partial_at_end(query),
2486                );
2487            }
2488        }
2489        // We're in WHERE clause but not after AND/OR
2490        return (CursorContext::WhereClause, extract_partial_at_end(query));
2491    }
2492
2493    // Check if we're after ORDER BY
2494    let query_upper = query.to_uppercase();
2495    if query_upper.ends_with(" ORDER BY") {
2496        return (CursorContext::OrderByClause, None);
2497    }
2498
2499    // Check other contexts based on what's in the statement
2500    if stmt.order_by.is_some() {
2501        return (CursorContext::OrderByClause, extract_partial_at_end(query));
2502    }
2503
2504    if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
2505        return (CursorContext::FromClause, extract_partial_at_end(query));
2506    }
2507
2508    if !stmt.columns.is_empty() && stmt.from_table.is_none() {
2509        return (CursorContext::SelectClause, extract_partial_at_end(query));
2510    }
2511
2512    (CursorContext::Unknown, None)
2513}
2514
2515/// Render a token for an error message: the literal text where we have it, so the
2516/// user sees what they typed rather than an internal variant name.
2517fn describe_token(token: &Token) -> String {
2518    if let Some(kw) = token.as_keyword_str() {
2519        return format!("keyword '{kw}'");
2520    }
2521    match token {
2522        Token::Identifier(s) | Token::QuotedIdentifier(s) => format!("'{s}'"),
2523        Token::StringLiteral(s) => format!("string literal '{s}'"),
2524        Token::NumberLiteral(s) => format!("number '{s}'"),
2525        Token::Comma => "','".to_string(),
2526        Token::Semicolon => "';'".to_string(),
2527        Token::LeftParen => "'('".to_string(),
2528        Token::RightParen => "')'".to_string(),
2529        Token::Star => "'*'".to_string(),
2530        Token::Dot => "'.'".to_string(),
2531        Token::Eof => "end of input".to_string(),
2532        other => format!("{other:?}"),
2533    }
2534}
2535
2536/// Helper function to find the last occurrence of a token type in the token stream
2537fn find_last_token(tokens: &[(usize, usize, Token)], target: &Token) -> Option<usize> {
2538    tokens
2539        .iter()
2540        .rposition(|(_, _, t)| t == target)
2541        .map(|idx| tokens[idx].0)
2542}
2543
2544/// Helper function to find the last occurrence of any matching token
2545fn find_last_matching_token<F>(
2546    tokens: &[(usize, usize, Token)],
2547    predicate: F,
2548) -> Option<(usize, &Token)>
2549where
2550    F: Fn(&Token) -> bool,
2551{
2552    tokens
2553        .iter()
2554        .rposition(|(_, _, t)| predicate(t))
2555        .map(|idx| (tokens[idx].0, &tokens[idx].2))
2556}
2557
2558/// Helper function to check if we're in a specific clause based on tokens
2559fn is_in_clause(
2560    tokens: &[(usize, usize, Token)],
2561    clause_token: Token,
2562    exclude_tokens: &[Token],
2563) -> bool {
2564    // Find the last occurrence of the clause token
2565    if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2566        // Check if any exclude tokens appear after it
2567        for (pos, _, token) in tokens.iter() {
2568            if *pos > clause_pos && exclude_tokens.contains(token) {
2569                return false;
2570            }
2571        }
2572        return true;
2573    }
2574    false
2575}
2576
2577fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2578    // Tokenize the query up to cursor position
2579    let mut lexer = Lexer::new(query);
2580    let tokens = lexer.tokenize_all_with_positions();
2581
2582    let trimmed = query.trim();
2583
2584    #[cfg(test)]
2585    {
2586        if trimmed.contains("\"Last Name\"") {
2587            eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
2588        }
2589    }
2590
2591    // Check if we're after a comparison operator (e.g., "createdDate > ")
2592    if let Some(result) = check_after_comparison_operator(query) {
2593        return result;
2594    }
2595
2596    // Look for the last dot in the query (method call context) - check this FIRST
2597    // before AND/OR detection to properly handle cases like "AND (Country."
2598    if let Some(dot_pos) = trimmed.rfind('.') {
2599        #[cfg(test)]
2600        {
2601            if trimmed.contains("\"Last Name\"") {
2602                eprintln!("DEBUG: Found dot at position {dot_pos}");
2603            }
2604        }
2605        // Check if we're after a column name and dot
2606        let before_dot = &trimmed[..dot_pos];
2607        let after_dot = &trimmed[dot_pos + 1..];
2608
2609        // Check if the part after dot looks like an incomplete method call
2610        // (not a complete method call like "Contains(...)")
2611        if !after_dot.contains('(') {
2612            // Try to extract the column name before the dot
2613            // It could be a quoted identifier like "Last Name" or a regular identifier
2614            let col_name = if before_dot.ends_with('"') {
2615                // Handle quoted identifier - search backwards for matching opening quote
2616                let bytes = before_dot.as_bytes();
2617                let pos = before_dot.len() - 1; // Position of closing quote
2618
2619                #[cfg(test)]
2620                {
2621                    if trimmed.contains("\"Last Name\"") {
2622                        eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
2623                    }
2624                }
2625
2626                let found_start = find_quote_start(bytes, pos);
2627
2628                if let Some(start) = found_start {
2629                    // Extract the full quoted identifier including quotes
2630                    let result = safe_slice_from(before_dot, start);
2631                    #[cfg(test)]
2632                    {
2633                        if trimmed.contains("\"Last Name\"") {
2634                            eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
2635                        }
2636                    }
2637                    Some(result)
2638                } else {
2639                    #[cfg(test)]
2640                    {
2641                        if trimmed.contains("\"Last Name\"") {
2642                            eprintln!("DEBUG: No opening quote found!");
2643                        }
2644                    }
2645                    None
2646                }
2647            } else {
2648                // Regular identifier - get the last word, handling parentheses
2649                // Strip all leading parentheses
2650                before_dot
2651                    .split_whitespace()
2652                    .last()
2653                    .map(|word| word.trim_start_matches('('))
2654            };
2655
2656            if let Some(col_name) = col_name {
2657                #[cfg(test)]
2658                {
2659                    if trimmed.contains("\"Last Name\"") {
2660                        eprintln!("DEBUG: col_name = '{col_name}'");
2661                    }
2662                }
2663
2664                // For quoted identifiers, keep the quotes, for regular identifiers check validity
2665                let is_valid = Parser::is_valid_identifier(col_name);
2666
2667                #[cfg(test)]
2668                {
2669                    if trimmed.contains("\"Last Name\"") {
2670                        eprintln!("DEBUG: is_valid = {is_valid}");
2671                    }
2672                }
2673
2674                if is_valid {
2675                    return handle_method_call_context(col_name, after_dot);
2676                }
2677            }
2678        }
2679    }
2680
2681    // Check if we're after AND/OR using tokens - but only after checking for method calls
2682    if let Some((pos, token)) =
2683        find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2684    {
2685        // Check if cursor is after the logical operator
2686        let token_end_pos = if matches!(token, Token::And) {
2687            pos + 3 // "AND" is 3 characters
2688        } else {
2689            pos + 2 // "OR" is 2 characters
2690        };
2691
2692        if cursor_pos > token_end_pos {
2693            // Extract any partial word after the operator
2694            let after_op = safe_slice_from(query, token_end_pos + 1); // +1 for the space
2695            let partial = extract_partial_at_end(after_op);
2696            let op = if matches!(token, Token::And) {
2697                LogicalOp::And
2698            } else {
2699                LogicalOp::Or
2700            };
2701            return (CursorContext::AfterLogicalOp(op), partial);
2702        }
2703    }
2704
2705    // Check if the last token is AND or OR (handles case where it's at the very end)
2706    if let Some((_, _, last_token)) = tokens.last() {
2707        if matches!(last_token, Token::And | Token::Or) {
2708            let op = if matches!(last_token, Token::And) {
2709                LogicalOp::And
2710            } else {
2711                LogicalOp::Or
2712            };
2713            return (CursorContext::AfterLogicalOp(op), None);
2714        }
2715    }
2716
2717    // Check if we're in ORDER BY clause using tokens
2718    if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2719        // Check if there's a BY token after ORDER
2720        let has_by = tokens
2721            .iter()
2722            .any(|(pos, _, t)| *pos > order_pos && matches!(t, Token::By));
2723        if has_by
2724            || tokens
2725                .last()
2726                .map_or(false, |(_, _, t)| matches!(t, Token::OrderBy))
2727        {
2728            return (CursorContext::OrderByClause, extract_partial_at_end(query));
2729        }
2730    }
2731
2732    // Check if we're in WHERE clause using tokens
2733    if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2734        return (CursorContext::WhereClause, extract_partial_at_end(query));
2735    }
2736
2737    // Check if we're in FROM clause using tokens
2738    if is_in_clause(
2739        &tokens,
2740        Token::From,
2741        &[Token::Where, Token::OrderBy, Token::GroupBy],
2742    ) {
2743        return (CursorContext::FromClause, extract_partial_at_end(query));
2744    }
2745
2746    // Check if we're in SELECT clause using tokens
2747    if find_last_token(&tokens, &Token::Select).is_some()
2748        && find_last_token(&tokens, &Token::From).is_none()
2749    {
2750        return (CursorContext::SelectClause, extract_partial_at_end(query));
2751    }
2752
2753    (CursorContext::Unknown, None)
2754}
2755
2756fn extract_partial_at_end(query: &str) -> Option<String> {
2757    let trimmed = query.trim();
2758
2759    // First check if the last word itself starts with a quote (unclosed quoted identifier being typed)
2760    if let Some(last_word) = trimmed.split_whitespace().last() {
2761        if last_word.starts_with('"') && !last_word.ends_with('"') {
2762            // This is an unclosed quoted identifier like "Cust
2763            return Some(last_word.to_string());
2764        }
2765    }
2766
2767    // Regular identifier extraction
2768    let last_word = trimmed.split_whitespace().last()?;
2769
2770    // Check if it's a partial identifier (not a keyword or operator)
2771    // First check if it's alphanumeric (potential identifier)
2772    if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2773        // Use lexer to determine if it's a keyword or identifier
2774        if !is_sql_keyword(last_word) {
2775            Some(last_word.to_string())
2776        } else {
2777            None
2778        }
2779    } else {
2780        None
2781    }
2782}
2783
2784// Implement the ParsePrimary trait for Parser to use the modular expression parsing
2785impl ParsePrimary for Parser {
2786    fn current_token(&self) -> &Token {
2787        &self.current_token
2788    }
2789
2790    fn advance(&mut self) {
2791        self.advance();
2792    }
2793
2794    fn consume(&mut self, expected: Token) -> Result<(), String> {
2795        self.consume(expected)
2796    }
2797
2798    fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2799        self.parse_case_expression()
2800    }
2801
2802    fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2803        self.parse_function_args()
2804    }
2805
2806    fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2807        self.parse_window_spec()
2808    }
2809
2810    fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2811        self.parse_logical_or()
2812    }
2813
2814    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2815        self.parse_comparison()
2816    }
2817
2818    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2819        self.parse_expression_list()
2820    }
2821
2822    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2823        // Parse subquery without parenthesis balance validation
2824        if matches!(self.current_token, Token::With) {
2825            self.parse_with_clause_inner()
2826        } else {
2827            self.parse_select_statement_inner()
2828        }
2829    }
2830}
2831
2832// Implement the ExpressionParser trait for Parser to use the modular expression parsing
2833impl ExpressionParser for Parser {
2834    fn current_token(&self) -> &Token {
2835        &self.current_token
2836    }
2837
2838    fn advance(&mut self) {
2839        // Call the main advance method directly to avoid recursion
2840        match &self.current_token {
2841            Token::LeftParen => self.paren_depth += 1,
2842            Token::RightParen => {
2843                self.paren_depth -= 1;
2844            }
2845            _ => {}
2846        }
2847        self.current_token = self.lexer.next_token();
2848    }
2849
2850    fn peek(&self) -> Option<&Token> {
2851        // We can't return a reference to a token from a temporary lexer,
2852        // so we need a different approach. For now, let's use a workaround
2853        // that checks the next token type without consuming it.
2854        // This is a limitation of the current design.
2855        // A proper fix would be to store the peeked token in the Parser struct.
2856        None // TODO: Implement proper lookahead
2857    }
2858
2859    fn is_at_end(&self) -> bool {
2860        matches!(self.current_token, Token::Eof)
2861    }
2862
2863    fn consume(&mut self, expected: Token) -> Result<(), String> {
2864        // Call the main consume method to avoid recursion
2865        if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
2866            self.update_paren_depth(&expected)?;
2867            self.current_token = self.lexer.next_token();
2868            Ok(())
2869        } else {
2870            Err(format!(
2871                "Expected {:?}, found {:?}",
2872                expected, self.current_token
2873            ))
2874        }
2875    }
2876
2877    fn parse_identifier(&mut self) -> Result<String, String> {
2878        if let Token::Identifier(id) = &self.current_token {
2879            let id = id.clone();
2880            self.advance();
2881            Ok(id)
2882        } else {
2883            Err(format!(
2884                "Expected identifier, found {:?}",
2885                self.current_token
2886            ))
2887        }
2888    }
2889}
2890
2891// Implement the ParseArithmetic trait for Parser to use the modular arithmetic parsing
2892impl ParseArithmetic for Parser {
2893    fn current_token(&self) -> &Token {
2894        &self.current_token
2895    }
2896
2897    fn advance(&mut self) {
2898        self.advance();
2899    }
2900
2901    fn consume(&mut self, expected: Token) -> Result<(), String> {
2902        self.consume(expected)
2903    }
2904
2905    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2906        self.parse_primary()
2907    }
2908
2909    fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2910        self.parse_multiplicative()
2911    }
2912
2913    fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2914        self.parse_method_args()
2915    }
2916}
2917
2918// Implement the ParseComparison trait for Parser to use the modular comparison parsing
2919impl ParseComparison for Parser {
2920    fn current_token(&self) -> &Token {
2921        &self.current_token
2922    }
2923
2924    fn advance(&mut self) {
2925        self.advance();
2926    }
2927
2928    fn consume(&mut self, expected: Token) -> Result<(), String> {
2929        self.consume(expected)
2930    }
2931
2932    fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2933        self.parse_primary()
2934    }
2935
2936    fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2937        self.parse_additive()
2938    }
2939
2940    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2941        self.parse_expression_list()
2942    }
2943
2944    fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2945        // Parse subquery without parenthesis balance validation
2946        if matches!(self.current_token, Token::With) {
2947            self.parse_with_clause_inner()
2948        } else {
2949            self.parse_select_statement_inner()
2950        }
2951    }
2952}
2953
2954// Implement the ParseLogical trait for Parser to use the modular logical parsing
2955impl ParseLogical for Parser {
2956    fn current_token(&self) -> &Token {
2957        &self.current_token
2958    }
2959
2960    fn advance(&mut self) {
2961        self.advance();
2962    }
2963
2964    fn consume(&mut self, expected: Token) -> Result<(), String> {
2965        self.consume(expected)
2966    }
2967
2968    fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2969        self.parse_logical_and()
2970    }
2971
2972    fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2973        // This is the base for logical AND - it should parse comparison expressions
2974        // to avoid infinite recursion with parse_expression
2975        self.parse_comparison()
2976    }
2977
2978    fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2979        self.parse_comparison()
2980    }
2981
2982    fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2983        self.parse_expression_list()
2984    }
2985}
2986
2987// Implement the ParseCase trait for Parser to use the modular CASE parsing
2988impl ParseCase for Parser {
2989    fn current_token(&self) -> &Token {
2990        &self.current_token
2991    }
2992
2993    fn advance(&mut self) {
2994        self.advance();
2995    }
2996
2997    fn consume(&mut self, expected: Token) -> Result<(), String> {
2998        self.consume(expected)
2999    }
3000
3001    fn parse_expression(&mut self) -> Result<SqlExpression, String> {
3002        self.parse_expression()
3003    }
3004}
3005
3006fn is_sql_keyword(word: &str) -> bool {
3007    // Use the lexer to check if this word produces a keyword token
3008    let mut lexer = Lexer::new(word);
3009    let token = lexer.next_token();
3010
3011    // Check if it's a keyword token (not an identifier)
3012    !matches!(token, Token::Identifier(_) | Token::Eof)
3013}
3014
3015#[cfg(test)]
3016mod tests {
3017    use super::*;
3018
3019    /// Test that Parser::new() defaults to Standard mode (backward compatible)
3020    #[test]
3021    fn test_parser_mode_default_is_standard() {
3022        let sql = "-- Leading comment\nSELECT * FROM users";
3023        let mut parser = Parser::new(sql);
3024        let stmt = parser.parse().unwrap();
3025
3026        // In Standard mode, comments should be empty
3027        assert!(stmt.leading_comments.is_empty());
3028        assert!(stmt.trailing_comment.is_none());
3029    }
3030
3031    /// Test that PreserveComments mode collects leading comments
3032    #[test]
3033    fn test_parser_mode_preserve_leading_comments() {
3034        let sql = "-- Important query\n-- Author: Alice\nSELECT id, name FROM users";
3035        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3036        let stmt = parser.parse().unwrap();
3037
3038        // Should have 2 leading comments
3039        assert_eq!(stmt.leading_comments.len(), 2);
3040        assert!(stmt.leading_comments[0].is_line_comment);
3041        assert!(stmt.leading_comments[0].text.contains("Important query"));
3042        assert!(stmt.leading_comments[1].text.contains("Author: Alice"));
3043    }
3044
3045    /// Test that PreserveComments mode collects trailing comments
3046    #[test]
3047    fn test_parser_mode_preserve_trailing_comment() {
3048        let sql = "SELECT * FROM users -- Fetch all users";
3049        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3050        let stmt = parser.parse().unwrap();
3051
3052        // Should have trailing comment
3053        assert!(stmt.trailing_comment.is_some());
3054        let comment = stmt.trailing_comment.unwrap();
3055        assert!(comment.is_line_comment);
3056        assert!(comment.text.contains("Fetch all users"));
3057    }
3058
3059    /// Test that PreserveComments mode handles block comments
3060    #[test]
3061    fn test_parser_mode_preserve_block_comments() {
3062        let sql = "/* Query explanation */\nSELECT * FROM users";
3063        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3064        let stmt = parser.parse().unwrap();
3065
3066        // Should have leading block comment
3067        assert_eq!(stmt.leading_comments.len(), 1);
3068        assert!(!stmt.leading_comments[0].is_line_comment); // It's a block comment
3069        assert!(stmt.leading_comments[0].text.contains("Query explanation"));
3070    }
3071
3072    /// Test that PreserveComments mode collects both leading and trailing
3073    #[test]
3074    fn test_parser_mode_preserve_both_comments() {
3075        let sql = "-- Leading\nSELECT * FROM users -- Trailing";
3076        let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3077        let stmt = parser.parse().unwrap();
3078
3079        // Should have both
3080        assert_eq!(stmt.leading_comments.len(), 1);
3081        assert!(stmt.leading_comments[0].text.contains("Leading"));
3082        assert!(stmt.trailing_comment.is_some());
3083        assert!(stmt.trailing_comment.unwrap().text.contains("Trailing"));
3084    }
3085
3086    /// Test that Standard mode has zero performance overhead (no comment parsing)
3087    #[test]
3088    fn test_parser_mode_standard_ignores_comments() {
3089        let sql = "-- Comment 1\n/* Comment 2 */\nSELECT * FROM users -- Comment 3";
3090        let mut parser = Parser::with_mode(sql, ParserMode::Standard);
3091        let stmt = parser.parse().unwrap();
3092
3093        // Comments should be completely ignored
3094        assert!(stmt.leading_comments.is_empty());
3095        assert!(stmt.trailing_comment.is_none());
3096
3097        // But query should still parse correctly
3098        assert_eq!(stmt.select_items.len(), 1);
3099        assert_eq!(stmt.from_table, Some("users".to_string()));
3100    }
3101
3102    /// Test backward compatibility - existing code using Parser::new() unchanged
3103    #[test]
3104    fn test_parser_backward_compatibility() {
3105        let sql = "SELECT id, name FROM users WHERE active = true";
3106
3107        // Old way (still works, defaults to Standard mode)
3108        let mut parser1 = Parser::new(sql);
3109        let stmt1 = parser1.parse().unwrap();
3110
3111        // Explicit Standard mode (same behavior)
3112        let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
3113        let stmt2 = parser2.parse().unwrap();
3114
3115        // Both should produce identical ASTs (comments are empty in both)
3116        assert_eq!(stmt1.select_items.len(), stmt2.select_items.len());
3117        assert_eq!(stmt1.from_table, stmt2.from_table);
3118        assert_eq!(stmt1.where_clause.is_some(), stmt2.where_clause.is_some());
3119        assert!(stmt1.leading_comments.is_empty());
3120        assert!(stmt2.leading_comments.is_empty());
3121    }
3122
3123    /// Test PIVOT parsing - currently returns error as execution is not implemented
3124    #[test]
3125    fn test_pivot_parsing_not_yet_supported() {
3126        let sql = "SELECT * FROM food_eaten PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle', 'Apple'))";
3127        let mut parser = Parser::new(sql);
3128        let result = parser.parse();
3129
3130        // PIVOT is now fully supported! Verify parsing succeeds
3131        assert!(result.is_ok());
3132        let stmt = result.unwrap();
3133
3134        // Verify from_source contains a PIVOT
3135        assert!(stmt.from_source.is_some());
3136        if let Some(crate::sql::parser::ast::TableSource::Pivot { .. }) = stmt.from_source {
3137            // Success!
3138        } else {
3139            panic!("Expected from_source to be a Pivot variant");
3140        }
3141    }
3142
3143    /// Test PIVOT syntax with different aggregate functions
3144    #[test]
3145    fn test_pivot_aggregate_functions() {
3146        // Test with SUM - PIVOT is now fully supported!
3147        let sql = "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb', 'Mar'))";
3148        let mut parser = Parser::new(sql);
3149        let result = parser.parse();
3150        assert!(result.is_ok());
3151
3152        // Test with COUNT
3153        let sql2 = "SELECT * FROM sales PIVOT (COUNT(*) FOR month IN ('Jan', 'Feb'))";
3154        let mut parser2 = Parser::new(sql2);
3155        let result2 = parser2.parse();
3156        assert!(result2.is_ok());
3157
3158        // Test with AVG
3159        let sql3 = "SELECT * FROM sales PIVOT (AVG(price) FOR category IN ('A', 'B'))";
3160        let mut parser3 = Parser::new(sql3);
3161        let result3 = parser3.parse();
3162        assert!(result3.is_ok());
3163    }
3164
3165    /// Test PIVOT with subquery source
3166    #[test]
3167    fn test_pivot_with_subquery() {
3168        let sql = "SELECT * FROM (SELECT * FROM food_eaten WHERE Id > 5) AS t \
3169                   PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle'))";
3170        let mut parser = Parser::new(sql);
3171        let result = parser.parse();
3172
3173        // PIVOT with subquery is now fully supported!
3174        assert!(result.is_ok());
3175        let stmt = result.unwrap();
3176        assert!(stmt.from_source.is_some());
3177    }
3178
3179    /// Test PIVOT with alias
3180    #[test]
3181    fn test_pivot_with_alias() {
3182        let sql =
3183            "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb')) AS pivot_table";
3184        let mut parser = Parser::new(sql);
3185        let result = parser.parse();
3186
3187        // PIVOT with alias is now fully supported!
3188        assert!(result.is_ok());
3189        let stmt = result.unwrap();
3190        assert!(stmt.from_source.is_some());
3191    }
3192
3193    /// Pull the WebCTESpec out of a parsed top-level statement that uses a
3194    /// single WEB CTE. Test helper.
3195    fn extract_web_spec(
3196        stmt: &crate::sql::parser::ast::SelectStatement,
3197    ) -> &crate::sql::parser::ast::WebCTESpec {
3198        use crate::sql::parser::ast::CTEType;
3199        assert!(!stmt.ctes.is_empty(), "statement should have CTEs");
3200        match &stmt.ctes[0].cte_type {
3201            CTEType::Web(spec) => spec,
3202            other => panic!("expected Web CTE, got {:?}", other),
3203        }
3204    }
3205
3206    #[test]
3207    fn test_web_cte_delimiter_pipe() {
3208        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '|') \
3209                   SELECT * FROM foo";
3210        let mut parser = Parser::new(sql);
3211        let stmt = parser.parse().expect("parse failed");
3212        let spec = extract_web_spec(&stmt);
3213        assert_eq!(spec.delimiter, Some(b'|'));
3214    }
3215
3216    #[test]
3217    fn test_web_cte_delimiter_tab_via_escape() {
3218        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '\\t') \
3219                   SELECT * FROM foo";
3220        let mut parser = Parser::new(sql);
3221        let stmt = parser.parse().expect("parse failed");
3222        let spec = extract_web_spec(&stmt);
3223        assert_eq!(spec.delimiter, Some(b'\t'));
3224    }
3225
3226    #[test]
3227    fn test_web_cte_no_delimiter_defaults_to_none() {
3228        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV) SELECT * FROM foo";
3229        let mut parser = Parser::new(sql);
3230        let stmt = parser.parse().expect("parse failed");
3231        let spec = extract_web_spec(&stmt);
3232        assert!(spec.delimiter.is_none());
3233    }
3234
3235    #[test]
3236    fn test_web_cte_delimiter_rejects_multi_char() {
3237        let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '||') \
3238                   SELECT * FROM foo";
3239        let mut parser = Parser::new(sql);
3240        let err = parser.parse().unwrap_err();
3241        let msg = err.to_string();
3242        assert!(
3243            msg.contains("DELIMITER") || msg.contains("single ASCII"),
3244            "should reject multi-char delimiter: {}",
3245            msg
3246        );
3247    }
3248}