From 10dcfb0edefdc1961720d413a8f76c61b5a47ade Mon Sep 17 00:00:00 2001 From: Mehmet Ozan Kabak Date: Wed, 5 Oct 2022 13:09:22 +0300 Subject: [PATCH] Remove the unnecessary ancillary struct Interval --- sqlparser_bench/Cargo.toml | 2 +- src/ast/mod.rs | 129 ++++++++++++++++--------------------- src/parser.rs | 8 +-- tests/sqlparser_common.rs | 32 ++++----- 4 files changed, 78 insertions(+), 93 deletions(-) diff --git a/sqlparser_bench/Cargo.toml b/sqlparser_bench/Cargo.toml index 76580e43a..f5dc85e4a 100644 --- a/sqlparser_bench/Cargo.toml +++ b/sqlparser_bench/Cargo.toml @@ -11,5 +11,5 @@ sqlparser = { path = "../" } criterion = "0.4" [[bench]] -harness = false name = "sqlparser_bench" +harness = false diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a2521f601..155563a19 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -205,73 +205,6 @@ impl fmt::Display for JsonOperator { } } -/// INTERVAL literals, roughly in the following format: -/// `INTERVAL '' [ [ () ] ] -/// [ TO [ () ] ]`, -/// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`. -/// -/// The parser does not validate the ``, nor does it ensure -/// that the `` units >= the units in ``, -/// so the user will have to reject intervals like `HOUR TO YEAR`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Interval { - pub value: Box, - pub leading_field: Option, - pub leading_precision: Option, - pub last_field: Option, - /// The seconds precision can be specified in SQL source as - /// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field` - /// will be `Second` and the `last_field` will be `None`), - /// or as `__ TO SECOND(x)`. - pub fractional_seconds_precision: Option, -} - -impl fmt::Display for Interval { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Interval { - value, - leading_field: Some(DateTimeField::Second), - leading_precision: Some(leading_precision), - last_field, - fractional_seconds_precision: Some(fractional_seconds_precision), - } => { - // When the leading field is SECOND, the parser guarantees that - // the last field is None. - assert!(last_field.is_none()); - write!( - f, - "INTERVAL {} SECOND ({}, {})", - value, leading_precision, fractional_seconds_precision - ) - } - Interval { - value, - leading_field, - leading_precision, - last_field, - fractional_seconds_precision, - } => { - write!(f, "INTERVAL {}", value)?; - if let Some(leading_field) = leading_field { - write!(f, " {}", leading_field)?; - } - if let Some(leading_precision) = leading_precision { - write!(f, " ({})", leading_precision)?; - } - if let Some(last_field) = last_field { - write!(f, " TO {}", last_field)?; - } - if let Some(fractional_seconds_precision) = fractional_seconds_precision { - write!(f, " ({})", fractional_seconds_precision)?; - } - Ok(()) - } - } - } -} - /// An SQL expression of any type. /// /// The parser does not distinguish between expressions of different types @@ -477,8 +410,25 @@ pub enum Expr { ArrayIndex { obj: Box, indexes: Vec }, /// An array expression e.g. `ARRAY[1, 2]` Array(Array), - /// INTERVAL literals, such as `INTERVAL '1 DAY'` - Interval(Interval), + /// INTERVAL literals, roughly in the following format: + /// `INTERVAL '' [ [ () ] ] + /// [ TO [ () ] ]`, + /// e.g. `INTERVAL '123:45.67' MINUTE(3) TO SECOND(2)`. + /// + /// The parser does not validate the ``, nor does it ensure + /// that the `` units >= the units in ``, + /// so the user will have to reject intervals like `HOUR TO YEAR`. + Interval { + value: Box, + leading_field: Option, + leading_precision: Option, + last_field: Option, + /// The seconds precision can be specified in SQL source as + /// `INTERVAL '__' SECOND(_, x)` (in which case the `leading_field` + /// will be `Second` and the `last_field` will be `None`), + /// or as `__ TO SECOND(x)`. + fractional_seconds_precision: Option, + }, } impl fmt::Display for Expr { @@ -791,8 +741,43 @@ impl fmt::Display for Expr { } => { write!(f, "{} AT TIME ZONE '{}'", timestamp, time_zone) } - Expr::Interval(interval) => { - write!(f, "{}", interval) + Expr::Interval { + value, + leading_field: Some(DateTimeField::Second), + leading_precision: Some(leading_precision), + last_field, + fractional_seconds_precision: Some(fractional_seconds_precision), + } => { + // When the leading field is SECOND, the parser guarantees that + // the last field is None. + assert!(last_field.is_none()); + write!( + f, + "INTERVAL {} SECOND ({}, {})", + value, leading_precision, fractional_seconds_precision + ) + } + Expr::Interval { + value, + leading_field, + leading_precision, + last_field, + fractional_seconds_precision, + } => { + write!(f, "INTERVAL {}", value)?; + if let Some(leading_field) = leading_field { + write!(f, " {}", leading_field)?; + } + if let Some(leading_precision) = leading_precision { + write!(f, " ({})", leading_precision)?; + } + if let Some(last_field) = last_field { + write!(f, " TO {}", last_field)?; + } + if let Some(fractional_seconds_precision) = fractional_seconds_precision { + write!(f, " ({})", fractional_seconds_precision)?; + } + Ok(()) } } } @@ -918,7 +903,7 @@ pub enum RangeBounds { /// Number literal, e.g `1`, `1.1` Number(String), /// Interval, such as `INTERVAL '1 DAY' ` - Interval(Interval), + Interval(Expr), } impl fmt::Display for RangeBounds { diff --git a/src/parser.rs b/src/parser.rs index 94aa3ed1f..17a018f18 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -402,7 +402,7 @@ impl<'a> Parser<'a> { // expression that should parse as the column name "date". return_ok_if_some!(self.maybe_parse(|parser| { match parser.parse_data_type()? { - DataType::Interval => Ok(Expr::Interval(parser.parse_interval()?)), + DataType::Interval => parser.parse_interval(), // PostgreSQL allows almost any identifier to be used as custom data type name, // and we support that in `parse_data_type()`. But unlike Postgres we don't // have a list of globally reserved keywords (since they vary across dialects), @@ -455,7 +455,7 @@ impl<'a> Parser<'a> { Keyword::SUBSTRING => self.parse_substring_expr(), Keyword::OVERLAY => self.parse_overlay_expr(), Keyword::TRIM => self.parse_trim_expr(), - Keyword::INTERVAL => Ok(Expr::Interval(self.parse_interval()?)), + Keyword::INTERVAL => self.parse_interval(), Keyword::LISTAGG => self.parse_listagg_expr(), // Treat ARRAY[1,2,3] as an array [1,2,3], otherwise try as subquery or a function call Keyword::ARRAY if self.peek_token() == Token::LBracket => { @@ -1110,7 +1110,7 @@ impl<'a> Parser<'a> { /// 7. (MySql and BigQuey only):`INTERVAL 1 DAY` /// /// Note that we do not currently attempt to parse the quoted value. - pub fn parse_interval(&mut self) -> Result { + pub fn parse_interval(&mut self) -> Result { // The SQL standard allows an optional sign before the value string, but // it is not clear if any implementations support that syntax, so we // don't currently try to parse it. (The sign can instead be included @@ -1185,7 +1185,7 @@ impl<'a> Parser<'a> { } }; - Ok(Interval { + Ok(Expr::Interval { value: Box::new(value), leading_field, leading_precision, diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index bb2704393..013eebb18 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2986,20 +2986,20 @@ fn parse_interval() { let sql = "SELECT INTERVAL '1-1' YEAR TO MONTH"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1-1")))), leading_field: Some(DateTimeField::Year), leading_precision: None, last_field: Some(DateTimeField::Month), fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL '01:01.01' MINUTE (5) TO SECOND (5)"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from( "01:01.01" )))), @@ -3007,53 +3007,53 @@ fn parse_interval() { leading_precision: Some(5), last_field: Some(DateTimeField::Second), fractional_seconds_precision: Some(5), - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL '1' SECOND (5, 4)"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("1")))), leading_field: Some(DateTimeField::Second), leading_precision: Some(5), last_field: None, fractional_seconds_precision: Some(4), - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL '10' HOUR"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))), leading_field: Some(DateTimeField::Hour), leading_precision: None, last_field: None, fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL 5 DAY"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(number("5"))), leading_field: Some(DateTimeField::Day), leading_precision: None, last_field: None, fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL 1 + 1 DAY"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::BinaryOp { left: Box::new(Expr::Value(number("1"))), op: BinaryOperator::Plus, @@ -3063,27 +3063,27 @@ fn parse_interval() { leading_precision: None, last_field: None, fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL '10' HOUR (1)"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from("10")))), leading_field: Some(DateTimeField::Hour), leading_precision: Some(1), last_field: None, fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), ); let sql = "SELECT INTERVAL '1 DAY'"; let select = verified_only_select(sql); assert_eq!( - &Expr::Interval(Interval { + &Expr::Interval { value: Box::new(Expr::Value(Value::SingleQuotedString(String::from( "1 DAY" )))), @@ -3091,7 +3091,7 @@ fn parse_interval() { leading_precision: None, last_field: None, fractional_seconds_precision: None, - }), + }, expr_from_projection(only(&select.projection)), );