From 5fc143466e789ef451dd361aa3f6d34a85f1ae12 Mon Sep 17 00:00:00 2001 From: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com> Date: Mon, 19 Sep 2022 19:29:39 +0400 Subject: [PATCH] fix: Correct `INTERVAL + INTERVAL` expression parsing Recheck this after rebase on commit 57083a0 "Fix interval parsing logic and precedence (#705)", first released in 0.28.0 --- src/parser.rs | 2 +- tests/sqlparser_common.rs | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index 51a764b9d..5d81c99dc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1095,7 +1095,7 @@ impl<'a> Parser<'a> { // The first token in an interval is a string literal which specifies // the duration of the interval. - let value = self.parse_expr()?; + let value = self.parse_subexpr(Self::PLUS_MINUS_PREC)?; // Following the string literal is a qualifier which indicates the units // of the duration specified in the string literal. diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index a60f0e3d5..4baf23985 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2864,6 +2864,59 @@ fn parse_literal_interval() { ); } +#[test] +fn parse_interval_math() { + let sql = "SELECT INTERVAL '1 DAY' + INTERVAL '2 DAY'"; + let select = verified_only_select(sql); + assert_eq!( + &Expr::BinaryOp { + left: Box::new(Expr::Value(Value::Interval { + value: Box::new(Expr::Value(Value::SingleQuotedString("1 DAY".to_string()))), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + })), + op: BinaryOperator::Plus, + right: Box::new(Expr::Value(Value::Interval { + value: Box::new(Expr::Value(Value::SingleQuotedString("2 DAY".to_string()))), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + })), + }, + expr_from_projection(only(&select.projection)), + ); + + let sql = "SELECT INTERVAL '1' || ' DAY' + INTERVAL '2 DAY'"; + let select = verified_only_select(sql); + assert_eq!( + &Expr::BinaryOp { + left: Box::new(Expr::Value(Value::Interval { + value: Box::new(Expr::BinaryOp { + left: Box::new(Expr::Value(Value::SingleQuotedString("1".to_string()))), + op: BinaryOperator::StringConcat, + right: Box::new(Expr::Value(Value::SingleQuotedString(" DAY".to_string()))), + }), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + })), + op: BinaryOperator::Plus, + right: Box::new(Expr::Value(Value::Interval { + value: Box::new(Expr::Value(Value::SingleQuotedString("2 DAY".to_string()))), + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + })), + }, + expr_from_projection(only(&select.projection)), + ); +} + #[test] fn parse_at_timezone() { let zero = Expr::Value(number("0"));