1pub 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
15pub use super::parser::formatter::{format_ast_tree, format_sql_pretty, format_sql_pretty_compact};
17
18pub use super::parser::ast_formatter::{format_sql_ast, format_sql_ast_with_config, FormatConfig};
20
21use super::parser::expressions::arithmetic::{
23 parse_additive as parse_additive_expr, parse_multiplicative as parse_multiplicative_expr,
24 ParseArithmetic,
25};
26use super::parser::expressions::case::{parse_case_expression as parse_case_expr, ParseCase};
27use super::parser::expressions::comparison::{
28 parse_comparison as parse_comparison_expr, parse_in_operator, ParseComparison,
29};
30use super::parser::expressions::logical::{
31 parse_logical_and as parse_logical_and_expr, parse_logical_or as parse_logical_or_expr,
32 ParseLogical,
33};
34use super::parser::expressions::primary::{
35 parse_primary as parse_primary_expr, ParsePrimary, PrimaryExpressionContext,
36};
37use super::parser::expressions::ExpressionParser;
38
39use crate::sql::functions::{FunctionCategory, FunctionRegistry};
41use crate::sql::generators::GeneratorRegistry;
42use std::sync::Arc;
43
44use super::parser::file_cte_parser::FileCteParser;
46use super::parser::web_cte_parser::WebCteParser;
47
48#[derive(Debug, Clone, Copy, PartialEq)]
50pub enum ParserMode {
51 Standard,
53 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, in_method_args: bool, columns: Vec<String>, paren_depth: i32, paren_depth_stack: Vec<i32>, _config: ParserConfig, debug_trace: bool, trace_depth: usize, function_registry: Arc<FunctionRegistry>, generator_registry: Arc<GeneratorRegistry>, mode: ParserMode, }
77
78impl Parser {
79 #[must_use]
80 pub fn new(input: &str) -> Self {
81 Self::with_mode(input, ParserMode::default())
82 }
83
84 #[must_use]
86 pub fn with_mode(input: &str, mode: ParserMode) -> Self {
87 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 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 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 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 self.update_paren_depth(&expected)?;
213
214 self.current_token = self.lexer.next_token();
215 Ok(())
216 } else {
217 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 match &self.current_token {
243 Token::LeftParen => self.paren_depth += 1,
244 Token::RightParen => {
245 self.paren_depth -= 1;
246 }
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 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 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 self.paren_depth = depth;
309 }
310 }
311
312 pub fn parse(&mut self) -> Result<SelectStatement, String> {
313 self.trace_enter("parse");
314
315 let leading_comments = if self.mode == ParserMode::PreserveComments {
318 self.collect_leading_comments()
319 } else {
320 vec![]
321 };
322
323 let result = if matches!(self.current_token, Token::With) {
325 let mut stmt = self.parse_with_clause()?;
326 stmt.leading_comments = leading_comments;
328 stmt
329 } else {
330 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 fn expect_end_of_statement(&mut self) -> Result<(), String> {
354 if matches!(self.current_token, Token::Semicolon) {
355 self.advance();
356 }
357
358 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 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 let mut main_query = self.parse_select_statement_inner_no_comments()?;
392 main_query.ctes = ctes;
393
394 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 let mut main_query = self.parse_select_statement_inner()?;
406 main_query.ctes = ctes;
407
408 Ok(main_query)
409 }
410
411 fn parse_cte_list(&mut self) -> Result<Vec<CTE>, String> {
413 let mut ctes = Vec::new();
414
415 loop {
417 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 let name = match &self.current_token {
430 Token::Identifier(name) => name.clone(),
431 token => {
432 if let Some(keyword) = token.as_keyword_str() {
434 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 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 self.consume(Token::As)?;
458
459 let cte_type = if is_web {
460 self.consume(Token::LeftParen)?;
462 let web_spec = WebCteParser::parse(self)?;
464 self.consume(Token::RightParen)?;
466 CTEType::Web(web_spec)
467 } else {
468 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 self.consume(Token::RightParen)?;
486 self.pop_paren_depth();
488 result
489 };
490
491 ctes.push(CTE {
492 name,
493 column_list,
494 cte_type,
495 });
496
497 if !matches!(self.current_token, Token::Comma) {
499 break;
500 }
501 self.advance();
502 }
503
504 Ok(ctes)
505 }
506
507 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 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 let alias = name.clone();
533 self.advance();
534 Ok(Some(alias))
535 } else {
536 Ok(None)
537 }
538 }
539
540 fn is_valid_identifier(name: &str) -> bool {
542 if name.starts_with('"') && name.ends_with('"') {
543 true
545 } else {
546 name.chars().all(|c| c.is_alphanumeric() || c == '_')
548 }
549 }
550
551 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 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 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 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 fn contains_aggregate_function(expr: &SqlExpression) -> bool {
607 match expr {
608 SqlExpression::FunctionCall { name, args, .. } => {
609 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 is_aggregate || args.iter().any(Self::contains_aggregate_function)
619 }
620 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 query
661 .having
662 .as_ref()
663 .map_or(false, |h| Self::contains_aggregate_function(h))
664 }
665 SqlExpression::Column(_)
667 | SqlExpression::StringLiteral(_)
668 | SqlExpression::NumberLiteral(_)
669 | SqlExpression::BooleanLiteral(_)
670 | SqlExpression::Null
671 | SqlExpression::DateTimeConstructor { .. }
672 | SqlExpression::DateTimeToday { .. } => false,
673
674 SqlExpression::WindowFunction { .. } => true,
676
677 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 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 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 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 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 self.check_balanced_parentheses()?;
721
722 Ok(result)
723 }
724
725 fn parse_select_statement_inner(&mut self) -> Result<SelectStatement, String> {
726 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 fn parse_select_statement_inner_no_comments(&mut self) -> Result<SelectStatement, String> {
739 self.parse_select_statement_with_comments(vec![])
740 }
741
742 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 let distinct = if matches!(self.current_token, Token::Distinct) {
751 self.advance();
752 true
753 } else {
754 false
755 };
756
757 let select_items = self.parse_select_items()?;
759
760 let columns = select_items
762 .iter()
763 .map(|item| match item {
764 SelectItem::Star { .. } => "*".to_string(),
765 SelectItem::StarExclude { .. } => "*".to_string(), SelectItem::Column {
767 column: col_ref, ..
768 } => col_ref.name.clone(),
769 SelectItem::Expression { alias, .. } => alias.clone(),
770 })
771 .collect();
772
773 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 let (from_table, from_subquery, from_function, from_alias) = if matches!(
783 self.current_token,
784 Token::From
785 ) {
786 self.advance();
787
788 let table_or_function_name = match &self.current_token {
791 Token::Identifier(name) => Some(name.clone()),
792 token => {
793 token.as_keyword_str().map(|k| k.to_lowercase())
795 }
796 };
797
798 if let Some(name) = table_or_function_name {
799 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 let is_table_function = if has_paren {
813 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 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 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 let function_name = name.clone();
870 self.advance(); self.consume(Token::LeftParen)?;
874 let args = self.parse_argument_list()?;
875 self.consume(Token::RightParen)?;
876
877 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 let table_name = name.clone();
918 self.advance();
919
920 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 self.advance();
928
929 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 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 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 let table_name = match &self.current_token {
979 Token::Identifier(table) => table.clone(),
980 Token::QuotedIdentifier(table) => table.clone(),
981 token => {
982 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 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 let pivot_source = if matches!(self.current_token, Token::Pivot) {
1006 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 let pivoted = self.parse_pivot_clause(source)?;
1020 Some(pivoted)
1021 } else {
1022 None
1023 };
1024
1025 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 Some(self.parse_expression_list()?)
1043 } else {
1044 None
1045 };
1046
1047 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 Some(having_expr)
1060 } else {
1061 None
1062 };
1063
1064 let qualify = if matches!(self.current_token, Token::Qualify) {
1068 self.advance();
1069 let qualify_expr = self.parse_expression()?;
1070
1071 Some(qualify_expr)
1075 } else {
1076 None
1077 };
1078
1079 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 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(); if matches!(&self.current_token, Token::By) {
1091 self.advance(); 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 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 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 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 };
1146
1147 let set_operations = self.parse_set_operations()?;
1149
1150 let trailing_comment = if self.mode == ParserMode::PreserveComments {
1152 self.collect_trailing_comment()
1153 } else {
1154 None
1155 };
1156
1157 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 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(), into_table,
1199 set_operations,
1200 leading_comments,
1201 trailing_comment,
1202 })
1203 }
1204
1205 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 let operation = match &self.current_token {
1218 Token::Union => {
1219 self.advance();
1220 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 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 fn parse_select_items(&mut self) -> Result<Vec<SelectItem>, String> {
1254 let mut items = Vec::new();
1255
1256 loop {
1257 if let Token::Identifier(name) = &self.current_token.clone() {
1260 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 items.push(SelectItem::Star {
1272 table_prefix: Some(table_name),
1273 leading_comments: vec![],
1274 trailing_comment: None,
1275 });
1276 self.advance();
1277
1278 if matches!(self.current_token, Token::Comma) {
1280 self.advance();
1281 continue;
1282 } else {
1283 break;
1284 }
1285 }
1286 }
1287
1288 self.lexer = saved_pos;
1290 self.current_token = saved_token;
1291 }
1292
1293 if matches!(self.current_token, Token::Star) {
1295 self.advance(); if matches!(self.current_token, Token::Exclude) {
1299 self.advance(); if !matches!(self.current_token, Token::LeftParen) {
1303 return Err("Expected '(' after EXCLUDE".to_string());
1304 }
1305 self.advance(); 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 if matches!(self.current_token, Token::Comma) {
1320 self.advance();
1321 } else if matches!(self.current_token, Token::RightParen) {
1322 self.advance(); 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 items.push(SelectItem::Star {
1342 table_prefix: None,
1343 leading_comments: vec![],
1344 trailing_comment: None,
1345 });
1346 }
1347 } else {
1348 let expr = self.parse_comparison()?; 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 match &expr {
1380 SqlExpression::Column(col_ref) => col_ref.name.clone(),
1381 _ => format!("expr_{}", items.len() + 1), }
1383 };
1384
1385 let item = match expr {
1387 SqlExpression::Column(col_ref) if alias == col_ref.name => {
1388 SelectItem::Column {
1390 column: col_ref,
1391 leading_comments: vec![],
1392 trailing_comment: None,
1393 }
1394 }
1395 _ => {
1396 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 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 if Self::is_identifier_reserved(id) {
1428 break;
1430 }
1431 let mut name = id.clone();
1432 self.advance();
1433
1434 if matches!(self.current_token, Token::Dot) {
1436 self.advance(); 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 identifiers.push(id.clone());
1457 self.advance();
1458 }
1459 _ => {
1460 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 if matches!(self.current_token, Token::Partition) {
1485 self.advance(); if !matches!(self.current_token, Token::By) {
1487 return Err("Expected BY after PARTITION".to_string());
1488 }
1489 self.advance(); partition_by = self.parse_identifier_list()?;
1493 }
1494
1495 if matches!(self.current_token, Token::OrderBy) {
1497 self.advance(); 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 self.advance(); if !matches!(self.current_token, Token::By) {
1504 return Err("Expected BY after ORDER".to_string());
1505 }
1506 self.advance(); order_by = self.parse_order_by_list()?;
1508 }
1509 }
1510
1511 let mut frame = self.parse_window_frame()?;
1513
1514 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 let expr = self.parse_expression()?;
1544
1545 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, };
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 fn parse_into_clause(&mut self) -> Result<IntoTable, String> {
1573 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 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 self.advance();
1606 FrameUnit::Range
1607 }
1608 _ => return Ok(None), };
1610
1611 let (start, end) = if let Token::Between = &self.current_token {
1613 self.advance(); let start = self.parse_frame_bound()?;
1616
1617 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 let end = self.parse_frame_bound()?;
1625 (start, Some(end))
1626 } else {
1627 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 let expr = self.parse_expression()?;
1684
1685 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 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 let mut left = self.parse_logical_or()?;
1706
1707 left = parse_in_operator(self, left)?;
1710
1711 let result = Ok(left);
1712 self.trace_exit("parse_expression", &result);
1713 result
1714 }
1715
1716 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1717 parse_comparison_expr(self)
1719 }
1720
1721 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1722 parse_additive_expr(self)
1724 }
1725
1726 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1727 parse_multiplicative_expr(self)
1729 }
1730
1731 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1732 parse_logical_or_expr(self)
1734 }
1735
1736 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1737 parse_logical_and_expr(self)
1739 }
1740
1741 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1742 parse_case_expr(self)
1744 }
1745
1746 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1747 let columns = self.columns.clone();
1750 let in_method_args = self.in_method_args;
1751 let ctx = PrimaryExpressionContext {
1752 columns: &columns,
1753 in_method_args,
1754 };
1755 parse_primary_expr(self, &ctx)
1756 }
1757
1758 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1760 self.in_method_args = true;
1762
1763 let args = self.parse_argument_list()?;
1764
1765 self.in_method_args = false;
1767
1768 Ok(args)
1769 }
1770
1771 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1772 let mut args = Vec::new();
1773 let mut has_distinct = false;
1774
1775 if !matches!(self.current_token, Token::RightParen) {
1776 if matches!(self.current_token, Token::Distinct) {
1778 self.advance(); has_distinct = true;
1780 }
1781
1782 args.push(self.parse_logical_or()?);
1785
1786 while matches!(self.current_token, Token::Comma) {
1788 self.advance();
1789 args.push(self.parse_logical_or()?);
1790 }
1791 }
1792
1793 Ok((args, has_distinct))
1794 }
1795
1796 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1797 let mut expressions = Vec::new();
1798
1799 loop {
1800 expressions.push(self.parse_expression()?);
1801
1802 if matches!(self.current_token, Token::Comma) {
1803 self.advance();
1804 } else {
1805 break;
1806 }
1807 }
1808
1809 Ok(expressions)
1810 }
1811
1812 #[must_use]
1813 pub fn get_position(&self) -> usize {
1814 self.lexer.get_position()
1815 }
1816
1817 fn is_join_token(&self) -> bool {
1819 matches!(
1820 self.current_token,
1821 Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
1822 )
1823 }
1824
1825 fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1827 let join_type = match &self.current_token {
1829 Token::Join => {
1830 self.advance();
1831 JoinType::Inner }
1833 Token::Inner => {
1834 self.advance();
1835 if !matches!(self.current_token, Token::Join) {
1836 return Err("Expected JOIN after INNER".to_string());
1837 }
1838 self.advance();
1839 JoinType::Inner
1840 }
1841 Token::Left => {
1842 self.advance();
1843 if matches!(self.current_token, Token::Outer) {
1845 self.advance();
1846 }
1847 if !matches!(self.current_token, Token::Join) {
1848 return Err("Expected JOIN after LEFT".to_string());
1849 }
1850 self.advance();
1851 JoinType::Left
1852 }
1853 Token::Right => {
1854 self.advance();
1855 if matches!(self.current_token, Token::Outer) {
1857 self.advance();
1858 }
1859 if !matches!(self.current_token, Token::Join) {
1860 return Err("Expected JOIN after RIGHT".to_string());
1861 }
1862 self.advance();
1863 JoinType::Right
1864 }
1865 Token::Full => {
1866 self.advance();
1867 if matches!(self.current_token, Token::Outer) {
1869 self.advance();
1870 }
1871 if !matches!(self.current_token, Token::Join) {
1872 return Err("Expected JOIN after FULL".to_string());
1873 }
1874 self.advance();
1875 JoinType::Full
1876 }
1877 Token::Cross => {
1878 self.advance();
1879 if !matches!(self.current_token, Token::Join) {
1880 return Err("Expected JOIN after CROSS".to_string());
1881 }
1882 self.advance();
1883 JoinType::Cross
1884 }
1885 _ => return Err("Expected JOIN keyword".to_string()),
1886 };
1887
1888 let (table, alias) = self.parse_join_table_source()?;
1890
1891 let condition = if join_type == JoinType::Cross {
1893 JoinCondition { conditions: vec![] }
1895 } else {
1896 if !matches!(self.current_token, Token::On) {
1897 return Err("Expected ON keyword after JOIN table".to_string());
1898 }
1899 self.advance();
1900 self.parse_join_condition()?
1901 };
1902
1903 Ok(JoinClause {
1904 join_type,
1905 table,
1906 alias,
1907 condition,
1908 })
1909 }
1910
1911 fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1912 let table = match &self.current_token {
1913 Token::Identifier(name) => {
1914 let table_name = name.clone();
1915 self.advance();
1916 TableSource::Table(table_name)
1917 }
1918 Token::LeftParen => {
1919 self.advance();
1921 let subquery = self.parse_select_statement_inner()?;
1922 if !matches!(self.current_token, Token::RightParen) {
1923 return Err("Expected ')' after subquery".to_string());
1924 }
1925 self.advance();
1926
1927 let alias = match &self.current_token {
1929 Token::Identifier(alias_name) => {
1930 let alias = alias_name.clone();
1931 self.advance();
1932 alias
1933 }
1934 Token::As => {
1935 self.advance();
1936 match &self.current_token {
1937 Token::Identifier(alias_name) => {
1938 let alias = alias_name.clone();
1939 self.advance();
1940 alias
1941 }
1942 _ => return Err("Expected alias after AS keyword".to_string()),
1943 }
1944 }
1945 _ => return Err("Subqueries must have an alias".to_string()),
1946 };
1947
1948 return Ok((
1949 TableSource::DerivedTable {
1950 query: Box::new(subquery),
1951 alias: alias.clone(),
1952 },
1953 Some(alias),
1954 ));
1955 }
1956 _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1957 };
1958
1959 let alias = match &self.current_token {
1961 Token::Identifier(alias_name) => {
1962 let alias = alias_name.clone();
1963 self.advance();
1964 Some(alias)
1965 }
1966 Token::As => {
1967 self.advance();
1968 match &self.current_token {
1969 Token::Identifier(alias_name) => {
1970 let alias = alias_name.clone();
1971 self.advance();
1972 Some(alias)
1973 }
1974 _ => return Err("Expected alias after AS keyword".to_string()),
1975 }
1976 }
1977 _ => None,
1978 };
1979
1980 Ok((table, alias))
1981 }
1982
1983 fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1984 let mut conditions = Vec::new();
1985
1986 conditions.push(self.parse_single_join_condition()?);
1988
1989 while matches!(self.current_token, Token::And) {
1991 self.advance(); conditions.push(self.parse_single_join_condition()?);
1993 }
1994
1995 Ok(JoinCondition { conditions })
1996 }
1997
1998 fn parse_single_join_condition(&mut self) -> Result<SingleJoinCondition, String> {
1999 let left_expr = self.parse_additive()?;
2002
2003 let operator = match &self.current_token {
2005 Token::Equal => JoinOperator::Equal,
2006 Token::NotEqual => JoinOperator::NotEqual,
2007 Token::LessThan => JoinOperator::LessThan,
2008 Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
2009 Token::GreaterThan => JoinOperator::GreaterThan,
2010 Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
2011 _ => return Err("Expected comparison operator in JOIN condition".to_string()),
2012 };
2013 self.advance();
2014
2015 let right_expr = self.parse_additive()?;
2017
2018 Ok(SingleJoinCondition {
2019 left_expr,
2020 operator,
2021 right_expr,
2022 })
2023 }
2024
2025 fn parse_column_reference(&mut self) -> Result<String, String> {
2026 match &self.current_token {
2027 Token::Identifier(name) => {
2028 let mut column_ref = name.clone();
2029 self.advance();
2030
2031 if matches!(self.current_token, Token::Dot) {
2033 self.advance();
2034 match &self.current_token {
2035 Token::Identifier(col_name) => {
2036 column_ref.push('.');
2037 column_ref.push_str(col_name);
2038 self.advance();
2039 }
2040 _ => return Err("Expected column name after '.'".to_string()),
2041 }
2042 }
2043
2044 Ok(column_ref)
2045 }
2046 _ => Err("Expected column reference".to_string()),
2047 }
2048 }
2049
2050 fn parse_pivot_clause(&mut self, source: TableSource) -> Result<TableSource, String> {
2055 self.consume(Token::Pivot)?;
2057
2058 self.consume(Token::LeftParen)?;
2060
2061 let aggregate = self.parse_pivot_aggregate()?;
2063
2064 self.consume(Token::For)?;
2066
2067 let pivot_column = match &self.current_token {
2069 Token::Identifier(col) => {
2070 let column = col.clone();
2071 self.advance();
2072 column
2073 }
2074 Token::QuotedIdentifier(col) => {
2075 let column = col.clone();
2076 self.advance();
2077 column
2078 }
2079 _ => return Err("Expected column name after FOR in PIVOT".to_string()),
2080 };
2081
2082 if !matches!(self.current_token, Token::In) {
2084 return Err("Expected IN keyword in PIVOT clause".to_string());
2085 }
2086 self.advance();
2087
2088 let pivot_values = self.parse_pivot_in_clause()?;
2090
2091 self.consume(Token::RightParen)?;
2093
2094 let alias = self.parse_optional_alias()?;
2096
2097 Ok(TableSource::Pivot {
2098 source: Box::new(source),
2099 aggregate,
2100 pivot_column,
2101 pivot_values,
2102 alias,
2103 })
2104 }
2105
2106 fn parse_pivot_aggregate(&mut self) -> Result<PivotAggregate, String> {
2109 let function = match &self.current_token {
2111 Token::Identifier(name) => {
2112 let func_name = name.to_uppercase();
2113 match func_name.as_str() {
2115 "MAX" | "MIN" | "SUM" | "AVG" | "COUNT" => {
2116 self.advance();
2117 func_name
2118 }
2119 _ => {
2120 return Err(format!(
2121 "Expected aggregate function (MAX, MIN, SUM, AVG, COUNT), got {}",
2122 func_name
2123 ))
2124 }
2125 }
2126 }
2127 _ => return Err("Expected aggregate function in PIVOT".to_string()),
2128 };
2129
2130 self.consume(Token::LeftParen)?;
2132
2133 let column = match &self.current_token {
2135 Token::Identifier(col) => {
2136 let column = col.clone();
2137 self.advance();
2138 column
2139 }
2140 Token::QuotedIdentifier(col) => {
2141 let column = col.clone();
2142 self.advance();
2143 column
2144 }
2145 Token::Star => {
2146 if function == "COUNT" {
2148 self.advance();
2149 "*".to_string()
2150 } else {
2151 return Err(format!("Only COUNT can use *, not {}", function));
2152 }
2153 }
2154 _ => return Err("Expected column name in aggregate function".to_string()),
2155 };
2156
2157 self.consume(Token::RightParen)?;
2159
2160 Ok(PivotAggregate { function, column })
2161 }
2162
2163 fn parse_pivot_in_clause(&mut self) -> Result<Vec<String>, String> {
2167 self.consume(Token::LeftParen)?;
2169
2170 let mut values = Vec::new();
2171
2172 match &self.current_token {
2174 Token::StringLiteral(val) => {
2175 values.push(val.clone());
2176 self.advance();
2177 }
2178 Token::Identifier(val) => {
2179 values.push(val.clone());
2181 self.advance();
2182 }
2183 Token::NumberLiteral(val) => {
2184 values.push(val.clone());
2186 self.advance();
2187 }
2188 _ => return Err("Expected value in PIVOT IN clause".to_string()),
2189 }
2190
2191 while matches!(self.current_token, Token::Comma) {
2193 self.advance(); match &self.current_token {
2196 Token::StringLiteral(val) => {
2197 values.push(val.clone());
2198 self.advance();
2199 }
2200 Token::Identifier(val) => {
2201 values.push(val.clone());
2202 self.advance();
2203 }
2204 Token::NumberLiteral(val) => {
2205 values.push(val.clone());
2206 self.advance();
2207 }
2208 _ => return Err("Expected value after comma in PIVOT IN clause".to_string()),
2209 }
2210 }
2211
2212 self.consume(Token::RightParen)?;
2214
2215 if values.is_empty() {
2216 return Err("PIVOT IN clause must have at least one value".to_string());
2217 }
2218
2219 Ok(values)
2220 }
2221}
2222
2223#[derive(Debug, Clone)]
2225pub enum CursorContext {
2226 SelectClause,
2227 FromClause,
2228 WhereClause,
2229 OrderByClause,
2230 AfterColumn(String),
2231 AfterLogicalOp(LogicalOp),
2232 AfterComparisonOp(String, String), InMethodCall(String, String), InExpression,
2235 Unknown,
2236}
2237
2238fn safe_slice_to(s: &str, pos: usize) -> &str {
2240 if pos >= s.len() {
2241 return s;
2242 }
2243
2244 let mut safe_pos = pos;
2246 while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
2247 safe_pos -= 1;
2248 }
2249
2250 &s[..safe_pos]
2251}
2252
2253fn safe_slice_from(s: &str, pos: usize) -> &str {
2255 if pos >= s.len() {
2256 return "";
2257 }
2258
2259 let mut safe_pos = pos;
2261 while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
2262 safe_pos += 1;
2263 }
2264
2265 &s[safe_pos..]
2266}
2267
2268#[must_use]
2269pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2270 let truncated = safe_slice_to(query, cursor_pos);
2271 let mut parser = Parser::new(truncated);
2272
2273 if let Ok(stmt) = parser.parse() {
2275 let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
2276 #[cfg(test)]
2277 println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2278 (ctx, partial)
2279 } else {
2280 let (ctx, partial) = analyze_partial(truncated, cursor_pos);
2282 #[cfg(test)]
2283 println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
2284 (ctx, partial)
2285 }
2286}
2287
2288#[must_use]
2289pub fn tokenize_query(query: &str) -> Vec<String> {
2290 let mut lexer = Lexer::new(query);
2291 let tokens = lexer.tokenize_all();
2292 tokens.iter().map(|t| format!("{t:?}")).collect()
2293}
2294
2295#[must_use]
2296fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
2298 if pos > 0 {
2300 pos -= 1;
2301 while pos > 0 {
2302 if bytes[pos] == b'"' {
2303 if pos == 0 || bytes[pos - 1] != b'\\' {
2305 return Some(pos);
2306 }
2307 }
2308 pos -= 1;
2309 }
2310 if bytes[0] == b'"' {
2312 return Some(0);
2313 }
2314 }
2315 None
2316}
2317
2318fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
2320 let partial_method = if after_dot.is_empty() {
2322 None
2323 } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
2324 Some(after_dot.to_string())
2325 } else {
2326 None
2327 };
2328
2329 let col_name_for_context =
2331 if col_name.starts_with('"') && col_name.ends_with('"') && col_name.len() > 2 {
2332 col_name[1..col_name.len() - 1].to_string()
2333 } else {
2334 col_name.to_string()
2335 };
2336
2337 (
2338 CursorContext::AfterColumn(col_name_for_context),
2339 partial_method,
2340 )
2341}
2342
2343fn check_after_comparison_operator(query: &str) -> Option<(CursorContext, Option<String>)> {
2345 for op in &Parser::COMPARISON_OPERATORS {
2346 if let Some(op_pos) = query.rfind(op) {
2347 let before_op = safe_slice_to(query, op_pos);
2348 let after_op_start = op_pos + op.len();
2349 let after_op = if after_op_start < query.len() {
2350 &query[after_op_start..]
2351 } else {
2352 ""
2353 };
2354
2355 if let Some(col_name) = before_op.split_whitespace().last() {
2357 if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2358 let after_op_trimmed = after_op.trim();
2360 if after_op_trimmed.is_empty()
2361 || (after_op_trimmed
2362 .chars()
2363 .all(|c| c.is_alphanumeric() || c == '_')
2364 && !after_op_trimmed.contains('('))
2365 {
2366 let partial = if after_op_trimmed.is_empty() {
2367 None
2368 } else {
2369 Some(after_op_trimmed.to_string())
2370 };
2371 return Some((
2372 CursorContext::AfterComparisonOp(
2373 col_name.to_string(),
2374 op.trim().to_string(),
2375 ),
2376 partial,
2377 ));
2378 }
2379 }
2380 }
2381 }
2382 }
2383 None
2384}
2385
2386fn analyze_statement(
2387 stmt: &SelectStatement,
2388 query: &str,
2389 _cursor_pos: usize,
2390) -> (CursorContext, Option<String>) {
2391 let trimmed = query.trim();
2393
2394 if let Some(result) = check_after_comparison_operator(query) {
2396 return result;
2397 }
2398
2399 let ends_with_logical_op = |s: &str| -> bool {
2402 let s_upper = s.to_uppercase();
2403 s_upper.ends_with(" AND") || s_upper.ends_with(" OR")
2404 };
2405
2406 if ends_with_logical_op(trimmed) {
2407 } else {
2409 if let Some(dot_pos) = trimmed.rfind('.') {
2411 let before_dot = safe_slice_to(trimmed, dot_pos);
2413 let after_dot_start = dot_pos + 1;
2414 let after_dot = if after_dot_start < trimmed.len() {
2415 &trimmed[after_dot_start..]
2416 } else {
2417 ""
2418 };
2419
2420 if !after_dot.contains('(') {
2423 let col_name = if before_dot.ends_with('"') {
2425 let bytes = before_dot.as_bytes();
2427 let pos = before_dot.len() - 1; find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2430 } else {
2431 before_dot
2434 .split_whitespace()
2435 .last()
2436 .map(|word| word.trim_start_matches('('))
2437 };
2438
2439 if let Some(col_name) = col_name {
2440 let is_valid = Parser::is_valid_identifier(col_name);
2442
2443 if is_valid {
2444 return handle_method_call_context(col_name, after_dot);
2445 }
2446 }
2447 }
2448 }
2449 }
2450
2451 if let Some(where_clause) = &stmt.where_clause {
2453 let trimmed_upper = trimmed.to_uppercase();
2455 if trimmed_upper.ends_with(" AND") || trimmed_upper.ends_with(" OR") {
2456 let op = if trimmed_upper.ends_with(" AND") {
2457 LogicalOp::And
2458 } else {
2459 LogicalOp::Or
2460 };
2461 return (CursorContext::AfterLogicalOp(op), None);
2462 }
2463
2464 let query_upper = query.to_uppercase();
2466 if let Some(and_pos) = query_upper.rfind(" AND ") {
2467 let after_and = safe_slice_from(query, and_pos + 5);
2468 let partial = extract_partial_at_end(after_and);
2469 if partial.is_some() {
2470 return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
2471 }
2472 }
2473
2474 if let Some(or_pos) = query_upper.rfind(" OR ") {
2475 let after_or = safe_slice_from(query, or_pos + 4);
2476 let partial = extract_partial_at_end(after_or);
2477 if partial.is_some() {
2478 return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
2479 }
2480 }
2481
2482 if let Some(last_condition) = where_clause.conditions.last() {
2483 if let Some(connector) = &last_condition.connector {
2484 return (
2486 CursorContext::AfterLogicalOp(connector.clone()),
2487 extract_partial_at_end(query),
2488 );
2489 }
2490 }
2491 return (CursorContext::WhereClause, extract_partial_at_end(query));
2493 }
2494
2495 let query_upper = query.to_uppercase();
2497 if query_upper.ends_with(" ORDER BY") {
2498 return (CursorContext::OrderByClause, None);
2499 }
2500
2501 if stmt.order_by.is_some() {
2503 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2504 }
2505
2506 if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
2507 return (CursorContext::FromClause, extract_partial_at_end(query));
2508 }
2509
2510 if !stmt.columns.is_empty() && stmt.from_table.is_none() {
2511 return (CursorContext::SelectClause, extract_partial_at_end(query));
2512 }
2513
2514 (CursorContext::Unknown, None)
2515}
2516
2517fn describe_token(token: &Token) -> String {
2520 if let Some(kw) = token.as_keyword_str() {
2521 return format!("keyword '{kw}'");
2522 }
2523 match token {
2524 Token::Identifier(s) | Token::QuotedIdentifier(s) => format!("'{s}'"),
2525 Token::StringLiteral(s) => format!("string literal '{s}'"),
2526 Token::NumberLiteral(s) => format!("number '{s}'"),
2527 Token::Comma => "','".to_string(),
2528 Token::Semicolon => "';'".to_string(),
2529 Token::LeftParen => "'('".to_string(),
2530 Token::RightParen => "')'".to_string(),
2531 Token::Star => "'*'".to_string(),
2532 Token::Dot => "'.'".to_string(),
2533 Token::Eof => "end of input".to_string(),
2534 other => format!("{other:?}"),
2535 }
2536}
2537
2538fn find_last_token(tokens: &[(usize, usize, Token)], target: &Token) -> Option<usize> {
2540 tokens
2541 .iter()
2542 .rposition(|(_, _, t)| t == target)
2543 .map(|idx| tokens[idx].0)
2544}
2545
2546fn find_last_matching_token<F>(
2548 tokens: &[(usize, usize, Token)],
2549 predicate: F,
2550) -> Option<(usize, &Token)>
2551where
2552 F: Fn(&Token) -> bool,
2553{
2554 tokens
2555 .iter()
2556 .rposition(|(_, _, t)| predicate(t))
2557 .map(|idx| (tokens[idx].0, &tokens[idx].2))
2558}
2559
2560fn is_in_clause(
2562 tokens: &[(usize, usize, Token)],
2563 clause_token: Token,
2564 exclude_tokens: &[Token],
2565) -> bool {
2566 if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2568 for (pos, _, token) in tokens.iter() {
2570 if *pos > clause_pos && exclude_tokens.contains(token) {
2571 return false;
2572 }
2573 }
2574 return true;
2575 }
2576 false
2577}
2578
2579fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2580 let mut lexer = Lexer::new(query);
2582 let tokens = lexer.tokenize_all_with_positions();
2583
2584 let trimmed = query.trim();
2585
2586 #[cfg(test)]
2587 {
2588 if trimmed.contains("\"Last Name\"") {
2589 eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
2590 }
2591 }
2592
2593 if let Some(result) = check_after_comparison_operator(query) {
2595 return result;
2596 }
2597
2598 if let Some(dot_pos) = trimmed.rfind('.') {
2601 #[cfg(test)]
2602 {
2603 if trimmed.contains("\"Last Name\"") {
2604 eprintln!("DEBUG: Found dot at position {dot_pos}");
2605 }
2606 }
2607 let before_dot = &trimmed[..dot_pos];
2609 let after_dot = &trimmed[dot_pos + 1..];
2610
2611 if !after_dot.contains('(') {
2614 let col_name = if before_dot.ends_with('"') {
2617 let bytes = before_dot.as_bytes();
2619 let pos = before_dot.len() - 1; #[cfg(test)]
2622 {
2623 if trimmed.contains("\"Last Name\"") {
2624 eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
2625 }
2626 }
2627
2628 let found_start = find_quote_start(bytes, pos);
2629
2630 if let Some(start) = found_start {
2631 let result = safe_slice_from(before_dot, start);
2633 #[cfg(test)]
2634 {
2635 if trimmed.contains("\"Last Name\"") {
2636 eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
2637 }
2638 }
2639 Some(result)
2640 } else {
2641 #[cfg(test)]
2642 {
2643 if trimmed.contains("\"Last Name\"") {
2644 eprintln!("DEBUG: No opening quote found!");
2645 }
2646 }
2647 None
2648 }
2649 } else {
2650 before_dot
2653 .split_whitespace()
2654 .last()
2655 .map(|word| word.trim_start_matches('('))
2656 };
2657
2658 if let Some(col_name) = col_name {
2659 #[cfg(test)]
2660 {
2661 if trimmed.contains("\"Last Name\"") {
2662 eprintln!("DEBUG: col_name = '{col_name}'");
2663 }
2664 }
2665
2666 let is_valid = Parser::is_valid_identifier(col_name);
2668
2669 #[cfg(test)]
2670 {
2671 if trimmed.contains("\"Last Name\"") {
2672 eprintln!("DEBUG: is_valid = {is_valid}");
2673 }
2674 }
2675
2676 if is_valid {
2677 return handle_method_call_context(col_name, after_dot);
2678 }
2679 }
2680 }
2681 }
2682
2683 if let Some((pos, token)) =
2685 find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2686 {
2687 let token_end_pos = if matches!(token, Token::And) {
2689 pos + 3 } else {
2691 pos + 2 };
2693
2694 if cursor_pos > token_end_pos {
2695 let after_op = safe_slice_from(query, token_end_pos + 1); let partial = extract_partial_at_end(after_op);
2698 let op = if matches!(token, Token::And) {
2699 LogicalOp::And
2700 } else {
2701 LogicalOp::Or
2702 };
2703 return (CursorContext::AfterLogicalOp(op), partial);
2704 }
2705 }
2706
2707 if let Some((_, _, last_token)) = tokens.last() {
2709 if matches!(last_token, Token::And | Token::Or) {
2710 let op = if matches!(last_token, Token::And) {
2711 LogicalOp::And
2712 } else {
2713 LogicalOp::Or
2714 };
2715 return (CursorContext::AfterLogicalOp(op), None);
2716 }
2717 }
2718
2719 if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2721 let has_by = tokens
2723 .iter()
2724 .any(|(pos, _, t)| *pos > order_pos && matches!(t, Token::By));
2725 if has_by
2726 || tokens
2727 .last()
2728 .map_or(false, |(_, _, t)| matches!(t, Token::OrderBy))
2729 {
2730 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2731 }
2732 }
2733
2734 if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2736 return (CursorContext::WhereClause, extract_partial_at_end(query));
2737 }
2738
2739 if is_in_clause(
2741 &tokens,
2742 Token::From,
2743 &[Token::Where, Token::OrderBy, Token::GroupBy],
2744 ) {
2745 return (CursorContext::FromClause, extract_partial_at_end(query));
2746 }
2747
2748 if find_last_token(&tokens, &Token::Select).is_some()
2750 && find_last_token(&tokens, &Token::From).is_none()
2751 {
2752 return (CursorContext::SelectClause, extract_partial_at_end(query));
2753 }
2754
2755 (CursorContext::Unknown, None)
2756}
2757
2758fn extract_partial_at_end(query: &str) -> Option<String> {
2759 let trimmed = query.trim();
2760
2761 if let Some(last_word) = trimmed.split_whitespace().last() {
2763 if last_word.starts_with('"') && !last_word.ends_with('"') {
2764 return Some(last_word.to_string());
2766 }
2767 }
2768
2769 let last_word = trimmed.split_whitespace().last()?;
2771
2772 if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2775 if !is_sql_keyword(last_word) {
2777 Some(last_word.to_string())
2778 } else {
2779 None
2780 }
2781 } else {
2782 None
2783 }
2784}
2785
2786impl ParsePrimary for Parser {
2788 fn current_token(&self) -> &Token {
2789 &self.current_token
2790 }
2791
2792 fn advance(&mut self) {
2793 self.advance();
2794 }
2795
2796 fn consume(&mut self, expected: Token) -> Result<(), String> {
2797 self.consume(expected)
2798 }
2799
2800 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2801 self.parse_case_expression()
2802 }
2803
2804 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2805 self.parse_function_args()
2806 }
2807
2808 fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2809 self.parse_window_spec()
2810 }
2811
2812 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2813 self.parse_logical_or()
2814 }
2815
2816 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2817 self.parse_comparison()
2818 }
2819
2820 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2821 self.parse_expression_list()
2822 }
2823
2824 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2825 if matches!(self.current_token, Token::With) {
2827 self.parse_with_clause_inner()
2828 } else {
2829 self.parse_select_statement_inner()
2830 }
2831 }
2832}
2833
2834impl ExpressionParser for Parser {
2836 fn current_token(&self) -> &Token {
2837 &self.current_token
2838 }
2839
2840 fn advance(&mut self) {
2841 match &self.current_token {
2843 Token::LeftParen => self.paren_depth += 1,
2844 Token::RightParen => {
2845 self.paren_depth -= 1;
2846 }
2847 _ => {}
2848 }
2849 self.current_token = self.lexer.next_token();
2850 }
2851
2852 fn peek(&self) -> Option<&Token> {
2853 None }
2860
2861 fn is_at_end(&self) -> bool {
2862 matches!(self.current_token, Token::Eof)
2863 }
2864
2865 fn consume(&mut self, expected: Token) -> Result<(), String> {
2866 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
2868 self.update_paren_depth(&expected)?;
2869 self.current_token = self.lexer.next_token();
2870 Ok(())
2871 } else {
2872 Err(format!(
2873 "Expected {:?}, found {:?}",
2874 expected, self.current_token
2875 ))
2876 }
2877 }
2878
2879 fn parse_identifier(&mut self) -> Result<String, String> {
2880 if let Token::Identifier(id) = &self.current_token {
2881 let id = id.clone();
2882 self.advance();
2883 Ok(id)
2884 } else {
2885 Err(format!(
2886 "Expected identifier, found {:?}",
2887 self.current_token
2888 ))
2889 }
2890 }
2891}
2892
2893impl ParseArithmetic for Parser {
2895 fn current_token(&self) -> &Token {
2896 &self.current_token
2897 }
2898
2899 fn advance(&mut self) {
2900 self.advance();
2901 }
2902
2903 fn consume(&mut self, expected: Token) -> Result<(), String> {
2904 self.consume(expected)
2905 }
2906
2907 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2908 self.parse_primary()
2909 }
2910
2911 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2912 self.parse_multiplicative()
2913 }
2914
2915 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2916 self.parse_method_args()
2917 }
2918}
2919
2920impl ParseComparison for Parser {
2922 fn current_token(&self) -> &Token {
2923 &self.current_token
2924 }
2925
2926 fn advance(&mut self) {
2927 self.advance();
2928 }
2929
2930 fn consume(&mut self, expected: Token) -> Result<(), String> {
2931 self.consume(expected)
2932 }
2933
2934 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2935 self.parse_primary()
2936 }
2937
2938 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2939 self.parse_additive()
2940 }
2941
2942 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2943 self.parse_expression_list()
2944 }
2945
2946 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2947 if matches!(self.current_token, Token::With) {
2949 self.parse_with_clause_inner()
2950 } else {
2951 self.parse_select_statement_inner()
2952 }
2953 }
2954}
2955
2956impl ParseLogical for Parser {
2958 fn current_token(&self) -> &Token {
2959 &self.current_token
2960 }
2961
2962 fn advance(&mut self) {
2963 self.advance();
2964 }
2965
2966 fn consume(&mut self, expected: Token) -> Result<(), String> {
2967 self.consume(expected)
2968 }
2969
2970 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2971 self.parse_logical_and()
2972 }
2973
2974 fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2975 self.parse_comparison()
2978 }
2979
2980 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2981 self.parse_comparison()
2982 }
2983
2984 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2985 self.parse_expression_list()
2986 }
2987}
2988
2989impl ParseCase for Parser {
2991 fn current_token(&self) -> &Token {
2992 &self.current_token
2993 }
2994
2995 fn advance(&mut self) {
2996 self.advance();
2997 }
2998
2999 fn consume(&mut self, expected: Token) -> Result<(), String> {
3000 self.consume(expected)
3001 }
3002
3003 fn parse_expression(&mut self) -> Result<SqlExpression, String> {
3004 self.parse_expression()
3005 }
3006}
3007
3008fn is_sql_keyword(word: &str) -> bool {
3009 let mut lexer = Lexer::new(word);
3011 let token = lexer.next_token();
3012
3013 !matches!(token, Token::Identifier(_) | Token::Eof)
3015}
3016
3017#[cfg(test)]
3018mod tests {
3019 use super::*;
3020
3021 #[test]
3023 fn test_parser_mode_default_is_standard() {
3024 let sql = "-- Leading comment\nSELECT * FROM users";
3025 let mut parser = Parser::new(sql);
3026 let stmt = parser.parse().unwrap();
3027
3028 assert!(stmt.leading_comments.is_empty());
3030 assert!(stmt.trailing_comment.is_none());
3031 }
3032
3033 #[test]
3035 fn test_parser_mode_preserve_leading_comments() {
3036 let sql = "-- Important query\n-- Author: Alice\nSELECT id, name FROM users";
3037 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3038 let stmt = parser.parse().unwrap();
3039
3040 assert_eq!(stmt.leading_comments.len(), 2);
3042 assert!(stmt.leading_comments[0].is_line_comment);
3043 assert!(stmt.leading_comments[0].text.contains("Important query"));
3044 assert!(stmt.leading_comments[1].text.contains("Author: Alice"));
3045 }
3046
3047 #[test]
3049 fn test_parser_mode_preserve_trailing_comment() {
3050 let sql = "SELECT * FROM users -- Fetch all users";
3051 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3052 let stmt = parser.parse().unwrap();
3053
3054 assert!(stmt.trailing_comment.is_some());
3056 let comment = stmt.trailing_comment.unwrap();
3057 assert!(comment.is_line_comment);
3058 assert!(comment.text.contains("Fetch all users"));
3059 }
3060
3061 #[test]
3063 fn test_parser_mode_preserve_block_comments() {
3064 let sql = "/* Query explanation */\nSELECT * FROM users";
3065 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3066 let stmt = parser.parse().unwrap();
3067
3068 assert_eq!(stmt.leading_comments.len(), 1);
3070 assert!(!stmt.leading_comments[0].is_line_comment); assert!(stmt.leading_comments[0].text.contains("Query explanation"));
3072 }
3073
3074 #[test]
3076 fn test_parser_mode_preserve_both_comments() {
3077 let sql = "-- Leading\nSELECT * FROM users -- Trailing";
3078 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
3079 let stmt = parser.parse().unwrap();
3080
3081 assert_eq!(stmt.leading_comments.len(), 1);
3083 assert!(stmt.leading_comments[0].text.contains("Leading"));
3084 assert!(stmt.trailing_comment.is_some());
3085 assert!(stmt.trailing_comment.unwrap().text.contains("Trailing"));
3086 }
3087
3088 #[test]
3090 fn test_parser_mode_standard_ignores_comments() {
3091 let sql = "-- Comment 1\n/* Comment 2 */\nSELECT * FROM users -- Comment 3";
3092 let mut parser = Parser::with_mode(sql, ParserMode::Standard);
3093 let stmt = parser.parse().unwrap();
3094
3095 assert!(stmt.leading_comments.is_empty());
3097 assert!(stmt.trailing_comment.is_none());
3098
3099 assert_eq!(stmt.select_items.len(), 1);
3101 assert_eq!(stmt.from_table, Some("users".to_string()));
3102 }
3103
3104 #[test]
3106 fn test_parser_backward_compatibility() {
3107 let sql = "SELECT id, name FROM users WHERE active = true";
3108
3109 let mut parser1 = Parser::new(sql);
3111 let stmt1 = parser1.parse().unwrap();
3112
3113 let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
3115 let stmt2 = parser2.parse().unwrap();
3116
3117 assert_eq!(stmt1.select_items.len(), stmt2.select_items.len());
3119 assert_eq!(stmt1.from_table, stmt2.from_table);
3120 assert_eq!(stmt1.where_clause.is_some(), stmt2.where_clause.is_some());
3121 assert!(stmt1.leading_comments.is_empty());
3122 assert!(stmt2.leading_comments.is_empty());
3123 }
3124
3125 #[test]
3127 fn test_pivot_parsing_not_yet_supported() {
3128 let sql = "SELECT * FROM food_eaten PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle', 'Apple'))";
3129 let mut parser = Parser::new(sql);
3130 let result = parser.parse();
3131
3132 assert!(result.is_ok());
3134 let stmt = result.unwrap();
3135
3136 assert!(stmt.from_source.is_some());
3138 if let Some(crate::sql::parser::ast::TableSource::Pivot { .. }) = stmt.from_source {
3139 } else {
3141 panic!("Expected from_source to be a Pivot variant");
3142 }
3143 }
3144
3145 #[test]
3147 fn test_pivot_aggregate_functions() {
3148 let sql = "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb', 'Mar'))";
3150 let mut parser = Parser::new(sql);
3151 let result = parser.parse();
3152 assert!(result.is_ok());
3153
3154 let sql2 = "SELECT * FROM sales PIVOT (COUNT(*) FOR month IN ('Jan', 'Feb'))";
3156 let mut parser2 = Parser::new(sql2);
3157 let result2 = parser2.parse();
3158 assert!(result2.is_ok());
3159
3160 let sql3 = "SELECT * FROM sales PIVOT (AVG(price) FOR category IN ('A', 'B'))";
3162 let mut parser3 = Parser::new(sql3);
3163 let result3 = parser3.parse();
3164 assert!(result3.is_ok());
3165 }
3166
3167 #[test]
3169 fn test_pivot_with_subquery() {
3170 let sql = "SELECT * FROM (SELECT * FROM food_eaten WHERE Id > 5) AS t \
3171 PIVOT (MAX(AmountEaten) FOR FoodName IN ('Sammich', 'Pickle'))";
3172 let mut parser = Parser::new(sql);
3173 let result = parser.parse();
3174
3175 assert!(result.is_ok());
3177 let stmt = result.unwrap();
3178 assert!(stmt.from_source.is_some());
3179 }
3180
3181 #[test]
3183 fn test_pivot_with_alias() {
3184 let sql =
3185 "SELECT * FROM sales PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb')) AS pivot_table";
3186 let mut parser = Parser::new(sql);
3187 let result = parser.parse();
3188
3189 assert!(result.is_ok());
3191 let stmt = result.unwrap();
3192 assert!(stmt.from_source.is_some());
3193 }
3194
3195 fn extract_web_spec(
3198 stmt: &crate::sql::parser::ast::SelectStatement,
3199 ) -> &crate::sql::parser::ast::WebCTESpec {
3200 use crate::sql::parser::ast::CTEType;
3201 assert!(!stmt.ctes.is_empty(), "statement should have CTEs");
3202 match &stmt.ctes[0].cte_type {
3203 CTEType::Web(spec) => spec,
3204 other => panic!("expected Web CTE, got {:?}", other),
3205 }
3206 }
3207
3208 #[test]
3209 fn test_web_cte_delimiter_pipe() {
3210 let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '|') \
3211 SELECT * FROM foo";
3212 let mut parser = Parser::new(sql);
3213 let stmt = parser.parse().expect("parse failed");
3214 let spec = extract_web_spec(&stmt);
3215 assert_eq!(spec.delimiter, Some(b'|'));
3216 }
3217
3218 #[test]
3219 fn test_web_cte_delimiter_tab_via_escape() {
3220 let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '\\t') \
3221 SELECT * FROM foo";
3222 let mut parser = Parser::new(sql);
3223 let stmt = parser.parse().expect("parse failed");
3224 let spec = extract_web_spec(&stmt);
3225 assert_eq!(spec.delimiter, Some(b'\t'));
3226 }
3227
3228 #[test]
3229 fn test_web_cte_no_delimiter_defaults_to_none() {
3230 let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV) SELECT * FROM foo";
3231 let mut parser = Parser::new(sql);
3232 let stmt = parser.parse().expect("parse failed");
3233 let spec = extract_web_spec(&stmt);
3234 assert!(spec.delimiter.is_none());
3235 }
3236
3237 #[test]
3238 fn test_web_cte_delimiter_rejects_multi_char() {
3239 let sql = "WITH WEB foo AS (URL 'file:///tmp/missing.dat' FORMAT CSV DELIMITER '||') \
3240 SELECT * FROM foo";
3241 let mut parser = Parser::new(sql);
3242 let err = parser.parse().unwrap_err();
3243 let msg = err.to_string();
3244 assert!(
3245 msg.contains("DELIMITER") || msg.contains("single ASCII"),
3246 "should reject multi-char delimiter: {}",
3247 msg
3248 );
3249 }
3250}