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 if function_name.eq_ignore_ascii_case("CONFIG") || function_name.eq_ignore_ascii_case("KV")
620 {
621 let mut args = Vec::new();
622 if !self.check(&Token::RParen) {
623 loop {
624 args.push(self.parse_config_kv_arg(start)?);
625 if !self.consume(&Token::Comma)? {
626 break;
627 }
628 }
629 }
630 self.expect(Token::RParen)?;
631 let end = self.position();
632 return Ok(Expr::FunctionCall {
633 name: function_name,
634 args,
635 span: Span::new(start, end),
636 });
637 }
638
639 let mut args = Vec::new();
640 if !self.check(&Token::RParen) {
641 loop {
642 args.push(self.parse_expr_prec(0)?);
643 if !self.consume(&Token::Comma)? {
644 break;
645 }
646 }
647 }
648 self.expect(Token::RParen)?;
649 let end = self.position();
650 Ok(Expr::FunctionCall {
651 name: function_name,
652 args,
653 span: Span::new(start, end),
654 })
655 }
656
657 fn parse_config_kv_arg(
664 &mut self,
665 start: crate::storage::query::lexer::Position,
666 ) -> Result<Expr, ParseError> {
667 let mut is_expression_start = matches!(
672 self.peek(),
673 Token::String(_)
674 | Token::Integer(_)
675 | Token::Float(_)
676 | Token::Dollar
677 | Token::Question
678 | Token::LParen
679 );
680 if matches!(self.peek(), Token::Ident(_)) && matches!(self.peek_next()?, Token::LParen) {
683 is_expression_start = true;
684 }
685 if !is_expression_start && !self.check(&Token::RParen) {
686 let mut path = self.expect_ident_or_keyword()?;
687 while self.consume(&Token::Dot)? {
688 let next = self.expect_ident_or_keyword()?;
689 path = format!("{path}.{next}");
690 }
691 let end = self.position();
692 return Ok(Expr::Literal {
693 value: Value::text(path.to_ascii_lowercase()),
694 span: Span::new(start, end),
695 });
696 }
697 self.parse_expr_prec(0)
698 }
699
700 fn lift_to_window_call(
707 &mut self,
708 start: crate::storage::query::lexer::Position,
709 call: Expr,
710 ) -> Result<Expr, ParseError> {
711 let (name, args) = match call {
712 Expr::FunctionCall { name, args, .. } => (name, args),
713 other => {
714 return Err(ParseError::new(
715 format!(
716 "OVER may only follow a function call, got {:?}",
717 std::mem::discriminant(&other)
718 ),
719 self.position(),
720 ));
721 }
722 };
723 if !is_window_eligible_function(&name) {
724 return Err(ParseError::new(
725 format!(
726 "function `{}` cannot be used with an OVER clause; \
727 expected a window function (LAG, LEAD, ROW_NUMBER, \
728 RANK, DENSE_RANK) or an aggregate",
729 name.to_uppercase()
730 ),
731 self.position(),
732 ));
733 }
734 let window = self.parse_over_clause()?;
735 let end = self.position();
736 Ok(Expr::WindowFunctionCall {
737 name,
738 args,
739 window,
740 span: Span::new(start, end),
741 })
742 }
743
744 fn parse_over_clause(&mut self) -> Result<crate::storage::query::ast::WindowSpec, ParseError> {
747 self.expect(Token::Over)?;
748 self.expect(Token::LParen)?;
749
750 let mut spec = crate::storage::query::ast::WindowSpec::default();
751
752 if self.consume(&Token::Partition)? {
753 self.expect(Token::By)?;
754 loop {
755 spec.partition_by.push(self.parse_expr_prec(0)?);
756 if !self.consume(&Token::Comma)? {
757 break;
758 }
759 }
760 }
761
762 if self.consume(&Token::Order)? {
763 self.expect(Token::By)?;
764 loop {
765 let expr = self.parse_expr_prec(0)?;
766 let ascending = if self.consume(&Token::Desc)? {
767 false
768 } else {
769 self.consume(&Token::Asc)?;
770 true
771 };
772 let mut nulls_first = !ascending;
775 if self.consume(&Token::Nulls)? {
776 if self.consume(&Token::First)? {
777 nulls_first = true;
778 } else if self.consume(&Token::Last)? {
779 nulls_first = false;
780 } else {
781 return Err(ParseError::new(
782 "expected FIRST or LAST after NULLS".to_string(),
783 self.position(),
784 ));
785 }
786 }
787 spec.order_by
788 .push(crate::storage::query::ast::WindowOrderItem {
789 expr,
790 ascending,
791 nulls_first,
792 });
793 if !self.consume(&Token::Comma)? {
794 break;
795 }
796 }
797 }
798
799 if matches!(self.peek(), Token::Rows | Token::Range) {
800 spec.frame = Some(self.parse_window_frame()?);
801 }
802
803 self.expect(Token::RParen)?;
804 Ok(spec)
805 }
806
807 fn parse_window_frame(
808 &mut self,
809 ) -> Result<crate::storage::query::ast::WindowFrame, ParseError> {
810 let unit = if self.consume(&Token::Rows)? {
811 crate::storage::query::ast::WindowFrameUnit::Rows
812 } else if self.consume(&Token::Range)? {
813 crate::storage::query::ast::WindowFrameUnit::Range
814 } else {
815 return Err(ParseError::new(
816 "expected ROWS or RANGE in window frame".to_string(),
817 self.position(),
818 ));
819 };
820
821 if self.consume(&Token::Between)? {
822 let start = self.parse_window_frame_bound()?;
823 self.expect(Token::And)?;
824 let end = self.parse_window_frame_bound()?;
825 Ok(crate::storage::query::ast::WindowFrame {
826 unit,
827 start,
828 end: Some(end),
829 })
830 } else {
831 let start = self.parse_window_frame_bound()?;
832 Ok(crate::storage::query::ast::WindowFrame {
833 unit,
834 start,
835 end: None,
836 })
837 }
838 }
839
840 fn parse_window_frame_bound(
841 &mut self,
842 ) -> Result<crate::storage::query::ast::WindowFrameBound, ParseError> {
843 use crate::storage::query::ast::WindowFrameBound;
844 if self.consume(&Token::Unbounded)? {
845 if self.consume(&Token::Preceding)? {
846 return Ok(WindowFrameBound::UnboundedPreceding);
847 }
848 if self.consume(&Token::Following)? {
849 return Ok(WindowFrameBound::UnboundedFollowing);
850 }
851 return Err(ParseError::new(
852 "expected PRECEDING or FOLLOWING after UNBOUNDED".to_string(),
853 self.position(),
854 ));
855 }
856 if self.consume(&Token::Current)? {
857 self.expect(Token::Row)?;
858 return Ok(WindowFrameBound::CurrentRow);
859 }
860 let offset = self.parse_expr_prec(0)?;
862 if self.consume(&Token::Preceding)? {
863 return Ok(WindowFrameBound::Preceding(Box::new(offset)));
864 }
865 if self.consume(&Token::Following)? {
866 return Ok(WindowFrameBound::Following(Box::new(offset)));
867 }
868 Err(ParseError::new(
869 "expected PRECEDING or FOLLOWING after frame offset".to_string(),
870 self.position(),
871 ))
872 }
873
874 fn parse_case_expr(
877 &mut self,
878 start: crate::storage::query::lexer::Position,
879 ) -> Result<Expr, ParseError> {
880 self.advance()?; let mut branches: Vec<(Expr, Expr)> = Vec::new();
882 loop {
883 if !self.consume_ident_ci("WHEN")? {
884 break;
885 }
886 let cond = self.parse_expr_prec(0)?;
887 if !self.consume_ident_ci("THEN")? {
888 return Err(ParseError::new(
889 "expected THEN after CASE WHEN condition".to_string(),
890 self.position(),
891 ));
892 }
893 let then_val = self.parse_expr_prec(0)?;
894 branches.push((cond, then_val));
895 }
896 if branches.is_empty() {
897 return Err(ParseError::new(
898 "CASE must have at least one WHEN branch".to_string(),
899 self.position(),
900 ));
901 }
902 let else_ = if self.consume_ident_ci("ELSE")? {
903 Some(Box::new(self.parse_expr_prec(0)?))
904 } else {
905 None
906 };
907 if !self.consume_ident_ci("END")? {
908 return Err(ParseError::new(
909 "expected END to close CASE expression".to_string(),
910 self.position(),
911 ));
912 }
913 let end = self.position();
914 Ok(Expr::Case {
915 branches,
916 else_,
917 span: Span::new(start, end),
918 })
919 }
920
921 fn parse_trim_expr_args(&mut self) -> Result<(String, Vec<Expr>), ParseError> {
922 let mut function_name = "TRIM".to_string();
923
924 if self.consume_ident_ci("LEADING")? {
925 function_name = "LTRIM".to_string();
926 } else if self.consume_ident_ci("TRAILING")? {
927 function_name = "RTRIM".to_string();
928 } else if self.consume_ident_ci("BOTH")? {
929 function_name = "TRIM".to_string();
930 }
931
932 if self.consume(&Token::From)? {
933 let source = self.parse_expr_prec(0)?;
934 return Ok((function_name, vec![source]));
935 }
936
937 let first = self.parse_expr_prec(0)?;
938
939 if self.consume(&Token::Comma)? {
940 let second = self.parse_expr_prec(0)?;
941 return Ok((function_name, vec![first, second]));
942 }
943
944 if self.consume(&Token::From)? {
945 let source = self.parse_expr_prec(0)?;
946 return Ok((function_name, vec![source, first]));
947 }
948
949 Ok((function_name, vec![first]))
950 }
951
952 fn parse_position_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
956 let needle = self.parse_expr_prec(35)?;
960 if !self.consume(&Token::Comma)? {
961 self.expect(Token::In)?;
962 }
963 let haystack = self.parse_expr_prec(0)?;
964 Ok(vec![needle, haystack])
965 }
966
967 fn parse_substring_expr_args(&mut self) -> Result<Vec<Expr>, ParseError> {
975 let source = self.parse_expr_prec(0)?;
976
977 if self.consume(&Token::Comma)? {
978 let mut args = vec![source];
979 loop {
980 args.push(self.parse_expr_prec(0)?);
981 if !self.consume(&Token::Comma)? {
982 break;
983 }
984 }
985 return Ok(args);
986 }
987
988 if self.consume(&Token::From)? {
989 let start = self.parse_expr_prec(0)?;
990 if self.consume(&Token::For)? {
991 let count = self.parse_expr_prec(0)?;
992 return Ok(vec![source, start, count]);
993 }
994 return Ok(vec![source, start]);
995 }
996
997 if self.consume(&Token::For)? {
998 let count = self.parse_expr_prec(0)?;
999 if self.consume(&Token::From)? {
1000 let start = self.parse_expr_prec(0)?;
1001 return Ok(vec![source, start, count]);
1002 }
1003 return Ok(vec![source, Expr::lit(Value::Integer(1)), count]);
1004 }
1005
1006 Ok(vec![source])
1007 }
1008
1009 fn try_parse_postfix(&mut self, left: &Expr) -> Result<Option<Expr>, ParseError> {
1019 let start = self.span_start_of(left);
1020
1021 if self.consume(&Token::Is)? {
1023 let negated = self.consume(&Token::Not)?;
1024 self.expect(Token::Null)?;
1025 let end = self.position();
1026 return Ok(Some(Expr::IsNull {
1027 operand: Box::new(left.clone()),
1028 negated,
1029 span: Span::new(start, end),
1030 }));
1031 }
1032
1033 let negated = if matches!(self.peek(), Token::Not) {
1037 self.advance()?;
1038 if !matches!(self.peek(), Token::Between | Token::In) {
1039 return Err(ParseError::new(
1040 "expected BETWEEN or IN after postfix NOT".to_string(),
1041 self.position(),
1042 ));
1043 }
1044 true
1045 } else {
1046 false
1047 };
1048
1049 if self.consume(&Token::Between)? {
1051 let low = self.parse_expr_prec(34)?;
1052 self.expect(Token::And)?;
1053 let high = self.parse_expr_prec(34)?;
1054 let end = self.position();
1055 return Ok(Some(Expr::Between {
1056 target: Box::new(left.clone()),
1057 low: Box::new(low),
1058 high: Box::new(high),
1059 negated,
1060 span: Span::new(start, end),
1061 }));
1062 }
1063
1064 if self.consume(&Token::In)? {
1066 self.expect(Token::LParen)?;
1067 let mut values = Vec::new();
1068 if self.check(&Token::Select) {
1069 let query = self.parse_select_query()?;
1070 values.push(Expr::Subquery {
1071 query: ExprSubquery {
1072 query: Box::new(query),
1073 },
1074 span: Span::new(self.span_start_of(left), self.position()),
1075 });
1076 } else if !self.check(&Token::RParen) {
1077 loop {
1078 values.push(self.parse_expr_prec(0)?);
1079 if !self.consume(&Token::Comma)? {
1080 break;
1081 }
1082 }
1083 }
1084 self.expect(Token::RParen)?;
1085 let end = self.position();
1086 return Ok(Some(Expr::InList {
1087 target: Box::new(left.clone()),
1088 values,
1089 negated,
1090 span: Span::new(start, end),
1091 }));
1092 }
1093
1094 if negated {
1095 return Err(ParseError::new(
1099 "internal: NOT consumed without BETWEEN/IN follow".to_string(),
1100 self.position(),
1101 ));
1102 }
1103 Ok(None)
1104 }
1105
1106 fn peek_binop(&self) -> Option<(BinOp, u8)> {
1110 let op = match self.peek() {
1111 Token::Or => BinOp::Or,
1112 Token::And => BinOp::And,
1113 Token::Eq => BinOp::Eq,
1114 Token::Ne => BinOp::Ne,
1115 Token::Lt => BinOp::Lt,
1116 Token::Le => BinOp::Le,
1117 Token::Gt => BinOp::Gt,
1118 Token::Ge => BinOp::Ge,
1119 Token::DoublePipe => BinOp::Concat,
1120 Token::Plus => BinOp::Add,
1121 Token::Dash => BinOp::Sub,
1122 Token::Star => BinOp::Mul,
1123 Token::Slash => BinOp::Div,
1124 Token::Percent => BinOp::Mod,
1125 _ => return None,
1126 };
1127 Some((op, op.precedence()))
1128 }
1129
1130 fn span_start_of(&self, expr: &Expr) -> crate::storage::query::lexer::Position {
1135 let s = expr.span();
1136 if s.is_synthetic() {
1137 self.position()
1138 } else {
1139 s.start
1140 }
1141 }
1142
1143 fn span_end_of(&self, expr: &Expr) -> crate::storage::query::lexer::Position {
1146 let s = expr.span();
1147 if s.is_synthetic() {
1148 self.position()
1149 } else {
1150 s.end
1151 }
1152 }
1153}
1154
1155#[allow(dead_code)]
1158fn _expr_module_used(_: Expr) {}
1159
1160#[cfg(test)]
1161mod tests {
1162 use super::*;
1163 use crate::storage::query::ast::FieldRef;
1164
1165 fn parse(input: &str) -> Expr {
1166 let mut parser = Parser::new(input).expect("lexer init");
1167 let expr = parser.parse_expr().expect("parse_expr");
1168 expr
1169 }
1170
1171 #[test]
1172 fn literal_integer() {
1173 let e = parse("42");
1174 match e {
1175 Expr::Literal {
1176 value: Value::Integer(42),
1177 ..
1178 } => {}
1179 other => panic!("expected Integer(42), got {other:?}"),
1180 }
1181 }
1182
1183 #[test]
1184 fn literal_float() {
1185 let e = parse("3.14");
1186 match e {
1187 Expr::Literal {
1188 value: Value::Float(f),
1189 ..
1190 } => assert!((f - 3.14).abs() < 1e-9),
1191 other => panic!("expected float literal, got {other:?}"),
1192 }
1193 }
1194
1195 #[test]
1196 fn literal_string() {
1197 let e = parse("'hello'");
1198 match e {
1199 Expr::Literal {
1200 value: Value::Text(ref s),
1201 ..
1202 } if s.as_ref() == "hello" => {}
1203 other => panic!("expected Text(hello), got {other:?}"),
1204 }
1205 }
1206
1207 #[test]
1208 fn literal_booleans_and_null() {
1209 assert!(matches!(
1210 parse("TRUE"),
1211 Expr::Literal {
1212 value: Value::Boolean(true),
1213 ..
1214 }
1215 ));
1216 assert!(matches!(
1217 parse("FALSE"),
1218 Expr::Literal {
1219 value: Value::Boolean(false),
1220 ..
1221 }
1222 ));
1223 assert!(matches!(
1224 parse("NULL"),
1225 Expr::Literal {
1226 value: Value::Null,
1227 ..
1228 }
1229 ));
1230 }
1231
1232 #[test]
1233 fn bare_column() {
1234 let e = parse("user_id");
1235 match e {
1236 Expr::Column {
1237 field: FieldRef::TableColumn { column, .. },
1238 ..
1239 } => {
1240 assert_eq!(column, "user_id");
1241 }
1242 other => panic!("expected column, got {other:?}"),
1243 }
1244 }
1245
1246 #[test]
1247 fn arithmetic_precedence_mul_over_add() {
1248 let e = parse("a + b * c");
1250 let Expr::BinaryOp {
1251 op: BinOp::Add,
1252 rhs,
1253 ..
1254 } = e
1255 else {
1256 panic!("root must be Add");
1257 };
1258 let Expr::BinaryOp { op: BinOp::Mul, .. } = *rhs else {
1259 panic!("rhs must be Mul");
1260 };
1261 }
1262
1263 #[test]
1264 fn arithmetic_left_associativity() {
1265 let e = parse("a - b - c");
1267 let Expr::BinaryOp {
1268 op: BinOp::Sub,
1269 lhs,
1270 ..
1271 } = e
1272 else {
1273 panic!("root must be Sub");
1274 };
1275 let Expr::BinaryOp { op: BinOp::Sub, .. } = *lhs else {
1276 panic!("lhs must be Sub (left-assoc)");
1277 };
1278 }
1279
1280 #[test]
1281 fn parenthesised_override() {
1282 let e = parse("(a + b) * c");
1284 let Expr::BinaryOp {
1285 op: BinOp::Mul,
1286 lhs,
1287 ..
1288 } = e
1289 else {
1290 panic!("root must be Mul");
1291 };
1292 let Expr::BinaryOp { op: BinOp::Add, .. } = *lhs else {
1293 panic!("lhs must be Add");
1294 };
1295 }
1296
1297 #[test]
1298 fn comparison_binds_weaker_than_arith() {
1299 let e = parse("a + 1 = b - 2");
1302 let Expr::BinaryOp {
1303 op: BinOp::Eq,
1304 lhs,
1305 rhs,
1306 ..
1307 } = e
1308 else {
1309 panic!("root must be Eq");
1310 };
1311 assert!(matches!(*lhs, Expr::BinaryOp { op: BinOp::Add, .. }));
1312 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::Sub, .. }));
1313 }
1314
1315 #[test]
1316 fn and_binds_tighter_than_or() {
1317 let e = parse("a OR b AND c");
1319 let Expr::BinaryOp {
1320 op: BinOp::Or, rhs, ..
1321 } = e
1322 else {
1323 panic!("root must be Or");
1324 };
1325 assert!(matches!(*rhs, Expr::BinaryOp { op: BinOp::And, .. }));
1326 }
1327
1328 #[test]
1329 fn unary_negation() {
1330 let e = parse("-a");
1331 let Expr::UnaryOp {
1332 op: UnaryOp::Neg, ..
1333 } = e
1334 else {
1335 panic!("expected unary Neg");
1336 };
1337 }
1338
1339 #[test]
1340 fn unary_not() {
1341 let e = parse("NOT a");
1342 let Expr::UnaryOp {
1343 op: UnaryOp::Not, ..
1344 } = e
1345 else {
1346 panic!("expected unary Not");
1347 };
1348 }
1349
1350 #[test]
1351 fn concat_operator() {
1352 let e = parse("'hello' || name");
1353 let Expr::BinaryOp {
1354 op: BinOp::Concat, ..
1355 } = e
1356 else {
1357 panic!("expected Concat");
1358 };
1359 }
1360
1361 #[test]
1362 fn cast_expr() {
1363 let e = parse("CAST(age AS TEXT)");
1364 let Expr::Cast { target, .. } = e else {
1365 panic!("expected Cast");
1366 };
1367 assert_eq!(target, DataType::Text);
1368 }
1369
1370 #[test]
1371 fn case_expr() {
1372 let e = parse("CASE WHEN a = 1 THEN 'one' WHEN a = 2 THEN 'two' ELSE 'other' END");
1373 let Expr::Case {
1374 branches, else_, ..
1375 } = e
1376 else {
1377 panic!("expected Case");
1378 };
1379 assert_eq!(branches.len(), 2);
1380 assert!(else_.is_some());
1381 }
1382
1383 #[test]
1384 fn is_null_postfix() {
1385 let e = parse("name IS NULL");
1386 assert!(matches!(e, Expr::IsNull { negated: false, .. }));
1387 }
1388
1389 #[test]
1390 fn is_not_null_postfix() {
1391 let e = parse("name IS NOT NULL");
1392 assert!(matches!(e, Expr::IsNull { negated: true, .. }));
1393 }
1394
1395 #[test]
1396 fn between_with_columns() {
1397 let e = parse("temp BETWEEN min_t AND max_t");
1398 let Expr::Between {
1399 target,
1400 low,
1401 high,
1402 negated,
1403 ..
1404 } = e
1405 else {
1406 panic!("expected Between");
1407 };
1408 assert!(!negated);
1409 assert!(matches!(*target, Expr::Column { .. }));
1410 assert!(matches!(*low, Expr::Column { .. }));
1411 assert!(matches!(*high, Expr::Column { .. }));
1412 }
1413
1414 #[test]
1415 fn not_between_negates() {
1416 let e = parse("temp NOT BETWEEN 0 AND 100");
1417 let Expr::Between { negated: true, .. } = e else {
1418 panic!("expected negated Between");
1419 };
1420 }
1421
1422 #[test]
1423 fn in_list_literal() {
1424 let e = parse("status IN (1, 2, 3)");
1425 let Expr::InList {
1426 values, negated, ..
1427 } = e
1428 else {
1429 panic!("expected InList");
1430 };
1431 assert!(!negated);
1432 assert_eq!(values.len(), 3);
1433 }
1434
1435 #[test]
1436 fn not_in_list() {
1437 let e = parse("status NOT IN (1, 2)");
1438 let Expr::InList { negated: true, .. } = e else {
1439 panic!("expected negated InList");
1440 };
1441 }
1442
1443 #[test]
1444 fn function_call_with_args() {
1445 let e = parse("UPPER(name)");
1446 let Expr::FunctionCall { name, args, .. } = e else {
1447 panic!("expected FunctionCall");
1448 };
1449 assert_eq!(name, "UPPER");
1450 assert_eq!(args.len(), 1);
1451 }
1452
1453 #[test]
1454 fn nested_function_call() {
1455 let e = parse("COALESCE(a, UPPER(b))");
1456 let Expr::FunctionCall { name, args, .. } = e else {
1457 panic!("expected FunctionCall");
1458 };
1459 assert_eq!(name, "COALESCE");
1460 assert_eq!(args.len(), 2);
1461 assert!(matches!(&args[1], Expr::FunctionCall { .. }));
1462 }
1463
1464 #[test]
1465 fn duration_literal_parses_as_text() {
1466 let e = parse("time_bucket(5m)");
1467 let Expr::FunctionCall { name, args, .. } = e else {
1468 panic!("expected FunctionCall, got {e:?}");
1469 };
1470 assert_eq!(name.to_uppercase(), "TIME_BUCKET");
1471 assert_eq!(args.len(), 1);
1472 assert!(
1473 matches!(&args[0], Expr::Literal { value: Value::Text(s), .. } if s.as_ref() == "5m"),
1474 "expected Text(\"5m\"), got {:?}",
1475 args[0]
1476 );
1477 }
1478
1479 #[test]
1480 fn placeholder_dollar_one() {
1481 let e = parse("$1");
1482 match e {
1483 Expr::Parameter { index: 0, .. } => {}
1484 other => panic!("expected Parameter(0), got {other:?}"),
1485 }
1486 }
1487
1488 #[test]
1489 fn placeholder_dollar_n() {
1490 let e = parse("$7");
1491 match e {
1492 Expr::Parameter { index: 6, .. } => {}
1493 other => panic!("expected Parameter(6), got {other:?}"),
1494 }
1495 }
1496
1497 #[test]
1498 fn placeholder_in_string_literal_is_text() {
1499 let e = parse("'$1'");
1501 match e {
1502 Expr::Literal {
1503 value: Value::Text(s),
1504 ..
1505 } if s.as_ref() == "$1" => {}
1506 other => panic!("expected text literal '$1', got {other:?}"),
1507 }
1508 }
1509
1510 #[test]
1511 fn placeholder_in_comparison() {
1512 let e = parse("id = $1");
1514 let Expr::BinaryOp {
1515 op: BinOp::Eq, rhs, ..
1516 } = e
1517 else {
1518 panic!("root must be Eq");
1519 };
1520 assert!(matches!(*rhs, Expr::Parameter { index: 0, .. }));
1521 }
1522
1523 #[test]
1524 fn placeholder_zero_rejected() {
1525 let mut parser = Parser::new("$0").expect("lexer");
1526 let err = parser.parse_expr().unwrap_err();
1527 assert!(err.to_string().contains("placeholder"));
1528 }
1529
1530 #[test]
1531 fn placeholder_question_single() {
1532 let e = parse("?");
1534 match e {
1535 Expr::Parameter { index: 0, .. } => {}
1536 other => panic!("expected Parameter(0), got {other:?}"),
1537 }
1538 }
1539
1540 #[test]
1541 fn placeholder_question_numbered() {
1542 let e = parse("?7");
1543 match e {
1544 Expr::Parameter { index: 6, .. } => {}
1545 other => panic!("expected Parameter(6), got {other:?}"),
1546 }
1547 }
1548
1549 #[test]
1550 fn placeholder_question_numbered_zero_rejected() {
1551 let mut parser = Parser::new("?0").expect("lexer");
1552 let err = parser.parse_expr().unwrap_err();
1553 assert!(err.to_string().contains("placeholder"));
1554 }
1555
1556 #[test]
1557 fn placeholder_question_left_to_right() {
1558 let e = parse("id = ? AND name = ?");
1560 let Expr::BinaryOp {
1561 op: BinOp::And,
1562 lhs,
1563 rhs,
1564 ..
1565 } = e
1566 else {
1567 panic!("root must be And");
1568 };
1569 let Expr::BinaryOp {
1570 op: BinOp::Eq,
1571 rhs: r1,
1572 ..
1573 } = *lhs
1574 else {
1575 panic!("lhs must be Eq");
1576 };
1577 assert!(matches!(*r1, Expr::Parameter { index: 0, .. }));
1578 let Expr::BinaryOp {
1579 op: BinOp::Eq,
1580 rhs: r2,
1581 ..
1582 } = *rhs
1583 else {
1584 panic!("rhs must be Eq");
1585 };
1586 assert!(matches!(*r2, Expr::Parameter { index: 1, .. }));
1587 }
1588
1589 #[test]
1590 fn placeholder_question_in_string_literal_is_text() {
1591 let e = parse("'?'");
1592 match e {
1593 Expr::Literal {
1594 value: Value::Text(s),
1595 ..
1596 } if s.as_ref() == "?" => {}
1597 other => panic!("expected text literal '?', got {other:?}"),
1598 }
1599 }
1600
1601 #[test]
1602 fn placeholder_mixing_question_then_dollar_rejected() {
1603 let mut parser = Parser::new("id = ? AND x = $2").expect("lexer");
1604 let err = parser.parse_expr().err().expect("should fail");
1605 assert!(
1606 err.to_string().contains("mix"),
1607 "expected mixing error, got: {err}"
1608 );
1609 }
1610
1611 #[test]
1612 fn placeholder_mixing_dollar_then_question_rejected() {
1613 let mut parser = Parser::new("id = $1 AND x = ?").expect("lexer");
1614 let err = parser.parse_expr().err().expect("should fail");
1615 assert!(
1616 err.to_string().contains("mix"),
1617 "expected mixing error, got: {err}"
1618 );
1619 }
1620
1621 #[test]
1622 fn placeholder_question_in_comment_ignored() {
1623 let mut parser = Parser::new("-- ? ignored\n ?").expect("lexer");
1626 let e = parser.parse_expr().expect("parse_expr");
1627 match e {
1628 Expr::Parameter { index: 0, .. } => {}
1629 other => panic!("expected Parameter(0), got {other:?}"),
1630 }
1631 }
1632
1633 #[test]
1634 fn span_tracks_token_range() {
1635 let mut parser = Parser::new("123 + 456").expect("lexer");
1637 let e = parser.parse_expr().expect("parse_expr");
1638 let span = e.span();
1639 assert!(!span.is_synthetic(), "root span must be real");
1640 assert!(span.start.offset < span.end.offset);
1641 }
1642
1643 fn try_parse(input: &str) -> Result<Expr, ParseError> {
1648 let mut parser = Parser::new(input).expect("lexer init");
1649 parser.parse_expr()
1650 }
1651
1652 #[test]
1653 fn window_lag_partition_and_order() {
1654 let e = parse("LAG(ts) OVER (PARTITION BY user_id ORDER BY ts)");
1655 let Expr::WindowFunctionCall {
1656 name, args, window, ..
1657 } = e
1658 else {
1659 panic!("expected WindowFunctionCall");
1660 };
1661 assert_eq!(name.to_uppercase(), "LAG");
1662 assert_eq!(args.len(), 1);
1663 assert_eq!(window.partition_by.len(), 1);
1664 assert_eq!(window.order_by.len(), 1);
1665 assert!(window.order_by[0].ascending);
1666 assert!(window.frame.is_none());
1667 }
1668
1669 #[test]
1670 fn window_row_number_empty_over() {
1671 let e = parse("ROW_NUMBER() OVER ()");
1672 let Expr::WindowFunctionCall {
1673 name, args, window, ..
1674 } = e
1675 else {
1676 panic!("expected WindowFunctionCall");
1677 };
1678 assert_eq!(name.to_uppercase(), "ROW_NUMBER");
1679 assert!(args.is_empty());
1680 assert!(window.partition_by.is_empty());
1681 assert!(window.order_by.is_empty());
1682 assert!(window.frame.is_none());
1683 }
1684
1685 #[test]
1686 fn window_sum_with_frame_rows_between() {
1687 let e = parse(
1688 "SUM(amount) OVER (PARTITION BY user_id ORDER BY ts \
1689 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)",
1690 );
1691 let Expr::WindowFunctionCall { name, window, .. } = e else {
1692 panic!("expected WindowFunctionCall");
1693 };
1694 assert_eq!(name.to_uppercase(), "SUM");
1695 let frame = window.frame.expect("frame present");
1696 assert!(matches!(
1697 frame.unit,
1698 crate::storage::query::ast::WindowFrameUnit::Rows
1699 ));
1700 assert!(matches!(
1701 frame.start,
1702 crate::storage::query::ast::WindowFrameBound::Preceding(_)
1703 ));
1704 assert!(matches!(
1705 frame.end,
1706 Some(crate::storage::query::ast::WindowFrameBound::CurrentRow)
1707 ));
1708 }
1709
1710 #[test]
1711 fn window_rank_order_desc_multiple_keys() {
1712 let e = parse("RANK() OVER (ORDER BY score DESC, ts)");
1713 let Expr::WindowFunctionCall { window, .. } = e else {
1714 panic!("expected WindowFunctionCall");
1715 };
1716 assert_eq!(window.order_by.len(), 2);
1717 assert!(!window.order_by[0].ascending);
1718 assert!(window.order_by[1].ascending);
1719 }
1720
1721 #[test]
1722 fn window_unbounded_preceding_following_frame() {
1723 let e = parse(
1724 "AVG(x) OVER (ORDER BY t \
1725 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)",
1726 );
1727 let Expr::WindowFunctionCall { window, .. } = e else {
1728 panic!("expected WindowFunctionCall");
1729 };
1730 let frame = window.frame.expect("frame present");
1731 assert!(matches!(
1732 frame.unit,
1733 crate::storage::query::ast::WindowFrameUnit::Range
1734 ));
1735 assert!(matches!(
1736 frame.start,
1737 crate::storage::query::ast::WindowFrameBound::UnboundedPreceding
1738 ));
1739 assert!(matches!(
1740 frame.end,
1741 Some(crate::storage::query::ast::WindowFrameBound::UnboundedFollowing)
1742 ));
1743 }
1744
1745 #[test]
1746 fn window_rejects_non_window_function() {
1747 let err = try_parse("UPPER(name) OVER (PARTITION BY id)")
1749 .err()
1750 .expect("should reject scalar OVER");
1751 let msg = err.to_string();
1752 assert!(
1753 msg.contains("UPPER") || msg.contains("upper"),
1754 "error should mention function name, got: {msg}"
1755 );
1756 assert!(msg.to_ascii_uppercase().contains("OVER") || msg.contains("window"));
1757 }
1758
1759 #[test]
1760 fn window_rejects_missing_open_paren() {
1761 let err = try_parse("LAG(ts) OVER PARTITION BY user_id")
1762 .err()
1763 .expect("should reject");
1764 let msg = err.to_string();
1765 assert!(
1766 msg.contains("(") || msg.to_ascii_uppercase().contains("EXPECTED"),
1767 "got: {msg}"
1768 );
1769 }
1770
1771 #[test]
1772 fn window_rejects_invalid_frame_syntax() {
1773 let err = try_parse("LAG(ts) OVER (ORDER BY ts ROWS CURRENT)")
1775 .err()
1776 .expect("should reject");
1777 let msg = err.to_string();
1778 assert!(
1779 !msg.is_empty(),
1780 "expected non-empty error for malformed frame"
1781 );
1782 }
1783
1784 #[test]
1785 fn window_first_value_with_partition_only() {
1786 let e = parse("FIRST_VALUE(price) OVER (PARTITION BY symbol)");
1787 let Expr::WindowFunctionCall {
1788 name, window, args, ..
1789 } = e
1790 else {
1791 panic!("expected WindowFunctionCall");
1792 };
1793 assert_eq!(name.to_uppercase(), "FIRST_VALUE");
1794 assert_eq!(args.len(), 1);
1795 assert_eq!(window.partition_by.len(), 1);
1796 assert!(window.order_by.is_empty());
1797 }
1798}