1use super::super::ast::{BinOp, Expr, ExprSubquery, FieldRef, Span, UnaryOp};
48use super::super::lexer::Token;
49use super::error::ParseError;
50use super::Parser;
51use super::PlaceholderMode;
52use crate::storage::schema::{DataType, Value};
53
54fn is_duration_unit(unit: &str) -> bool {
55 matches!(
56 unit.to_ascii_lowercase().as_str(),
57 "ms" | "msec"
58 | "millisecond"
59 | "milliseconds"
60 | "s"
61 | "sec"
62 | "secs"
63 | "second"
64 | "seconds"
65 | "m"
66 | "min"
67 | "mins"
68 | "minute"
69 | "minutes"
70 | "h"
71 | "hr"
72 | "hrs"
73 | "hour"
74 | "hours"
75 | "d"
76 | "day"
77 | "days"
78 )
79}
80
81fn keyword_function_name(token: &Token) -> Option<&'static str> {
82 match token {
83 Token::Count => Some("COUNT"),
84 Token::Sum => Some("SUM"),
85 Token::Avg => Some("AVG"),
86 Token::Min => Some("MIN"),
87 Token::Max => Some("MAX"),
88 Token::First => Some("FIRST"),
89 Token::Last => Some("LAST"),
90 Token::Left => Some("LEFT"),
91 Token::Right => Some("RIGHT"),
92 Token::Contains => Some("CONTAINS"),
93 Token::Kv => Some("KV"),
94 _ => None,
95 }
96}
97
98fn is_window_eligible_function(name: &str) -> bool {
104 matches!(
105 name.to_ascii_uppercase().as_str(),
106 "LAG"
108 | "LEAD"
109 | "ROW_NUMBER"
110 | "RANK"
111 | "DENSE_RANK"
112 | "PERCENT_RANK"
113 | "CUME_DIST"
114 | "NTILE"
115 | "FIRST_VALUE"
116 | "LAST_VALUE"
117 | "NTH_VALUE"
118 | "COUNT"
120 | "SUM"
121 | "AVG"
122 | "MIN"
123 | "MAX"
124 | "STDDEV"
125 | "VARIANCE"
126 | "MEDIAN"
127 | "PERCENTILE"
128 | "GROUP_CONCAT"
129 | "STRING_AGG"
130 | "FIRST"
131 | "LAST"
132 | "ARRAY_AGG"
133 | "COUNT_DISTINCT"
134 )
135}
136
137fn bare_zero_arg_function_name(name: &str) -> Option<&'static str> {
138 match name.to_ascii_uppercase().as_str() {
139 "CURRENT_TIMESTAMP" => Some("CURRENT_TIMESTAMP"),
140 "CURRENT_DATE" => Some("CURRENT_DATE"),
141 "CURRENT_TIME" => Some("CURRENT_TIME"),
142 _ => None,
143 }
144}
145
146impl<'a> Parser<'a> {
147 pub fn parse_expr(&mut self) -> Result<Expr, ParseError> {
150 self.parse_expr_prec(0)
151 }
152
153 pub(crate) fn parse_expr_with_min_precedence(
154 &mut self,
155 min_prec: u8,
156 ) -> Result<Expr, ParseError> {
157 self.parse_expr_prec(min_prec)
158 }
159
160 pub(crate) fn continue_expr(&mut self, left: Expr, min_prec: u8) -> Result<Expr, ParseError> {
163 self.parse_expr_suffix(left, min_prec)
164 }
165
166 fn parse_expr_prec(&mut self, min_prec: u8) -> Result<Expr, ParseError> {
169 self.enter_depth()?;
174 let result = (|| {
175 let left = self.parse_expr_unary()?;
176 self.parse_expr_suffix(left, min_prec)
177 })();
178 self.exit_depth();
179 result
180 }
181
182 fn parse_expr_suffix(&mut self, mut left: Expr, min_prec: u8) -> Result<Expr, ParseError> {
183 loop {
184 let Some((op, prec)) = self.peek_binop() else {
185 if min_prec <= 32 {
187 if let Some(node) = self.try_parse_postfix(&left)? {
188 left = node;
189 continue;
190 }
191 }
192 break;
193 };
194 if prec < min_prec {
195 break;
196 }
197 self.advance()?; let start_span = self.span_start_of(&left);
199 let rhs = self.parse_expr_prec(prec + 1)?;
200 let end_span = self.span_end_of(&rhs);
201 left = Expr::BinaryOp {
202 op,
203 lhs: Box::new(left),
204 rhs: Box::new(rhs),
205 span: Span::new(start_span, end_span),
206 };
207 }
208 Ok(left)
209 }
210
211 fn parse_expr_unary(&mut self) -> Result<Expr, ParseError> {
214 match self.peek() {
215 Token::Not => {
216 let start = self.position();
217 self.advance()?;
218 let operand = self.parse_expr_prec(25)?;
219 let end = self.span_end_of(&operand);
220 Ok(Expr::UnaryOp {
221 op: UnaryOp::Not,
222 operand: Box::new(operand),
223 span: Span::new(start, end),
224 })
225 }
226 Token::Dash => {
227 let start = self.position();
228 self.advance()?;
229 let operand = self.parse_expr_prec(70)?;
230 let end = self.span_end_of(&operand);
231 Ok(Expr::UnaryOp {
232 op: UnaryOp::Neg,
233 operand: Box::new(operand),
234 span: Span::new(start, end),
235 })
236 }
237 Token::Plus => {
238 self.advance()?;
240 self.parse_expr_prec(70)
241 }
242 _ => self.parse_expr_factor(),
243 }
244 }
245
246 fn parse_expr_factor(&mut self) -> Result<Expr, ParseError> {
249 let start = self.position();
250
251 if self.consume(&Token::LParen)? {
253 if self.check(&Token::Select) {
254 let query = self.parse_select_query()?;
255 self.expect(Token::RParen)?;
256 return Ok(Expr::Subquery {
257 query: ExprSubquery {
258 query: Box::new(query),
259 },
260 span: Span::new(start, self.position()),
261 });
262 }
263 let inner = self.parse_expr_prec(0)?;
264 self.expect(Token::RParen)?;
265 return Ok(inner);
266 }
267
268 if self.consume(&Token::True)? {
270 return Ok(Expr::Literal {
271 value: Value::Boolean(true),
272 span: Span::new(start, self.position()),
273 });
274 }
275 if self.consume(&Token::False)? {
276 return Ok(Expr::Literal {
277 value: Value::Boolean(false),
278 span: Span::new(start, self.position()),
279 });
280 }
281 if self.consume(&Token::Null)? {
282 return Ok(Expr::Literal {
283 value: Value::Null,
284 span: Span::new(start, self.position()),
285 });
286 }
287
288 if let Token::Integer(n) = *self.peek() {
292 self.advance()?;
293 if let Token::Ident(ref unit) = *self.peek() {
294 if is_duration_unit(unit) {
295 let duration = format!("{n}{}", unit.to_ascii_lowercase());
296 self.advance()?;
297 return Ok(Expr::Literal {
298 value: Value::text(duration),
299 span: Span::new(start, self.position()),
300 });
301 }
302 }
303 return Ok(Expr::Literal {
304 value: Value::Integer(n),
305 span: Span::new(start, self.position()),
306 });
307 }
308 if let Token::Float(n) = *self.peek() {
309 self.advance()?;
310 return Ok(Expr::Literal {
311 value: Value::Float(n),
312 span: Span::new(start, self.position()),
313 });
314 }
315 if let Token::String(ref s) = *self.peek() {
316 let text = s.clone();
317 self.advance()?;
318 return Ok(Expr::Literal {
319 value: Value::text(text),
320 span: Span::new(start, self.position()),
321 });
322 }
323
324 if matches!(
329 self.peek(),
330 Token::LBrace | Token::LBracket | Token::JsonLiteral(_)
331 ) {
332 let value = self
333 .parse_literal_value()
334 .map_err(|e| ParseError::new(e.message, self.position()))?;
335 return Ok(Expr::Literal {
336 value,
337 span: Span::new(start, self.position()),
338 });
339 }
340
341 if self.check(&Token::Question) {
345 let (index, span) = self.parse_question_param_index()?;
346 return Ok(Expr::Parameter { index, span });
347 }
348
349 if self.consume(&Token::Dollar)? {
350 if let Token::Integer(n) = *self.peek() {
355 if n < 1 {
356 return Err(ParseError::new(
357 "placeholder index must be >= 1".to_string(),
358 self.position(),
359 ));
360 }
361 if self.placeholder_mode == PlaceholderMode::Question {
362 return Err(ParseError::new(
363 "cannot mix `?` and `$N` placeholders in one statement".to_string(),
364 self.position(),
365 ));
366 }
367 self.placeholder_mode = PlaceholderMode::Dollar;
368 self.advance()?;
369 return Ok(Expr::Parameter {
370 index: (n - 1) as usize,
371 span: Span::new(start, self.position()),
372 });
373 }
374 let path = self.parse_dollar_ref_path()?;
375 let path_lc = path.to_ascii_lowercase();
376 let (name, key) = if let Some(rest) = path_lc.strip_prefix("secret.") {
377 ("__SECRET_REF", format!("red.vault/{rest}"))
378 } else if path_lc.starts_with("red.secret.") {
379 let rest = path_lc.trim_start_matches("red.secret.");
380 ("__SECRET_REF", format!("red.vault/{rest}"))
381 } else if let Some(rest) = path_lc.strip_prefix("config.") {
382 ("CONFIG", format!("red.config/{rest}"))
383 } else if path_lc.starts_with("red.config.") {
384 let rest = path_lc.trim_start_matches("red.config.");
385 ("CONFIG", format!("red.config/{rest}"))
386 } else {
387 return Err(ParseError::new(
388 format!(
389 "unknown $ reference `${path}`; expected $secret.*, $red.secret.*, $config.*, or $red.config.*"
390 ),
391 self.position(),
392 ));
393 };
394 return Ok(Expr::FunctionCall {
395 name: name.to_string(),
396 args: vec![Expr::Literal {
397 value: Value::text(key),
398 span: Span::new(start, self.position()),
399 }],
400 span: Span::new(start, self.position()),
401 });
402 }
403
404 if let Some(name) = keyword_function_name(self.peek()) {
405 if matches!(self.peek_next()?, Token::LParen) {
406 self.advance()?; return self.parse_function_call_expr_with_name(start, name.to_string());
408 }
409 }
410
411 if let Token::Ident(ref name) = *self.peek() {
419 let name_upper = name.to_uppercase();
420
421 if name_upper == "CASE" {
431 return self.parse_case_expr(start);
432 }
433
434 let saved_name = name.clone();
435 self.advance()?; if matches!(self.peek(), Token::LParen) {
439 return self.parse_function_call_expr_with_name(start, saved_name);
440 }
441
442 if let Some(function_name) = bare_zero_arg_function_name(&saved_name) {
443 let end = self.position();
444 return Ok(Expr::FunctionCall {
445 name: function_name.to_string(),
446 args: Vec::new(),
447 span: Span::new(start, end),
448 });
449 }
450
451 if matches!(self.peek(), Token::Dot) {
453 let mut segments = vec![saved_name];
454 while self.consume(&Token::Dot)? {
455 segments.push(self.expect_ident_or_keyword()?);
456 }
457 let field = FieldRef::TableColumn {
458 table: segments.remove(0),
459 column: segments.join("."),
460 };
461 let end = self.position();
462 return Ok(Expr::Column {
463 field,
464 span: Span::new(start, end),
465 });
466 }
467
468 let field = FieldRef::TableColumn {
470 table: String::new(),
471 column: saved_name,
472 };
473 let end = self.position();
474 return Ok(Expr::Column {
475 field,
476 span: Span::new(start, end),
477 });
478 }
479
480 let field = self.parse_field_ref()?;
485 let end = self.position();
486 Ok(Expr::Column {
487 field,
488 span: Span::new(start, end),
489 })
490 }
491
492 fn parse_dollar_ref_path(&mut self) -> Result<String, ParseError> {
493 let mut path = self.expect_ident_or_keyword()?;
494 while self.consume(&Token::Dot)? {
495 let next = self.expect_ident_or_keyword()?;
496 path = format!("{path}.{next}");
497 }
498 Ok(path)
499 }
500
501 fn parse_function_call_expr_with_name(
502 &mut self,
503 start: crate::storage::query::lexer::Position,
504 function_name: String,
505 ) -> Result<Expr, ParseError> {
506 let call = self.parse_function_call_expr_with_name_inner(start, function_name)?;
507 if matches!(self.peek(), Token::Over) {
513 return self.lift_to_window_call(start, call);
514 }
515 Ok(call)
516 }
517
518 fn parse_function_call_expr_with_name_inner(
519 &mut self,
520 start: crate::storage::query::lexer::Position,
521 function_name: String,
522 ) -> Result<Expr, ParseError> {
523 self.expect(Token::LParen)?;
524
525 if function_name.eq_ignore_ascii_case("CAST") {
526 let inner = self.parse_expr_prec(0)?;
527 self.expect(Token::As)?;
528 let type_name = self.expect_ident_or_keyword()?;
529 self.expect(Token::RParen)?;
530 let end = self.position();
531 let Some(target) = DataType::from_sql_name(&type_name) else {
532 return Err(ParseError::new(
533 format!("unknown type name {type_name:?} in CAST"),
537 self.position(),
538 ));
539 };
540 return Ok(Expr::Cast {
541 inner: Box::new(inner),
542 target,
543 span: Span::new(start, end),
544 });
545 }
546
547 if function_name.eq_ignore_ascii_case("TRIM") {
548 let (name, args) = self.parse_trim_expr_args()?;
549 self.expect(Token::RParen)?;
550 let end = self.position();
551 return Ok(Expr::FunctionCall {
552 name,
553 args,
554 span: Span::new(start, end),
555 });
556 }
557
558 if function_name.eq_ignore_ascii_case("POSITION") {
559 let args = self.parse_position_expr_args()?;
560 self.expect(Token::RParen)?;
561 let end = self.position();
562 return Ok(Expr::FunctionCall {
563 name: function_name,
564 args,
565 span: Span::new(start, end),
566 });
567 }
568
569 if function_name.eq_ignore_ascii_case("SUBSTRING") {
570 let args = self.parse_substring_expr_args()?;
571 self.expect(Token::RParen)?;
572 let end = self.position();
573 return Ok(Expr::FunctionCall {
574 name: function_name,
575 args,
576 span: Span::new(start, end),
577 });
578 }
579
580 if function_name.eq_ignore_ascii_case("COUNT") {
581 if self.consume(&Token::Distinct)? {
582 let arg = self.parse_expr_prec(0)?;
583 self.expect(Token::RParen)?;
584 let end = self.position();
585 return Ok(Expr::FunctionCall {
586 name: "COUNT_DISTINCT".to_string(),
587 args: vec![arg],
588 span: Span::new(start, end),
589 });
590 }
591
592 if self.consume(&Token::Star)? {
593 self.expect(Token::RParen)?;
594 let end = self.position();
595 return Ok(Expr::FunctionCall {
596 name: function_name,
597 args: vec![Expr::Column {
598 field: FieldRef::TableColumn {
599 table: String::new(),
600 column: "*".to_string(),
601 },
602 span: Span::synthetic(),
603 }],
604 span: Span::new(start, end),
605 });
606 }
607 }
608
609 let mut args = Vec::new();
610 if !self.check(&Token::RParen) {
611 loop {
612 args.push(self.parse_expr_prec(0)?);
613 if !self.consume(&Token::Comma)? {
614 break;
615 }
616 }
617 }
618 self.expect(Token::RParen)?;
619 let end = self.position();
620 Ok(Expr::FunctionCall {
621 name: function_name,
622 args,
623 span: Span::new(start, end),
624 })
625 }
626
627 fn lift_to_window_call(
634 &mut self,
635 start: crate::storage::query::lexer::Position,
636 call: Expr,
637 ) -> Result<Expr, ParseError> {
638 let (name, args) = match call {
639 Expr::FunctionCall { name, args, .. } => (name, args),
640 other => {
641 return Err(ParseError::new(
642 format!(
643 "OVER may only follow a function call, got {:?}",
644 std::mem::discriminant(&other)
645 ),
646 self.position(),
647 ));
648 }
649 };
650 if !is_window_eligible_function(&name) {
651 return Err(ParseError::new(
652 format!(
653 "function `{}` cannot be used with an OVER clause; \
654 expected a window function (LAG, LEAD, ROW_NUMBER, \
655 RANK, DENSE_RANK) or an aggregate",
656 name.to_uppercase()
657 ),
658 self.position(),
659 ));
660 }
661 let window = self.parse_over_clause()?;
662 let end = self.position();
663 Ok(Expr::WindowFunctionCall {
664 name,
665 args,
666 window,
667 span: Span::new(start, end),
668 })
669 }
670
671 fn parse_over_clause(&mut self) -> Result<crate::storage::query::ast::WindowSpec, ParseError> {
674 self.expect(Token::Over)?;
675 self.expect(Token::LParen)?;
676
677 let mut spec = crate::storage::query::ast::WindowSpec::default();
678
679 if self.consume(&Token::Partition)? {
680 self.expect(Token::By)?;
681 loop {
682 spec.partition_by.push(self.parse_expr_prec(0)?);
683 if !self.consume(&Token::Comma)? {
684 break;
685 }
686 }
687 }
688
689 if self.consume(&Token::Order)? {
690 self.expect(Token::By)?;
691 loop {
692 let expr = self.parse_expr_prec(0)?;
693 let ascending = if self.consume(&Token::Desc)? {
694 false
695 } else {
696 self.consume(&Token::Asc)?;
697 true
698 };
699 let mut nulls_first = !ascending;
702 if self.consume(&Token::Nulls)? {
703 if self.consume(&Token::First)? {
704 nulls_first = true;
705 } else if self.consume(&Token::Last)? {
706 nulls_first = false;
707 } else {
708 return Err(ParseError::new(
709 "expected FIRST or LAST after NULLS".to_string(),
710 self.position(),
711 ));
712 }
713 }
714 spec.order_by
715 .push(crate::storage::query::ast::WindowOrderItem {
716 expr,
717 ascending,
718 nulls_first,
719 });
720 if !self.consume(&Token::Comma)? {
721 break;
722 }
723 }
724 }
725
726 if matches!(self.peek(), Token::Rows | Token::Range) {
727 spec.frame = Some(self.parse_window_frame()?);
728 }
729
730 self.expect(Token::RParen)?;
731 Ok(spec)
732 }
733
734 fn parse_window_frame(
735 &mut self,
736 ) -> Result<crate::storage::query::ast::WindowFrame, ParseError> {
737 let unit = if self.consume(&Token::Rows)? {
738 crate::storage::query::ast::WindowFrameUnit::Rows
739 } else if self.consume(&Token::Range)? {
740 crate::storage::query::ast::WindowFrameUnit::Range
741 } else {
742 return Err(ParseError::new(
743 "expected ROWS or RANGE in window frame".to_string(),
744 self.position(),
745 ));
746 };
747
748 if self.consume(&Token::Between)? {
749 let start = self.parse_window_frame_bound()?;
750 self.expect(Token::And)?;
751 let end = self.parse_window_frame_bound()?;
752 Ok(crate::storage::query::ast::WindowFrame {
753 unit,
754 start,
755 end: Some(end),
756 })
757 } else {
758 let start = self.parse_window_frame_bound()?;
759 Ok(crate::storage::query::ast::WindowFrame {
760 unit,
761 start,
762 end: None,
763 })
764 }
765 }
766
767 fn parse_window_frame_bound(
768 &mut self,
769 ) -> Result<crate::storage::query::ast::WindowFrameBound, ParseError> {
770 use crate::storage::query::ast::WindowFrameBound;
771 if self.consume(&Token::Unbounded)? {
772 if self.consume(&Token::Preceding)? {
773 return Ok(WindowFrameBound::UnboundedPreceding);
774 }
775 if self.consume(&Token::Following)? {
776 return Ok(WindowFrameBound::UnboundedFollowing);
777 }
778 return Err(ParseError::new(
779 "expected PRECEDING or FOLLOWING after UNBOUNDED".to_string(),
780 self.position(),
781 ));
782 }
783 if self.consume(&Token::Current)? {
784 self.expect(Token::Row)?;
785 return Ok(WindowFrameBound::CurrentRow);
786 }
787 let offset = self.parse_expr_prec(0)?;
789 if self.consume(&Token::Preceding)? {
790 return Ok(WindowFrameBound::Preceding(Box::new(offset)));
791 }
792 if self.consume(&Token::Following)? {
793 return Ok(WindowFrameBound::Following(Box::new(offset)));
794 }
795 Err(ParseError::new(
796 "expected PRECEDING or FOLLOWING after frame offset".to_string(),
797 self.position(),
798 ))
799 }
800
801 fn parse_case_expr(
804 &mut self,
805 start: crate::storage::query::lexer::Position,
806 ) -> Result<Expr, ParseError> {
807 self.advance()?; let mut branches: Vec<(Expr, Expr)> = Vec::new();
809 loop {
810 if !self.consume_ident_ci("WHEN")? {
811 break;
812 }
813 let cond = self.parse_expr_prec(0)?;
814 if !self.consume_ident_ci("THEN")? {
815 return Err(ParseError::new(
816 "expected THEN after CASE WHEN condition".to_string(),
817 self.position(),
818 ));
819 }
820 let then_val = self.parse_expr_prec(0)?;
821 branches.push((cond, then_val));
822 }
823 if branches.is_empty() {
824 return Err(ParseError::new(
825 "CASE must have at least one WHEN branch".to_string(),
826 self.position(),
827 ));
828 }
829 let else_ = if self.consume_ident_ci("ELSE")? {
830 Some(Box::new(self.parse_expr_prec(0)?))
831 } else {
832 None
833 };
834 if !self.consume_ident_ci("END")? {
835 return Err(ParseError::new(
836 "expected END to close CASE expression".to_string(),
837 self.position(),
838 ));
839 }
840 let end = self.position();
841 Ok(Expr::Case {
842 branches,
843 else_,
844 span: Span::new(start, end),
845 })
846 }
847
848 fn parse_trim_expr_args(&mut self) -> Result<(String, Vec<Expr>), ParseError> {
849 let mut function_name = "TRIM".to_string();
850
851 if self.consume_ident_ci("LEADING")? {
852 function_name = "LTRIM".to_string();
853 } else if self.consume_ident_ci("TRAILING")? {
854 function_name = "RTRIM".to_string();
855 } else if self.consume_ident_ci("BOTH")? {
856 function_name = "TRIM".to_string();
857 }
858
859 if self.consume(&Token::From)? {
860 let source = self.parse_expr_prec(0)?;
861 return Ok((function_name, vec![source]));
862 }
863
864 let first = self.parse_expr_prec(0)?;
865
866 if self.consume(&Token::Comma)? {
867 let second = self.parse_expr_prec(0)?;
868 return Ok((function_name, vec![first, second]));
869 }
870
871 if self.consume(&Token::From)? {
872 let source = self.parse_expr_prec(0)?;
873 return Ok((function_name, vec![source, first]));
874 }
875
876 Ok((function_name, vec![first]))
877 }
878
879 fn parse_position_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
883 let needle = self.parse_expr_prec(35)?;
887 if !self.consume(&Token::Comma)? {
888 self.expect(Token::In)?;
889 }
890 let haystack = self.parse_expr_prec(0)?;
891 Ok(vec![needle, haystack])
892 }
893
894 fn parse_substring_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
902 let source = self.parse_expr_prec(0)?;
903
904 if self.consume(&Token::Comma)? {
905 let mut args = vec![source];
906 loop {
907 args.push(self.parse_expr_prec(0)?);
908 if !self.consume(&Token::Comma)? {
909 break;
910 }
911 }
912 return Ok(args);
913 }
914
915 if self.consume(&Token::From)? {
916 let start = self.parse_expr_prec(0)?;
917 if self.consume(&Token::For)? {
918 let count = self.parse_expr_prec(0)?;
919 return Ok(vec![source, start, count]);
920 }
921 return Ok(vec![source, start]);
922 }
923
924 if self.consume(&Token::For)? {
925 let count = self.parse_expr_prec(0)?;
926 if self.consume(&Token::From)? {
927 let start = self.parse_expr_prec(0)?;
928 return Ok(vec![source, start, count]);
929 }
930 return Ok(vec![source, Expr::lit(Value::Integer(1)), count]);
931 }
932
933 Ok(vec![source])
934 }
935
936 fn try_parse_postfix(&mut self, left: &Expr) -> Result<Option<Expr>, ParseError> {
946 let start = self.span_start_of(left);
947
948 if self.consume(&Token::Is)? {
950 let negated = self.consume(&Token::Not)?;
951 self.expect(Token::Null)?;
952 let end = self.position();
953 return Ok(Some(Expr::IsNull {
954 operand: Box::new(left.clone()),
955 negated,
956 span: Span::new(start, end),
957 }));
958 }
959
960 let negated = if matches!(self.peek(), Token::Not) {
964 self.advance()?;
965 if !matches!(self.peek(), Token::Between | Token::In) {
966 return Err(ParseError::new(
967 "expected BETWEEN or IN after postfix NOT".to_string(),
968 self.position(),
969 ));
970 }
971 true
972 } else {
973 false
974 };
975
976 if self.consume(&Token::Between)? {
978 let low = self.parse_expr_prec(34)?;
979 self.expect(Token::And)?;
980 let high = self.parse_expr_prec(34)?;
981 let end = self.position();
982 return Ok(Some(Expr::Between {
983 target: Box::new(left.clone()),
984 low: Box::new(low),
985 high: Box::new(high),
986 negated,
987 span: Span::new(start, end),
988 }));
989 }
990
991 if self.consume(&Token::In)? {
993 self.expect(Token::LParen)?;
994 let mut values = Vec::new();
995 if self.check(&Token::Select) {
996 let query = self.parse_select_query()?;
997 values.push(Expr::Subquery {
998 query: ExprSubquery {
999 query: Box::new(query),
1000 },
1001 span: Span::new(self.span_start_of(left), self.position()),
1002 });
1003 } else if !self.check(&Token::RParen) {
1004 loop {
1005 values.push(self.parse_expr_prec(0)?);
1006 if !self.consume(&Token::Comma)? {
1007 break;
1008 }
1009 }
1010 }
1011 self.expect(Token::RParen)?;
1012 let end = self.position();
1013 return Ok(Some(Expr::InList {
1014 target: Box::new(left.clone()),
1015 values,
1016 negated,
1017 span: Span::new(start, end),
1018 }));
1019 }
1020
1021 if negated {
1022 return Err(ParseError::new(
1026 "internal: NOT consumed without BETWEEN/IN follow".to_string(),
1027 self.position(),
1028 ));
1029 }
1030 Ok(None)
1031 }
1032
1033 fn peek_binop(&self) -> Option<(BinOp, u8)> {
1037 let op = match self.peek() {
1038 Token::Or => BinOp::Or,
1039 Token::And => BinOp::And,
1040 Token::Eq => BinOp::Eq,
1041 Token::Ne => BinOp::Ne,
1042 Token::Lt => BinOp::Lt,
1043 Token::Le => BinOp::Le,
1044 Token::Gt => BinOp::Gt,
1045 Token::Ge => BinOp::Ge,
1046 Token::DoublePipe => BinOp::Concat,
1047 Token::Plus => BinOp::Add,
1048 Token::Dash => BinOp::Sub,
1049 Token::Star => BinOp::Mul,
1050 Token::Slash => BinOp::Div,
1051 Token::Percent => BinOp::Mod,
1052 _ => return None,
1053 };
1054 Some((op, op.precedence()))
1055 }
1056
1057 fn span_start_of(&self, expr: &Expr) -> crate::storage::query::lexer::Position {
1062 let s = expr.span();
1063 if s.is_synthetic() {
1064 self.position()
1065 } else {
1066 s.start
1067 }
1068 }
1069
1070 fn span_end_of(&self, expr: &Expr) -> crate::storage::query::lexer::Position {
1073 let s = expr.span();
1074 if s.is_synthetic() {
1075 self.position()
1076 } else {
1077 s.end
1078 }
1079 }
1080}
1081
1082#[allow(dead_code)]
1085fn _expr_module_used(_: Expr) {}
1086
1087#[cfg(test)]
1088mod tests {
1089 use super::*;
1090 use crate::storage::query::ast::FieldRef;
1091
1092 fn parse(input: &str) -> Expr {
1093 let mut parser = Parser::new(input).expect("lexer init");
1094 let expr = parser.parse_expr().expect("parse_expr");
1095 expr
1096 }
1097
1098 #[test]
1099 fn literal_integer() {
1100 let e = parse("42");
1101 match e {
1102 Expr::Literal {
1103 value: Value::Integer(42),
1104 ..
1105 } => {}
1106 other => panic!("expected Integer(42), got {other:?}"),
1107 }
1108 }
1109
1110 #[test]
1111 fn literal_float() {
1112 let e = parse("3.14");
1113 match e {
1114 Expr::Literal {
1115 value: Value::Float(f),
1116 ..
1117 } => assert!((f - 3.14).abs() < 1e-9),
1118 other => panic!("expected float literal, got {other:?}"),
1119 }
1120 }
1121
1122 #[test]
1123 fn literal_string() {
1124 let e = parse("'hello'");
1125 match e {
1126 Expr::Literal {
1127 value: Value::Text(ref s),
1128 ..
1129 } if s.as_ref() == "hello" => {}
1130 other => panic!("expected Text(hello), got {other:?}"),
1131 }
1132 }
1133
1134 #[test]
1135 fn literal_booleans_and_null() {
1136 assert!(matches!(
1137 parse("TRUE"),
1138 Expr::Literal {
1139 value: Value::Boolean(true),
1140 ..
1141 }
1142 ));
1143 assert!(matches!(
1144 parse("FALSE"),
1145 Expr::Literal {
1146 value: Value::Boolean(false),
1147 ..
1148 }
1149 ));
1150 assert!(matches!(
1151 parse("NULL"),
1152 Expr::Literal {
1153 value: Value::Null,
1154 ..
1155 }
1156 ));
1157 }
1158
1159 #[test]
1160 fn bare_column() {
1161 let e = parse("user_id");
1162 match e {
1163 Expr::Column {
1164 field: FieldRef::TableColumn { column, .. },
1165 ..
1166 } => {
1167 assert_eq!(column, "user_id");
1168 }
1169 other => panic!("expected column, got {other:?}"),
1170 }
1171 }
1172
1173 #[test]
1174 fn arithmetic_precedence_mul_over_add() {
1175 let e = parse("a + b * c");
1177 let Expr::BinaryOp {
1178 op: BinOp::Add,
1179 rhs,
1180 ..
1181 } = e
1182 else {
1183 panic!("root must be Add");
1184 };
1185 let Expr::BinaryOp { op: BinOp::Mul, .. } = *rhs else {
1186 panic!("rhs must be Mul");
1187 };
1188 }
1189
1190 #[test]
1191 fn arithmetic_left_associativity() {
1192 let e = parse("a - b - c");
1194 let Expr::BinaryOp {
1195 op: BinOp::Sub,
1196 lhs,
1197 ..
1198 } = e
1199 else {
1200 panic!("root must be Sub");
1201 };
1202 let Expr::BinaryOp { op: BinOp::Sub, .. } = *lhs else {
1203 panic!("lhs must be Sub (left-assoc)");
1204 };
1205 }
1206
1207 #[test]
1208 fn parenthesised_override() {
1209 let e = parse("(a + b) * c");
1211 let Expr::BinaryOp {
1212 op: BinOp::Mul,
1213 lhs,
1214 ..
1215 } = e
1216 else {
1217 panic!("root must be Mul");
1218 };
1219 let Expr::BinaryOp { op: BinOp::Add, .. } = *lhs else {
1220 panic!("lhs must be Add");
1221 };
1222 }
1223
1224 #[test]
1225 fn comparison_binds_weaker_than_arith() {
1226 let e = parse("a + 1 = b - 2");
1229 let Expr::BinaryOp {
1230 op: BinOp::Eq,
1231 lhs,
1232 rhs,
1233 ..
1234 } = e
1235 else {
1236 panic!("root must be Eq");
1237 };
1238 assert!(matches!(*lhs, Expr::BinaryOp { op: BinOp::Add, .. }));
1239 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::Sub, .. }));
1240 }
1241
1242 #[test]
1243 fn and_binds_tighter_than_or() {
1244 let e = parse("a OR b AND c");
1246 let Expr::BinaryOp {
1247 op: BinOp::Or, rhs, ..
1248 } = e
1249 else {
1250 panic!("root must be Or");
1251 };
1252 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::And, .. }));
1253 }
1254
1255 #[test]
1256 fn unary_negation() {
1257 let e = parse("-a");
1258 let Expr::UnaryOp {
1259 op: UnaryOp::Neg, ..
1260 } = e
1261 else {
1262 panic!("expected unary Neg");
1263 };
1264 }
1265
1266 #[test]
1267 fn unary_not() {
1268 let e = parse("NOT a");
1269 let Expr::UnaryOp {
1270 op: UnaryOp::Not, ..
1271 } = e
1272 else {
1273 panic!("expected unary Not");
1274 };
1275 }
1276
1277 #[test]
1278 fn concat_operator() {
1279 let e = parse("'hello' || name");
1280 let Expr::BinaryOp {
1281 op: BinOp::Concat, ..
1282 } = e
1283 else {
1284 panic!("expected Concat");
1285 };
1286 }
1287
1288 #[test]
1289 fn cast_expr() {
1290 let e = parse("CAST(age AS TEXT)");
1291 let Expr::Cast { target, .. } = e else {
1292 panic!("expected Cast");
1293 };
1294 assert_eq!(target, DataType::Text);
1295 }
1296
1297 #[test]
1298 fn case_expr() {
1299 let e = parse("CASE WHEN a = 1 THEN 'one' WHEN a = 2 THEN 'two' ELSE 'other' END");
1300 let Expr::Case {
1301 branches, else_, ..
1302 } = e
1303 else {
1304 panic!("expected Case");
1305 };
1306 assert_eq!(branches.len(), 2);
1307 assert!(else_.is_some());
1308 }
1309
1310 #[test]
1311 fn is_null_postfix() {
1312 let e = parse("name IS NULL");
1313 assert!(matches!(e, Expr::IsNull { negated: false, .. }));
1314 }
1315
1316 #[test]
1317 fn is_not_null_postfix() {
1318 let e = parse("name IS NOT NULL");
1319 assert!(matches!(e, Expr::IsNull { negated: true, .. }));
1320 }
1321
1322 #[test]
1323 fn between_with_columns() {
1324 let e = parse("temp BETWEEN min_t AND max_t");
1325 let Expr::Between {
1326 target,
1327 low,
1328 high,
1329 negated,
1330 ..
1331 } = e
1332 else {
1333 panic!("expected Between");
1334 };
1335 assert!(!negated);
1336 assert!(matches!(*target, Expr::Column { .. }));
1337 assert!(matches!(*low, Expr::Column { .. }));
1338 assert!(matches!(*high, Expr::Column { .. }));
1339 }
1340
1341 #[test]
1342 fn not_between_negates() {
1343 let e = parse("temp NOT BETWEEN 0 AND 100");
1344 let Expr::Between { negated: true, .. } = e else {
1345 panic!("expected negated Between");
1346 };
1347 }
1348
1349 #[test]
1350 fn in_list_literal() {
1351 let e = parse("status IN (1, 2, 3)");
1352 let Expr::InList {
1353 values, negated, ..
1354 } = e
1355 else {
1356 panic!("expected InList");
1357 };
1358 assert!(!negated);
1359 assert_eq!(values.len(), 3);
1360 }
1361
1362 #[test]
1363 fn not_in_list() {
1364 let e = parse("status NOT IN (1, 2)");
1365 let Expr::InList { negated: true, .. } = e else {
1366 panic!("expected negated InList");
1367 };
1368 }
1369
1370 #[test]
1371 fn function_call_with_args() {
1372 let e = parse("UPPER(name)");
1373 let Expr::FunctionCall { name, args, .. } = e else {
1374 panic!("expected FunctionCall");
1375 };
1376 assert_eq!(name, "UPPER");
1377 assert_eq!(args.len(), 1);
1378 }
1379
1380 #[test]
1381 fn nested_function_call() {
1382 let e = parse("COALESCE(a, UPPER(b))");
1383 let Expr::FunctionCall { name, args, .. } = e else {
1384 panic!("expected FunctionCall");
1385 };
1386 assert_eq!(name, "COALESCE");
1387 assert_eq!(args.len(), 2);
1388 assert!(matches!(&args[1], Expr::FunctionCall { .. }));
1389 }
1390
1391 #[test]
1392 fn duration_literal_parses_as_text() {
1393 let e = parse("time_bucket(5m)");
1394 let Expr::FunctionCall { name, args, .. } = e else {
1395 panic!("expected FunctionCall, got {e:?}");
1396 };
1397 assert_eq!(name.to_uppercase(), "TIME_BUCKET");
1398 assert_eq!(args.len(), 1);
1399 assert!(
1400 matches!(&args[0], Expr::Literal { value: Value::Text(s), .. } if s.as_ref() == "5m"),
1401 "expected Text(\"5m\"), got {:?}",
1402 args[0]
1403 );
1404 }
1405
1406 #[test]
1407 fn placeholder_dollar_one() {
1408 let e = parse("$1");
1409 match e {
1410 Expr::Parameter { index: 0, .. } => {}
1411 other => panic!("expected Parameter(0), got {other:?}"),
1412 }
1413 }
1414
1415 #[test]
1416 fn placeholder_dollar_n() {
1417 let e = parse("$7");
1418 match e {
1419 Expr::Parameter { index: 6, .. } => {}
1420 other => panic!("expected Parameter(6), got {other:?}"),
1421 }
1422 }
1423
1424 #[test]
1425 fn placeholder_in_string_literal_is_text() {
1426 let e = parse("'$1'");
1428 match e {
1429 Expr::Literal {
1430 value: Value::Text(s),
1431 ..
1432 } if s.as_ref() == "$1" => {}
1433 other => panic!("expected text literal '$1', got {other:?}"),
1434 }
1435 }
1436
1437 #[test]
1438 fn placeholder_in_comparison() {
1439 let e = parse("id = $1");
1441 let Expr::BinaryOp {
1442 op: BinOp::Eq, rhs, ..
1443 } = e
1444 else {
1445 panic!("root must be Eq");
1446 };
1447 assert!(matches!(*rhs, Expr::Parameter { index: 0, .. }));
1448 }
1449
1450 #[test]
1451 fn placeholder_zero_rejected() {
1452 let mut parser = Parser::new("$0").expect("lexer");
1453 let err = parser.parse_expr().unwrap_err();
1454 assert!(err.to_string().contains("placeholder"));
1455 }
1456
1457 #[test]
1458 fn placeholder_question_single() {
1459 let e = parse("?");
1461 match e {
1462 Expr::Parameter { index: 0, .. } => {}
1463 other => panic!("expected Parameter(0), got {other:?}"),
1464 }
1465 }
1466
1467 #[test]
1468 fn placeholder_question_numbered() {
1469 let e = parse("?7");
1470 match e {
1471 Expr::Parameter { index: 6, .. } => {}
1472 other => panic!("expected Parameter(6), got {other:?}"),
1473 }
1474 }
1475
1476 #[test]
1477 fn placeholder_question_numbered_zero_rejected() {
1478 let mut parser = Parser::new("?0").expect("lexer");
1479 let err = parser.parse_expr().unwrap_err();
1480 assert!(err.to_string().contains("placeholder"));
1481 }
1482
1483 #[test]
1484 fn placeholder_question_left_to_right() {
1485 let e = parse("id = ? AND name = ?");
1487 let Expr::BinaryOp {
1488 op: BinOp::And,
1489 lhs,
1490 rhs,
1491 ..
1492 } = e
1493 else {
1494 panic!("root must be And");
1495 };
1496 let Expr::BinaryOp {
1497 op: BinOp::Eq,
1498 rhs: r1,
1499 ..
1500 } = *lhs
1501 else {
1502 panic!("lhs must be Eq");
1503 };
1504 assert!(matches!(*r1, Expr::Parameter { index: 0, .. }));
1505 let Expr::BinaryOp {
1506 op: BinOp::Eq,
1507 rhs: r2,
1508 ..
1509 } = *rhs
1510 else {
1511 panic!("rhs must be Eq");
1512 };
1513 assert!(matches!(*r2, Expr::Parameter { index: 1, .. }));
1514 }
1515
1516 #[test]
1517 fn placeholder_question_in_string_literal_is_text() {
1518 let e = parse("'?'");
1519 match e {
1520 Expr::Literal {
1521 value: Value::Text(s),
1522 ..
1523 } if s.as_ref() == "?" => {}
1524 other => panic!("expected text literal '?', got {other:?}"),
1525 }
1526 }
1527
1528 #[test]
1529 fn placeholder_mixing_question_then_dollar_rejected() {
1530 let mut parser = Parser::new("id = ? AND x = $2").expect("lexer");
1531 let err = parser.parse_expr().err().expect("should fail");
1532 assert!(
1533 err.to_string().contains("mix"),
1534 "expected mixing error, got: {err}"
1535 );
1536 }
1537
1538 #[test]
1539 fn placeholder_mixing_dollar_then_question_rejected() {
1540 let mut parser = Parser::new("id = $1 AND x = ?").expect("lexer");
1541 let err = parser.parse_expr().err().expect("should fail");
1542 assert!(
1543 err.to_string().contains("mix"),
1544 "expected mixing error, got: {err}"
1545 );
1546 }
1547
1548 #[test]
1549 fn placeholder_question_in_comment_ignored() {
1550 let mut parser = Parser::new("-- ? ignored\n ?").expect("lexer");
1553 let e = parser.parse_expr().expect("parse_expr");
1554 match e {
1555 Expr::Parameter { index: 0, .. } => {}
1556 other => panic!("expected Parameter(0), got {other:?}"),
1557 }
1558 }
1559
1560 #[test]
1561 fn span_tracks_token_range() {
1562 let mut parser = Parser::new("123 + 456").expect("lexer");
1564 let e = parser.parse_expr().expect("parse_expr");
1565 let span = e.span();
1566 assert!(!span.is_synthetic(), "root span must be real");
1567 assert!(span.start.offset < span.end.offset);
1568 }
1569
1570 fn try_parse(input: &str) -> Result<Expr, ParseError> {
1575 let mut parser = Parser::new(input).expect("lexer init");
1576 parser.parse_expr()
1577 }
1578
1579 #[test]
1580 fn window_lag_partition_and_order() {
1581 let e = parse("LAG(ts) OVER (PARTITION BY user_id ORDER BY ts)");
1582 let Expr::WindowFunctionCall {
1583 name, args, window, ..
1584 } = e
1585 else {
1586 panic!("expected WindowFunctionCall");
1587 };
1588 assert_eq!(name.to_uppercase(), "LAG");
1589 assert_eq!(args.len(), 1);
1590 assert_eq!(window.partition_by.len(), 1);
1591 assert_eq!(window.order_by.len(), 1);
1592 assert!(window.order_by[0].ascending);
1593 assert!(window.frame.is_none());
1594 }
1595
1596 #[test]
1597 fn window_row_number_empty_over() {
1598 let e = parse("ROW_NUMBER() OVER ()");
1599 let Expr::WindowFunctionCall {
1600 name, args, window, ..
1601 } = e
1602 else {
1603 panic!("expected WindowFunctionCall");
1604 };
1605 assert_eq!(name.to_uppercase(), "ROW_NUMBER");
1606 assert!(args.is_empty());
1607 assert!(window.partition_by.is_empty());
1608 assert!(window.order_by.is_empty());
1609 assert!(window.frame.is_none());
1610 }
1611
1612 #[test]
1613 fn window_sum_with_frame_rows_between() {
1614 let e = parse(
1615 "SUM(amount) OVER (PARTITION BY user_id ORDER BY ts \
1616 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)",
1617 );
1618 let Expr::WindowFunctionCall { name, window, .. } = e else {
1619 panic!("expected WindowFunctionCall");
1620 };
1621 assert_eq!(name.to_uppercase(), "SUM");
1622 let frame = window.frame.expect("frame present");
1623 assert!(matches!(
1624 frame.unit,
1625 crate::storage::query::ast::WindowFrameUnit::Rows
1626 ));
1627 assert!(matches!(
1628 frame.start,
1629 crate::storage::query::ast::WindowFrameBound::Preceding(_)
1630 ));
1631 assert!(matches!(
1632 frame.end,
1633 Some(crate::storage::query::ast::WindowFrameBound::CurrentRow)
1634 ));
1635 }
1636
1637 #[test]
1638 fn window_rank_order_desc_multiple_keys() {
1639 let e = parse("RANK() OVER (ORDER BY score DESC, ts)");
1640 let Expr::WindowFunctionCall { window, .. } = e else {
1641 panic!("expected WindowFunctionCall");
1642 };
1643 assert_eq!(window.order_by.len(), 2);
1644 assert!(!window.order_by[0].ascending);
1645 assert!(window.order_by[1].ascending);
1646 }
1647
1648 #[test]
1649 fn window_unbounded_preceding_following_frame() {
1650 let e = parse(
1651 "AVG(x) OVER (ORDER BY t \
1652 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)",
1653 );
1654 let Expr::WindowFunctionCall { window, .. } = e else {
1655 panic!("expected WindowFunctionCall");
1656 };
1657 let frame = window.frame.expect("frame present");
1658 assert!(matches!(
1659 frame.unit,
1660 crate::storage::query::ast::WindowFrameUnit::Range
1661 ));
1662 assert!(matches!(
1663 frame.start,
1664 crate::storage::query::ast::WindowFrameBound::UnboundedPreceding
1665 ));
1666 assert!(matches!(
1667 frame.end,
1668 Some(crate::storage::query::ast::WindowFrameBound::UnboundedFollowing)
1669 ));
1670 }
1671
1672 #[test]
1673 fn window_rejects_non_window_function() {
1674 let err = try_parse("UPPER(name) OVER (PARTITION BY id)")
1676 .err()
1677 .expect("should reject scalar OVER");
1678 let msg = err.to_string();
1679 assert!(
1680 msg.contains("UPPER") || msg.contains("upper"),
1681 "error should mention function name, got: {msg}"
1682 );
1683 assert!(msg.to_ascii_uppercase().contains("OVER") || msg.contains("window"));
1684 }
1685
1686 #[test]
1687 fn window_rejects_missing_open_paren() {
1688 let err = try_parse("LAG(ts) OVER PARTITION BY user_id")
1689 .err()
1690 .expect("should reject");
1691 let msg = err.to_string();
1692 assert!(
1693 msg.contains("(") || msg.to_ascii_uppercase().contains("EXPECTED"),
1694 "got: {msg}"
1695 );
1696 }
1697
1698 #[test]
1699 fn window_rejects_invalid_frame_syntax() {
1700 let err = try_parse("LAG(ts) OVER (ORDER BY ts ROWS CURRENT)")
1702 .err()
1703 .expect("should reject");
1704 let msg = err.to_string();
1705 assert!(
1706 !msg.is_empty(),
1707 "expected non-empty error for malformed frame"
1708 );
1709 }
1710
1711 #[test]
1712 fn window_first_value_with_partition_only() {
1713 let e = parse("FIRST_VALUE(price) OVER (PARTITION BY symbol)");
1714 let Expr::WindowFunctionCall {
1715 name, window, args, ..
1716 } = e
1717 else {
1718 panic!("expected WindowFunctionCall");
1719 };
1720 assert_eq!(name.to_uppercase(), "FIRST_VALUE");
1721 assert_eq!(args.len(), 1);
1722 assert_eq!(window.partition_by.len(), 1);
1723 assert!(window.order_by.is_empty());
1724 }
1725}