diff --git a/src/parser.rs b/src/parser.rs index 51a764b9d8..5d81c99dc9 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 1564ff682d..882824defd 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2863,6 +2863,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"));