1pub use super::parser::ast::{
5 CTEType, Comment, Condition, DataFormat, FrameBound, FrameUnit, HttpMethod, IntoTable,
6 JoinClause, JoinCondition, JoinOperator, JoinType, LogicalOp, OrderByColumn, SelectItem,
7 SelectStatement, SetOperation, SingleJoinCondition, SortDirection, SqlExpression,
8 TableFunction, TableSource, WebCTESpec, WhenBranch, WhereClause, WindowFrame, WindowSpec, CTE,
9};
10pub use super::parser::legacy::{ParseContext, ParseState, Schema, SqlParser, SqlToken, TableInfo};
11pub use super::parser::lexer::{Lexer, LexerMode, Token};
12pub use super::parser::ParserConfig;
13
14pub use super::parser::formatter::{format_ast_tree, format_sql_pretty, format_sql_pretty_compact};
16
17pub use super::parser::ast_formatter::{format_sql_ast, format_sql_ast_with_config, FormatConfig};
19
20use super::parser::expressions::arithmetic::{
22 parse_additive as parse_additive_expr, parse_multiplicative as parse_multiplicative_expr,
23 ParseArithmetic,
24};
25use super::parser::expressions::case::{parse_case_expression as parse_case_expr, ParseCase};
26use super::parser::expressions::comparison::{
27 parse_comparison as parse_comparison_expr, parse_in_operator, ParseComparison,
28};
29use super::parser::expressions::logical::{
30 parse_logical_and as parse_logical_and_expr, parse_logical_or as parse_logical_or_expr,
31 ParseLogical,
32};
33use super::parser::expressions::primary::{
34 parse_primary as parse_primary_expr, ParsePrimary, PrimaryExpressionContext,
35};
36use super::parser::expressions::ExpressionParser;
37
38use crate::sql::functions::{FunctionCategory, FunctionRegistry};
40use crate::sql::generators::GeneratorRegistry;
41use std::sync::Arc;
42
43use super::parser::web_cte_parser::WebCteParser;
45
46#[derive(Debug, Clone, Copy, PartialEq)]
48pub enum ParserMode {
49 Standard,
51 PreserveComments,
53}
54
55impl Default for ParserMode {
56 fn default() -> Self {
57 ParserMode::Standard
58 }
59}
60
61pub struct Parser {
62 lexer: Lexer,
63 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, }
75
76impl Parser {
77 #[must_use]
78 pub fn new(input: &str) -> Self {
79 Self::with_mode(input, ParserMode::default())
80 }
81
82 #[must_use]
84 pub fn with_mode(input: &str, mode: ParserMode) -> Self {
85 let lexer_mode = match mode {
87 ParserMode::Standard => LexerMode::SkipComments,
88 ParserMode::PreserveComments => LexerMode::PreserveComments,
89 };
90
91 let mut lexer = Lexer::with_mode(input, lexer_mode);
92 let current_token = lexer.next_token();
93 Self {
94 lexer,
95 current_token,
96 in_method_args: false,
97 columns: Vec::new(),
98 paren_depth: 0,
99 paren_depth_stack: Vec::new(),
100 _config: ParserConfig::default(),
101 debug_trace: false,
102 trace_depth: 0,
103 function_registry: Arc::new(FunctionRegistry::new()),
104 generator_registry: Arc::new(GeneratorRegistry::new()),
105 mode,
106 }
107 }
108
109 #[must_use]
110 pub fn with_config(input: &str, config: ParserConfig) -> Self {
111 let mut lexer = Lexer::new(input);
112 let current_token = lexer.next_token();
113 Self {
114 lexer,
115 current_token,
116 in_method_args: false,
117 columns: Vec::new(),
118 paren_depth: 0,
119 paren_depth_stack: Vec::new(),
120 _config: config,
121 debug_trace: false,
122 trace_depth: 0,
123 function_registry: Arc::new(FunctionRegistry::new()),
124 generator_registry: Arc::new(GeneratorRegistry::new()),
125 mode: ParserMode::default(),
126 }
127 }
128
129 #[must_use]
130 pub fn with_columns(mut self, columns: Vec<String>) -> Self {
131 self.columns = columns;
132 self
133 }
134
135 #[must_use]
136 pub fn with_debug_trace(mut self, enabled: bool) -> Self {
137 self.debug_trace = enabled;
138 self
139 }
140
141 #[must_use]
142 pub fn with_function_registry(mut self, registry: Arc<FunctionRegistry>) -> Self {
143 self.function_registry = registry;
144 self
145 }
146
147 #[must_use]
148 pub fn with_generator_registry(mut self, registry: Arc<GeneratorRegistry>) -> Self {
149 self.generator_registry = registry;
150 self
151 }
152
153 fn trace_enter(&mut self, context: &str) {
154 if self.debug_trace {
155 let indent = " ".repeat(self.trace_depth);
156 eprintln!("{}→ {} | Token: {:?}", indent, context, self.current_token);
157 self.trace_depth += 1;
158 }
159 }
160
161 fn trace_exit(&mut self, context: &str, result: &Result<impl std::fmt::Debug, String>) {
162 if self.debug_trace {
163 self.trace_depth = self.trace_depth.saturating_sub(1);
164 let indent = " ".repeat(self.trace_depth);
165 match result {
166 Ok(val) => eprintln!("{}← {} ✓ | Result: {:?}", indent, context, val),
167 Err(e) => eprintln!("{}← {} ✗ | Error: {}", indent, context, e),
168 }
169 }
170 }
171
172 fn trace_token(&self, action: &str) {
173 if self.debug_trace {
174 let indent = " ".repeat(self.trace_depth);
175 eprintln!("{} {} | Token: {:?}", indent, action, self.current_token);
176 }
177 }
178
179 #[allow(dead_code)]
180 fn peek_token(&self) -> Option<Token> {
181 let mut temp_lexer = self.lexer.clone();
183 let next_token = temp_lexer.next_token();
184 if matches!(next_token, Token::Eof) {
185 None
186 } else {
187 Some(next_token)
188 }
189 }
190
191 fn is_identifier_reserved(id: &str) -> bool {
196 let id_upper = id.to_uppercase();
197 matches!(
198 id_upper.as_str(),
199 "ORDER" | "HAVING" | "LIMIT" | "OFFSET" | "UNION" | "INTERSECT" | "EXCEPT"
200 )
201 }
202
203 const COMPARISON_OPERATORS: [&'static str; 6] = [" > ", " < ", " >= ", " <= ", " = ", " != "];
205
206 pub fn consume(&mut self, expected: Token) -> Result<(), String> {
207 self.trace_token(&format!("Consuming expected {:?}", expected));
208 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
209 self.update_paren_depth(&expected)?;
211
212 self.current_token = self.lexer.next_token();
213 Ok(())
214 } else {
215 let error_msg = match (&expected, &self.current_token) {
217 (Token::RightParen, Token::Eof) if self.paren_depth > 0 => {
218 format!(
219 "Unclosed parenthesis - missing {} closing parenthes{}",
220 self.paren_depth,
221 if self.paren_depth == 1 { "is" } else { "es" }
222 )
223 }
224 (Token::RightParen, _) if self.paren_depth > 0 => {
225 format!(
226 "Expected closing parenthesis but found {:?} (currently {} unclosed parenthes{})",
227 self.current_token,
228 self.paren_depth,
229 if self.paren_depth == 1 { "is" } else { "es" }
230 )
231 }
232 _ => format!("Expected {:?}, found {:?}", expected, self.current_token),
233 };
234 Err(error_msg)
235 }
236 }
237
238 pub fn advance(&mut self) {
239 match &self.current_token {
241 Token::LeftParen => self.paren_depth += 1,
242 Token::RightParen => {
243 self.paren_depth -= 1;
244 }
247 _ => {}
248 }
249 let old_token = self.current_token.clone();
250 self.current_token = self.lexer.next_token();
251 if self.debug_trace {
252 let indent = " ".repeat(self.trace_depth);
253 eprintln!(
254 "{} Advanced: {:?} → {:?}",
255 indent, old_token, self.current_token
256 );
257 }
258 }
259
260 fn collect_leading_comments(&mut self) -> Vec<Comment> {
263 let mut comments = Vec::new();
264 loop {
265 match &self.current_token {
266 Token::LineComment(text) => {
267 comments.push(Comment::line(text.clone()));
268 self.advance();
269 }
270 Token::BlockComment(text) => {
271 comments.push(Comment::block(text.clone()));
272 self.advance();
273 }
274 _ => break,
275 }
276 }
277 comments
278 }
279
280 fn collect_trailing_comment(&mut self) -> Option<Comment> {
283 match &self.current_token {
284 Token::LineComment(text) => {
285 let comment = Some(Comment::line(text.clone()));
286 self.advance();
287 comment
288 }
289 Token::BlockComment(text) => {
290 let comment = Some(Comment::block(text.clone()));
291 self.advance();
292 comment
293 }
294 _ => None,
295 }
296 }
297
298 fn push_paren_depth(&mut self) {
299 self.paren_depth_stack.push(self.paren_depth);
300 self.paren_depth = 0;
301 }
302
303 fn pop_paren_depth(&mut self) {
304 if let Some(depth) = self.paren_depth_stack.pop() {
305 self.paren_depth = depth;
307 }
308 }
309
310 pub fn parse(&mut self) -> Result<SelectStatement, String> {
311 self.trace_enter("parse");
312
313 let leading_comments = if self.mode == ParserMode::PreserveComments {
316 self.collect_leading_comments()
317 } else {
318 vec![]
319 };
320
321 let result = if matches!(self.current_token, Token::With) {
323 let mut stmt = self.parse_with_clause()?;
324 stmt.leading_comments = leading_comments;
326 stmt
327 } else {
328 let stmt = self.parse_select_statement_with_comments_public(leading_comments)?;
330 self.check_balanced_parentheses()?;
331 stmt
332 };
333
334 self.trace_exit("parse", &Ok(&result));
335 Ok(result)
336 }
337
338 fn parse_select_statement_with_comments_public(
340 &mut self,
341 comments: Vec<Comment>,
342 ) -> Result<SelectStatement, String> {
343 self.parse_select_statement_with_comments(comments)
344 }
345
346 fn parse_with_clause(&mut self) -> Result<SelectStatement, String> {
347 self.consume(Token::With)?;
348 let ctes = self.parse_cte_list()?;
349
350 let mut main_query = self.parse_select_statement_inner_no_comments()?;
352 main_query.ctes = ctes;
353
354 self.check_balanced_parentheses()?;
356
357 Ok(main_query)
358 }
359
360 fn parse_with_clause_inner(&mut self) -> Result<SelectStatement, String> {
361 self.consume(Token::With)?;
362 let ctes = self.parse_cte_list()?;
363
364 let mut main_query = self.parse_select_statement_inner()?;
366 main_query.ctes = ctes;
367
368 Ok(main_query)
369 }
370
371 fn parse_cte_list(&mut self) -> Result<Vec<CTE>, String> {
373 let mut ctes = Vec::new();
374
375 loop {
377 let is_web = if matches!(&self.current_token, Token::Web) {
379 self.trace_token("Found WEB keyword for CTE");
380 self.advance();
381 true
382 } else {
383 false
384 };
385
386 let name = match &self.current_token {
388 Token::Identifier(name) => name.clone(),
389 _ => {
390 return Err(format!(
391 "Expected CTE name after {}",
392 if is_web { "WEB" } else { "WITH or comma" }
393 ))
394 }
395 };
396 self.advance();
397
398 let column_list = if matches!(self.current_token, Token::LeftParen) {
400 self.advance();
401 let cols = self.parse_identifier_list()?;
402 self.consume(Token::RightParen)?;
403 Some(cols)
404 } else {
405 None
406 };
407
408 self.consume(Token::As)?;
410
411 let cte_type = if is_web {
412 self.consume(Token::LeftParen)?;
414 let web_spec = WebCteParser::parse(self)?;
416 self.consume(Token::RightParen)?;
418 CTEType::Web(web_spec)
419 } else {
420 self.push_paren_depth();
423 self.consume(Token::LeftParen)?;
425 let query = self.parse_select_statement_inner()?;
426 self.consume(Token::RightParen)?;
428 self.pop_paren_depth();
430 CTEType::Standard(query)
431 };
432
433 ctes.push(CTE {
434 name,
435 column_list,
436 cte_type,
437 });
438
439 if !matches!(self.current_token, Token::Comma) {
441 break;
442 }
443 self.advance();
444 }
445
446 Ok(ctes)
447 }
448
449 fn parse_optional_alias(&mut self) -> Result<Option<String>, String> {
451 if matches!(self.current_token, Token::As) {
452 self.advance();
453 match &self.current_token {
454 Token::Identifier(name) => {
455 let alias = name.clone();
456 self.advance();
457 Ok(Some(alias))
458 }
459 token => {
460 if let Some(keyword) = token.as_keyword_str() {
462 Err(format!(
463 "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
464 keyword,
465 keyword.to_lowercase()
466 ))
467 } else {
468 Err("Expected alias name after AS".to_string())
469 }
470 }
471 }
472 } else if let Token::Identifier(name) = &self.current_token {
473 let alias = name.clone();
475 self.advance();
476 Ok(Some(alias))
477 } else {
478 Ok(None)
479 }
480 }
481
482 fn is_valid_identifier(name: &str) -> bool {
484 if name.starts_with('"') && name.ends_with('"') {
485 true
487 } else {
488 name.chars().all(|c| c.is_alphanumeric() || c == '_')
490 }
491 }
492
493 fn update_paren_depth(&mut self, token: &Token) -> Result<(), String> {
495 match token {
496 Token::LeftParen => self.paren_depth += 1,
497 Token::RightParen => {
498 self.paren_depth -= 1;
499 if self.paren_depth < 0 {
501 return Err(
502 "Unexpected closing parenthesis - no matching opening parenthesis"
503 .to_string(),
504 );
505 }
506 }
507 _ => {}
508 }
509 Ok(())
510 }
511
512 fn parse_argument_list(&mut self) -> Result<Vec<SqlExpression>, String> {
514 let mut args = Vec::new();
515
516 if !matches!(self.current_token, Token::RightParen) {
517 loop {
518 args.push(self.parse_expression()?);
519
520 if matches!(self.current_token, Token::Comma) {
521 self.advance();
522 } else {
523 break;
524 }
525 }
526 }
527
528 Ok(args)
529 }
530
531 fn check_balanced_parentheses(&self) -> Result<(), String> {
533 if self.paren_depth > 0 {
534 Err(format!(
535 "Unclosed parenthesis - missing {} closing parenthes{}",
536 self.paren_depth,
537 if self.paren_depth == 1 { "is" } else { "es" }
538 ))
539 } else if self.paren_depth < 0 {
540 Err("Extra closing parenthesis found - no matching opening parenthesis".to_string())
541 } else {
542 Ok(())
543 }
544 }
545
546 fn contains_aggregate_function(expr: &SqlExpression) -> bool {
549 match expr {
550 SqlExpression::FunctionCall { name, args, .. } => {
551 let upper_name = name.to_uppercase();
553 let is_aggregate = matches!(
554 upper_name.as_str(),
555 "COUNT" | "SUM" | "AVG" | "MIN" | "MAX" | "GROUP_CONCAT" | "STRING_AGG"
556 );
557
558 is_aggregate || args.iter().any(Self::contains_aggregate_function)
561 }
562 SqlExpression::BinaryOp { left, right, .. } => {
564 Self::contains_aggregate_function(left) || Self::contains_aggregate_function(right)
565 }
566 SqlExpression::Not { expr } => Self::contains_aggregate_function(expr),
567 SqlExpression::MethodCall { args, .. } => {
568 args.iter().any(Self::contains_aggregate_function)
569 }
570 SqlExpression::ChainedMethodCall { base, args, .. } => {
571 Self::contains_aggregate_function(base)
572 || args.iter().any(Self::contains_aggregate_function)
573 }
574 SqlExpression::CaseExpression {
575 when_branches,
576 else_branch,
577 } => {
578 when_branches.iter().any(|branch| {
579 Self::contains_aggregate_function(&branch.condition)
580 || Self::contains_aggregate_function(&branch.result)
581 }) || else_branch
582 .as_ref()
583 .map_or(false, |e| Self::contains_aggregate_function(e))
584 }
585 SqlExpression::SimpleCaseExpression {
586 expr,
587 when_branches,
588 else_branch,
589 } => {
590 Self::contains_aggregate_function(expr)
591 || when_branches.iter().any(|branch| {
592 Self::contains_aggregate_function(&branch.value)
593 || Self::contains_aggregate_function(&branch.result)
594 })
595 || else_branch
596 .as_ref()
597 .map_or(false, |e| Self::contains_aggregate_function(e))
598 }
599 SqlExpression::ScalarSubquery { query } => {
600 query
603 .having
604 .as_ref()
605 .map_or(false, |h| Self::contains_aggregate_function(h))
606 }
607 SqlExpression::Column(_)
609 | SqlExpression::StringLiteral(_)
610 | SqlExpression::NumberLiteral(_)
611 | SqlExpression::BooleanLiteral(_)
612 | SqlExpression::Null
613 | SqlExpression::DateTimeConstructor { .. }
614 | SqlExpression::DateTimeToday { .. } => false,
615
616 SqlExpression::WindowFunction { .. } => true,
618
619 SqlExpression::Between { expr, lower, upper } => {
621 Self::contains_aggregate_function(expr)
622 || Self::contains_aggregate_function(lower)
623 || Self::contains_aggregate_function(upper)
624 }
625
626 SqlExpression::InList { expr, values } | SqlExpression::NotInList { expr, values } => {
628 Self::contains_aggregate_function(expr)
629 || values.iter().any(Self::contains_aggregate_function)
630 }
631
632 SqlExpression::InSubquery { expr, subquery }
634 | SqlExpression::NotInSubquery { expr, subquery } => {
635 Self::contains_aggregate_function(expr)
636 || subquery
637 .having
638 .as_ref()
639 .map_or(false, |h| Self::contains_aggregate_function(h))
640 }
641
642 SqlExpression::Unnest { column, .. } => Self::contains_aggregate_function(column),
644 }
645 }
646
647 fn parse_select_statement(&mut self) -> Result<SelectStatement, String> {
648 self.trace_enter("parse_select_statement");
649 let result = self.parse_select_statement_inner()?;
650
651 self.check_balanced_parentheses()?;
653
654 Ok(result)
655 }
656
657 fn parse_select_statement_inner(&mut self) -> Result<SelectStatement, String> {
658 let leading_comments = if self.mode == ParserMode::PreserveComments {
660 self.collect_leading_comments()
661 } else {
662 vec![]
663 };
664
665 self.parse_select_statement_with_comments(leading_comments)
666 }
667
668 fn parse_select_statement_inner_no_comments(&mut self) -> Result<SelectStatement, String> {
671 self.parse_select_statement_with_comments(vec![])
672 }
673
674 fn parse_select_statement_with_comments(
676 &mut self,
677 leading_comments: Vec<Comment>,
678 ) -> Result<SelectStatement, String> {
679 self.consume(Token::Select)?;
680
681 let distinct = if matches!(self.current_token, Token::Distinct) {
683 self.advance();
684 true
685 } else {
686 false
687 };
688
689 let select_items = self.parse_select_items()?;
691
692 let columns = select_items
694 .iter()
695 .map(|item| match item {
696 SelectItem::Star { .. } => "*".to_string(),
697 SelectItem::Column {
698 column: col_ref, ..
699 } => col_ref.name.clone(),
700 SelectItem::Expression { alias, .. } => alias.clone(),
701 })
702 .collect();
703
704 let into_table = if matches!(self.current_token, Token::Into) {
706 self.advance();
707 Some(self.parse_into_clause()?)
708 } else {
709 None
710 };
711
712 let (from_table, from_subquery, from_function, from_alias) = if matches!(
714 self.current_token,
715 Token::From
716 ) {
717 self.advance();
718
719 if let Token::Identifier(name) = &self.current_token.clone() {
721 let has_paren = self.peek_token() == Some(Token::LeftParen);
725 if self.debug_trace {
726 eprintln!(
727 " Checking {} for table function, has_paren={}",
728 name, has_paren
729 );
730 }
731
732 let is_table_function = if has_paren {
735 if self.debug_trace {
737 eprintln!(" Checking generator registry for {}", name.to_uppercase());
738 }
739 if let Some(_gen) = self.generator_registry.get(&name.to_uppercase()) {
740 if self.debug_trace {
741 eprintln!(" Found {} in generator registry", name);
742 }
743 self.trace_token(&format!("Found generator: {}", name));
744 true
745 } else {
746 if let Some(func) = self.function_registry.get(&name.to_uppercase()) {
748 let sig = func.signature();
749 let is_table_fn = sig.category == FunctionCategory::TableFunction;
750 if self.debug_trace {
751 eprintln!(
752 " Found {} in function registry, is_table_function={}",
753 name, is_table_fn
754 );
755 }
756 if is_table_fn {
757 self.trace_token(&format!(
758 "Found table function in function registry: {}",
759 name
760 ));
761 }
762 is_table_fn
763 } else {
764 if self.debug_trace {
765 eprintln!(" {} not found in either registry", name);
766 self.trace_token(&format!(
767 "Not found as generator or table function: {}",
768 name
769 ));
770 }
771 false
772 }
773 }
774 } else {
775 if self.debug_trace {
776 eprintln!(" No parenthesis after {}, treating as table", name);
777 }
778 false
779 };
780
781 if is_table_function {
782 let function_name = name.clone();
784 self.advance(); self.consume(Token::LeftParen)?;
788 let args = self.parse_argument_list()?;
789 self.consume(Token::RightParen)?;
790
791 let alias = if matches!(self.current_token, Token::As) {
793 self.advance();
794 match &self.current_token {
795 Token::Identifier(name) => {
796 let alias = name.clone();
797 self.advance();
798 Some(alias)
799 }
800 token => {
801 if let Some(keyword) = token.as_keyword_str() {
802 return Err(format!(
803 "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
804 keyword,
805 keyword.to_lowercase()
806 ));
807 } else {
808 return Err("Expected alias name after AS".to_string());
809 }
810 }
811 }
812 } else if let Token::Identifier(name) = &self.current_token {
813 let alias = name.clone();
814 self.advance();
815 Some(alias)
816 } else {
817 None
818 };
819
820 (
821 None,
822 None,
823 Some(TableFunction::Generator {
824 name: function_name,
825 args,
826 }),
827 alias,
828 )
829 } else {
830 let table_name = name.clone();
832 self.advance();
833
834 let alias = self.parse_optional_alias()?;
836
837 (Some(table_name), None, None, alias)
838 }
839 } else if matches!(self.current_token, Token::LeftParen) {
840 self.advance();
842
843 let subquery = if matches!(self.current_token, Token::With) {
845 self.parse_with_clause_inner()?
846 } else {
847 self.parse_select_statement_inner()?
848 };
849
850 self.consume(Token::RightParen)?;
851
852 let alias = if matches!(self.current_token, Token::As) {
854 self.advance();
855 match &self.current_token {
856 Token::Identifier(name) => {
857 let alias = name.clone();
858 self.advance();
859 alias
860 }
861 token => {
862 if let Some(keyword) = token.as_keyword_str() {
863 return Err(format!(
864 "Reserved keyword '{}' cannot be used as subquery alias. Use a different name or quote it with double quotes: \"{}\"",
865 keyword,
866 keyword.to_lowercase()
867 ));
868 } else {
869 return Err("Expected alias name after AS".to_string());
870 }
871 }
872 }
873 } else {
874 match &self.current_token {
876 Token::Identifier(name) => {
877 let alias = name.clone();
878 self.advance();
879 alias
880 }
881 _ => {
882 return Err(
883 "Subquery in FROM must have an alias (e.g., AS t)".to_string()
884 )
885 }
886 }
887 };
888
889 (None, Some(Box::new(subquery)), None, Some(alias))
890 } else {
891 match &self.current_token {
893 Token::Identifier(table) => {
894 let table_name = table.clone();
895 self.advance();
896
897 let alias = self.parse_optional_alias()?;
899
900 (Some(table_name), None, None, alias)
901 }
902 Token::QuotedIdentifier(table) => {
903 let table_name = table.clone();
905 self.advance();
906
907 let alias = self.parse_optional_alias()?;
909
910 (Some(table_name), None, None, alias)
911 }
912 _ => return Err("Expected table name or subquery after FROM".to_string()),
913 }
914 }
915 } else {
916 (None, None, None, None)
917 };
918
919 let mut joins = Vec::new();
921 while self.is_join_token() {
922 joins.push(self.parse_join_clause()?);
923 }
924
925 let where_clause = if matches!(self.current_token, Token::Where) {
926 self.advance();
927 Some(self.parse_where_clause()?)
928 } else {
929 None
930 };
931
932 let group_by = if matches!(self.current_token, Token::GroupBy) {
933 self.advance();
934 Some(self.parse_expression_list()?)
937 } else {
938 None
939 };
940
941 let having = if matches!(self.current_token, Token::Having) {
943 if group_by.is_none() {
944 return Err("HAVING clause requires GROUP BY".to_string());
945 }
946 self.advance();
947 let having_expr = self.parse_expression()?;
948
949 if Self::contains_aggregate_function(&having_expr) {
951 return Err(
952 "HAVING clause with aggregate functions is not supported. \
953 Use an alias in SELECT for the aggregate and reference it in HAVING.\n\
954 Example: SELECT trader, COUNT(*) as trade_count FROM trades GROUP BY trader HAVING trade_count > 1"
955 .to_string()
956 );
957 }
958
959 Some(having_expr)
960 } else {
961 None
962 };
963
964 let order_by = if matches!(self.current_token, Token::OrderBy) {
966 self.trace_token("Found OrderBy token");
967 self.advance();
968 Some(self.parse_order_by_list()?)
969 } else if let Token::Identifier(s) = &self.current_token {
970 if Self::is_identifier_reserved(s) && s.to_uppercase() == "ORDER" {
973 self.trace_token("Warning: ORDER as identifier instead of OrderBy token");
974 self.advance(); if matches!(&self.current_token, Token::By) {
976 self.advance(); Some(self.parse_order_by_list()?)
978 } else {
979 return Err("Expected BY after ORDER".to_string());
980 }
981 } else {
982 None
983 }
984 } else {
985 None
986 };
987
988 let limit = if matches!(self.current_token, Token::Limit) {
990 self.advance();
991 match &self.current_token {
992 Token::NumberLiteral(num) => {
993 let limit_val = num
994 .parse::<usize>()
995 .map_err(|_| format!("Invalid LIMIT value: {num}"))?;
996 self.advance();
997 Some(limit_val)
998 }
999 _ => return Err("Expected number after LIMIT".to_string()),
1000 }
1001 } else {
1002 None
1003 };
1004
1005 let offset = if matches!(self.current_token, Token::Offset) {
1007 self.advance();
1008 match &self.current_token {
1009 Token::NumberLiteral(num) => {
1010 let offset_val = num
1011 .parse::<usize>()
1012 .map_err(|_| format!("Invalid OFFSET value: {num}"))?;
1013 self.advance();
1014 Some(offset_val)
1015 }
1016 _ => return Err("Expected number after OFFSET".to_string()),
1017 }
1018 } else {
1019 None
1020 };
1021
1022 let into_table = if into_table.is_none() && matches!(self.current_token, Token::Into) {
1026 self.advance();
1027 Some(self.parse_into_clause()?)
1028 } else {
1029 into_table };
1031
1032 let set_operations = self.parse_set_operations()?;
1034
1035 let trailing_comment = if self.mode == ParserMode::PreserveComments {
1037 self.collect_trailing_comment()
1038 } else {
1039 None
1040 };
1041
1042 Ok(SelectStatement {
1043 distinct,
1044 columns,
1045 select_items,
1046 from_table,
1047 from_subquery,
1048 from_function,
1049 from_alias,
1050 joins,
1051 where_clause,
1052 order_by,
1053 group_by,
1054 having,
1055 limit,
1056 offset,
1057 ctes: Vec::new(), into_table,
1059 set_operations,
1060 leading_comments,
1061 trailing_comment,
1062 })
1063 }
1064
1065 fn parse_set_operations(
1068 &mut self,
1069 ) -> Result<Vec<(SetOperation, Box<SelectStatement>)>, String> {
1070 let mut operations = Vec::new();
1071
1072 while matches!(
1073 self.current_token,
1074 Token::Union | Token::Intersect | Token::Except
1075 ) {
1076 let operation = match &self.current_token {
1078 Token::Union => {
1079 self.advance();
1080 if let Token::Identifier(id) = &self.current_token {
1082 if id.to_uppercase() == "ALL" {
1083 self.advance();
1084 SetOperation::UnionAll
1085 } else {
1086 SetOperation::Union
1087 }
1088 } else {
1089 SetOperation::Union
1090 }
1091 }
1092 Token::Intersect => {
1093 self.advance();
1094 SetOperation::Intersect
1095 }
1096 Token::Except => {
1097 self.advance();
1098 SetOperation::Except
1099 }
1100 _ => unreachable!(),
1101 };
1102
1103 let next_select = self.parse_select_statement_inner()?;
1105
1106 operations.push((operation, Box::new(next_select)));
1107 }
1108
1109 Ok(operations)
1110 }
1111
1112 fn parse_select_items(&mut self) -> Result<Vec<SelectItem>, String> {
1114 let mut items = Vec::new();
1115
1116 loop {
1117 if let Token::Identifier(name) = &self.current_token.clone() {
1120 let saved_pos = self.lexer.clone();
1122 let saved_token = self.current_token.clone();
1123 let table_name = name.clone();
1124
1125 self.advance();
1126
1127 if matches!(self.current_token, Token::Dot) {
1128 self.advance();
1129 if matches!(self.current_token, Token::Star) {
1130 items.push(SelectItem::Star {
1132 table_prefix: Some(table_name),
1133 leading_comments: vec![],
1134 trailing_comment: None,
1135 });
1136 self.advance();
1137
1138 if matches!(self.current_token, Token::Comma) {
1140 self.advance();
1141 continue;
1142 } else {
1143 break;
1144 }
1145 }
1146 }
1147
1148 self.lexer = saved_pos;
1150 self.current_token = saved_token;
1151 }
1152
1153 if matches!(self.current_token, Token::Star) {
1155 items.push(SelectItem::Star {
1156 table_prefix: None,
1157 leading_comments: vec![],
1158 trailing_comment: None,
1159 });
1160 self.advance();
1161 } else {
1162 let expr = self.parse_comparison()?; let alias = if matches!(self.current_token, Token::As) {
1167 self.advance();
1168 match &self.current_token {
1169 Token::Identifier(alias_name) => {
1170 let alias = alias_name.clone();
1171 self.advance();
1172 alias
1173 }
1174 Token::QuotedIdentifier(alias_name) => {
1175 let alias = alias_name.clone();
1176 self.advance();
1177 alias
1178 }
1179 token => {
1180 if let Some(keyword) = token.as_keyword_str() {
1181 return Err(format!(
1182 "Reserved keyword '{}' cannot be used as column alias. Use a different name or quote it with double quotes: \"{}\"",
1183 keyword,
1184 keyword.to_lowercase()
1185 ));
1186 } else {
1187 return Err("Expected alias name after AS".to_string());
1188 }
1189 }
1190 }
1191 } else {
1192 match &expr {
1194 SqlExpression::Column(col_ref) => col_ref.name.clone(),
1195 _ => format!("expr_{}", items.len() + 1), }
1197 };
1198
1199 let item = match expr {
1201 SqlExpression::Column(col_ref) if alias == col_ref.name => {
1202 SelectItem::Column {
1204 column: col_ref,
1205 leading_comments: vec![],
1206 trailing_comment: None,
1207 }
1208 }
1209 _ => {
1210 SelectItem::Expression {
1212 expr,
1213 alias,
1214 leading_comments: vec![],
1215 trailing_comment: None,
1216 }
1217 }
1218 };
1219
1220 items.push(item);
1221 }
1222
1223 if matches!(self.current_token, Token::Comma) {
1225 self.advance();
1226 } else {
1227 break;
1228 }
1229 }
1230
1231 Ok(items)
1232 }
1233
1234 fn parse_identifier_list(&mut self) -> Result<Vec<String>, String> {
1235 let mut identifiers = Vec::new();
1236
1237 loop {
1238 match &self.current_token {
1239 Token::Identifier(id) => {
1240 if Self::is_identifier_reserved(id) {
1242 break;
1244 }
1245 identifiers.push(id.clone());
1246 self.advance();
1247 }
1248 Token::QuotedIdentifier(id) => {
1249 identifiers.push(id.clone());
1251 self.advance();
1252 }
1253 _ => {
1254 break;
1256 }
1257 }
1258
1259 if matches!(self.current_token, Token::Comma) {
1260 self.advance();
1261 } else {
1262 break;
1263 }
1264 }
1265
1266 if identifiers.is_empty() {
1267 return Err("Expected at least one identifier".to_string());
1268 }
1269
1270 Ok(identifiers)
1271 }
1272
1273 fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
1274 let mut partition_by = Vec::new();
1275 let mut order_by = Vec::new();
1276
1277 if matches!(self.current_token, Token::Partition) {
1279 self.advance(); if !matches!(self.current_token, Token::By) {
1281 return Err("Expected BY after PARTITION".to_string());
1282 }
1283 self.advance(); partition_by = self.parse_identifier_list()?;
1287 }
1288
1289 if matches!(self.current_token, Token::OrderBy) {
1291 self.advance(); order_by = self.parse_order_by_list()?;
1293 } else if let Token::Identifier(s) = &self.current_token {
1294 if Self::is_identifier_reserved(s) && s.to_uppercase() == "ORDER" {
1295 self.advance(); if !matches!(self.current_token, Token::By) {
1298 return Err("Expected BY after ORDER".to_string());
1299 }
1300 self.advance(); order_by = self.parse_order_by_list()?;
1302 }
1303 }
1304
1305 let frame = self.parse_window_frame()?;
1307
1308 Ok(WindowSpec {
1309 partition_by,
1310 order_by,
1311 frame,
1312 })
1313 }
1314
1315 fn parse_order_by_list(&mut self) -> Result<Vec<OrderByColumn>, String> {
1316 let mut order_columns = Vec::new();
1317
1318 loop {
1319 let column = match &self.current_token {
1320 Token::Identifier(id) => {
1321 let col = id.clone();
1322 self.advance();
1323
1324 if matches!(self.current_token, Token::Dot) {
1326 self.advance();
1327 match &self.current_token {
1328 Token::Identifier(col_name) => {
1329 let mut qualified = col;
1330 qualified.push('.');
1331 qualified.push_str(col_name);
1332 self.advance();
1333 qualified
1334 }
1335 _ => return Err("Expected column name after '.'".to_string()),
1336 }
1337 } else {
1338 col
1339 }
1340 }
1341 Token::QuotedIdentifier(id) => {
1342 let col = id.clone();
1343 self.advance();
1344 col
1345 }
1346 Token::NumberLiteral(num) if self.columns.iter().any(|col| col == num) => {
1347 let col = num.clone();
1349 self.advance();
1350 col
1351 }
1352 Token::Row => {
1354 self.advance();
1355 "row".to_string()
1356 }
1357 Token::Rows => {
1358 self.advance();
1359 "rows".to_string()
1360 }
1361 Token::Range => {
1362 self.advance();
1363 "range".to_string()
1364 }
1365 _ => return Err("Expected column name in ORDER BY".to_string()),
1366 };
1367
1368 let direction = match &self.current_token {
1370 Token::Asc => {
1371 self.advance();
1372 SortDirection::Asc
1373 }
1374 Token::Desc => {
1375 self.advance();
1376 SortDirection::Desc
1377 }
1378 _ => SortDirection::Asc, };
1380
1381 order_columns.push(OrderByColumn { column, direction });
1382
1383 if matches!(self.current_token, Token::Comma) {
1384 self.advance();
1385 } else {
1386 break;
1387 }
1388 }
1389
1390 Ok(order_columns)
1391 }
1392
1393 fn parse_into_clause(&mut self) -> Result<IntoTable, String> {
1396 let name = match &self.current_token {
1398 Token::Identifier(id) if id.starts_with('#') => {
1399 let table_name = id.clone();
1400 self.advance();
1401 table_name
1402 }
1403 Token::Identifier(id) => {
1404 return Err(format!(
1405 "Temporary table name must start with #, got: {}",
1406 id
1407 ));
1408 }
1409 _ => {
1410 return Err(
1411 "Expected temporary table name (starting with #) after INTO".to_string()
1412 );
1413 }
1414 };
1415
1416 Ok(IntoTable { name })
1417 }
1418
1419 fn parse_window_frame(&mut self) -> Result<Option<WindowFrame>, String> {
1420 let unit = match &self.current_token {
1422 Token::Rows => {
1423 self.advance();
1424 FrameUnit::Rows
1425 }
1426 Token::Identifier(id) if id.to_uppercase() == "RANGE" => {
1427 self.advance();
1429 FrameUnit::Range
1430 }
1431 _ => return Ok(None), };
1433
1434 let (start, end) = if let Token::Between = &self.current_token {
1436 self.advance(); let start = self.parse_frame_bound()?;
1439
1440 if !matches!(&self.current_token, Token::And) {
1442 return Err("Expected AND after window frame start bound".to_string());
1443 }
1444 self.advance();
1445
1446 let end = self.parse_frame_bound()?;
1448 (start, Some(end))
1449 } else {
1450 let bound = self.parse_frame_bound()?;
1452 (bound, None)
1453 };
1454
1455 Ok(Some(WindowFrame { unit, start, end }))
1456 }
1457
1458 fn parse_frame_bound(&mut self) -> Result<FrameBound, String> {
1459 match &self.current_token {
1460 Token::Unbounded => {
1461 self.advance();
1462 match &self.current_token {
1463 Token::Preceding => {
1464 self.advance();
1465 Ok(FrameBound::UnboundedPreceding)
1466 }
1467 Token::Following => {
1468 self.advance();
1469 Ok(FrameBound::UnboundedFollowing)
1470 }
1471 _ => Err("Expected PRECEDING or FOLLOWING after UNBOUNDED".to_string()),
1472 }
1473 }
1474 Token::Current => {
1475 self.advance();
1476 if matches!(&self.current_token, Token::Row) {
1477 self.advance();
1478 return Ok(FrameBound::CurrentRow);
1479 }
1480 Err("Expected ROW after CURRENT".to_string())
1481 }
1482 Token::NumberLiteral(num) => {
1483 let n: i64 = num
1484 .parse()
1485 .map_err(|_| "Invalid number in window frame".to_string())?;
1486 self.advance();
1487 match &self.current_token {
1488 Token::Preceding => {
1489 self.advance();
1490 Ok(FrameBound::Preceding(n))
1491 }
1492 Token::Following => {
1493 self.advance();
1494 Ok(FrameBound::Following(n))
1495 }
1496 _ => Err("Expected PRECEDING or FOLLOWING after number".to_string()),
1497 }
1498 }
1499 _ => Err("Invalid window frame bound".to_string()),
1500 }
1501 }
1502
1503 fn parse_where_clause(&mut self) -> Result<WhereClause, String> {
1504 let expr = self.parse_expression()?;
1507
1508 if matches!(self.current_token, Token::RightParen) && self.paren_depth <= 0 {
1510 return Err(
1511 "Unexpected closing parenthesis - no matching opening parenthesis".to_string(),
1512 );
1513 }
1514
1515 let conditions = vec![Condition {
1517 expr,
1518 connector: None,
1519 }];
1520
1521 Ok(WhereClause { conditions })
1522 }
1523
1524 fn parse_expression(&mut self) -> Result<SqlExpression, String> {
1525 self.trace_enter("parse_expression");
1526 let mut left = self.parse_logical_or()?;
1529
1530 left = parse_in_operator(self, left)?;
1533
1534 let result = Ok(left);
1535 self.trace_exit("parse_expression", &result);
1536 result
1537 }
1538
1539 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
1540 parse_comparison_expr(self)
1542 }
1543
1544 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
1545 parse_additive_expr(self)
1547 }
1548
1549 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
1550 parse_multiplicative_expr(self)
1552 }
1553
1554 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
1555 parse_logical_or_expr(self)
1557 }
1558
1559 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
1560 parse_logical_and_expr(self)
1562 }
1563
1564 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
1565 parse_case_expr(self)
1567 }
1568
1569 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
1570 let columns = self.columns.clone();
1573 let in_method_args = self.in_method_args;
1574 let ctx = PrimaryExpressionContext {
1575 columns: &columns,
1576 in_method_args,
1577 };
1578 parse_primary_expr(self, &ctx)
1579 }
1580
1581 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
1583 self.in_method_args = true;
1585
1586 let args = self.parse_argument_list()?;
1587
1588 self.in_method_args = false;
1590
1591 Ok(args)
1592 }
1593
1594 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
1595 let mut args = Vec::new();
1596 let mut has_distinct = false;
1597
1598 if !matches!(self.current_token, Token::RightParen) {
1599 if matches!(self.current_token, Token::Distinct) {
1601 self.advance(); has_distinct = true;
1603 }
1604
1605 args.push(self.parse_additive()?);
1607
1608 while matches!(self.current_token, Token::Comma) {
1610 self.advance();
1611 args.push(self.parse_additive()?);
1612 }
1613 }
1614
1615 Ok((args, has_distinct))
1616 }
1617
1618 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
1619 let mut expressions = Vec::new();
1620
1621 loop {
1622 expressions.push(self.parse_expression()?);
1623
1624 if matches!(self.current_token, Token::Comma) {
1625 self.advance();
1626 } else {
1627 break;
1628 }
1629 }
1630
1631 Ok(expressions)
1632 }
1633
1634 #[must_use]
1635 pub fn get_position(&self) -> usize {
1636 self.lexer.get_position()
1637 }
1638
1639 fn is_join_token(&self) -> bool {
1641 matches!(
1642 self.current_token,
1643 Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
1644 )
1645 }
1646
1647 fn parse_join_clause(&mut self) -> Result<JoinClause, String> {
1649 let join_type = match &self.current_token {
1651 Token::Join => {
1652 self.advance();
1653 JoinType::Inner }
1655 Token::Inner => {
1656 self.advance();
1657 if !matches!(self.current_token, Token::Join) {
1658 return Err("Expected JOIN after INNER".to_string());
1659 }
1660 self.advance();
1661 JoinType::Inner
1662 }
1663 Token::Left => {
1664 self.advance();
1665 if matches!(self.current_token, Token::Outer) {
1667 self.advance();
1668 }
1669 if !matches!(self.current_token, Token::Join) {
1670 return Err("Expected JOIN after LEFT".to_string());
1671 }
1672 self.advance();
1673 JoinType::Left
1674 }
1675 Token::Right => {
1676 self.advance();
1677 if matches!(self.current_token, Token::Outer) {
1679 self.advance();
1680 }
1681 if !matches!(self.current_token, Token::Join) {
1682 return Err("Expected JOIN after RIGHT".to_string());
1683 }
1684 self.advance();
1685 JoinType::Right
1686 }
1687 Token::Full => {
1688 self.advance();
1689 if matches!(self.current_token, Token::Outer) {
1691 self.advance();
1692 }
1693 if !matches!(self.current_token, Token::Join) {
1694 return Err("Expected JOIN after FULL".to_string());
1695 }
1696 self.advance();
1697 JoinType::Full
1698 }
1699 Token::Cross => {
1700 self.advance();
1701 if !matches!(self.current_token, Token::Join) {
1702 return Err("Expected JOIN after CROSS".to_string());
1703 }
1704 self.advance();
1705 JoinType::Cross
1706 }
1707 _ => return Err("Expected JOIN keyword".to_string()),
1708 };
1709
1710 let (table, alias) = self.parse_join_table_source()?;
1712
1713 let condition = if join_type == JoinType::Cross {
1715 JoinCondition { conditions: vec![] }
1717 } else {
1718 if !matches!(self.current_token, Token::On) {
1719 return Err("Expected ON keyword after JOIN table".to_string());
1720 }
1721 self.advance();
1722 self.parse_join_condition()?
1723 };
1724
1725 Ok(JoinClause {
1726 join_type,
1727 table,
1728 alias,
1729 condition,
1730 })
1731 }
1732
1733 fn parse_join_table_source(&mut self) -> Result<(TableSource, Option<String>), String> {
1734 let table = match &self.current_token {
1735 Token::Identifier(name) => {
1736 let table_name = name.clone();
1737 self.advance();
1738 TableSource::Table(table_name)
1739 }
1740 Token::LeftParen => {
1741 self.advance();
1743 let subquery = self.parse_select_statement_inner()?;
1744 if !matches!(self.current_token, Token::RightParen) {
1745 return Err("Expected ')' after subquery".to_string());
1746 }
1747 self.advance();
1748
1749 let alias = match &self.current_token {
1751 Token::Identifier(alias_name) => {
1752 let alias = alias_name.clone();
1753 self.advance();
1754 alias
1755 }
1756 Token::As => {
1757 self.advance();
1758 match &self.current_token {
1759 Token::Identifier(alias_name) => {
1760 let alias = alias_name.clone();
1761 self.advance();
1762 alias
1763 }
1764 _ => return Err("Expected alias after AS keyword".to_string()),
1765 }
1766 }
1767 _ => return Err("Subqueries must have an alias".to_string()),
1768 };
1769
1770 return Ok((
1771 TableSource::DerivedTable {
1772 query: Box::new(subquery),
1773 alias: alias.clone(),
1774 },
1775 Some(alias),
1776 ));
1777 }
1778 _ => return Err("Expected table name or subquery in JOIN clause".to_string()),
1779 };
1780
1781 let alias = match &self.current_token {
1783 Token::Identifier(alias_name) => {
1784 let alias = alias_name.clone();
1785 self.advance();
1786 Some(alias)
1787 }
1788 Token::As => {
1789 self.advance();
1790 match &self.current_token {
1791 Token::Identifier(alias_name) => {
1792 let alias = alias_name.clone();
1793 self.advance();
1794 Some(alias)
1795 }
1796 _ => return Err("Expected alias after AS keyword".to_string()),
1797 }
1798 }
1799 _ => None,
1800 };
1801
1802 Ok((table, alias))
1803 }
1804
1805 fn parse_join_condition(&mut self) -> Result<JoinCondition, String> {
1806 let mut conditions = Vec::new();
1807
1808 conditions.push(self.parse_single_join_condition()?);
1810
1811 while matches!(self.current_token, Token::And) {
1813 self.advance(); conditions.push(self.parse_single_join_condition()?);
1815 }
1816
1817 Ok(JoinCondition { conditions })
1818 }
1819
1820 fn parse_single_join_condition(&mut self) -> Result<SingleJoinCondition, String> {
1821 let left_expr = self.parse_additive()?;
1824
1825 let operator = match &self.current_token {
1827 Token::Equal => JoinOperator::Equal,
1828 Token::NotEqual => JoinOperator::NotEqual,
1829 Token::LessThan => JoinOperator::LessThan,
1830 Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
1831 Token::GreaterThan => JoinOperator::GreaterThan,
1832 Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
1833 _ => return Err("Expected comparison operator in JOIN condition".to_string()),
1834 };
1835 self.advance();
1836
1837 let right_expr = self.parse_additive()?;
1839
1840 Ok(SingleJoinCondition {
1841 left_expr,
1842 operator,
1843 right_expr,
1844 })
1845 }
1846
1847 fn parse_column_reference(&mut self) -> Result<String, String> {
1848 match &self.current_token {
1849 Token::Identifier(name) => {
1850 let mut column_ref = name.clone();
1851 self.advance();
1852
1853 if matches!(self.current_token, Token::Dot) {
1855 self.advance();
1856 match &self.current_token {
1857 Token::Identifier(col_name) => {
1858 column_ref.push('.');
1859 column_ref.push_str(col_name);
1860 self.advance();
1861 }
1862 _ => return Err("Expected column name after '.'".to_string()),
1863 }
1864 }
1865
1866 Ok(column_ref)
1867 }
1868 _ => Err("Expected column reference".to_string()),
1869 }
1870 }
1871}
1872
1873#[derive(Debug, Clone)]
1875pub enum CursorContext {
1876 SelectClause,
1877 FromClause,
1878 WhereClause,
1879 OrderByClause,
1880 AfterColumn(String),
1881 AfterLogicalOp(LogicalOp),
1882 AfterComparisonOp(String, String), InMethodCall(String, String), InExpression,
1885 Unknown,
1886}
1887
1888fn safe_slice_to(s: &str, pos: usize) -> &str {
1890 if pos >= s.len() {
1891 return s;
1892 }
1893
1894 let mut safe_pos = pos;
1896 while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
1897 safe_pos -= 1;
1898 }
1899
1900 &s[..safe_pos]
1901}
1902
1903fn safe_slice_from(s: &str, pos: usize) -> &str {
1905 if pos >= s.len() {
1906 return "";
1907 }
1908
1909 let mut safe_pos = pos;
1911 while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
1912 safe_pos += 1;
1913 }
1914
1915 &s[safe_pos..]
1916}
1917
1918#[must_use]
1919pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1920 let truncated = safe_slice_to(query, cursor_pos);
1921 let mut parser = Parser::new(truncated);
1922
1923 if let Ok(stmt) = parser.parse() {
1925 let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
1926 #[cfg(test)]
1927 println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1928 (ctx, partial)
1929 } else {
1930 let (ctx, partial) = analyze_partial(truncated, cursor_pos);
1932 #[cfg(test)]
1933 println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1934 (ctx, partial)
1935 }
1936}
1937
1938#[must_use]
1939pub fn tokenize_query(query: &str) -> Vec<String> {
1940 let mut lexer = Lexer::new(query);
1941 let tokens = lexer.tokenize_all();
1942 tokens.iter().map(|t| format!("{t:?}")).collect()
1943}
1944
1945#[must_use]
1946fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
1948 if pos > 0 {
1950 pos -= 1;
1951 while pos > 0 {
1952 if bytes[pos] == b'"' {
1953 if pos == 0 || bytes[pos - 1] != b'\\' {
1955 return Some(pos);
1956 }
1957 }
1958 pos -= 1;
1959 }
1960 if bytes[0] == b'"' {
1962 return Some(0);
1963 }
1964 }
1965 None
1966}
1967
1968fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
1970 let partial_method = if after_dot.is_empty() {
1972 None
1973 } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1974 Some(after_dot.to_string())
1975 } else {
1976 None
1977 };
1978
1979 let col_name_for_context =
1981 if col_name.starts_with('"') && col_name.ends_with('"') && col_name.len() > 2 {
1982 col_name[1..col_name.len() - 1].to_string()
1983 } else {
1984 col_name.to_string()
1985 };
1986
1987 (
1988 CursorContext::AfterColumn(col_name_for_context),
1989 partial_method,
1990 )
1991}
1992
1993fn check_after_comparison_operator(query: &str) -> Option<(CursorContext, Option<String>)> {
1995 for op in &Parser::COMPARISON_OPERATORS {
1996 if let Some(op_pos) = query.rfind(op) {
1997 let before_op = safe_slice_to(query, op_pos);
1998 let after_op_start = op_pos + op.len();
1999 let after_op = if after_op_start < query.len() {
2000 &query[after_op_start..]
2001 } else {
2002 ""
2003 };
2004
2005 if let Some(col_name) = before_op.split_whitespace().last() {
2007 if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2008 let after_op_trimmed = after_op.trim();
2010 if after_op_trimmed.is_empty()
2011 || (after_op_trimmed
2012 .chars()
2013 .all(|c| c.is_alphanumeric() || c == '_')
2014 && !after_op_trimmed.contains('('))
2015 {
2016 let partial = if after_op_trimmed.is_empty() {
2017 None
2018 } else {
2019 Some(after_op_trimmed.to_string())
2020 };
2021 return Some((
2022 CursorContext::AfterComparisonOp(
2023 col_name.to_string(),
2024 op.trim().to_string(),
2025 ),
2026 partial,
2027 ));
2028 }
2029 }
2030 }
2031 }
2032 }
2033 None
2034}
2035
2036fn analyze_statement(
2037 stmt: &SelectStatement,
2038 query: &str,
2039 _cursor_pos: usize,
2040) -> (CursorContext, Option<String>) {
2041 let trimmed = query.trim();
2043
2044 if let Some(result) = check_after_comparison_operator(query) {
2046 return result;
2047 }
2048
2049 let ends_with_logical_op = |s: &str| -> bool {
2052 let s_upper = s.to_uppercase();
2053 s_upper.ends_with(" AND") || s_upper.ends_with(" OR")
2054 };
2055
2056 if ends_with_logical_op(trimmed) {
2057 } else {
2059 if let Some(dot_pos) = trimmed.rfind('.') {
2061 let before_dot = safe_slice_to(trimmed, dot_pos);
2063 let after_dot_start = dot_pos + 1;
2064 let after_dot = if after_dot_start < trimmed.len() {
2065 &trimmed[after_dot_start..]
2066 } else {
2067 ""
2068 };
2069
2070 if !after_dot.contains('(') {
2073 let col_name = if before_dot.ends_with('"') {
2075 let bytes = before_dot.as_bytes();
2077 let pos = before_dot.len() - 1; find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2080 } else {
2081 before_dot
2084 .split_whitespace()
2085 .last()
2086 .map(|word| word.trim_start_matches('('))
2087 };
2088
2089 if let Some(col_name) = col_name {
2090 let is_valid = Parser::is_valid_identifier(col_name);
2092
2093 if is_valid {
2094 return handle_method_call_context(col_name, after_dot);
2095 }
2096 }
2097 }
2098 }
2099 }
2100
2101 if let Some(where_clause) = &stmt.where_clause {
2103 let trimmed_upper = trimmed.to_uppercase();
2105 if trimmed_upper.ends_with(" AND") || trimmed_upper.ends_with(" OR") {
2106 let op = if trimmed_upper.ends_with(" AND") {
2107 LogicalOp::And
2108 } else {
2109 LogicalOp::Or
2110 };
2111 return (CursorContext::AfterLogicalOp(op), None);
2112 }
2113
2114 let query_upper = query.to_uppercase();
2116 if let Some(and_pos) = query_upper.rfind(" AND ") {
2117 let after_and = safe_slice_from(query, and_pos + 5);
2118 let partial = extract_partial_at_end(after_and);
2119 if partial.is_some() {
2120 return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
2121 }
2122 }
2123
2124 if let Some(or_pos) = query_upper.rfind(" OR ") {
2125 let after_or = safe_slice_from(query, or_pos + 4);
2126 let partial = extract_partial_at_end(after_or);
2127 if partial.is_some() {
2128 return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
2129 }
2130 }
2131
2132 if let Some(last_condition) = where_clause.conditions.last() {
2133 if let Some(connector) = &last_condition.connector {
2134 return (
2136 CursorContext::AfterLogicalOp(connector.clone()),
2137 extract_partial_at_end(query),
2138 );
2139 }
2140 }
2141 return (CursorContext::WhereClause, extract_partial_at_end(query));
2143 }
2144
2145 let query_upper = query.to_uppercase();
2147 if query_upper.ends_with(" ORDER BY") {
2148 return (CursorContext::OrderByClause, None);
2149 }
2150
2151 if stmt.order_by.is_some() {
2153 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2154 }
2155
2156 if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
2157 return (CursorContext::FromClause, extract_partial_at_end(query));
2158 }
2159
2160 if !stmt.columns.is_empty() && stmt.from_table.is_none() {
2161 return (CursorContext::SelectClause, extract_partial_at_end(query));
2162 }
2163
2164 (CursorContext::Unknown, None)
2165}
2166
2167fn find_last_token(tokens: &[(usize, usize, Token)], target: &Token) -> Option<usize> {
2169 tokens
2170 .iter()
2171 .rposition(|(_, _, t)| t == target)
2172 .map(|idx| tokens[idx].0)
2173}
2174
2175fn find_last_matching_token<F>(
2177 tokens: &[(usize, usize, Token)],
2178 predicate: F,
2179) -> Option<(usize, &Token)>
2180where
2181 F: Fn(&Token) -> bool,
2182{
2183 tokens
2184 .iter()
2185 .rposition(|(_, _, t)| predicate(t))
2186 .map(|idx| (tokens[idx].0, &tokens[idx].2))
2187}
2188
2189fn is_in_clause(
2191 tokens: &[(usize, usize, Token)],
2192 clause_token: Token,
2193 exclude_tokens: &[Token],
2194) -> bool {
2195 if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2197 for (pos, _, token) in tokens.iter() {
2199 if *pos > clause_pos && exclude_tokens.contains(token) {
2200 return false;
2201 }
2202 }
2203 return true;
2204 }
2205 false
2206}
2207
2208fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2209 let mut lexer = Lexer::new(query);
2211 let tokens = lexer.tokenize_all_with_positions();
2212
2213 let trimmed = query.trim();
2214
2215 #[cfg(test)]
2216 {
2217 if trimmed.contains("\"Last Name\"") {
2218 eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
2219 }
2220 }
2221
2222 if let Some(result) = check_after_comparison_operator(query) {
2224 return result;
2225 }
2226
2227 if let Some(dot_pos) = trimmed.rfind('.') {
2230 #[cfg(test)]
2231 {
2232 if trimmed.contains("\"Last Name\"") {
2233 eprintln!("DEBUG: Found dot at position {dot_pos}");
2234 }
2235 }
2236 let before_dot = &trimmed[..dot_pos];
2238 let after_dot = &trimmed[dot_pos + 1..];
2239
2240 if !after_dot.contains('(') {
2243 let col_name = if before_dot.ends_with('"') {
2246 let bytes = before_dot.as_bytes();
2248 let pos = before_dot.len() - 1; #[cfg(test)]
2251 {
2252 if trimmed.contains("\"Last Name\"") {
2253 eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
2254 }
2255 }
2256
2257 let found_start = find_quote_start(bytes, pos);
2258
2259 if let Some(start) = found_start {
2260 let result = safe_slice_from(before_dot, start);
2262 #[cfg(test)]
2263 {
2264 if trimmed.contains("\"Last Name\"") {
2265 eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
2266 }
2267 }
2268 Some(result)
2269 } else {
2270 #[cfg(test)]
2271 {
2272 if trimmed.contains("\"Last Name\"") {
2273 eprintln!("DEBUG: No opening quote found!");
2274 }
2275 }
2276 None
2277 }
2278 } else {
2279 before_dot
2282 .split_whitespace()
2283 .last()
2284 .map(|word| word.trim_start_matches('('))
2285 };
2286
2287 if let Some(col_name) = col_name {
2288 #[cfg(test)]
2289 {
2290 if trimmed.contains("\"Last Name\"") {
2291 eprintln!("DEBUG: col_name = '{col_name}'");
2292 }
2293 }
2294
2295 let is_valid = Parser::is_valid_identifier(col_name);
2297
2298 #[cfg(test)]
2299 {
2300 if trimmed.contains("\"Last Name\"") {
2301 eprintln!("DEBUG: is_valid = {is_valid}");
2302 }
2303 }
2304
2305 if is_valid {
2306 return handle_method_call_context(col_name, after_dot);
2307 }
2308 }
2309 }
2310 }
2311
2312 if let Some((pos, token)) =
2314 find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2315 {
2316 let token_end_pos = if matches!(token, Token::And) {
2318 pos + 3 } else {
2320 pos + 2 };
2322
2323 if cursor_pos > token_end_pos {
2324 let after_op = safe_slice_from(query, token_end_pos + 1); let partial = extract_partial_at_end(after_op);
2327 let op = if matches!(token, Token::And) {
2328 LogicalOp::And
2329 } else {
2330 LogicalOp::Or
2331 };
2332 return (CursorContext::AfterLogicalOp(op), partial);
2333 }
2334 }
2335
2336 if let Some((_, _, last_token)) = tokens.last() {
2338 if matches!(last_token, Token::And | Token::Or) {
2339 let op = if matches!(last_token, Token::And) {
2340 LogicalOp::And
2341 } else {
2342 LogicalOp::Or
2343 };
2344 return (CursorContext::AfterLogicalOp(op), None);
2345 }
2346 }
2347
2348 if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2350 let has_by = tokens
2352 .iter()
2353 .any(|(pos, _, t)| *pos > order_pos && matches!(t, Token::By));
2354 if has_by
2355 || tokens
2356 .last()
2357 .map_or(false, |(_, _, t)| matches!(t, Token::OrderBy))
2358 {
2359 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2360 }
2361 }
2362
2363 if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2365 return (CursorContext::WhereClause, extract_partial_at_end(query));
2366 }
2367
2368 if is_in_clause(
2370 &tokens,
2371 Token::From,
2372 &[Token::Where, Token::OrderBy, Token::GroupBy],
2373 ) {
2374 return (CursorContext::FromClause, extract_partial_at_end(query));
2375 }
2376
2377 if find_last_token(&tokens, &Token::Select).is_some()
2379 && find_last_token(&tokens, &Token::From).is_none()
2380 {
2381 return (CursorContext::SelectClause, extract_partial_at_end(query));
2382 }
2383
2384 (CursorContext::Unknown, None)
2385}
2386
2387fn extract_partial_at_end(query: &str) -> Option<String> {
2388 let trimmed = query.trim();
2389
2390 if let Some(last_word) = trimmed.split_whitespace().last() {
2392 if last_word.starts_with('"') && !last_word.ends_with('"') {
2393 return Some(last_word.to_string());
2395 }
2396 }
2397
2398 let last_word = trimmed.split_whitespace().last()?;
2400
2401 if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2404 if !is_sql_keyword(last_word) {
2406 Some(last_word.to_string())
2407 } else {
2408 None
2409 }
2410 } else {
2411 None
2412 }
2413}
2414
2415impl ParsePrimary for Parser {
2417 fn current_token(&self) -> &Token {
2418 &self.current_token
2419 }
2420
2421 fn advance(&mut self) {
2422 self.advance();
2423 }
2424
2425 fn consume(&mut self, expected: Token) -> Result<(), String> {
2426 self.consume(expected)
2427 }
2428
2429 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2430 self.parse_case_expression()
2431 }
2432
2433 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2434 self.parse_function_args()
2435 }
2436
2437 fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2438 self.parse_window_spec()
2439 }
2440
2441 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2442 self.parse_logical_or()
2443 }
2444
2445 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2446 self.parse_comparison()
2447 }
2448
2449 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2450 self.parse_expression_list()
2451 }
2452
2453 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2454 if matches!(self.current_token, Token::With) {
2456 self.parse_with_clause_inner()
2457 } else {
2458 self.parse_select_statement_inner()
2459 }
2460 }
2461}
2462
2463impl ExpressionParser for Parser {
2465 fn current_token(&self) -> &Token {
2466 &self.current_token
2467 }
2468
2469 fn advance(&mut self) {
2470 match &self.current_token {
2472 Token::LeftParen => self.paren_depth += 1,
2473 Token::RightParen => {
2474 self.paren_depth -= 1;
2475 }
2476 _ => {}
2477 }
2478 self.current_token = self.lexer.next_token();
2479 }
2480
2481 fn peek(&self) -> Option<&Token> {
2482 None }
2489
2490 fn is_at_end(&self) -> bool {
2491 matches!(self.current_token, Token::Eof)
2492 }
2493
2494 fn consume(&mut self, expected: Token) -> Result<(), String> {
2495 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
2497 self.update_paren_depth(&expected)?;
2498 self.current_token = self.lexer.next_token();
2499 Ok(())
2500 } else {
2501 Err(format!(
2502 "Expected {:?}, found {:?}",
2503 expected, self.current_token
2504 ))
2505 }
2506 }
2507
2508 fn parse_identifier(&mut self) -> Result<String, String> {
2509 if let Token::Identifier(id) = &self.current_token {
2510 let id = id.clone();
2511 self.advance();
2512 Ok(id)
2513 } else {
2514 Err(format!(
2515 "Expected identifier, found {:?}",
2516 self.current_token
2517 ))
2518 }
2519 }
2520}
2521
2522impl ParseArithmetic for Parser {
2524 fn current_token(&self) -> &Token {
2525 &self.current_token
2526 }
2527
2528 fn advance(&mut self) {
2529 self.advance();
2530 }
2531
2532 fn consume(&mut self, expected: Token) -> Result<(), String> {
2533 self.consume(expected)
2534 }
2535
2536 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2537 self.parse_primary()
2538 }
2539
2540 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2541 self.parse_multiplicative()
2542 }
2543
2544 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2545 self.parse_method_args()
2546 }
2547}
2548
2549impl ParseComparison for Parser {
2551 fn current_token(&self) -> &Token {
2552 &self.current_token
2553 }
2554
2555 fn advance(&mut self) {
2556 self.advance();
2557 }
2558
2559 fn consume(&mut self, expected: Token) -> Result<(), String> {
2560 self.consume(expected)
2561 }
2562
2563 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2564 self.parse_primary()
2565 }
2566
2567 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2568 self.parse_additive()
2569 }
2570
2571 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2572 self.parse_expression_list()
2573 }
2574
2575 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2576 if matches!(self.current_token, Token::With) {
2578 self.parse_with_clause_inner()
2579 } else {
2580 self.parse_select_statement_inner()
2581 }
2582 }
2583}
2584
2585impl ParseLogical for Parser {
2587 fn current_token(&self) -> &Token {
2588 &self.current_token
2589 }
2590
2591 fn advance(&mut self) {
2592 self.advance();
2593 }
2594
2595 fn consume(&mut self, expected: Token) -> Result<(), String> {
2596 self.consume(expected)
2597 }
2598
2599 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2600 self.parse_logical_and()
2601 }
2602
2603 fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2604 self.parse_comparison()
2607 }
2608
2609 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2610 self.parse_comparison()
2611 }
2612
2613 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2614 self.parse_expression_list()
2615 }
2616}
2617
2618impl ParseCase for Parser {
2620 fn current_token(&self) -> &Token {
2621 &self.current_token
2622 }
2623
2624 fn advance(&mut self) {
2625 self.advance();
2626 }
2627
2628 fn consume(&mut self, expected: Token) -> Result<(), String> {
2629 self.consume(expected)
2630 }
2631
2632 fn parse_expression(&mut self) -> Result<SqlExpression, String> {
2633 self.parse_expression()
2634 }
2635}
2636
2637fn is_sql_keyword(word: &str) -> bool {
2638 let mut lexer = Lexer::new(word);
2640 let token = lexer.next_token();
2641
2642 !matches!(token, Token::Identifier(_) | Token::Eof)
2644}
2645
2646#[cfg(test)]
2647mod tests {
2648 use super::*;
2649
2650 #[test]
2652 fn test_parser_mode_default_is_standard() {
2653 let sql = "-- Leading comment\nSELECT * FROM users";
2654 let mut parser = Parser::new(sql);
2655 let stmt = parser.parse().unwrap();
2656
2657 assert!(stmt.leading_comments.is_empty());
2659 assert!(stmt.trailing_comment.is_none());
2660 }
2661
2662 #[test]
2664 fn test_parser_mode_preserve_leading_comments() {
2665 let sql = "-- Important query\n-- Author: Alice\nSELECT id, name FROM users";
2666 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2667 let stmt = parser.parse().unwrap();
2668
2669 assert_eq!(stmt.leading_comments.len(), 2);
2671 assert!(stmt.leading_comments[0].is_line_comment);
2672 assert!(stmt.leading_comments[0].text.contains("Important query"));
2673 assert!(stmt.leading_comments[1].text.contains("Author: Alice"));
2674 }
2675
2676 #[test]
2678 fn test_parser_mode_preserve_trailing_comment() {
2679 let sql = "SELECT * FROM users -- Fetch all users";
2680 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2681 let stmt = parser.parse().unwrap();
2682
2683 assert!(stmt.trailing_comment.is_some());
2685 let comment = stmt.trailing_comment.unwrap();
2686 assert!(comment.is_line_comment);
2687 assert!(comment.text.contains("Fetch all users"));
2688 }
2689
2690 #[test]
2692 fn test_parser_mode_preserve_block_comments() {
2693 let sql = "/* Query explanation */\nSELECT * FROM users";
2694 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2695 let stmt = parser.parse().unwrap();
2696
2697 assert_eq!(stmt.leading_comments.len(), 1);
2699 assert!(!stmt.leading_comments[0].is_line_comment); assert!(stmt.leading_comments[0].text.contains("Query explanation"));
2701 }
2702
2703 #[test]
2705 fn test_parser_mode_preserve_both_comments() {
2706 let sql = "-- Leading\nSELECT * FROM users -- Trailing";
2707 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2708 let stmt = parser.parse().unwrap();
2709
2710 assert_eq!(stmt.leading_comments.len(), 1);
2712 assert!(stmt.leading_comments[0].text.contains("Leading"));
2713 assert!(stmt.trailing_comment.is_some());
2714 assert!(stmt.trailing_comment.unwrap().text.contains("Trailing"));
2715 }
2716
2717 #[test]
2719 fn test_parser_mode_standard_ignores_comments() {
2720 let sql = "-- Comment 1\n/* Comment 2 */\nSELECT * FROM users -- Comment 3";
2721 let mut parser = Parser::with_mode(sql, ParserMode::Standard);
2722 let stmt = parser.parse().unwrap();
2723
2724 assert!(stmt.leading_comments.is_empty());
2726 assert!(stmt.trailing_comment.is_none());
2727
2728 assert_eq!(stmt.select_items.len(), 1);
2730 assert_eq!(stmt.from_table, Some("users".to_string()));
2731 }
2732
2733 #[test]
2735 fn test_parser_backward_compatibility() {
2736 let sql = "SELECT id, name FROM users WHERE active = true";
2737
2738 let mut parser1 = Parser::new(sql);
2740 let stmt1 = parser1.parse().unwrap();
2741
2742 let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
2744 let stmt2 = parser2.parse().unwrap();
2745
2746 assert_eq!(stmt1.select_items.len(), stmt2.select_items.len());
2748 assert_eq!(stmt1.from_table, stmt2.from_table);
2749 assert_eq!(stmt1.where_clause.is_some(), stmt2.where_clause.is_some());
2750 assert!(stmt1.leading_comments.is_empty());
2751 assert!(stmt2.leading_comments.is_empty());
2752 }
2753}