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_column = self.parse_column_reference()?;
1823
1824 let operator = match &self.current_token {
1826 Token::Equal => JoinOperator::Equal,
1827 Token::NotEqual => JoinOperator::NotEqual,
1828 Token::LessThan => JoinOperator::LessThan,
1829 Token::LessThanOrEqual => JoinOperator::LessThanOrEqual,
1830 Token::GreaterThan => JoinOperator::GreaterThan,
1831 Token::GreaterThanOrEqual => JoinOperator::GreaterThanOrEqual,
1832 _ => return Err("Expected comparison operator in JOIN condition".to_string()),
1833 };
1834 self.advance();
1835
1836 let right_expr = self.parse_expression()?;
1838
1839 Ok(SingleJoinCondition {
1840 left_column,
1841 operator,
1842 right_expr,
1843 })
1844 }
1845
1846 fn parse_column_reference(&mut self) -> Result<String, String> {
1847 match &self.current_token {
1848 Token::Identifier(name) => {
1849 let mut column_ref = name.clone();
1850 self.advance();
1851
1852 if matches!(self.current_token, Token::Dot) {
1854 self.advance();
1855 match &self.current_token {
1856 Token::Identifier(col_name) => {
1857 column_ref.push('.');
1858 column_ref.push_str(col_name);
1859 self.advance();
1860 }
1861 _ => return Err("Expected column name after '.'".to_string()),
1862 }
1863 }
1864
1865 Ok(column_ref)
1866 }
1867 _ => Err("Expected column reference".to_string()),
1868 }
1869 }
1870}
1871
1872#[derive(Debug, Clone)]
1874pub enum CursorContext {
1875 SelectClause,
1876 FromClause,
1877 WhereClause,
1878 OrderByClause,
1879 AfterColumn(String),
1880 AfterLogicalOp(LogicalOp),
1881 AfterComparisonOp(String, String), InMethodCall(String, String), InExpression,
1884 Unknown,
1885}
1886
1887fn safe_slice_to(s: &str, pos: usize) -> &str {
1889 if pos >= s.len() {
1890 return s;
1891 }
1892
1893 let mut safe_pos = pos;
1895 while safe_pos > 0 && !s.is_char_boundary(safe_pos) {
1896 safe_pos -= 1;
1897 }
1898
1899 &s[..safe_pos]
1900}
1901
1902fn safe_slice_from(s: &str, pos: usize) -> &str {
1904 if pos >= s.len() {
1905 return "";
1906 }
1907
1908 let mut safe_pos = pos;
1910 while safe_pos < s.len() && !s.is_char_boundary(safe_pos) {
1911 safe_pos += 1;
1912 }
1913
1914 &s[safe_pos..]
1915}
1916
1917#[must_use]
1918pub fn detect_cursor_context(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
1919 let truncated = safe_slice_to(query, cursor_pos);
1920 let mut parser = Parser::new(truncated);
1921
1922 if let Ok(stmt) = parser.parse() {
1924 let (ctx, partial) = analyze_statement(&stmt, truncated, cursor_pos);
1925 #[cfg(test)]
1926 println!("analyze_statement returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1927 (ctx, partial)
1928 } else {
1929 let (ctx, partial) = analyze_partial(truncated, cursor_pos);
1931 #[cfg(test)]
1932 println!("analyze_partial returned: {ctx:?}, {partial:?} for query: '{truncated}'");
1933 (ctx, partial)
1934 }
1935}
1936
1937#[must_use]
1938pub fn tokenize_query(query: &str) -> Vec<String> {
1939 let mut lexer = Lexer::new(query);
1940 let tokens = lexer.tokenize_all();
1941 tokens.iter().map(|t| format!("{t:?}")).collect()
1942}
1943
1944#[must_use]
1945fn find_quote_start(bytes: &[u8], mut pos: usize) -> Option<usize> {
1947 if pos > 0 {
1949 pos -= 1;
1950 while pos > 0 {
1951 if bytes[pos] == b'"' {
1952 if pos == 0 || bytes[pos - 1] != b'\\' {
1954 return Some(pos);
1955 }
1956 }
1957 pos -= 1;
1958 }
1959 if bytes[0] == b'"' {
1961 return Some(0);
1962 }
1963 }
1964 None
1965}
1966
1967fn handle_method_call_context(col_name: &str, after_dot: &str) -> (CursorContext, Option<String>) {
1969 let partial_method = if after_dot.is_empty() {
1971 None
1972 } else if after_dot.chars().all(|c| c.is_alphanumeric() || c == '_') {
1973 Some(after_dot.to_string())
1974 } else {
1975 None
1976 };
1977
1978 let col_name_for_context =
1980 if col_name.starts_with('"') && col_name.ends_with('"') && col_name.len() > 2 {
1981 col_name[1..col_name.len() - 1].to_string()
1982 } else {
1983 col_name.to_string()
1984 };
1985
1986 (
1987 CursorContext::AfterColumn(col_name_for_context),
1988 partial_method,
1989 )
1990}
1991
1992fn check_after_comparison_operator(query: &str) -> Option<(CursorContext, Option<String>)> {
1994 for op in &Parser::COMPARISON_OPERATORS {
1995 if let Some(op_pos) = query.rfind(op) {
1996 let before_op = safe_slice_to(query, op_pos);
1997 let after_op_start = op_pos + op.len();
1998 let after_op = if after_op_start < query.len() {
1999 &query[after_op_start..]
2000 } else {
2001 ""
2002 };
2003
2004 if let Some(col_name) = before_op.split_whitespace().last() {
2006 if col_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
2007 let after_op_trimmed = after_op.trim();
2009 if after_op_trimmed.is_empty()
2010 || (after_op_trimmed
2011 .chars()
2012 .all(|c| c.is_alphanumeric() || c == '_')
2013 && !after_op_trimmed.contains('('))
2014 {
2015 let partial = if after_op_trimmed.is_empty() {
2016 None
2017 } else {
2018 Some(after_op_trimmed.to_string())
2019 };
2020 return Some((
2021 CursorContext::AfterComparisonOp(
2022 col_name.to_string(),
2023 op.trim().to_string(),
2024 ),
2025 partial,
2026 ));
2027 }
2028 }
2029 }
2030 }
2031 }
2032 None
2033}
2034
2035fn analyze_statement(
2036 stmt: &SelectStatement,
2037 query: &str,
2038 _cursor_pos: usize,
2039) -> (CursorContext, Option<String>) {
2040 let trimmed = query.trim();
2042
2043 if let Some(result) = check_after_comparison_operator(query) {
2045 return result;
2046 }
2047
2048 let ends_with_logical_op = |s: &str| -> bool {
2051 let s_upper = s.to_uppercase();
2052 s_upper.ends_with(" AND") || s_upper.ends_with(" OR")
2053 };
2054
2055 if ends_with_logical_op(trimmed) {
2056 } else {
2058 if let Some(dot_pos) = trimmed.rfind('.') {
2060 let before_dot = safe_slice_to(trimmed, dot_pos);
2062 let after_dot_start = dot_pos + 1;
2063 let after_dot = if after_dot_start < trimmed.len() {
2064 &trimmed[after_dot_start..]
2065 } else {
2066 ""
2067 };
2068
2069 if !after_dot.contains('(') {
2072 let col_name = if before_dot.ends_with('"') {
2074 let bytes = before_dot.as_bytes();
2076 let pos = before_dot.len() - 1; find_quote_start(bytes, pos).map(|start| safe_slice_from(before_dot, start))
2079 } else {
2080 before_dot
2083 .split_whitespace()
2084 .last()
2085 .map(|word| word.trim_start_matches('('))
2086 };
2087
2088 if let Some(col_name) = col_name {
2089 let is_valid = Parser::is_valid_identifier(col_name);
2091
2092 if is_valid {
2093 return handle_method_call_context(col_name, after_dot);
2094 }
2095 }
2096 }
2097 }
2098 }
2099
2100 if let Some(where_clause) = &stmt.where_clause {
2102 let trimmed_upper = trimmed.to_uppercase();
2104 if trimmed_upper.ends_with(" AND") || trimmed_upper.ends_with(" OR") {
2105 let op = if trimmed_upper.ends_with(" AND") {
2106 LogicalOp::And
2107 } else {
2108 LogicalOp::Or
2109 };
2110 return (CursorContext::AfterLogicalOp(op), None);
2111 }
2112
2113 let query_upper = query.to_uppercase();
2115 if let Some(and_pos) = query_upper.rfind(" AND ") {
2116 let after_and = safe_slice_from(query, and_pos + 5);
2117 let partial = extract_partial_at_end(after_and);
2118 if partial.is_some() {
2119 return (CursorContext::AfterLogicalOp(LogicalOp::And), partial);
2120 }
2121 }
2122
2123 if let Some(or_pos) = query_upper.rfind(" OR ") {
2124 let after_or = safe_slice_from(query, or_pos + 4);
2125 let partial = extract_partial_at_end(after_or);
2126 if partial.is_some() {
2127 return (CursorContext::AfterLogicalOp(LogicalOp::Or), partial);
2128 }
2129 }
2130
2131 if let Some(last_condition) = where_clause.conditions.last() {
2132 if let Some(connector) = &last_condition.connector {
2133 return (
2135 CursorContext::AfterLogicalOp(connector.clone()),
2136 extract_partial_at_end(query),
2137 );
2138 }
2139 }
2140 return (CursorContext::WhereClause, extract_partial_at_end(query));
2142 }
2143
2144 let query_upper = query.to_uppercase();
2146 if query_upper.ends_with(" ORDER BY") {
2147 return (CursorContext::OrderByClause, None);
2148 }
2149
2150 if stmt.order_by.is_some() {
2152 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2153 }
2154
2155 if stmt.from_table.is_some() && stmt.where_clause.is_none() && stmt.order_by.is_none() {
2156 return (CursorContext::FromClause, extract_partial_at_end(query));
2157 }
2158
2159 if !stmt.columns.is_empty() && stmt.from_table.is_none() {
2160 return (CursorContext::SelectClause, extract_partial_at_end(query));
2161 }
2162
2163 (CursorContext::Unknown, None)
2164}
2165
2166fn find_last_token(tokens: &[(usize, usize, Token)], target: &Token) -> Option<usize> {
2168 tokens
2169 .iter()
2170 .rposition(|(_, _, t)| t == target)
2171 .map(|idx| tokens[idx].0)
2172}
2173
2174fn find_last_matching_token<F>(
2176 tokens: &[(usize, usize, Token)],
2177 predicate: F,
2178) -> Option<(usize, &Token)>
2179where
2180 F: Fn(&Token) -> bool,
2181{
2182 tokens
2183 .iter()
2184 .rposition(|(_, _, t)| predicate(t))
2185 .map(|idx| (tokens[idx].0, &tokens[idx].2))
2186}
2187
2188fn is_in_clause(
2190 tokens: &[(usize, usize, Token)],
2191 clause_token: Token,
2192 exclude_tokens: &[Token],
2193) -> bool {
2194 if let Some(clause_pos) = find_last_token(tokens, &clause_token) {
2196 for (pos, _, token) in tokens.iter() {
2198 if *pos > clause_pos && exclude_tokens.contains(token) {
2199 return false;
2200 }
2201 }
2202 return true;
2203 }
2204 false
2205}
2206
2207fn analyze_partial(query: &str, cursor_pos: usize) -> (CursorContext, Option<String>) {
2208 let mut lexer = Lexer::new(query);
2210 let tokens = lexer.tokenize_all_with_positions();
2211
2212 let trimmed = query.trim();
2213
2214 #[cfg(test)]
2215 {
2216 if trimmed.contains("\"Last Name\"") {
2217 eprintln!("DEBUG analyze_partial: query='{query}', trimmed='{trimmed}'");
2218 }
2219 }
2220
2221 if let Some(result) = check_after_comparison_operator(query) {
2223 return result;
2224 }
2225
2226 if let Some(dot_pos) = trimmed.rfind('.') {
2229 #[cfg(test)]
2230 {
2231 if trimmed.contains("\"Last Name\"") {
2232 eprintln!("DEBUG: Found dot at position {dot_pos}");
2233 }
2234 }
2235 let before_dot = &trimmed[..dot_pos];
2237 let after_dot = &trimmed[dot_pos + 1..];
2238
2239 if !after_dot.contains('(') {
2242 let col_name = if before_dot.ends_with('"') {
2245 let bytes = before_dot.as_bytes();
2247 let pos = before_dot.len() - 1; #[cfg(test)]
2250 {
2251 if trimmed.contains("\"Last Name\"") {
2252 eprintln!("DEBUG: before_dot='{before_dot}', looking for opening quote");
2253 }
2254 }
2255
2256 let found_start = find_quote_start(bytes, pos);
2257
2258 if let Some(start) = found_start {
2259 let result = safe_slice_from(before_dot, start);
2261 #[cfg(test)]
2262 {
2263 if trimmed.contains("\"Last Name\"") {
2264 eprintln!("DEBUG: Extracted quoted identifier: '{result}'");
2265 }
2266 }
2267 Some(result)
2268 } else {
2269 #[cfg(test)]
2270 {
2271 if trimmed.contains("\"Last Name\"") {
2272 eprintln!("DEBUG: No opening quote found!");
2273 }
2274 }
2275 None
2276 }
2277 } else {
2278 before_dot
2281 .split_whitespace()
2282 .last()
2283 .map(|word| word.trim_start_matches('('))
2284 };
2285
2286 if let Some(col_name) = col_name {
2287 #[cfg(test)]
2288 {
2289 if trimmed.contains("\"Last Name\"") {
2290 eprintln!("DEBUG: col_name = '{col_name}'");
2291 }
2292 }
2293
2294 let is_valid = Parser::is_valid_identifier(col_name);
2296
2297 #[cfg(test)]
2298 {
2299 if trimmed.contains("\"Last Name\"") {
2300 eprintln!("DEBUG: is_valid = {is_valid}");
2301 }
2302 }
2303
2304 if is_valid {
2305 return handle_method_call_context(col_name, after_dot);
2306 }
2307 }
2308 }
2309 }
2310
2311 if let Some((pos, token)) =
2313 find_last_matching_token(&tokens, |t| matches!(t, Token::And | Token::Or))
2314 {
2315 let token_end_pos = if matches!(token, Token::And) {
2317 pos + 3 } else {
2319 pos + 2 };
2321
2322 if cursor_pos > token_end_pos {
2323 let after_op = safe_slice_from(query, token_end_pos + 1); let partial = extract_partial_at_end(after_op);
2326 let op = if matches!(token, Token::And) {
2327 LogicalOp::And
2328 } else {
2329 LogicalOp::Or
2330 };
2331 return (CursorContext::AfterLogicalOp(op), partial);
2332 }
2333 }
2334
2335 if let Some((_, _, last_token)) = tokens.last() {
2337 if matches!(last_token, Token::And | Token::Or) {
2338 let op = if matches!(last_token, Token::And) {
2339 LogicalOp::And
2340 } else {
2341 LogicalOp::Or
2342 };
2343 return (CursorContext::AfterLogicalOp(op), None);
2344 }
2345 }
2346
2347 if let Some(order_pos) = find_last_token(&tokens, &Token::OrderBy) {
2349 let has_by = tokens
2351 .iter()
2352 .any(|(pos, _, t)| *pos > order_pos && matches!(t, Token::By));
2353 if has_by
2354 || tokens
2355 .last()
2356 .map_or(false, |(_, _, t)| matches!(t, Token::OrderBy))
2357 {
2358 return (CursorContext::OrderByClause, extract_partial_at_end(query));
2359 }
2360 }
2361
2362 if is_in_clause(&tokens, Token::Where, &[Token::OrderBy, Token::GroupBy]) {
2364 return (CursorContext::WhereClause, extract_partial_at_end(query));
2365 }
2366
2367 if is_in_clause(
2369 &tokens,
2370 Token::From,
2371 &[Token::Where, Token::OrderBy, Token::GroupBy],
2372 ) {
2373 return (CursorContext::FromClause, extract_partial_at_end(query));
2374 }
2375
2376 if find_last_token(&tokens, &Token::Select).is_some()
2378 && find_last_token(&tokens, &Token::From).is_none()
2379 {
2380 return (CursorContext::SelectClause, extract_partial_at_end(query));
2381 }
2382
2383 (CursorContext::Unknown, None)
2384}
2385
2386fn extract_partial_at_end(query: &str) -> Option<String> {
2387 let trimmed = query.trim();
2388
2389 if let Some(last_word) = trimmed.split_whitespace().last() {
2391 if last_word.starts_with('"') && !last_word.ends_with('"') {
2392 return Some(last_word.to_string());
2394 }
2395 }
2396
2397 let last_word = trimmed.split_whitespace().last()?;
2399
2400 if last_word.chars().all(|c| c.is_alphanumeric() || c == '_') {
2403 if !is_sql_keyword(last_word) {
2405 Some(last_word.to_string())
2406 } else {
2407 None
2408 }
2409 } else {
2410 None
2411 }
2412}
2413
2414impl ParsePrimary for Parser {
2416 fn current_token(&self) -> &Token {
2417 &self.current_token
2418 }
2419
2420 fn advance(&mut self) {
2421 self.advance();
2422 }
2423
2424 fn consume(&mut self, expected: Token) -> Result<(), String> {
2425 self.consume(expected)
2426 }
2427
2428 fn parse_case_expression(&mut self) -> Result<SqlExpression, String> {
2429 self.parse_case_expression()
2430 }
2431
2432 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String> {
2433 self.parse_function_args()
2434 }
2435
2436 fn parse_window_spec(&mut self) -> Result<WindowSpec, String> {
2437 self.parse_window_spec()
2438 }
2439
2440 fn parse_logical_or(&mut self) -> Result<SqlExpression, String> {
2441 self.parse_logical_or()
2442 }
2443
2444 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2445 self.parse_comparison()
2446 }
2447
2448 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2449 self.parse_expression_list()
2450 }
2451
2452 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2453 if matches!(self.current_token, Token::With) {
2455 self.parse_with_clause_inner()
2456 } else {
2457 self.parse_select_statement_inner()
2458 }
2459 }
2460}
2461
2462impl ExpressionParser for Parser {
2464 fn current_token(&self) -> &Token {
2465 &self.current_token
2466 }
2467
2468 fn advance(&mut self) {
2469 match &self.current_token {
2471 Token::LeftParen => self.paren_depth += 1,
2472 Token::RightParen => {
2473 self.paren_depth -= 1;
2474 }
2475 _ => {}
2476 }
2477 self.current_token = self.lexer.next_token();
2478 }
2479
2480 fn peek(&self) -> Option<&Token> {
2481 None }
2488
2489 fn is_at_end(&self) -> bool {
2490 matches!(self.current_token, Token::Eof)
2491 }
2492
2493 fn consume(&mut self, expected: Token) -> Result<(), String> {
2494 if std::mem::discriminant(&self.current_token) == std::mem::discriminant(&expected) {
2496 self.update_paren_depth(&expected)?;
2497 self.current_token = self.lexer.next_token();
2498 Ok(())
2499 } else {
2500 Err(format!(
2501 "Expected {:?}, found {:?}",
2502 expected, self.current_token
2503 ))
2504 }
2505 }
2506
2507 fn parse_identifier(&mut self) -> Result<String, String> {
2508 if let Token::Identifier(id) = &self.current_token {
2509 let id = id.clone();
2510 self.advance();
2511 Ok(id)
2512 } else {
2513 Err(format!(
2514 "Expected identifier, found {:?}",
2515 self.current_token
2516 ))
2517 }
2518 }
2519}
2520
2521impl ParseArithmetic for Parser {
2523 fn current_token(&self) -> &Token {
2524 &self.current_token
2525 }
2526
2527 fn advance(&mut self) {
2528 self.advance();
2529 }
2530
2531 fn consume(&mut self, expected: Token) -> Result<(), String> {
2532 self.consume(expected)
2533 }
2534
2535 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2536 self.parse_primary()
2537 }
2538
2539 fn parse_multiplicative(&mut self) -> Result<SqlExpression, String> {
2540 self.parse_multiplicative()
2541 }
2542
2543 fn parse_method_args(&mut self) -> Result<Vec<SqlExpression>, String> {
2544 self.parse_method_args()
2545 }
2546}
2547
2548impl ParseComparison for Parser {
2550 fn current_token(&self) -> &Token {
2551 &self.current_token
2552 }
2553
2554 fn advance(&mut self) {
2555 self.advance();
2556 }
2557
2558 fn consume(&mut self, expected: Token) -> Result<(), String> {
2559 self.consume(expected)
2560 }
2561
2562 fn parse_primary(&mut self) -> Result<SqlExpression, String> {
2563 self.parse_primary()
2564 }
2565
2566 fn parse_additive(&mut self) -> Result<SqlExpression, String> {
2567 self.parse_additive()
2568 }
2569
2570 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2571 self.parse_expression_list()
2572 }
2573
2574 fn parse_subquery(&mut self) -> Result<SelectStatement, String> {
2575 if matches!(self.current_token, Token::With) {
2577 self.parse_with_clause_inner()
2578 } else {
2579 self.parse_select_statement_inner()
2580 }
2581 }
2582}
2583
2584impl ParseLogical for Parser {
2586 fn current_token(&self) -> &Token {
2587 &self.current_token
2588 }
2589
2590 fn advance(&mut self) {
2591 self.advance();
2592 }
2593
2594 fn consume(&mut self, expected: Token) -> Result<(), String> {
2595 self.consume(expected)
2596 }
2597
2598 fn parse_logical_and(&mut self) -> Result<SqlExpression, String> {
2599 self.parse_logical_and()
2600 }
2601
2602 fn parse_base_logical_expression(&mut self) -> Result<SqlExpression, String> {
2603 self.parse_comparison()
2606 }
2607
2608 fn parse_comparison(&mut self) -> Result<SqlExpression, String> {
2609 self.parse_comparison()
2610 }
2611
2612 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String> {
2613 self.parse_expression_list()
2614 }
2615}
2616
2617impl ParseCase for Parser {
2619 fn current_token(&self) -> &Token {
2620 &self.current_token
2621 }
2622
2623 fn advance(&mut self) {
2624 self.advance();
2625 }
2626
2627 fn consume(&mut self, expected: Token) -> Result<(), String> {
2628 self.consume(expected)
2629 }
2630
2631 fn parse_expression(&mut self) -> Result<SqlExpression, String> {
2632 self.parse_expression()
2633 }
2634}
2635
2636fn is_sql_keyword(word: &str) -> bool {
2637 let mut lexer = Lexer::new(word);
2639 let token = lexer.next_token();
2640
2641 !matches!(token, Token::Identifier(_) | Token::Eof)
2643}
2644
2645#[cfg(test)]
2646mod tests {
2647 use super::*;
2648
2649 #[test]
2651 fn test_parser_mode_default_is_standard() {
2652 let sql = "-- Leading comment\nSELECT * FROM users";
2653 let mut parser = Parser::new(sql);
2654 let stmt = parser.parse().unwrap();
2655
2656 assert!(stmt.leading_comments.is_empty());
2658 assert!(stmt.trailing_comment.is_none());
2659 }
2660
2661 #[test]
2663 fn test_parser_mode_preserve_leading_comments() {
2664 let sql = "-- Important query\n-- Author: Alice\nSELECT id, name FROM users";
2665 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2666 let stmt = parser.parse().unwrap();
2667
2668 assert_eq!(stmt.leading_comments.len(), 2);
2670 assert!(stmt.leading_comments[0].is_line_comment);
2671 assert!(stmt.leading_comments[0].text.contains("Important query"));
2672 assert!(stmt.leading_comments[1].text.contains("Author: Alice"));
2673 }
2674
2675 #[test]
2677 fn test_parser_mode_preserve_trailing_comment() {
2678 let sql = "SELECT * FROM users -- Fetch all users";
2679 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2680 let stmt = parser.parse().unwrap();
2681
2682 assert!(stmt.trailing_comment.is_some());
2684 let comment = stmt.trailing_comment.unwrap();
2685 assert!(comment.is_line_comment);
2686 assert!(comment.text.contains("Fetch all users"));
2687 }
2688
2689 #[test]
2691 fn test_parser_mode_preserve_block_comments() {
2692 let sql = "/* Query explanation */\nSELECT * FROM users";
2693 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2694 let stmt = parser.parse().unwrap();
2695
2696 assert_eq!(stmt.leading_comments.len(), 1);
2698 assert!(!stmt.leading_comments[0].is_line_comment); assert!(stmt.leading_comments[0].text.contains("Query explanation"));
2700 }
2701
2702 #[test]
2704 fn test_parser_mode_preserve_both_comments() {
2705 let sql = "-- Leading\nSELECT * FROM users -- Trailing";
2706 let mut parser = Parser::with_mode(sql, ParserMode::PreserveComments);
2707 let stmt = parser.parse().unwrap();
2708
2709 assert_eq!(stmt.leading_comments.len(), 1);
2711 assert!(stmt.leading_comments[0].text.contains("Leading"));
2712 assert!(stmt.trailing_comment.is_some());
2713 assert!(stmt.trailing_comment.unwrap().text.contains("Trailing"));
2714 }
2715
2716 #[test]
2718 fn test_parser_mode_standard_ignores_comments() {
2719 let sql = "-- Comment 1\n/* Comment 2 */\nSELECT * FROM users -- Comment 3";
2720 let mut parser = Parser::with_mode(sql, ParserMode::Standard);
2721 let stmt = parser.parse().unwrap();
2722
2723 assert!(stmt.leading_comments.is_empty());
2725 assert!(stmt.trailing_comment.is_none());
2726
2727 assert_eq!(stmt.select_items.len(), 1);
2729 assert_eq!(stmt.from_table, Some("users".to_string()));
2730 }
2731
2732 #[test]
2734 fn test_parser_backward_compatibility() {
2735 let sql = "SELECT id, name FROM users WHERE active = true";
2736
2737 let mut parser1 = Parser::new(sql);
2739 let stmt1 = parser1.parse().unwrap();
2740
2741 let mut parser2 = Parser::with_mode(sql, ParserMode::Standard);
2743 let stmt2 = parser2.parse().unwrap();
2744
2745 assert_eq!(stmt1.select_items.len(), stmt2.select_items.len());
2747 assert_eq!(stmt1.from_table, stmt2.from_table);
2748 assert_eq!(stmt1.where_clause.is_some(), stmt2.where_clause.is_some());
2749 assert!(stmt1.leading_comments.is_empty());
2750 assert!(stmt2.leading_comments.is_empty());
2751 }
2752}