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, 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 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 parse_comparison_expr(self)
1717 }
1718
1719 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1720 parse_additive_expr(self)
1722 }
1723
1724 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1725 parse_multiplicative_expr(self)
1727 }
1728
1729 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1730 parse_logical_or_expr(self)
1732 }
1733
1734 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1735 parse_logical_and_expr(self)
1737 }
1738
1739 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1740 parse_case_expr(self)
1742 }
1743
1744 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1745 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 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1758 self.in_method_args = true;
1760
1761 let args = self.parse_argument_list()?;
1762
1763 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 if matches!(self.current_token, Token::Distinct) {
1776 self.advance(); has_distinct = true;
1778 }
1779
1780 args.push(self.parse_logical_or()?);
1783
1784 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 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 fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1825 let join_type = match &self.current_token {
1827 Token::Join => {
1828 self.advance();
1829 JoinType::Inner }
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 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 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 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 let (table, alias) = self.parse_join_table_source()?;
1888
1889 let condition = if join_type == JoinType::Cross {
1891 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 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 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 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 conditions.push(self.parse_single_join_condition()?);
1986
1987 while matches!(self.current_token, Token::And) {
1989 self.advance(); 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 let left_expr = self.parse_additive()?;
2000
2001 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 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 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 fn parse_pivot_clause(&mut self, source: TableSource) -> Result<TableSource, String> {
2053 self.consume(Token::Pivot)?;
2055
2056 self.consume(Token::LeftParen)?;
2058
2059 let aggregate = self.parse_pivot_aggregate()?;
2061
2062 self.consume(Token::For)?;
2064
2065 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 if !matches!(self.current_token, Token::In) {
2082 return Err("Expected IN keyword in PIVOT clause".to_string());
2083 }
2084 self.advance();
2085
2086 let pivot_values = self.parse_pivot_in_clause()?;
2088
2089 self.consume(Token::RightParen)?;
2091
2092 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 fn parse_pivot_aggregate(&mut self) -> Result<PivotAggregate, String> {
2107 let function = match &self.current_token {
2109 Token::Identifier(name) => {
2110 let func_name = name.to_uppercase();
2111 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 self.consume(Token::LeftParen)?;
2130
2131 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 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 self.consume(Token::RightParen)?;
2157
2158 Ok(PivotAggregate { function, column })
2159 }
2160
2161 fn parse_pivot_in_clause(&mut self) -> Result<Vec<String>, String> {
2165 self.consume(Token::LeftParen)?;
2167
2168 let mut values = Vec::new();
2169
2170 match &self.current_token {
2172 Token::StringLiteral(val) => {
2173 values.push(val.clone());
2174 self.advance();
2175 }
2176 Token::Identifier(val) => {
2177 values.push(val.clone());
2179 self.advance();
2180 }
2181 Token::NumberLiteral(val) => {
2182 values.push(val.clone());
2184 self.advance();
2185 }
2186 _ => return Err("Expected value in PIVOT IN clause".to_string()),
2187 }
2188
2189 while matches!(self.current_token, Token::Comma) {
2191 self.advance(); 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 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#[derive(Debug, Clone)]
2223pub enum CursorContext {
2224 SelectClause,
2225 FromClause,
2226 WhereClause,
2227 OrderByClause,
2228 AfterColumn(String),
2229 AfterLogicalOp(LogicalOp),
2230 AfterComparisonOp(String, String), InMethodCall(String, String), InExpression,
2233 Unknown,
2234}
2235
2236fn safe_slice_to(s: &str, pos: usize) -> &str {
2238 if pos >= s.len() {
2239 return s;
2240 }
2241
2242 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
2251fn safe_slice_from(s: &str, pos: usize) -> &str {
2253 if pos >= s.len() {
2254 return "";
2255 }
2256
2257 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 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 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]
2294fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
2296 if pos > 0 {
2298 pos -= 1;
2299 while pos > 0 {
2300 if bytes[pos] == b'"' {
2301 if pos == 0 || bytes[pos - 1] != b'\\' {
2303 return Some(pos);
2304 }
2305 }
2306 pos -= 1;
2307 }
2308 if bytes[0] == b'"' {
2310 return Some(0);
2311 }
2312 }
2313 None
2314}
2315
2316fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
2318 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 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
2341fn 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 if let Some(col_name) = before_op.split_whitespace().last() {
2355 if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2356 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 let trimmed = query.trim();
2391
2392 if let Some(result) = check_after_comparison_operator(query) {
2394 return result;
2395 }
2396
2397 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 } else {
2407 if let Some(dot_pos) = trimmed.rfind('.') {
2409 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 if !after_dot.contains('(') {
2421 let col_name = if before_dot.ends_with('"') {
2423 let bytes = before_dot.as_bytes();
2425 let pos = before_dot.len() - 1; find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2428 } else {
2429 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 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 if let Some(where_clause) = &stmt.where_clause {
2451 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 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 return (
2484 CursorContext::AfterLogicalOp(connector.clone()),
2485 extract_partial_at_end(query),
2486 );
2487 }
2488 }
2489 return (CursorContext::WhereClause, extract_partial_at_end(query));
2491 }
2492
2493 let query_upper = query.to_uppercase();
2495 if query_upper.ends_with(" ORDER BY") {
2496 return (CursorContext::OrderByClause, None);
2497 }
2498
2499 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
2515fn 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
2536fn 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
2544fn 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
2558fn is_in_clause(
2560 tokens: &[(usize, usize, Token)],
2561 clause_token: Token,
2562 exclude_tokens: &[Token],
2563) -> bool {
2564 if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2566 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 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 if let Some(result) = check_after_comparison_operator(query) {
2593 return result;
2594 }
2595
2596 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 let before_dot = &trimmed[..dot_pos];
2607 let after_dot = &trimmed[dot_pos + 1..];
2608
2609 if !after_dot.contains('(') {
2612 let col_name = if before_dot.ends_with('"') {
2615 let bytes = before_dot.as_bytes();
2617 let pos = before_dot.len() - 1; #[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 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 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 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 if let Some((pos, token)) =
2683 find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2684 {
2685 let token_end_pos = if matches!(token, Token::And) {
2687 pos + 3 } else {
2689 pos + 2 };
2691
2692 if cursor_pos > token_end_pos {
2693 let after_op = safe_slice_from(query, token_end_pos + 1); 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 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 if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2719 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 if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2734 return (CursorContext::WhereClause, extract_partial_at_end(query));
2735 }
2736
2737 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 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 if let Some(last_word) = trimmed.split_whitespace().last() {
2761 if last_word.starts_with('"') && !last_word.ends_with('"') {
2762 return Some(last_word.to_string());
2764 }
2765 }
2766
2767 let last_word = trimmed.split_whitespace().last()?;
2769
2770 if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2773 if !is_sql_keyword(last_word) {
2775 Some(last_word.to_string())
2776 } else {
2777 None
2778 }
2779 } else {
2780 None
2781 }
2782}
2783
2784impl 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 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
2832impl ExpressionParser for Parser {
2834 fn current_token(&self) -> &Token {
2835 &self.current_token
2836 }
2837
2838 fn advance(&mut self) {
2839 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 None }
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 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
2891impl 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
2918impl 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 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
2954impl 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 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
2987impl 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 let mut lexer = Lexer::new(word);
3009 let token = lexer.next_token();
3010
3011 !matches!(token, Token::Identifier(_) | Token::Eof)
3013}
3014
3015#[cfg(test)]
3016mod tests {
3017 use super::*;
3018
3019 #[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 assert!(stmt.leading_comments.is_empty());
3028 assert!(stmt.trailing_comment.is_none());
3029 }
3030
3031 #[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 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]
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 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]
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 assert_eq!(stmt.leading_comments.len(), 1);
3068 assert!(!stmt.leading_comments[0].is_line_comment); assert!(stmt.leading_comments[0].text.contains("Query explanation"));
3070 }
3071
3072 #[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 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]
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 assert!(stmt.leading_comments.is_empty());
3095 assert!(stmt.trailing_comment.is_none());
3096
3097 assert_eq!(stmt.select_items.len(), 1);
3099 assert_eq!(stmt.from_table, Some("users".to_string()));
3100 }
3101
3102 #[test]
3104 fn test_parser_backward_compatibility() {
3105 let sql = "SELECT id, name FROM users WHERE active = true";
3106
3107 let mut parser1 = Parser::new(sql);
3109 let stmt1 = parser1.parse().unwrap();
3110
3111 let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
3113 let stmt2 = parser2.parse().unwrap();
3114
3115 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]
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 assert!(result.is_ok());
3132 let stmt = result.unwrap();
3133
3134 assert!(stmt.from_source.is_some());
3136 if let Some(crate::sql::parser::ast::TableSource::Pivot { .. }) = stmt.from_source {
3137 } else {
3139 panic!("Expected from_source to be a Pivot variant");
3140 }
3141 }
3142
3143 #[test]
3145 fn test_pivot_aggregate_functions() {
3146 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 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 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]
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 assert!(result.is_ok());
3175 let stmt = result.unwrap();
3176 assert!(stmt.from_source.is_some());
3177 }
3178
3179 #[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 assert!(result.is_ok());
3189 let stmt = result.unwrap();
3190 assert!(stmt.from_source.is_some());
3191 }
3192
3193 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}