1use radixdb_core::SmartString;
18
19use super::ast::*;
20use super::parser::Parser;
21use super::precedence::Precedence;
22use super::token::{Token, TokenType};
23
24fn validate_cast_type_name(type_name: &str) -> Result<(), String> {
25 let upper = type_name.to_ascii_uppercase();
26 let (base, arguments) = match upper.split_once('(') {
27 Some((base, suffix)) => {
28 let Some(arguments) = suffix.strip_suffix(')') else {
29 return Err(format!("invalid CAST target type: {type_name}"));
30 };
31 (base, Some(arguments))
32 }
33 None => (upper.as_str(), None),
34 };
35
36 if arguments.is_none()
40 && base.contains('.')
41 && base.split('.').all(|component| !component.is_empty())
42 {
43 return Ok(());
44 }
45
46 if !matches!(
47 base,
48 "INTEGER"
49 | "INT"
50 | "BIGINT"
51 | "SMALLINT"
52 | "TINYINT"
53 | "FLOAT"
54 | "DOUBLE"
55 | "REAL"
56 | "DECIMAL"
57 | "NUMERIC"
58 | "TEXT"
59 | "VARCHAR"
60 | "CHAR"
61 | "STRING"
62 | "CLOB"
63 | "BOOLEAN"
64 | "BOOL"
65 | "TIMESTAMP"
66 | "DATETIME"
67 | "TIME"
68 | "DATE"
69 | "JSON"
70 | "JSONB"
71 | "UUID"
72 | "BYTES"
73 | "BLOB"
74 | "BINARY"
75 | "VARBINARY"
76 | "VECTOR"
77 ) {
78 return Err(format!("unknown CAST target type: {type_name}"));
79 }
80
81 let Some(arguments) = arguments else {
82 return Ok(());
83 };
84 let values: Vec<&str> = arguments.split(',').map(str::trim).collect();
85 let parse_positive = |value: &str| value.parse::<usize>().ok().filter(|&parsed| parsed > 0);
86
87 match base {
88 "VARCHAR" | "CHAR" => {
89 if values.len() == 1 && parse_positive(values[0]).is_some() {
90 Ok(())
91 } else {
92 Err(format!("{base} requires one positive length"))
93 }
94 }
95 "DECIMAL" | "NUMERIC" => {
96 let Some(precision) = values.first().and_then(|value| parse_positive(value)) else {
97 return Err(format!("{base} requires a positive precision"));
98 };
99 if values.len() > 2 || precision > 38 {
100 return Err(format!("invalid {base} precision/scale: {arguments}"));
101 }
102 if let Some(scale) = values.get(1).and_then(|value| value.parse::<usize>().ok()) {
103 if scale <= precision {
104 Ok(())
105 } else {
106 Err(format!("{base} scale cannot exceed precision"))
107 }
108 } else if values.len() == 1 {
109 Ok(())
110 } else {
111 Err(format!("invalid {base} precision/scale: {arguments}"))
112 }
113 }
114 "VECTOR" => {
115 if values.len() == 1
116 && parse_positive(values[0]).is_some_and(|dimension| dimension <= u16::MAX as usize)
117 {
118 Ok(())
119 } else {
120 Err("VECTOR requires one dimension between 1 and 65535".to_string())
121 }
122 }
123 _ => Err(format!("type modifiers are not supported for {base}")),
124 }
125}
126
127fn window_frame_rank(bound: &WindowFrameBound) -> i128 {
128 match bound {
129 WindowFrameBound::UnboundedPreceding => i128::MIN,
130 WindowFrameBound::Preceding(expression) => match expression.as_ref() {
131 Expression::IntegerLiteral(value) => -(value.value as i128),
132 _ => unreachable!("window offsets are validated before frame ordering"),
133 },
134 WindowFrameBound::CurrentRow => 0,
135 WindowFrameBound::Following(expression) => match expression.as_ref() {
136 Expression::IntegerLiteral(value) => value.value as i128,
137 _ => unreachable!("window offsets are validated before frame ordering"),
138 },
139 WindowFrameBound::UnboundedFollowing => i128::MAX,
140 }
141}
142
143fn window_frame_is_ordered(start: &WindowFrameBound, end: Option<&WindowFrameBound>) -> bool {
144 if matches!(start, WindowFrameBound::UnboundedFollowing)
145 || end.is_some_and(|bound| matches!(bound, WindowFrameBound::UnboundedPreceding))
146 {
147 return false;
148 }
149 window_frame_rank(start)
150 <= end
151 .map(window_frame_rank)
152 .unwrap_or_else(|| window_frame_rank(&WindowFrameBound::CurrentRow))
153}
154
155impl Parser {
156 pub fn parse_expression(&mut self, precedence: Precedence) -> Option<Expression> {
158 if !self.enter_expression() {
159 return None;
160 }
161 let result = self.parse_expression_inner(precedence);
162 self.expression_depth -= 1;
163 result
164 }
165
166 fn parse_expression_inner(&mut self, precedence: Precedence) -> Option<Expression> {
167 let mut left = self.parse_prefix_expression()?;
169
170 while !self.peek_token_is(TokenType::Eof) && precedence < self.peek_precedence() {
172 if !self.is_infix_token() {
174 return Some(left);
175 }
176
177 self.next_token();
178 left = self.parse_infix_expression(left)?;
179 }
180
181 Some(left)
182 }
183
184 fn is_infix_token(&self) -> bool {
186 match self.peek_token.token_type {
187 TokenType::Operator => true,
188 TokenType::Keyword => {
189 let kw = self.peek_token.literal.to_uppercase();
190 matches!(
191 kw.as_str(),
192 "AND"
193 | "OR"
194 | "XOR"
195 | "LIKE"
196 | "ILIKE"
197 | "GLOB"
198 | "REGEXP"
199 | "RLIKE"
200 | "IS"
201 | "IN"
202 | "BETWEEN"
203 | "NOT"
204 )
205 }
206 TokenType::Punctuator => {
207 matches!(self.peek_token.literal.as_str(), "." | "(" | "[")
208 }
209 _ => false,
210 }
211 }
212
213 fn parse_prefix_expression(&mut self) -> Option<Expression> {
215 match self.cur_token.token_type {
216 TokenType::Identifier => Some(self.parse_identifier()),
217 TokenType::Integer => self.parse_integer_literal(),
218 TokenType::Float => self.parse_float_literal(),
219 TokenType::String => Some(self.parse_string_literal()),
220 TokenType::Parameter => self.parse_parameter(),
221 TokenType::Keyword => self.parse_keyword_expression(),
222 TokenType::Operator => self.parse_unary_expression(),
223 TokenType::Punctuator => self.parse_punctuator_expression(),
224 TokenType::Error => {
225 self.add_error(self.cur_token.literal.to_string());
227 None
228 }
229 _ => {
230 if self.cur_token.token_type == TokenType::Eof {
231 if self.current_clause.is_empty() {
232 self.add_error("unexpected end of input, expected expression".to_string());
233 } else {
234 self.add_error(format!(
235 "expected expression after {}",
236 self.current_clause
237 ));
238 }
239 } else {
240 self.add_error(format!(
241 "unexpected '{}', expected expression",
242 self.cur_token.literal
243 ));
244 }
245 None
246 }
247 }
248 }
249
250 fn parse_identifier(&self) -> Expression {
252 if !self.cur_token.quoted && !self.peek_token_is_punctuator("(") {
259 let upper = self.cur_token.literal.to_uppercase();
260 if upper == "CURRENT_DATE" || upper == "CURRENT_TIME" || upper == "CURRENT_TIMESTAMP" {
261 return Expression::FunctionCall(Box::new(FunctionCall {
262 token: self.cur_token.clone(),
263 function: SmartString::new(&upper),
264 arguments: vec![],
265 is_distinct: false,
266 order_by: vec![],
267 filter: None,
268 }));
269 }
270 }
271 Expression::Identifier(Identifier::new(
272 self.cur_token.clone(),
273 self.cur_token.literal.clone(),
274 ))
275 }
276
277 fn parse_integer_literal(&mut self) -> Option<Expression> {
279 match self.cur_token.literal.parse::<i64>() {
280 Ok(value) => Some(Expression::IntegerLiteral(IntegerLiteral {
281 token: self.cur_token.clone(),
282 value,
283 })),
284 Err(error) => {
285 self.add_error(format!(
286 "integer literal {} is out of range for i64: {}",
287 self.cur_token.literal, error
288 ));
289 None
290 }
291 }
292 }
293
294 fn parse_float_literal(&mut self) -> Option<Expression> {
296 self.parse_finite_float_value().map(|value| {
297 Expression::FloatLiteral(FloatLiteral {
298 token: self.cur_token.clone(),
299 value,
300 })
301 })
302 }
303
304 fn parse_finite_float_value(&mut self) -> Option<f64> {
306 let source = self.cur_token.literal.as_str();
307 match source.parse::<f64>() {
308 Ok(value) if !value.is_finite() => {
309 self.add_error(format!(
310 "float literal {} is out of finite f64 range",
311 source
312 ));
313 None
314 }
315 Ok(value)
316 if value == 0.0
317 && source.split(['e', 'E']).next().is_some_and(|mantissa| {
318 mantissa.bytes().any(|b| matches!(b, b'1'..=b'9'))
319 }) =>
320 {
321 self.add_error(format!("float literal {} underflows finite f64", source));
322 None
323 }
324 Ok(value) => Some(value),
325 Err(e) => {
326 self.add_error(format!("could not parse {} as float: {}", source, e));
327 None
328 }
329 }
330 }
331
332 fn parse_string_literal(&self) -> Expression {
334 let literal = &self.cur_token.literal;
335 let value = if literal.len() >= 2 {
337 let inner = &literal[1..literal.len() - 1];
338 if inner.contains('\\') {
343 let mut result = String::with_capacity(inner.len());
345 let mut chars = inner.chars().peekable();
346 while let Some(c) = chars.next() {
347 if c == '\\' {
348 match chars.peek() {
349 Some('n') => {
350 result.push('\n');
351 chars.next();
352 }
353 Some('t') => {
354 result.push('\t');
355 chars.next();
356 }
357 Some('r') => {
358 result.push('\r');
359 chars.next();
360 }
361 Some('\'') => {
362 result.push('\'');
363 chars.next();
364 }
365 Some('\\') => {
366 result.push('\\');
367 chars.next();
368 }
369 _ => result.push(c), }
371 } else {
372 result.push(c);
373 }
374 }
375 SmartString::from_string(result)
376 } else {
377 SmartString::new(inner)
379 }
380 } else {
381 literal.clone()
382 };
383
384 Expression::StringLiteral(StringLiteral {
385 token: self.cur_token.clone(),
386 value,
387 type_hint: None,
388 })
389 }
390
391 fn parse_parameter(&mut self) -> Option<Expression> {
393 let name = self.cur_token.literal.clone();
394 let index = if name == "?" {
395 if self.positional_parameter_style
396 == Some(super::parser::PositionalParameterStyle::Explicit)
397 {
398 self.add_error("cannot mix '?' and '$n' positional parameters".to_string());
399 return None;
400 }
401 self.positional_parameter_style =
402 Some(super::parser::PositionalParameterStyle::Anonymous);
403 self.next_parameter_index()
404 } else if let Some(stripped) = name.strip_prefix('$') {
405 if self.positional_parameter_style
406 == Some(super::parser::PositionalParameterStyle::Anonymous)
407 {
408 self.add_error("cannot mix '?' and '$n' positional parameters".to_string());
409 return None;
410 }
411 self.positional_parameter_style =
412 Some(super::parser::PositionalParameterStyle::Explicit);
413 match stripped.parse::<usize>() {
414 Ok(0) => {
415 self.add_error(
416 "positional parameter indexes start at $1; $0 is invalid".to_string(),
417 );
418 return None;
419 }
420 Ok(idx) => idx,
421 Err(e) => {
422 self.add_error(format!("invalid parameter index: {}", e));
423 return None;
424 }
425 }
426 } else if name.starts_with(':') {
427 0
429 } else {
430 self.add_error(format!("invalid parameter format: {}", name));
431 return None;
432 };
433
434 Some(Expression::Parameter(Parameter {
435 token: self.cur_token.clone(),
436 name,
437 index,
438 field: None,
439 }))
440 }
441
442 fn parse_keyword_expression(&mut self) -> Option<Expression> {
444 let keyword = self.cur_token.literal.to_uppercase();
445 match keyword.as_str() {
446 "TRUE" => Some(Expression::BooleanLiteral(BooleanLiteral {
447 token: self.cur_token.clone(),
448 value: true,
449 })),
450 "FALSE" => Some(Expression::BooleanLiteral(BooleanLiteral {
451 token: self.cur_token.clone(),
452 value: false,
453 })),
454 "NULL" => Some(Expression::NullLiteral(NullLiteral {
455 token: self.cur_token.clone(),
456 })),
457 "CASE" => self.parse_case_expression(),
458 "CAST" => self.parse_cast_expression(),
459 "EXTRACT" => self.parse_extract_expression(),
460 "EXISTS" => self.parse_exists_expression(),
461 "NOT" => self.parse_not_expression(),
462 "INTERVAL" => self.parse_interval_literal(),
463 "DEFAULT" => Some(Expression::Default(DefaultExpression {
464 token: self.cur_token.clone(),
465 })),
466 "TIMESTAMP" | "DATE" | "TIME" => {
467 if self.peek_token_is(TokenType::String) {
469 self.parse_typed_literal()
470 } else {
471 Some(Expression::Identifier(Identifier::new(
473 self.cur_token.clone(),
474 self.cur_token.literal.clone(),
475 )))
476 }
477 }
478 "LEFT" | "RIGHT" | "CHAR" | "FIRST" | "LAST" | "TRUNCATE" => {
480 if self.peek_token_is_punctuator("(") {
481 let ident = Expression::Identifier(Identifier::new(
483 self.cur_token.clone(),
484 self.cur_token.literal.clone(),
485 ));
486 self.next_token(); self.parse_function_call(ident)
488 } else {
489 Some(Expression::Identifier(Identifier::new(
491 self.cur_token.clone(),
492 self.cur_token.literal.clone(),
493 )))
494 }
495 }
496 _ if !Self::is_reserved_keyword(&keyword) => Some(Expression::Identifier(
498 Identifier::new(self.cur_token.clone(), self.cur_token.literal.clone()),
499 )),
500 _ => {
501 if self.current_clause.is_empty() {
502 self.add_error(format!(
503 "'{}' cannot be used here, expected expression",
504 keyword
505 ));
506 } else {
507 self.add_error(format!(
508 "'{}' cannot be used in {} clause, expected expression",
509 keyword, self.current_clause
510 ));
511 }
512 None
513 }
514 }
515 }
516
517 fn parse_unary_expression(&mut self) -> Option<Expression> {
519 let token = self.cur_token.clone();
520 let operator = self.cur_token.literal.clone();
521
522 if operator == "*" {
526 if self.peek_token.is_eof()
529 || self.peek_token.is_punctuator(",")
530 || self.peek_token.is_punctuator(";")
531 || self.peek_token.is_punctuator(")")
532 || self.peek_token_is_keyword("FROM")
533 || self.peek_token_is_keyword("WHERE")
534 || self.peek_token_is_keyword("ORDER")
535 || self.peek_token_is_keyword("GROUP")
536 || self.peek_token_is_keyword("HAVING")
537 || self.peek_token_is_keyword("LIMIT")
538 || self.peek_token_is_keyword("UNION")
539 || self.peek_token_is_keyword("INTERSECT")
540 || self.peek_token_is_keyword("EXCEPT")
541 {
542 return Some(Expression::Star(StarExpression { token }));
543 }
544 }
545
546 self.next_token();
547
548 if operator == "-"
550 && (self.cur_token_is(TokenType::Integer) || self.cur_token_is(TokenType::Float))
551 {
552 if self.cur_token_is(TokenType::Integer) {
553 if self.cur_token.literal == "9223372036854775808" {
557 return Some(Expression::IntegerLiteral(IntegerLiteral {
558 token: self.cur_token.clone(),
559 value: i64::MIN,
560 }));
561 }
562 if let Ok(value) = self.cur_token.literal.parse::<i64>() {
563 return Some(Expression::IntegerLiteral(IntegerLiteral {
564 token: self.cur_token.clone(),
565 value: -value,
566 }));
567 }
568 } else {
569 let value = self.parse_finite_float_value()?;
570 return Some(Expression::FloatLiteral(FloatLiteral {
571 token: self.cur_token.clone(),
572 value: -value,
573 }));
574 }
575 }
576
577 let right = self.parse_expression(Precedence::Prefix)?;
578
579 Some(Expression::Prefix(PrefixExpression::new(
580 token,
581 operator,
582 Box::new(right),
583 )))
584 }
585
586 fn parse_punctuator_expression(&mut self) -> Option<Expression> {
588 match self.cur_token.literal.as_str() {
589 "(" => self.parse_grouped_expression(),
590 "*" => Some(Expression::Star(StarExpression {
591 token: self.cur_token.clone(),
592 })),
593 _ => {
594 self.add_error(format!(
595 "unexpected punctuator: {} at {}",
596 self.cur_token.literal, self.cur_token.position
597 ));
598 None
599 }
600 }
601 }
602
603 fn parse_grouped_expression(&mut self) -> Option<Expression> {
605 let token = self.cur_token.clone();
606
607 if self.peek_token_is_keyword("SELECT") {
609 self.next_token(); let subquery = self.parse_select_statement()?;
611
612 if !self.peek_token_is_punctuator(")") {
613 self.add_error(format!(
614 "expected ')' after scalar subquery, got {}",
615 Self::format_token_for_error(&self.peek_token)
616 ));
617 return None;
618 }
619 self.next_token();
620
621 return Some(Expression::ScalarSubquery(ScalarSubquery {
622 token,
623 subquery: Box::new(subquery),
624 }));
625 }
626
627 self.next_token(); if self.cur_token_is_punctuator(")") {
631 return Some(Expression::Identifier(Identifier::new(
632 self.cur_token.clone(),
633 SmartString::const_new("()"),
634 )));
635 }
636
637 let first_expr = self.parse_expression(Precedence::Lowest)?;
638
639 if self.peek_token_is_punctuator(",") {
641 let mut expressions = vec![first_expr];
642
643 while self.peek_token_is_punctuator(",") {
644 self.next_token(); self.next_token(); if let Some(expr) = self.parse_expression(Precedence::Lowest) {
648 expressions.push(expr);
649 }
650 }
651
652 if !self.peek_token_is_punctuator(")") {
653 self.add_error(format!(
654 "expected ')', got {}",
655 Self::format_token_for_error(&self.peek_token)
656 ));
657 return None;
658 }
659 self.next_token();
660
661 return Some(Expression::ExpressionList(Box::new(ExpressionList {
663 token,
664 expressions,
665 })));
666 }
667
668 if !self.peek_token_is_punctuator(")") {
669 self.add_error(format!(
670 "expected ')', got {}",
671 Self::format_token_for_error(&self.peek_token)
672 ));
673 return None;
674 }
675 self.next_token();
676
677 Some(first_expr)
678 }
679
680 fn parse_infix_expression(&mut self, left: Expression) -> Option<Expression> {
682 match self.cur_token.token_type {
683 TokenType::Operator => self.parse_binary_expression(left),
684 TokenType::Keyword => self.parse_keyword_infix(left),
685 TokenType::Punctuator => self.parse_punctuator_infix(left),
686 _ => {
687 self.add_error(format!(
688 "unexpected infix token: {:?} at {}",
689 self.cur_token.token_type, self.cur_token.position
690 ));
691 None
692 }
693 }
694 }
695
696 fn parse_binary_expression(&mut self, left: Expression) -> Option<Expression> {
698 let token = self.cur_token.clone();
699 let operator = self.cur_token.literal.clone();
700 let precedence = self.cur_precedence();
701
702 self.next_token();
703
704 if self.cur_token_is_keyword("ALL")
706 || self.cur_token_is_keyword("ANY")
707 || self.cur_token_is_keyword("SOME")
708 {
709 if !matches!(
710 operator.as_str(),
711 "=" | "<>" | "!=" | "<" | "<=" | ">" | ">="
712 ) {
713 self.add_error(format!(
714 "{} is not a valid comparison operator before {}",
715 operator, self.cur_token.literal
716 ));
717 return None;
718 }
719 return self.parse_all_any_expression(left, token, operator);
720 }
721
722 let right = self.parse_expression(precedence)?;
723
724 Some(Expression::Infix(InfixExpression::new(
725 token,
726 Box::new(left),
727 operator,
728 Box::new(right),
729 )))
730 }
731
732 fn parse_all_any_expression(
734 &mut self,
735 left: Expression,
736 token: Token,
737 operator: SmartString,
738 ) -> Option<Expression> {
739 use super::ast::{AllAnyExpression, AllAnyType};
740
741 let all_any_type = if self.cur_token_is_keyword("ALL") {
742 AllAnyType::All
743 } else {
744 AllAnyType::Any };
746
747 self.next_token();
749
750 if !self.cur_token_is_punctuator("(") {
752 self.add_error(format!(
753 "expected '(' after {} at {}",
754 all_any_type, self.cur_token.position
755 ));
756 return None;
757 }
758
759 self.next_token();
761
762 if !self.cur_token_is_keyword("SELECT") {
764 self.add_error(format!(
765 "expected SELECT in {} subquery at {}",
766 all_any_type, self.cur_token.position
767 ));
768 return None;
769 }
770
771 let subquery = self.parse_select_statement()?;
772
773 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
775 self.add_error(format!(
776 "expected ')' after {} subquery at {}",
777 all_any_type, self.cur_token.position
778 ));
779 return None;
780 }
781
782 Some(Expression::AllAny(AllAnyExpression {
783 token,
784 left: Box::new(left),
785 operator,
786 all_any_type,
787 subquery: Box::new(subquery),
788 }))
789 }
790
791 fn parse_keyword_infix(&mut self, left: Expression) -> Option<Expression> {
793 let keyword = self.cur_token.literal.to_uppercase();
794 match keyword.as_str() {
795 "AND" | "OR" | "XOR" => {
796 let token = self.cur_token.clone();
797 let operator = keyword.clone();
798 let precedence = self.cur_precedence();
799
800 self.next_token();
801 let right = self.parse_expression(precedence)?;
802
803 Some(Expression::Infix(InfixExpression::new(
804 token,
805 Box::new(left),
806 operator,
807 Box::new(right),
808 )))
809 }
810 "LIKE" | "ILIKE" | "GLOB" | "REGEXP" | "RLIKE" => {
811 self.parse_like_expression(left, keyword.clone(), false)
812 }
813 "IS" => self.parse_is_expression(left),
814 "IN" => self.parse_in_expression(left, false),
815 "BETWEEN" => self.parse_between_expression(left, false),
816 "NOT" => {
817 if self.peek_token_is_keyword("IN") {
819 self.next_token(); self.parse_in_expression(left, true)
821 } else if self.peek_token_is_keyword("BETWEEN") {
822 self.next_token(); self.parse_between_expression(left, true)
824 } else if self.peek_token_is_keyword("LIKE") {
825 self.next_token(); self.parse_like_expression(left, SmartString::const_new("LIKE"), true)
827 } else if self.peek_token_is_keyword("ILIKE") {
828 self.next_token(); self.parse_like_expression(left, SmartString::const_new("ILIKE"), true)
830 } else if self.peek_token_is_keyword("GLOB") {
831 self.next_token(); self.parse_like_expression(left, SmartString::const_new("GLOB"), true)
833 } else if self.peek_token_is_keyword("REGEXP") {
834 self.next_token(); self.parse_like_expression(left, SmartString::const_new("REGEXP"), true)
836 } else if self.peek_token_is_keyword("RLIKE") {
837 self.next_token(); self.parse_like_expression(left, SmartString::const_new("RLIKE"), true)
839 } else {
840 self.add_error(format!(
841 "NOT must be followed by IN, BETWEEN, LIKE, ILIKE, GLOB, REGEXP, or RLIKE at {}",
842 self.peek_token.position
843 ));
844 None
845 }
846 }
847 _ => {
848 self.add_error(format!(
849 "unexpected infix keyword: {} at {}",
850 keyword, self.cur_token.position
851 ));
852 None
853 }
854 }
855 }
856
857 fn parse_punctuator_infix(&mut self, left: Expression) -> Option<Expression> {
859 match self.cur_token.literal.as_str() {
860 "." => self.parse_qualified_identifier(left),
861 "(" => self.parse_function_call(left),
862 "[" => self.parse_index_expression(left),
863 "*" => {
864 let token = self.cur_token.clone();
866 let precedence = Precedence::Product;
867
868 self.next_token();
869 let right = self.parse_expression(precedence)?;
870
871 Some(Expression::Infix(InfixExpression::new(
872 token,
873 Box::new(left),
874 SmartString::const_new("*"),
875 Box::new(right),
876 )))
877 }
878 _ => {
879 self.add_error(format!(
880 "unexpected infix punctuator: {} at {}",
881 self.cur_token.literal, self.cur_token.position
882 ));
883 None
884 }
885 }
886 }
887
888 fn parse_qualified_identifier(&mut self, left: Expression) -> Option<Expression> {
891 if let Expression::Parameter(mut parameter) = left {
892 if parameter.index != 0 || !parameter.name.starts_with(':') || parameter.field.is_some()
893 {
894 self.add_error(format!(
895 "only one field may follow a named parameter at {}",
896 self.cur_token.position
897 ));
898 return None;
899 }
900 if !self.peek_token_is(TokenType::Identifier) && !self.peek_token_is(TokenType::Keyword)
901 {
902 self.peek_error(TokenType::Identifier);
903 return None;
904 }
905 self.next_token();
906 parameter.field = Some(Box::new(Identifier::new(
907 self.cur_token.clone(),
908 self.cur_token.literal.clone(),
909 )));
910 return Some(Expression::Parameter(parameter));
911 }
912 let mut qualified = match left {
913 Expression::Identifier(id) => QualifiedIdentifier {
914 token: id.token.clone(),
915 qualifier: Box::new(id),
916 intermediate: None,
917 name: Box::new(Identifier::new(
918 self.cur_token.clone(),
919 SmartString::const_new(""),
920 )),
921 },
922 Expression::QualifiedIdentifier(path) => path,
923 _ => {
924 self.add_error(format!(
925 "left side of '.' must be an identifier path at {}",
926 self.cur_token.position
927 ));
928 return None;
929 }
930 };
931
932 if self.peek_token_is_operator("*") {
934 if qualified.is_multi_part_path() || !qualified.name.value.is_empty() {
935 self.add_error(format!(
936 "qualified star cannot follow a multi-part identifier path at {}",
937 self.cur_token.position
938 ));
939 return None;
940 }
941 self.next_token(); return Some(Expression::QualifiedStar(QualifiedStarExpression {
943 token: qualified.qualifier.token.clone(),
944 qualifier: qualified.qualifier.value,
945 }));
946 }
947
948 if !self.peek_token_is(TokenType::Identifier) && !self.peek_token_is(TokenType::Keyword) {
951 self.peek_error(TokenType::Identifier);
952 return None;
953 }
954 self.next_token();
955 let next = Identifier::new(self.cur_token.clone(), self.cur_token.literal.clone());
956 if !qualified.name.value.is_empty() {
957 qualified
958 .intermediate
959 .get_or_insert_with(|| Box::new(Vec::new()))
960 .push(*qualified.name);
961 }
962 qualified.name = Box::new(next);
963
964 Some(Expression::QualifiedIdentifier(qualified))
965 }
966
967 fn parse_function_call(&mut self, left: Expression) -> Option<Expression> {
969 let left_ident = match left {
970 Expression::Identifier(id) => id,
971 _ => {
972 self.add_error(format!(
973 "left side of '(' must be an identifier at {}",
974 self.cur_token.position
975 ));
976 return None;
977 }
978 };
979
980 let mut call = FunctionCall {
981 token: left_ident.token.clone(),
982 function: left_ident.value.to_uppercase(),
983 arguments: Vec::new(),
984 is_distinct: false,
985 order_by: Vec::new(),
986 filter: None,
987 };
988
989 if self.peek_token_is_punctuator(")") {
991 self.next_token();
992 if self.peek_token_is_keyword("FILTER") {
994 call.filter = self.parse_filter_clause();
995 }
996 if self.peek_token_is_keyword("OVER") {
998 return self.parse_window_expression(call);
999 }
1000 return Some(Expression::FunctionCall(Box::new(call)));
1001 }
1002
1003 if self.peek_token_is_operator("*") {
1005 self.next_token();
1006 call.arguments.push(Expression::Star(StarExpression {
1007 token: self.cur_token.clone(),
1008 }));
1009
1010 if self.peek_token_is_keyword("ORDER") {
1012 self.parse_function_order_by(&mut call);
1013 }
1014
1015 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1016 self.add_error(format!("expected ')' at {}", self.cur_token.position));
1017 return None;
1018 }
1019
1020 if self.peek_token_is_keyword("FILTER") {
1022 call.filter = self.parse_filter_clause();
1023 }
1024
1025 if self.peek_token_is_keyword("OVER") {
1027 return self.parse_window_expression(call);
1028 }
1029
1030 return Some(Expression::FunctionCall(Box::new(call)));
1031 }
1032
1033 if self.peek_token_is_keyword("DISTINCT") {
1035 self.next_token();
1036 call.is_distinct = true;
1037 }
1038
1039 self.next_token();
1040
1041 let first_arg_precedence = if call.function == "POSITION" {
1044 Precedence::LessGreater } else {
1046 Precedence::Lowest
1047 };
1048
1049 if let Some(arg) = self.parse_expression(first_arg_precedence) {
1051 call.arguments.push(arg);
1052 }
1053
1054 if call.function == "POSITION" && self.peek_token_is_keyword("IN") {
1057 self.next_token(); self.next_token(); if let Some(string_arg) = self.parse_expression(Precedence::Lowest) {
1061 call.arguments.push(string_arg);
1063 } else {
1064 self.add_error(format!(
1065 "expected expression after IN in POSITION at {}",
1066 self.cur_token.position
1067 ));
1068 return None;
1069 }
1070 }
1071
1072 while self.peek_token_is_punctuator(",") {
1074 self.next_token(); self.next_token(); if let Some(arg) = self.parse_expression(Precedence::Lowest) {
1078 call.arguments.push(arg);
1079 } else {
1080 self.add_error(format!(
1081 "expected expression after ',' at {}",
1082 self.cur_token.position
1083 ));
1084 return None;
1085 }
1086 }
1087
1088 if self.peek_token_is_keyword("ORDER") {
1090 self.parse_function_order_by(&mut call);
1091 }
1092
1093 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1094 self.add_error(format!("expected ')' at {}", self.cur_token.position));
1095 return None;
1096 }
1097
1098 if self.peek_token_is_keyword("FILTER") {
1100 call.filter = self.parse_filter_clause();
1101 }
1102
1103 if self.peek_token_is_keyword("OVER") {
1105 return self.parse_window_expression(call);
1106 }
1107
1108 Some(Expression::FunctionCall(Box::new(call)))
1109 }
1110
1111 fn parse_filter_clause(&mut self) -> Option<Box<Expression>> {
1113 self.next_token(); if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
1117 self.add_error(format!(
1118 "expected '(' after FILTER at {}",
1119 self.cur_token.position
1120 ));
1121 return None;
1122 }
1123
1124 if !self.expect_keyword("WHERE") {
1126 self.add_error(format!(
1127 "expected WHERE after FILTER( at {}",
1128 self.cur_token.position
1129 ));
1130 return None;
1131 }
1132
1133 self.next_token();
1135 let condition = self.parse_expression(Precedence::Lowest)?;
1136
1137 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1139 self.add_error(format!(
1140 "expected ')' after FILTER condition at {}",
1141 self.cur_token.position
1142 ));
1143 return None;
1144 }
1145
1146 Some(Box::new(condition))
1147 }
1148
1149 fn parse_function_order_by(&mut self, call: &mut FunctionCall) {
1151 self.next_token(); if !self.expect_keyword("BY") {
1154 return;
1155 }
1156
1157 self.next_token(); if let Some(order_expr) = self.parse_order_by_expression() {
1160 call.order_by.push(order_expr);
1161 }
1162
1163 while self.peek_token_is_punctuator(",") {
1164 self.next_token(); self.next_token(); if let Some(order_expr) = self.parse_order_by_expression() {
1168 call.order_by.push(order_expr);
1169 }
1170 }
1171 }
1172
1173 fn parse_window_expression(&mut self, function: FunctionCall) -> Option<Expression> {
1175 self.next_token(); let token = self.cur_token.clone();
1177
1178 if matches!(
1180 self.peek_token.token_type,
1181 TokenType::Identifier | TokenType::Keyword
1182 ) {
1183 self.next_token(); let window_ref = self.cur_token.literal.clone();
1185 return Some(Expression::Window(Box::new(WindowExpression {
1186 token,
1187 function: Box::new(function),
1188 window_ref: Some(window_ref),
1189 partition_by: Vec::new(),
1190 order_by: Vec::new(),
1191 frame: None,
1192 })));
1193 }
1194
1195 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
1196 self.add_error(format!(
1197 "expected '(' or window name after OVER at {}",
1198 self.cur_token.position
1199 ));
1200 return None;
1201 }
1202
1203 let mut partition_by = Vec::new();
1204 let mut order_by = Vec::new();
1205 let mut frame = None;
1206
1207 if self.peek_token_is_keyword("PARTITION") {
1209 self.next_token(); if !self.expect_keyword("BY") {
1211 return None;
1212 }
1213
1214 self.next_token();
1215 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
1216 partition_by.push(expr);
1217 }
1218
1219 while self.peek_token_is_punctuator(",") {
1220 self.next_token(); self.next_token();
1222 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
1223 partition_by.push(expr);
1224 }
1225 }
1226 }
1227
1228 if self.peek_token_is_keyword("ORDER") {
1230 self.next_token(); if !self.expect_keyword("BY") {
1232 return None;
1233 }
1234
1235 self.next_token();
1236 if let Some(order_expr) = self.parse_order_by_expression() {
1237 order_by.push(order_expr);
1238 }
1239
1240 while self.peek_token_is_punctuator(",") {
1241 self.next_token(); self.next_token();
1243 if let Some(order_expr) = self.parse_order_by_expression() {
1244 order_by.push(order_expr);
1245 }
1246 }
1247 }
1248
1249 if self.peek_token_is_keyword("ROWS") || self.peek_token_is_keyword("RANGE") {
1251 frame = self.parse_window_frame();
1252 }
1253
1254 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1255 self.add_error(format!(
1256 "expected ')' after window specification at {}",
1257 self.cur_token.position
1258 ));
1259 return None;
1260 }
1261
1262 Some(Expression::Window(Box::new(WindowExpression {
1263 token,
1264 function: Box::new(function),
1265 window_ref: None,
1266 partition_by,
1267 order_by,
1268 frame,
1269 })))
1270 }
1271
1272 fn parse_window_frame(&mut self) -> Option<WindowFrame> {
1274 self.next_token();
1275 let unit = if self.cur_token_is_keyword("ROWS") {
1276 WindowFrameUnit::Rows
1277 } else {
1278 WindowFrameUnit::Range
1279 };
1280
1281 self.next_token();
1282
1283 let (start, end) = if self.cur_token_is_keyword("BETWEEN") {
1285 self.next_token();
1286 let start = self.parse_window_frame_bound()?;
1287
1288 if !self.expect_keyword("AND") {
1289 return None;
1290 }
1291 self.next_token();
1292 let end = self.parse_window_frame_bound()?;
1293
1294 (start, Some(end))
1295 } else {
1296 let start = self.parse_window_frame_bound()?;
1297 (start, None)
1298 };
1299
1300 if !window_frame_is_ordered(&start, end.as_ref()) {
1301 self.add_error("window frame start must not follow its end".to_string());
1302 return None;
1303 }
1304
1305 Some(WindowFrame { unit, start, end })
1306 }
1307
1308 fn parse_window_frame_bound(&mut self) -> Option<WindowFrameBound> {
1310 if self.cur_token_is_keyword("CURRENT") {
1311 if !self.expect_keyword("ROW") {
1312 return None;
1313 }
1314 Some(WindowFrameBound::CurrentRow)
1315 } else if self.cur_token_is_keyword("UNBOUNDED") {
1316 self.next_token();
1317 if self.cur_token_is_keyword("PRECEDING") {
1318 Some(WindowFrameBound::UnboundedPreceding)
1319 } else if self.cur_token_is_keyword("FOLLOWING") {
1320 Some(WindowFrameBound::UnboundedFollowing)
1321 } else {
1322 self.add_error(format!(
1323 "expected PRECEDING or FOLLOWING after UNBOUNDED at {}",
1324 self.cur_token.position
1325 ));
1326 None
1327 }
1328 } else {
1329 let expr = self.parse_expression(Precedence::Lowest)?;
1331 if !matches!(&expr, Expression::IntegerLiteral(value) if value.value >= 0) {
1332 self.add_error(
1333 "window frame offset must be a non-negative integer literal".to_string(),
1334 );
1335 return None;
1336 }
1337 self.next_token();
1338 if self.cur_token_is_keyword("PRECEDING") {
1339 Some(WindowFrameBound::Preceding(Box::new(expr)))
1340 } else if self.cur_token_is_keyword("FOLLOWING") {
1341 Some(WindowFrameBound::Following(Box::new(expr)))
1342 } else {
1343 self.add_error(format!(
1344 "expected PRECEDING or FOLLOWING at {}",
1345 self.cur_token.position
1346 ));
1347 None
1348 }
1349 }
1350 }
1351
1352 fn parse_index_expression(&mut self, left: Expression) -> Option<Expression> {
1354 let token = self.cur_token.clone();
1355
1356 self.next_token();
1357 let index = self.parse_expression(Precedence::Lowest)?;
1358
1359 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "]" {
1360 self.add_error(format!("expected ']' at {}", self.cur_token.position));
1361 return None;
1362 }
1363
1364 Some(Expression::Infix(InfixExpression::new(
1365 token,
1366 Box::new(left),
1367 "[]".to_string(),
1368 Box::new(index),
1369 )))
1370 }
1371
1372 fn parse_is_expression(&mut self, left: Expression) -> Option<Expression> {
1374 let token = self.cur_token.clone();
1375 let mut operator = "IS".to_string();
1376
1377 if self.peek_token_is_keyword("NOT") {
1379 self.next_token();
1380 operator = "IS NOT".to_string();
1381 }
1382
1383 self.next_token();
1384
1385 if self.cur_token_is_keyword("NULL") {
1387 return Some(Expression::Infix(InfixExpression::new(
1388 token,
1389 Box::new(left),
1390 operator,
1391 Box::new(Expression::NullLiteral(NullLiteral {
1392 token: self.cur_token.clone(),
1393 })),
1394 )));
1395 }
1396
1397 if self.cur_token_is_keyword("TRUE") {
1399 return Some(Expression::Infix(InfixExpression::new(
1400 token,
1401 Box::new(left),
1402 operator,
1403 Box::new(Expression::BooleanLiteral(BooleanLiteral {
1404 token: self.cur_token.clone(),
1405 value: true,
1406 })),
1407 )));
1408 }
1409
1410 if self.cur_token_is_keyword("FALSE") {
1412 return Some(Expression::Infix(InfixExpression::new(
1413 token,
1414 Box::new(left),
1415 operator,
1416 Box::new(Expression::BooleanLiteral(BooleanLiteral {
1417 token: self.cur_token.clone(),
1418 value: false,
1419 })),
1420 )));
1421 }
1422
1423 if self.cur_token_is_keyword("DISTINCT") {
1425 if !self.expect_keyword("FROM") {
1426 return None;
1427 }
1428 self.next_token();
1429 let right = self.parse_expression(Precedence::Equals)?;
1430 let distinct_op = if operator == "IS" {
1431 "IS DISTINCT FROM".to_string()
1432 } else {
1433 "IS NOT DISTINCT FROM".to_string()
1434 };
1435 return Some(Expression::Infix(InfixExpression::new(
1436 token,
1437 Box::new(left),
1438 distinct_op,
1439 Box::new(right),
1440 )));
1441 }
1442
1443 self.add_error(format!(
1444 "expected NULL, TRUE, FALSE, or DISTINCT FROM after IS at {}",
1445 self.cur_token.position
1446 ));
1447 None
1448 }
1449
1450 fn parse_in_expression(&mut self, left: Expression, not: bool) -> Option<Expression> {
1452 let token = self.cur_token.clone();
1453
1454 if !self.peek_token_is_punctuator("(") {
1455 self.add_error(format!(
1456 "expected '(' after IN, got {}",
1457 Self::format_token_for_error(&self.peek_token)
1458 ));
1459 return None;
1460 }
1461 self.next_token();
1462
1463 if self.peek_token_is_keyword("SELECT") {
1465 self.next_token();
1466 let subquery = self.parse_select_statement()?;
1467
1468 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1469 self.add_error(format!(
1470 "expected ')' after IN subquery at {}",
1471 self.cur_token.position
1472 ));
1473 return None;
1474 }
1475
1476 return Some(Expression::In(InExpression {
1477 token,
1478 left: Box::new(left),
1479 right: Box::new(Expression::ScalarSubquery(ScalarSubquery {
1480 token: self.cur_token.clone(),
1481 subquery: Box::new(subquery),
1482 })),
1483 not,
1484 }));
1485 }
1486
1487 let list_token = self.cur_token.clone();
1489 self.next_token();
1490
1491 let mut expressions = Vec::new();
1492
1493 if self.cur_token_is_punctuator(")") {
1495 return Some(Expression::In(InExpression {
1496 token,
1497 left: Box::new(left),
1498 right: Box::new(Expression::ExpressionList(Box::new(ExpressionList {
1499 token: list_token,
1500 expressions,
1501 }))),
1502 not,
1503 }));
1504 }
1505
1506 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
1508 expressions.push(expr);
1509 }
1510
1511 while self.peek_token_is_punctuator(",") {
1513 self.next_token(); self.next_token(); if let Some(expr) = self.parse_expression(Precedence::Lowest) {
1517 expressions.push(expr);
1518 }
1519 }
1520
1521 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1522 self.add_error(format!(
1523 "expected ')' in IN expression at {}",
1524 self.cur_token.position
1525 ));
1526 return None;
1527 }
1528
1529 Some(Expression::In(InExpression {
1530 token,
1531 left: Box::new(left),
1532 right: Box::new(Expression::ExpressionList(Box::new(ExpressionList {
1533 token: list_token,
1534 expressions,
1535 }))),
1536 not,
1537 }))
1538 }
1539
1540 fn parse_between_expression(&mut self, left: Expression, not: bool) -> Option<Expression> {
1542 let token = self.cur_token.clone();
1543
1544 self.next_token();
1545 let lower = self.parse_expression(Precedence::Equals)?;
1546
1547 if !self.expect_keyword("AND") {
1548 return None;
1549 }
1550
1551 self.next_token();
1552 let upper = self.parse_expression(Precedence::Equals)?;
1553
1554 Some(Expression::Between(BetweenExpression {
1555 token,
1556 expr: Box::new(left),
1557 lower: Box::new(lower),
1558 upper: Box::new(upper),
1559 not,
1560 }))
1561 }
1562
1563 fn parse_like_expression(
1565 &mut self,
1566 left: Expression,
1567 op: SmartString,
1568 not: bool,
1569 ) -> Option<Expression> {
1570 let token = self.cur_token.clone();
1571 let operator = if not {
1572 SmartString::from_string(format!("NOT {}", op))
1573 } else {
1574 op
1575 };
1576 let precedence = self.cur_precedence();
1577
1578 self.next_token();
1579 let pattern = self.parse_expression(precedence)?;
1580
1581 let escape = if self.peek_token_is_keyword("ESCAPE") {
1583 self.next_token(); self.next_token(); let escape = self.parse_expression(Precedence::Lowest)?;
1586 match &escape {
1587 Expression::StringLiteral(lit) if lit.value.chars().count() == 1 => {}
1588 _ => {
1589 self.add_error(
1590 "LIKE ESCAPE must be a string literal containing exactly one character"
1591 .to_string(),
1592 );
1593 return None;
1594 }
1595 }
1596 Some(Box::new(escape))
1597 } else {
1598 None
1599 };
1600
1601 Some(Expression::Like(LikeExpression {
1602 token,
1603 left: Box::new(left),
1604 pattern: Box::new(pattern),
1605 operator,
1606 escape,
1607 }))
1608 }
1609
1610 fn parse_case_expression(&mut self) -> Option<Expression> {
1612 let token = self.cur_token.clone();
1613 let mut value = None;
1614 let mut when_clauses = Vec::new();
1615 let mut else_value = None;
1616
1617 if !self.peek_token_is_keyword("WHEN") {
1619 self.next_token();
1620 value = Some(Box::new(self.parse_expression(Precedence::Lowest)?));
1621 }
1622
1623 while self.peek_token_is_keyword("WHEN") {
1625 self.next_token(); let when_token = self.cur_token.clone();
1627
1628 self.next_token();
1629 let condition = self.parse_expression(Precedence::Lowest)?;
1630
1631 if !self.expect_keyword("THEN") {
1632 return None;
1633 }
1634
1635 self.next_token();
1636 let then_result = self.parse_expression(Precedence::Lowest)?;
1637
1638 when_clauses.push(WhenClause {
1639 token: when_token,
1640 condition,
1641 then_result,
1642 });
1643 }
1644
1645 if when_clauses.is_empty() {
1646 self.add_error(format!(
1647 "expected at least one WHEN clause in CASE at {}",
1648 self.cur_token.position
1649 ));
1650 return None;
1651 }
1652
1653 if self.peek_token_is_keyword("ELSE") {
1655 self.next_token(); self.next_token();
1657 else_value = Some(Box::new(self.parse_expression(Precedence::Lowest)?));
1658 }
1659
1660 if !self.expect_keyword("END") {
1661 return None;
1662 }
1663
1664 Some(Expression::Case(Box::new(CaseExpression {
1665 token,
1666 value,
1667 when_clauses,
1668 else_value,
1669 })))
1670 }
1671
1672 fn parse_cast_expression(&mut self) -> Option<Expression> {
1674 let token = self.cur_token.clone();
1675
1676 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
1677 self.add_error(format!(
1678 "expected '(' after CAST at {}",
1679 self.cur_token.position
1680 ));
1681 return None;
1682 }
1683
1684 self.next_token();
1685 let expr = self.parse_expression(Precedence::Equals)?;
1687
1688 if !self.expect_keyword("AS") {
1689 return None;
1690 }
1691
1692 let type_name = self.parse_column_data_type()?;
1693 if let Err(message) = validate_cast_type_name(&type_name) {
1694 self.add_error(message);
1695 return None;
1696 }
1697
1698 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1699 self.add_error(format!(
1700 "expected ')' after type name in CAST at {}",
1701 self.cur_token.position
1702 ));
1703 return None;
1704 }
1705
1706 Some(Expression::Cast(CastExpression {
1707 token,
1708 expr: Box::new(expr),
1709 type_name,
1710 }))
1711 }
1712
1713 fn parse_extract_expression(&mut self) -> Option<Expression> {
1716 let token = self.cur_token.clone();
1717
1718 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
1719 self.add_error(format!(
1720 "expected '(' after EXTRACT at {}",
1721 self.cur_token.position
1722 ));
1723 return None;
1724 }
1725
1726 if !self.peek_token_is(TokenType::Keyword) && !self.peek_token_is(TokenType::Identifier) {
1728 self.add_error(format!(
1729 "expected field name (YEAR, MONTH, DAY, etc.) in EXTRACT at {}",
1730 self.peek_token.position
1731 ));
1732 return None;
1733 }
1734 self.next_token();
1735 let field = self.cur_token.literal.to_uppercase();
1736
1737 let valid_fields = [
1739 "YEAR",
1740 "MONTH",
1741 "DAY",
1742 "HOUR",
1743 "MINUTE",
1744 "SECOND",
1745 "DOW",
1746 "DAYOFWEEK",
1747 "ISODOW",
1748 "DOY",
1749 "DAYOFYEAR",
1750 "WEEK",
1751 "ISOWEEK",
1752 "QUARTER",
1753 "EPOCH",
1754 "MILLISECOND",
1755 "MILLISECONDS",
1756 "MICROSECOND",
1757 "MICROSECONDS",
1758 ];
1759 if !valid_fields.contains(&field.as_str()) {
1760 self.add_error(format!(
1761 "invalid EXTRACT field '{}'. Valid fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DOW, DOY, WEEK, QUARTER, EPOCH, etc.",
1762 field
1763 ));
1764 return None;
1765 }
1766
1767 if !self.expect_keyword("FROM") {
1769 return None;
1770 }
1771
1772 self.next_token();
1774 let source = self.parse_expression(Precedence::Lowest)?;
1775
1776 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1777 self.add_error(format!(
1778 "expected ')' after source in EXTRACT at {}",
1779 self.cur_token.position
1780 ));
1781 return None;
1782 }
1783
1784 let basic_fields = ["YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"];
1787 if basic_fields.contains(&field.as_str()) {
1788 Some(Expression::FunctionCall(Box::new(FunctionCall {
1789 token,
1790 function: field,
1791 arguments: vec![source],
1792 is_distinct: false,
1793 order_by: Vec::new(),
1794 filter: None,
1795 })))
1796 } else {
1797 let field_literal = Expression::StringLiteral(StringLiteral {
1799 token: Token {
1800 token_type: TokenType::String,
1801 literal: field.to_lowercase(),
1802 position: token.position,
1803 quoted: false,
1804 },
1805 value: field.to_lowercase(),
1806 type_hint: None,
1807 });
1808 Some(Expression::FunctionCall(Box::new(FunctionCall {
1809 token,
1810 function: SmartString::const_new("EXTRACT"),
1811 arguments: vec![field_literal, source],
1812 is_distinct: false,
1813 order_by: Vec::new(),
1814 filter: None,
1815 })))
1816 }
1817 }
1818
1819 fn parse_exists_expression(&mut self) -> Option<Expression> {
1821 let token = self.cur_token.clone();
1822
1823 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
1824 self.add_error(format!(
1825 "expected '(' after EXISTS at {}",
1826 self.cur_token.position
1827 ));
1828 return None;
1829 }
1830
1831 self.next_token();
1832 if !self.cur_token_is_keyword("SELECT") {
1833 self.add_error(format!(
1834 "expected SELECT in EXISTS subquery at {}",
1835 self.cur_token.position
1836 ));
1837 return None;
1838 }
1839
1840 let subquery = self.parse_select_statement()?;
1841
1842 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
1843 self.add_error(format!(
1844 "expected ')' after EXISTS subquery at {}",
1845 self.cur_token.position
1846 ));
1847 return None;
1848 }
1849
1850 Some(Expression::Exists(ExistsExpression {
1851 token,
1852 subquery: Box::new(subquery),
1853 }))
1854 }
1855
1856 fn parse_not_expression(&mut self) -> Option<Expression> {
1858 let token = self.cur_token.clone();
1859
1860 if self.peek_token_is_keyword("EXISTS") {
1862 self.next_token();
1863 let exists_expr = self.parse_exists_expression()?;
1864 return Some(Expression::Prefix(PrefixExpression::new(
1865 token,
1866 "NOT".to_string(),
1867 Box::new(exists_expr),
1868 )));
1869 }
1870
1871 self.next_token();
1872 let right = self.parse_expression(Precedence::Not)?;
1875
1876 Some(Expression::Prefix(PrefixExpression::new(
1877 token,
1878 "NOT".to_string(),
1879 Box::new(right),
1880 )))
1881 }
1882
1883 fn parse_interval_literal(&mut self) -> Option<Expression> {
1888 let token = self.cur_token.clone();
1889
1890 if self.peek_token_is(TokenType::Integer) {
1892 self.next_token();
1894 let quantity = match self.cur_token.literal.parse::<i64>() {
1895 Ok(q) => q,
1896 Err(_) => {
1897 self.add_error(format!(
1898 "invalid interval quantity: {} at {}",
1899 self.cur_token.literal, self.cur_token.position
1900 ));
1901 return None;
1902 }
1903 };
1904
1905 self.next_token();
1907 let unit_raw = self.cur_token.literal.to_uppercase();
1908 let unit = match unit_raw.as_str() {
1909 "SECOND" | "SECONDS" => "second",
1910 "MINUTE" | "MINUTES" => "minute",
1911 "HOUR" | "HOURS" => "hour",
1912 "DAY" | "DAYS" => "day",
1913 "WEEK" | "WEEKS" => "week",
1914 "MONTH" | "MONTHS" => "month",
1915 "YEAR" | "YEARS" => "year",
1916 _ => {
1917 self.add_error(format!(
1918 "invalid interval unit: {} at {}. Expected SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR",
1919 self.cur_token.literal, self.cur_token.position
1920 ));
1921 return None;
1922 }
1923 };
1924
1925 let value = SmartString::from_string(format!("{} {}", quantity, unit));
1926 Some(Expression::IntervalLiteral(IntervalLiteral {
1927 token,
1928 value,
1929 quantity,
1930 unit: SmartString::new(unit),
1931 }))
1932 } else if self.expect_peek(TokenType::String) {
1933 let literal = &self.cur_token.literal;
1935 let value_str = if literal.len() >= 2 {
1936 &literal[1..literal.len() - 1]
1937 } else {
1938 literal.as_str()
1939 };
1940
1941 let parts: Vec<&str> = value_str.split_whitespace().collect();
1943 if parts.len() != 2 {
1944 self.add_error(format!(
1945 "invalid interval format: {} at {}",
1946 value_str, self.cur_token.position
1947 ));
1948 return None;
1949 }
1950
1951 let quantity = match parts[0].parse::<i64>() {
1952 Ok(q) => q,
1953 Err(_) => {
1954 self.add_error(format!(
1955 "invalid interval quantity: {} at {}",
1956 parts[0], self.cur_token.position
1957 ));
1958 return None;
1959 }
1960 };
1961
1962 let unit_raw = parts[1].to_ascii_uppercase();
1963 let unit = match unit_raw.as_str() {
1964 "SECOND" | "SECONDS" => "second",
1965 "MINUTE" | "MINUTES" => "minute",
1966 "HOUR" | "HOURS" => "hour",
1967 "DAY" | "DAYS" => "day",
1968 "WEEK" | "WEEKS" => "week",
1969 "MONTH" | "MONTHS" => "month",
1970 "YEAR" | "YEARS" => "year",
1971 _ => {
1972 self.add_error(format!(
1973 "invalid interval unit: {} at {}. Expected SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR",
1974 parts[1], self.cur_token.position
1975 ));
1976 return None;
1977 }
1978 };
1979
1980 Some(Expression::IntervalLiteral(IntervalLiteral {
1981 token,
1982 value: SmartString::from(value_str),
1983 quantity,
1984 unit: SmartString::new(unit),
1985 }))
1986 } else {
1987 None
1988 }
1989 }
1990
1991 fn parse_typed_literal(&mut self) -> Option<Expression> {
1993 let type_hint = self.cur_token.literal.clone();
1994
1995 if !self.peek_token_is(TokenType::String) {
1996 self.add_error(format!(
1997 "expected string literal after {} at {}",
1998 type_hint, self.cur_token.position
1999 ));
2000 return None;
2001 }
2002
2003 self.next_token();
2004
2005 let literal = &self.cur_token.literal;
2006 let value = if literal.len() >= 2 && literal.starts_with('\'') && literal.ends_with('\'') {
2007 SmartString::from(&literal[1..literal.len() - 1])
2008 } else {
2009 literal.clone()
2010 };
2011
2012 Some(Expression::StringLiteral(StringLiteral {
2013 token: self.cur_token.clone(),
2014 value,
2015 type_hint: Some(type_hint),
2016 }))
2017 }
2018
2019 pub fn parse_expression_list(&mut self) -> Vec<Expression> {
2021 let mut list = Vec::with_capacity(8);
2023
2024 self.next_token();
2025 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2026 list.push(expr);
2027 }
2028
2029 while self.peek_token_is_punctuator(",") {
2030 self.next_token(); self.next_token();
2032 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2033 list.push(expr);
2034 }
2035 }
2036
2037 list
2038 }
2039
2040 pub fn parse_group_by_clause(&mut self) -> GroupByClause {
2042 use crate::ast::{GroupByClause, GroupByModifier};
2043
2044 self.next_token();
2045
2046 let modifier = if self.cur_token.token_type == TokenType::Identifier
2048 || self.cur_token.token_type == TokenType::Keyword
2049 {
2050 let upper = self.cur_token.literal.to_uppercase();
2051 if upper == "ROLLUP" {
2052 self.next_token(); if self.cur_token.literal == "(" {
2055 self.next_token(); let columns = self.parse_group_by_columns();
2057 return GroupByClause {
2061 columns,
2062 modifier: GroupByModifier::Rollup,
2063 };
2064 }
2065 GroupByModifier::None
2066 } else if upper == "CUBE" {
2067 self.next_token(); if self.cur_token.literal == "(" {
2070 self.next_token(); let columns = self.parse_group_by_columns();
2072 return GroupByClause {
2075 columns,
2076 modifier: GroupByModifier::Cube,
2077 };
2078 }
2079 GroupByModifier::None
2080 } else if upper == "GROUPING" {
2081 if self.peek_token.literal.to_uppercase() == "SETS" {
2083 self.next_token(); self.next_token(); if self.cur_token.literal == "(" {
2087 self.next_token(); let sets = self.parse_grouping_sets();
2089 return GroupByClause {
2091 columns: Vec::new(),
2092 modifier: GroupByModifier::GroupingSets(sets),
2093 };
2094 }
2095 }
2096 GroupByModifier::None
2097 } else {
2098 GroupByModifier::None
2099 }
2100 } else {
2101 GroupByModifier::None
2102 };
2103
2104 let mut columns = Vec::new();
2106 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2107 columns.push(expr);
2108 }
2109
2110 while self.peek_token_is_punctuator(",") {
2111 self.next_token(); self.next_token();
2113 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2114 columns.push(expr);
2115 }
2116 }
2117
2118 GroupByClause { columns, modifier }
2119 }
2120
2121 fn parse_group_by_columns(&mut self) -> Vec<Expression> {
2123 let mut columns = Vec::new();
2124
2125 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2126 columns.push(expr);
2127 }
2128
2129 while self.peek_token_is_punctuator(",") {
2130 self.next_token(); self.next_token();
2132 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2133 columns.push(expr);
2134 }
2135 }
2136
2137 if self.peek_token_is_punctuator(")") {
2139 self.next_token();
2140 }
2141
2142 columns
2143 }
2144
2145 fn parse_grouping_sets(&mut self) -> Vec<Vec<Expression>> {
2148 let mut sets = Vec::new();
2149
2150 if self.cur_token.literal == "(" {
2152 sets.push(self.parse_single_grouping_set());
2153 }
2154
2155 while self.cur_token.literal == "," {
2157 self.next_token(); if self.cur_token.literal == "(" {
2159 sets.push(self.parse_single_grouping_set());
2160 }
2161 }
2162
2163 sets
2165 }
2166
2167 fn parse_single_grouping_set(&mut self) -> Vec<Expression> {
2169 let mut columns = Vec::new();
2170
2171 self.next_token(); if self.cur_token.literal == ")" {
2175 self.next_token(); return columns;
2177 }
2178
2179 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2181 columns.push(expr);
2182 }
2183
2184 while self.peek_token_is_punctuator(",") {
2186 self.next_token(); self.next_token(); if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2189 columns.push(expr);
2190 }
2191 }
2192
2193 if self.peek_token_is_punctuator(")") {
2195 self.next_token(); }
2197 self.next_token(); columns
2200 }
2201
2202 pub fn parse_window_definitions(&mut self) -> Vec<WindowDefinition> {
2204 let mut defs = Vec::new();
2205
2206 if let Some(def) = self.parse_single_window_definition() {
2208 defs.push(def);
2209 }
2210
2211 while self.peek_token_is_punctuator(",") {
2213 self.next_token(); self.next_token(); if let Some(def) = self.parse_single_window_definition() {
2216 defs.push(def);
2217 }
2218 }
2219
2220 defs
2221 }
2222
2223 fn parse_single_window_definition(&mut self) -> Option<WindowDefinition> {
2225 self.next_token(); let name = if self.cur_token_is(TokenType::Identifier) {
2229 self.cur_token.literal.clone()
2230 } else if self.cur_token_is(TokenType::Keyword) {
2231 self.cur_token.literal.clone()
2233 } else {
2234 self.add_error(format!(
2235 "expected window name at {}",
2236 self.cur_token.position
2237 ));
2238 return None;
2239 };
2240
2241 if !self.expect_keyword("AS") {
2243 return None;
2244 }
2245
2246 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != "(" {
2248 self.add_error(format!(
2249 "expected '(' after AS in window definition at {}",
2250 self.cur_token.position
2251 ));
2252 return None;
2253 }
2254
2255 let mut partition_by = Vec::new();
2256 let mut order_by = Vec::new();
2257 let mut frame = None;
2258
2259 if self.peek_token_is_keyword("PARTITION") {
2261 self.next_token(); if !self.expect_keyword("BY") {
2263 return None;
2264 }
2265
2266 self.next_token();
2267 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2268 partition_by.push(expr);
2269 }
2270
2271 while self.peek_token_is_punctuator(",") {
2272 self.next_token(); self.next_token();
2274 if let Some(expr) = self.parse_expression(Precedence::Lowest) {
2275 partition_by.push(expr);
2276 }
2277 }
2278 }
2279
2280 if self.peek_token_is_keyword("ORDER") {
2282 self.next_token(); if !self.expect_keyword("BY") {
2284 return None;
2285 }
2286
2287 self.next_token();
2288 if let Some(order_expr) = self.parse_order_by_expression() {
2289 order_by.push(order_expr);
2290 }
2291
2292 while self.peek_token_is_punctuator(",") {
2293 self.next_token(); self.next_token();
2295 if let Some(order_expr) = self.parse_order_by_expression() {
2296 order_by.push(order_expr);
2297 }
2298 }
2299 }
2300
2301 if self.peek_token_is_keyword("ROWS") || self.peek_token_is_keyword("RANGE") {
2303 frame = self.parse_window_frame();
2304 }
2305
2306 if !self.expect_peek(TokenType::Punctuator) || self.cur_token.literal != ")" {
2308 self.add_error(format!(
2309 "expected ')' after window specification at {}",
2310 self.cur_token.position
2311 ));
2312 return None;
2313 }
2314
2315 Some(WindowDefinition {
2316 name,
2317 partition_by,
2318 order_by,
2319 frame,
2320 })
2321 }
2322
2323 pub fn parse_order_by_expression(&mut self) -> Option<OrderByExpression> {
2325 let expression = self.parse_expression(Precedence::Lowest)?;
2326
2327 let mut ascending = true;
2328 if self.peek_token_is_keyword("ASC") {
2329 self.next_token();
2330 ascending = true;
2331 } else if self.peek_token_is_keyword("DESC") {
2332 self.next_token();
2333 ascending = false;
2334 }
2335
2336 let nulls_first = if self.peek_token_is_keyword("NULLS") {
2338 self.next_token(); if self.peek_token_is_keyword("FIRST") {
2340 self.next_token(); Some(true)
2342 } else if self.peek_token_is_keyword("LAST") {
2343 self.next_token(); Some(false)
2345 } else {
2346 self.add_error(format!(
2347 "expected FIRST or LAST after NULLS at {}",
2348 self.peek_token.position
2349 ));
2350 return None;
2351 }
2352 } else {
2353 None
2354 };
2355
2356 Some(OrderByExpression {
2357 expression,
2358 ascending,
2359 nulls_first,
2360 })
2361 }
2362
2363 pub fn parse_order_by_expressions(&mut self) -> Vec<OrderByExpression> {
2365 let mut list = Vec::new();
2366
2367 self.next_token();
2368 if let Some(expr) = self.parse_order_by_expression() {
2369 list.push(expr);
2370 }
2371
2372 while self.peek_token_is_punctuator(",") {
2373 self.next_token(); self.next_token();
2375 if let Some(expr) = self.parse_order_by_expression() {
2376 list.push(expr);
2377 }
2378 }
2379
2380 list
2381 }
2382}
2383
2384#[cfg(test)]
2385mod tests {
2386 use super::*;
2387
2388 fn parse_expr(input: &str) -> Option<Expression> {
2389 let mut parser = Parser::new(input);
2390 parser.parse_expression(Precedence::Lowest)
2391 }
2392
2393 #[test]
2394 fn test_parse_identifier() {
2395 let expr = parse_expr("users").unwrap();
2396 match expr {
2397 Expression::Identifier(id) => assert_eq!(id.value, "users"),
2398 _ => panic!("expected Identifier"),
2399 }
2400 }
2401
2402 #[test]
2403 fn test_parse_integer() {
2404 let expr = parse_expr("42").unwrap();
2405 match expr {
2406 Expression::IntegerLiteral(lit) => assert_eq!(lit.value, 42),
2407 _ => panic!("expected IntegerLiteral"),
2408 }
2409 }
2410
2411 #[test]
2412 fn test_parse_integer_i64_boundaries() {
2413 let mut max_parser = Parser::new("9223372036854775807");
2414 let max_expr = max_parser
2415 .parse_expression(Precedence::Lowest)
2416 .expect("i64::MAX should parse as an integer literal");
2417 assert!(max_parser.errors().is_empty());
2418 match max_expr {
2419 Expression::IntegerLiteral(lit) => assert_eq!(lit.value, i64::MAX),
2420 other => panic!("expected IntegerLiteral, got {other:?}"),
2421 }
2422
2423 let mut min_parser = Parser::new("-9223372036854775808");
2424 let min_expr = min_parser
2425 .parse_expression(Precedence::Lowest)
2426 .expect("i64::MIN should parse through the unary-minus special case");
2427 assert!(min_parser.errors().is_empty());
2428 match min_expr {
2429 Expression::IntegerLiteral(lit) => assert_eq!(lit.value, i64::MIN),
2430 other => panic!("expected IntegerLiteral, got {other:?}"),
2431 }
2432 }
2433
2434 #[test]
2435 fn test_parse_integer_overflow_is_an_error() {
2436 for literal in ["9223372036854775808", "-9223372036854775809"] {
2437 let mut parser = Parser::new(literal);
2438 let expression = parser.parse_expression(Precedence::Lowest);
2439
2440 assert!(expression.is_none(), "{literal} must not produce an AST");
2441 assert_eq!(
2442 parser.errors().len(),
2443 1,
2444 "{literal} must produce exactly one parser error"
2445 );
2446 assert!(
2447 parser.errors()[0]
2448 .message
2449 .contains("is out of range for i64"),
2450 "unexpected parser error for {literal}: {}",
2451 parser.errors()[0].message
2452 );
2453 }
2454 }
2455
2456 #[test]
2457 fn test_parse_float() {
2458 let expr = parse_expr("3.5").unwrap();
2459 match expr {
2460 Expression::FloatLiteral(lit) => assert!((lit.value - 3.5).abs() < 0.001),
2461 _ => panic!("expected FloatLiteral"),
2462 }
2463 }
2464
2465 #[test]
2466 fn test_parse_string() {
2467 let expr = parse_expr("'hello'").unwrap();
2468 match expr {
2469 Expression::StringLiteral(lit) => assert_eq!(lit.value, "hello"),
2470 _ => panic!("expected StringLiteral"),
2471 }
2472 }
2473
2474 #[test]
2475 fn test_parse_boolean() {
2476 let expr = parse_expr("TRUE").unwrap();
2477 match expr {
2478 Expression::BooleanLiteral(lit) => assert!(lit.value),
2479 _ => panic!("expected BooleanLiteral"),
2480 }
2481
2482 let expr = parse_expr("FALSE").unwrap();
2483 match expr {
2484 Expression::BooleanLiteral(lit) => assert!(!lit.value),
2485 _ => panic!("expected BooleanLiteral"),
2486 }
2487 }
2488
2489 #[test]
2490 fn test_parse_null() {
2491 let expr = parse_expr("NULL").unwrap();
2492 match expr {
2493 Expression::NullLiteral(_) => {}
2494 _ => panic!("expected NullLiteral"),
2495 }
2496 }
2497
2498 #[test]
2499 fn test_parse_infix() {
2500 let expr = parse_expr("1 + 2").unwrap();
2501 match expr {
2502 Expression::Infix(infix) => {
2503 assert_eq!(infix.operator, "+");
2504 }
2505 _ => panic!("expected InfixExpression"),
2506 }
2507 }
2508
2509 #[test]
2510 fn test_parse_precedence() {
2511 let expr = parse_expr("1 + 2 * 3").unwrap();
2512 match expr {
2514 Expression::Infix(infix) => {
2515 assert_eq!(infix.operator, "+");
2516 match infix.right.as_ref() {
2517 Expression::Infix(right) => {
2518 assert_eq!(right.operator, "*");
2519 }
2520 _ => panic!("expected nested InfixExpression"),
2521 }
2522 }
2523 _ => panic!("expected InfixExpression"),
2524 }
2525 }
2526
2527 #[test]
2528 fn test_expression_stops_before_statement_owned_alias() {
2529 let mut parser = Parser::new("1 AS answer");
2530 let expression = parser
2531 .parse_expression(Precedence::Lowest)
2532 .expect("integer expression should parse");
2533
2534 assert!(matches!(expression, Expression::IntegerLiteral(_)));
2535 assert!(parser.peek_token_is_keyword("AS"));
2536 }
2537
2538 #[test]
2539 fn test_parse_qualified_identifier() {
2540 let expr = parse_expr("users.id").unwrap();
2541 match expr {
2542 Expression::QualifiedIdentifier(qi) => {
2543 assert_eq!(qi.qualifier.value, "users");
2544 assert!(qi.intermediate.is_none());
2545 assert_eq!(qi.name.value, "id");
2546 assert_eq!(qi.component_count(), 2);
2547 }
2548 _ => panic!("expected QualifiedIdentifier"),
2549 }
2550 }
2551
2552 #[test]
2553 fn test_parse_multi_part_identifier_path_preserves_components_and_positions() {
2554 let expr = parse_expr("m.sender_id.profile_id.display_name").unwrap();
2555 let Expression::QualifiedIdentifier(path) = expr else {
2556 panic!("expected unresolved multi-part QualifiedIdentifier");
2557 };
2558
2559 let components: Vec<_> = path
2560 .components()
2561 .map(|component| {
2562 (
2563 component.value().to_string(),
2564 component.token.position.column,
2565 )
2566 })
2567 .collect();
2568 assert_eq!(
2569 components,
2570 vec![
2571 ("m".to_string(), 1),
2572 ("sender_id".to_string(), 3),
2573 ("profile_id".to_string(), 13),
2574 ("display_name".to_string(), 24),
2575 ]
2576 );
2577 assert_eq!(path.component_count(), 4);
2578 assert!(path.is_multi_part_path());
2579 assert_eq!(path.to_string(), "m.sender_id.profile_id.display_name");
2580 }
2581
2582 #[test]
2583 fn test_parse_identifier_path_supports_eight_components_and_roundtrip() {
2584 let sql = "a.b.c.d.e.f.g.h";
2585 let expr = parse_expr(sql).unwrap();
2586 let Expression::QualifiedIdentifier(path) = &expr else {
2587 panic!("expected eight-component path");
2588 };
2589 assert_eq!(path.component_count(), 8);
2590 assert_eq!(expr.to_string(), sql);
2591
2592 let reparsed = parse_expr(&expr.to_string()).unwrap();
2593 let Expression::QualifiedIdentifier(reparsed) = reparsed else {
2594 panic!("expected round-tripped path");
2595 };
2596 let values: Vec<_> = reparsed
2597 .components()
2598 .map(|component| component.value().to_string())
2599 .collect();
2600 assert_eq!(values, ["a", "b", "c", "d", "e", "f", "g", "h"]);
2601 }
2602
2603 #[test]
2604 fn test_parse_identifier_path_preserves_quoted_and_keyword_components() {
2605 let expr = parse_expr("\"Root\".type.\"Target Field\"").unwrap();
2606 let Expression::QualifiedIdentifier(path) = expr else {
2607 panic!("expected quoted identifier path");
2608 };
2609 let values: Vec<_> = path
2610 .components()
2611 .map(|component| component.value().to_string())
2612 .collect();
2613 assert_eq!(values, ["Root", "type", "Target Field"]);
2614 assert_eq!(path.to_string(), "\"Root\".type.\"Target Field\"");
2615 }
2616
2617 #[test]
2618 fn test_multi_part_qualified_star_is_rejected_without_breaking_table_star() {
2619 assert!(matches!(
2620 parse_expr("users.*").unwrap(),
2621 Expression::QualifiedStar(_)
2622 ));
2623
2624 let mut parser = Parser::new("users.profile_id.*");
2625 assert!(parser.parse_expression(Precedence::Lowest).is_none());
2626 assert!(parser
2627 .errors()
2628 .iter()
2629 .any(|error| error.message.contains("qualified star cannot follow")));
2630 }
2631
2632 #[test]
2633 fn test_parse_function_call() {
2634 let expr = parse_expr("COUNT(*)").unwrap();
2635 match expr {
2636 Expression::FunctionCall(fc) => {
2637 assert_eq!(fc.function, "COUNT");
2638 assert_eq!(fc.arguments.len(), 1);
2639 }
2640 _ => panic!("expected FunctionCall"),
2641 }
2642 }
2643
2644 #[test]
2645 fn test_parse_count_star_with_filter() {
2646 let expr = parse_expr("COUNT(*) FILTER (WHERE x = 1)").unwrap();
2647 match expr {
2648 Expression::FunctionCall(fc) => {
2649 assert_eq!(fc.function, "COUNT");
2650 assert_eq!(fc.arguments.len(), 1);
2651 assert!(
2652 fc.filter.is_some(),
2653 "FILTER clause should be parsed for COUNT(*)"
2654 );
2655 }
2656 _ => panic!("expected FunctionCall"),
2657 }
2658 }
2659
2660 #[test]
2661 fn test_parse_function_call_with_multiple_args() {
2662 let expr = parse_expr("STRING_AGG(name, '; ')").unwrap();
2663 match expr {
2664 Expression::FunctionCall(fc) => {
2665 assert_eq!(fc.function, "STRING_AGG");
2666 assert_eq!(
2667 fc.arguments.len(),
2668 2,
2669 "Expected 2 arguments, got: {:?}",
2670 fc.arguments
2671 );
2672 match &fc.arguments[0] {
2674 Expression::Identifier(id) => assert_eq!(id.value, "name"),
2675 other => panic!("Expected Identifier, got: {:?}", other),
2676 }
2677 match &fc.arguments[1] {
2679 Expression::StringLiteral(lit) => assert_eq!(lit.value, "; "),
2680 other => panic!("Expected StringLiteral, got: {:?}", other),
2681 }
2682 }
2683 _ => panic!("expected FunctionCall"),
2684 }
2685 }
2686
2687 #[test]
2688 fn test_parse_is_null() {
2689 let expr = parse_expr("x IS NULL").unwrap();
2690 match expr {
2691 Expression::Infix(infix) => {
2692 assert_eq!(infix.operator, "IS");
2693 }
2694 _ => panic!("expected InfixExpression"),
2695 }
2696 }
2697
2698 #[test]
2699 fn test_parse_is_not_null() {
2700 let expr = parse_expr("x IS NOT NULL").unwrap();
2701 match expr {
2702 Expression::Infix(infix) => {
2703 assert_eq!(infix.operator, "IS NOT");
2704 }
2705 _ => panic!("expected InfixExpression"),
2706 }
2707 }
2708
2709 #[test]
2710 fn test_parse_in() {
2711 let expr = parse_expr("x IN (1, 2, 3)").unwrap();
2712 match expr {
2713 Expression::In(in_expr) => {
2714 assert!(!in_expr.not);
2715 }
2716 _ => panic!("expected InExpression"),
2717 }
2718 }
2719
2720 #[test]
2721 fn test_parse_not_in() {
2722 let expr = parse_expr("x NOT IN (1, 2, 3)").unwrap();
2723 match expr {
2724 Expression::In(in_expr) => {
2725 assert!(in_expr.not);
2726 }
2727 _ => panic!("expected InExpression"),
2728 }
2729 }
2730
2731 #[test]
2732 fn test_parse_between() {
2733 let expr = parse_expr("x BETWEEN 1 AND 10").unwrap();
2734 match expr {
2735 Expression::Between(between) => {
2736 assert!(!between.not);
2737 }
2738 _ => panic!("expected BetweenExpression"),
2739 }
2740 }
2741
2742 #[test]
2743 fn test_parse_case() {
2744 let expr = parse_expr("CASE WHEN x = 1 THEN 'one' ELSE 'other' END").unwrap();
2745 match expr {
2746 Expression::Case(case) => {
2747 assert!(case.value.is_none());
2748 assert_eq!(case.when_clauses.len(), 1);
2749 assert!(case.else_value.is_some());
2750 }
2751 _ => panic!("expected CaseExpression"),
2752 }
2753 }
2754
2755 #[test]
2756 fn test_parse_cast() {
2757 let expr = parse_expr("CAST(x AS INTEGER)").unwrap();
2758 match expr {
2759 Expression::Cast(cast) => {
2760 assert_eq!(cast.type_name, "INTEGER");
2761 }
2762 _ => panic!("expected CastExpression"),
2763 }
2764 }
2765}