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