diff --git a/src/sql/src/parsers/create_parser.rs b/src/sql/src/parsers/create_parser.rs index 60d9424720..b99b88b721 100644 --- a/src/sql/src/parsers/create_parser.rs +++ b/src/sql/src/parsers/create_parser.rs @@ -2475,4 +2475,13 @@ CREATE TABLE log ( assert!(extensions.fulltext_index_options.is_some()); } } + + #[test] + fn test_parse_interval_cast() { + let s = "select '10s'::INTERVAL"; + let stmts = + ParserContext::create_with_dialect(s, &GreptimeDbDialect {}, ParseOptions::default()) + .unwrap(); + assert_eq!("SELECT '10 seconds'::INTERVAL", &stmts[0].to_string()); + } } diff --git a/src/sql/src/statements/transform/expand_interval.rs b/src/sql/src/statements/transform/expand_interval.rs index 9761dcb0d7..8cddaf8b73 100644 --- a/src/sql/src/statements/transform/expand_interval.rs +++ b/src/sql/src/statements/transform/expand_interval.rs @@ -99,15 +99,21 @@ impl TransformRule for ExpandIntervalTransformRule { Expr::Cast { expr: cast_exp, data_type, - .. + kind, + format, } => { if DataType::Interval == *data_type { match &**cast_exp { Expr::Value(Value::SingleQuotedString(value)) | Expr::Value(Value::DoubleQuotedString(value)) => { - let interval_name = + let interval_value = normalize_interval_name(value).unwrap_or_else(|| value.to_string()); - *expr = create_interval(single_quoted_string_expr(interval_name)); + *expr = Expr::Cast { + kind: kind.clone(), + expr: single_quoted_string_expr(interval_value), + data_type: DataType::Interval, + format: std::mem::take(format), + } } _ => {} } @@ -123,16 +129,6 @@ fn single_quoted_string_expr(string: String) -> Box { Box::new(Expr::Value(Value::SingleQuotedString(string))) } -fn create_interval(value: Box) -> Expr { - Expr::Interval(Interval { - value, - leading_field: None, - leading_precision: None, - last_field: None, - fractional_seconds_precision: None, - }) -} - fn update_existing_interval_with_value(interval: &Interval, value: Box) -> Expr { Expr::Interval(Interval { value, @@ -199,14 +195,23 @@ fn expand_interval_abbreviation(interval_str: &str) -> Option { mod tests { use std::ops::ControlFlow; - use sqlparser::ast::{BinaryOperator, DataType, Expr, Interval, Value}; + use sqlparser::ast::{BinaryOperator, CastKind, DataType, Expr, Interval, Value}; use crate::statements::transform::expand_interval::{ - create_interval, normalize_interval_name, single_quoted_string_expr, - ExpandIntervalTransformRule, + normalize_interval_name, single_quoted_string_expr, ExpandIntervalTransformRule, }; use crate::statements::transform::TransformRule; + fn create_interval(value: Box) -> Expr { + Expr::Interval(Interval { + value, + leading_field: None, + leading_precision: None, + last_field: None, + fractional_seconds_precision: None, + }) + } + #[test] fn test_transform_interval_basic_conversions() { let test_cases = vec![ @@ -379,15 +384,14 @@ mod tests { assert_eq!(control_flow, ControlFlow::Continue(())); assert_eq!( cast_to_interval_expr, - Expr::Interval(Interval { - value: Box::new(Expr::Value(Value::SingleQuotedString( + Expr::Cast { + kind: CastKind::Cast, + expr: Box::new(Expr::Value(Value::SingleQuotedString( "3 years 2 months".to_string() ))), - leading_field: None, - leading_precision: None, - last_field: None, - fractional_seconds_precision: None, - }) + data_type: DataType::Interval, + format: None, + } ); let mut cast_to_i64_expr = Expr::Cast { diff --git a/tests/cases/standalone/common/types/interval/interval.result b/tests/cases/standalone/common/types/interval/interval.result index c98b422838..2a5bd55525 100644 --- a/tests/cases/standalone/common/types/interval/interval.result +++ b/tests/cases/standalone/common/types/interval/interval.result @@ -25,11 +25,11 @@ SELECT INTERVAL '-2 months'; SELECT '3 hours'::INTERVAL; -+--------------------------------------------------------------------------------------------------+ -| IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 10800000000000 }") | -+--------------------------------------------------------------------------------------------------+ -| 3 hours | -+--------------------------------------------------------------------------------------------------+ ++-----------------+ +| Utf8("3 hours") | ++-----------------+ +| 3 hours | ++-----------------+ SELECT INTERVAL '1 year 2 months 3 days 4 hours' + INTERVAL '1 year'; @@ -128,11 +128,11 @@ SELECT INTERVAL '1y2w3d4h'; SELECT '3y2mon'::INTERVAL; -+--------------------------------------------------------------------------------------+ -| IntervalMonthDayNano("IntervalMonthDayNano { months: 38, days: 0, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------+ -| 38 mons | -+--------------------------------------------------------------------------------------+ ++--------------------------+ +| Utf8("3 years 2 months") | ++--------------------------+ +| 38 mons | ++--------------------------+ SELECT INTERVAL '7 days' - INTERVAL '1d'; @@ -169,11 +169,11 @@ SELECT INTERVAL '-P3Y3M700DT133H17M36.789S'; SELECT 'P3Y3M700DT133H17M36.789S'::INTERVAL; -+------------------------------------------------------------------------------------------------------+ -| IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 163343856789000000 }") | -+------------------------------------------------------------------------------------------------------+ -| 45373 hours 17 mins 36.789000000 secs | -+------------------------------------------------------------------------------------------------------+ ++---------------------------------------+ +| Utf8("163343856789 milliseconds") | ++---------------------------------------+ +| 45373 hours 17 mins 36.789000000 secs | ++---------------------------------------+ SELECT INTERVAL '2h' + INTERVAL 'P3Y3M700DT133H17M36.789S'; @@ -185,115 +185,115 @@ SELECT INTERVAL '2h' + INTERVAL 'P3Y3M700DT133H17M36.789S'; select '2022-01-01T00:00:01'::timestamp + '1 days'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 1, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2022-01-02T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("1 days") | ++-----------------------------------------------------------------------------------------------+ +| 2022-01-02T00:00:01 | ++-----------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp + '2 days'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 2, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2022-01-03T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("2 days") | ++-----------------------------------------------------------------------------------------------+ +| 2022-01-03T00:00:01 | ++-----------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp - '1 days'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) - IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 1, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2021-12-31T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) - Utf8("1 days") | ++-----------------------------------------------------------------------------------------------+ +| 2021-12-31T00:00:01 | ++-----------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp - '2 days'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) - IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 2, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2021-12-30T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) - Utf8("2 days") | ++-----------------------------------------------------------------------------------------------+ +| 2021-12-30T00:00:01 | ++-----------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp + '1 month'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 1, days: 0, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2022-02-01T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("1 month") | ++------------------------------------------------------------------------------------------------+ +| 2022-02-01T00:00:01 | ++------------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp + '2 months'::interval; -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 2, days: 0, nanoseconds: 0 }") | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2022-03-01T00:00:01 | -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("2 months") | ++-------------------------------------------------------------------------------------------------+ +| 2022-03-01T00:00:01 | ++-------------------------------------------------------------------------------------------------+ select '2022-01-01T00:00:01'::timestamp + '1 year'::interval; -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 12, days: 0, nanoseconds: 0 }") | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2023-01-01T00:00:01 | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2022-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("1 year") | ++-----------------------------------------------------------------------------------------------+ +| 2023-01-01T00:00:01 | ++-----------------------------------------------------------------------------------------------+ select '2023-01-01T00:00:01'::timestamp + '2 years'::interval; -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| arrow_cast(Utf8("2023-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + IntervalMonthDayNano("IntervalMonthDayNano { months: 24, days: 0, nanoseconds: 0 }") | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| 2025-01-01T00:00:01 | -+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------+ +| arrow_cast(Utf8("2023-01-01T00:00:01"),Utf8("Timestamp(Millisecond, None)")) + Utf8("2 years") | ++------------------------------------------------------------------------------------------------+ +| 2025-01-01T00:00:01 | ++------------------------------------------------------------------------------------------------+ -- DATE + INTERVAL SELECT DATE '2000-10-30' + '1 days'::interval; -+----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") + IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 1, nanoseconds: 0 }") | -+----------------------------------------------------------------------------------------------------------+ -| 2000-10-31 | -+----------------------------------------------------------------------------------------------------------+ ++-------------------------------------+ +| Utf8("2000-10-30") + Utf8("1 days") | ++-------------------------------------+ +| 2000-10-31 | ++-------------------------------------+ SELECT DATE '2000-10-30' + '2 months'::interval; -+----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") + IntervalMonthDayNano("IntervalMonthDayNano { months: 2, days: 0, nanoseconds: 0 }") | -+----------------------------------------------------------------------------------------------------------+ -| 2000-12-30 | -+----------------------------------------------------------------------------------------------------------+ ++---------------------------------------+ +| Utf8("2000-10-30") + Utf8("2 months") | ++---------------------------------------+ +| 2000-12-30 | ++---------------------------------------+ SELECT DATE '2000-10-30' + '2 years'::interval; -+-----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") + IntervalMonthDayNano("IntervalMonthDayNano { months: 24, days: 0, nanoseconds: 0 }") | -+-----------------------------------------------------------------------------------------------------------+ -| 2002-10-30 | -+-----------------------------------------------------------------------------------------------------------+ ++--------------------------------------+ +| Utf8("2000-10-30") + Utf8("2 years") | ++--------------------------------------+ +| 2002-10-30 | ++--------------------------------------+ -- DATE - INTERVAL SELECT DATE '2000-10-30' - '1 days'::interval; -+----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") - IntervalMonthDayNano("IntervalMonthDayNano { months: 0, days: 1, nanoseconds: 0 }") | -+----------------------------------------------------------------------------------------------------------+ -| 2000-10-29 | -+----------------------------------------------------------------------------------------------------------+ ++-------------------------------------+ +| Utf8("2000-10-30") - Utf8("1 days") | ++-------------------------------------+ +| 2000-10-29 | ++-------------------------------------+ SELECT DATE '2000-10-30' - '2 months'::interval; -+----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") - IntervalMonthDayNano("IntervalMonthDayNano { months: 2, days: 0, nanoseconds: 0 }") | -+----------------------------------------------------------------------------------------------------------+ -| 2000-08-30 | -+----------------------------------------------------------------------------------------------------------+ ++---------------------------------------+ +| Utf8("2000-10-30") - Utf8("2 months") | ++---------------------------------------+ +| 2000-08-30 | ++---------------------------------------+ SELECT DATE '2000-10-30' - '2 years'::interval; -+-----------------------------------------------------------------------------------------------------------+ -| Utf8("2000-10-30") - IntervalMonthDayNano("IntervalMonthDayNano { months: 24, days: 0, nanoseconds: 0 }") | -+-----------------------------------------------------------------------------------------------------------+ -| 1998-10-30 | -+-----------------------------------------------------------------------------------------------------------+ ++--------------------------------------+ +| Utf8("2000-10-30") - Utf8("2 years") | ++--------------------------------------+ +| 1998-10-30 | ++--------------------------------------+