diff --git a/src/api/src/helper.rs b/src/api/src/helper.rs index 101cae880207..4281201c4293 100644 --- a/src/api/src/helper.rs +++ b/src/api/src/helper.rs @@ -17,10 +17,11 @@ use std::sync::Arc; use common_base::BitVec; use common_decimal::decimal128::{DECIMAL128_DEFAULT_SCALE, DECIMAL128_MAX_PRECISION}; use common_decimal::Decimal128; -use common_time::interval::IntervalUnit; use common_time::time::Time; use common_time::timestamp::TimeUnit; -use common_time::{Date, DateTime, Interval, Timestamp}; +use common_time::{ + Date, DateTime, IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth, Timestamp, +}; use datatypes::prelude::{ConcreteDataType, ValueRef}; use datatypes::scalars::ScalarVector; use datatypes::types::{ @@ -456,13 +457,11 @@ pub fn push_vals(column: &mut Column, origin_count: usize, vector: VectorRef) { TimeUnit::Microsecond => values.time_microsecond_values.push(val.value()), TimeUnit::Nanosecond => values.time_nanosecond_values.push(val.value()), }, - Value::Interval(val) => match val.unit() { - IntervalUnit::YearMonth => values.interval_year_month_values.push(val.to_i32()), - IntervalUnit::DayTime => values.interval_day_time_values.push(val.to_i64()), - IntervalUnit::MonthDayNano => values - .interval_month_day_nano_values - .push(convert_i128_to_interval(val.to_i128())), - }, + Value::IntervalYearMonth(val) => values.interval_year_month_values.push(val.to_i32()), + Value::IntervalDayTime(val) => values.interval_day_time_values.push(val.to_i64()), + Value::IntervalMonthDayNano(val) => values + .interval_month_day_nano_values + .push(convert_month_day_nano_to_pb(val)), Value::Decimal128(val) => values.decimal128_values.push(convert_to_pb_decimal128(val)), Value::List(_) | Value::Duration(_) => unreachable!(), }); @@ -507,14 +506,12 @@ fn ddl_request_type(request: &DdlRequest) -> &'static str { } } -/// Converts an i128 value to google protobuf type [IntervalMonthDayNano]. -pub fn convert_i128_to_interval(v: i128) -> v1::IntervalMonthDayNano { - let interval = Interval::from_i128(v); - let (months, days, nanoseconds) = interval.to_month_day_nano(); +/// Converts an interval to google protobuf type [IntervalMonthDayNano]. +pub fn convert_month_day_nano_to_pb(v: IntervalMonthDayNano) -> v1::IntervalMonthDayNano { v1::IntervalMonthDayNano { - months, - days, - nanoseconds, + months: v.months, + days: v.days, + nanoseconds: v.nanoseconds, } } @@ -562,11 +559,15 @@ pub fn pb_value_to_value_ref<'a>( ValueData::TimeMillisecondValue(t) => ValueRef::Time(Time::new_millisecond(*t)), ValueData::TimeMicrosecondValue(t) => ValueRef::Time(Time::new_microsecond(*t)), ValueData::TimeNanosecondValue(t) => ValueRef::Time(Time::new_nanosecond(*t)), - ValueData::IntervalYearMonthValue(v) => ValueRef::Interval(Interval::from_i32(*v)), - ValueData::IntervalDayTimeValue(v) => ValueRef::Interval(Interval::from_i64(*v)), + ValueData::IntervalYearMonthValue(v) => { + ValueRef::IntervalYearMonth(IntervalYearMonth::from_i32(*v)) + } + ValueData::IntervalDayTimeValue(v) => { + ValueRef::IntervalDayTime(IntervalDayTime::from_i64(*v)) + } ValueData::IntervalMonthDayNanoValue(v) => { - let interval = Interval::from_month_day_nano(v.months, v.days, v.nanoseconds); - ValueRef::Interval(interval) + let interval = IntervalMonthDayNano::new(v.months, v.days, v.nanoseconds); + ValueRef::IntervalMonthDayNano(interval) } ValueData::Decimal128Value(v) => { // get precision and scale from datatype_extension @@ -657,7 +658,7 @@ pub fn pb_values_to_vector_ref(data_type: &ConcreteDataType, values: Values) -> IntervalType::MonthDayNano(_) => { Arc::new(IntervalMonthDayNanoVector::from_iter_values( values.interval_month_day_nano_values.iter().map(|x| { - Interval::from_month_day_nano(x.months, x.days, x.nanoseconds).to_i128() + IntervalMonthDayNano::new(x.months, x.days, x.nanoseconds).to_i128() }), )) } @@ -802,18 +803,18 @@ pub fn pb_values_to_values(data_type: &ConcreteDataType, values: Values) -> Vec< ConcreteDataType::Interval(IntervalType::YearMonth(_)) => values .interval_year_month_values .into_iter() - .map(|v| Value::Interval(Interval::from_i32(v))) + .map(|v| Value::IntervalYearMonth(IntervalYearMonth::from_i32(v))) .collect(), ConcreteDataType::Interval(IntervalType::DayTime(_)) => values .interval_day_time_values .into_iter() - .map(|v| Value::Interval(Interval::from_i64(v))) + .map(|v| Value::IntervalDayTime(IntervalDayTime::from_i64(v))) .collect(), ConcreteDataType::Interval(IntervalType::MonthDayNano(_)) => values .interval_month_day_nano_values .into_iter() .map(|v| { - Value::Interval(Interval::from_month_day_nano( + Value::IntervalMonthDayNano(IntervalMonthDayNano::new( v.months, v.days, v.nanoseconds, @@ -941,18 +942,16 @@ pub fn to_proto_value(value: Value) -> Option { value_data: Some(ValueData::TimeNanosecondValue(v.value())), }, }, - Value::Interval(v) => match v.unit() { - IntervalUnit::YearMonth => v1::Value { - value_data: Some(ValueData::IntervalYearMonthValue(v.to_i32())), - }, - IntervalUnit::DayTime => v1::Value { - value_data: Some(ValueData::IntervalDayTimeValue(v.to_i64())), - }, - IntervalUnit::MonthDayNano => v1::Value { - value_data: Some(ValueData::IntervalMonthDayNanoValue( - convert_i128_to_interval(v.to_i128()), - )), - }, + Value::IntervalYearMonth(v) => v1::Value { + value_data: Some(ValueData::IntervalYearMonthValue(v.to_i32())), + }, + Value::IntervalDayTime(v) => v1::Value { + value_data: Some(ValueData::IntervalDayTimeValue(v.to_i64())), + }, + Value::IntervalMonthDayNano(v) => v1::Value { + value_data: Some(ValueData::IntervalMonthDayNanoValue( + convert_month_day_nano_to_pb(v), + )), }, Value::Decimal128(v) => v1::Value { value_data: Some(ValueData::Decimal128Value(convert_to_pb_decimal128(v))), @@ -1044,13 +1043,11 @@ pub fn value_to_grpc_value(value: Value) -> GrpcValue { TimeUnit::Microsecond => ValueData::TimeMicrosecondValue(v.value()), TimeUnit::Nanosecond => ValueData::TimeNanosecondValue(v.value()), }), - Value::Interval(v) => Some(match v.unit() { - IntervalUnit::YearMonth => ValueData::IntervalYearMonthValue(v.to_i32()), - IntervalUnit::DayTime => ValueData::IntervalDayTimeValue(v.to_i64()), - IntervalUnit::MonthDayNano => { - ValueData::IntervalMonthDayNanoValue(convert_i128_to_interval(v.to_i128())) - } - }), + Value::IntervalYearMonth(v) => Some(ValueData::IntervalYearMonthValue(v.to_i32())), + Value::IntervalDayTime(v) => Some(ValueData::IntervalDayTimeValue(v.to_i64())), + Value::IntervalMonthDayNano(v) => Some(ValueData::IntervalMonthDayNanoValue( + convert_month_day_nano_to_pb(v), + )), Value::Decimal128(v) => Some(ValueData::Decimal128Value(convert_to_pb_decimal128(v))), Value::List(_) | Value::Duration(_) => unreachable!(), }, @@ -1061,6 +1058,7 @@ pub fn value_to_grpc_value(value: Value) -> GrpcValue { mod tests { use std::sync::Arc; + use common_time::interval::IntervalUnit; use datatypes::types::{ Int32Type, IntervalDayTimeType, IntervalMonthDayNanoType, IntervalYearMonthType, TimeMillisecondType, TimeSecondType, TimestampMillisecondType, TimestampSecondType, @@ -1506,11 +1504,11 @@ mod tests { #[test] fn test_convert_i128_to_interval() { - let i128_val = 3000; - let interval = convert_i128_to_interval(i128_val); + let i128_val = 3; + let interval = convert_month_day_nano_to_pb(IntervalMonthDayNano::from_i128(i128_val)); assert_eq!(interval.months, 0); assert_eq!(interval.days, 0); - assert_eq!(interval.nanoseconds, 3000); + assert_eq!(interval.nanoseconds, 3); } #[test] @@ -1590,9 +1588,9 @@ mod tests { }, ); let expect = vec![ - Value::Interval(Interval::from_year_month(1_i32)), - Value::Interval(Interval::from_year_month(2_i32)), - Value::Interval(Interval::from_year_month(3_i32)), + Value::IntervalYearMonth(IntervalYearMonth::new(1_i32)), + Value::IntervalYearMonth(IntervalYearMonth::new(2_i32)), + Value::IntervalYearMonth(IntervalYearMonth::new(3_i32)), ]; assert_eq!(expect, actual); @@ -1605,9 +1603,9 @@ mod tests { }, ); let expect = vec![ - Value::Interval(Interval::from_i64(1_i64)), - Value::Interval(Interval::from_i64(2_i64)), - Value::Interval(Interval::from_i64(3_i64)), + Value::IntervalDayTime(IntervalDayTime::from_i64(1_i64)), + Value::IntervalDayTime(IntervalDayTime::from_i64(2_i64)), + Value::IntervalDayTime(IntervalDayTime::from_i64(3_i64)), ]; assert_eq!(expect, actual); @@ -1636,9 +1634,9 @@ mod tests { }, ); let expect = vec![ - Value::Interval(Interval::from_month_day_nano(1, 2, 3)), - Value::Interval(Interval::from_month_day_nano(5, 6, 7)), - Value::Interval(Interval::from_month_day_nano(9, 10, 11)), + Value::IntervalMonthDayNano(IntervalMonthDayNano::new(1, 2, 3)), + Value::IntervalMonthDayNano(IntervalMonthDayNano::new(5, 6, 7)), + Value::IntervalMonthDayNano(IntervalMonthDayNano::new(9, 10, 11)), ]; assert_eq!(expect, actual); } diff --git a/src/common/function/src/scalars/date/date_add.rs b/src/common/function/src/scalars/date/date_add.rs index 1052acb86863..2307d2caab56 100644 --- a/src/common/function/src/scalars/date/date_add.rs +++ b/src/common/function/src/scalars/date/date_add.rs @@ -14,18 +14,19 @@ use std::fmt; -use common_query::error::{InvalidFuncArgsSnafu, Result, UnsupportedInputDataTypeSnafu}; +use common_query::error::{ArrowComputeSnafu, IntoVectorSnafu, InvalidFuncArgsSnafu, Result}; use common_query::prelude::Signature; -use datatypes::data_type::DataType; +use datatypes::arrow::compute::kernels::numeric; use datatypes::prelude::ConcreteDataType; -use datatypes::value::ValueRef; -use datatypes::vectors::VectorRef; -use snafu::ensure; +use datatypes::vectors::{Helper, VectorRef}; +use snafu::{ensure, ResultExt}; use crate::function::{Function, FunctionContext}; use crate::helper; -/// A function adds an interval value to Timestamp, Date or DateTime, and return the result. +/// A function adds an interval value to Timestamp, Date, and return the result. +/// The implementation of datetime type is based on Date64 which is incorrect so this function +/// doesn't support the datetime type. #[derive(Clone, Debug, Default)] pub struct DateAddFunction; @@ -44,7 +45,6 @@ impl Function for DateAddFunction { helper::one_of_sigs2( vec![ ConcreteDataType::date_datatype(), - ConcreteDataType::datetime_datatype(), ConcreteDataType::timestamp_second_datatype(), ConcreteDataType::timestamp_millisecond_datatype(), ConcreteDataType::timestamp_microsecond_datatype(), @@ -69,64 +69,14 @@ impl Function for DateAddFunction { } ); - let left = &columns[0]; - let right = &columns[1]; + let left = columns[0].to_arrow_array(); + let right = columns[1].to_arrow_array(); - let size = left.len(); - let left_datatype = columns[0].data_type(); - match left_datatype { - ConcreteDataType::Timestamp(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let ts = left.get(i).as_timestamp(); - let interval = right.get(i).as_interval(); - - let new_ts = match (ts, interval) { - (Some(ts), Some(interval)) => ts.add_interval(interval), - _ => ts, - }; - - result.push_value_ref(ValueRef::from(new_ts)); - } - - Ok(result.to_vector()) - } - ConcreteDataType::Date(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let date = left.get(i).as_date(); - let interval = right.get(i).as_interval(); - let new_date = match (date, interval) { - (Some(date), Some(interval)) => date.add_interval(interval), - _ => date, - }; - - result.push_value_ref(ValueRef::from(new_date)); - } - - Ok(result.to_vector()) - } - ConcreteDataType::DateTime(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let datetime = left.get(i).as_datetime(); - let interval = right.get(i).as_interval(); - let new_datetime = match (datetime, interval) { - (Some(datetime), Some(interval)) => datetime.add_interval(interval), - _ => datetime, - }; - - result.push_value_ref(ValueRef::from(new_datetime)); - } - - Ok(result.to_vector()) - } - _ => UnsupportedInputDataTypeSnafu { - function: NAME, - datatypes: columns.iter().map(|c| c.data_type()).collect::>(), - } - .fail(), - } + let result = numeric::add(&left, &right).context(ArrowComputeSnafu)?; + let arrow_type = result.data_type().clone(); + Helper::try_into_vector(result).context(IntoVectorSnafu { + data_type: arrow_type, + }) } } @@ -144,8 +94,7 @@ mod tests { use datatypes::prelude::ConcreteDataType; use datatypes::value::Value; use datatypes::vectors::{ - DateTimeVector, DateVector, IntervalDayTimeVector, IntervalYearMonthVector, - TimestampSecondVector, + DateVector, IntervalDayTimeVector, IntervalYearMonthVector, TimestampSecondVector, }; use super::{DateAddFunction, *}; @@ -168,16 +117,15 @@ mod tests { ConcreteDataType::date_datatype(), f.return_type(&[ConcreteDataType::date_datatype()]).unwrap() ); - assert_eq!( - ConcreteDataType::datetime_datatype(), - f.return_type(&[ConcreteDataType::datetime_datatype()]) - .unwrap() - ); - assert!(matches!(f.signature(), + assert!( + matches!(f.signature(), Signature { type_signature: TypeSignature::OneOf(sigs), volatility: Volatility::Immutable - } if sigs.len() == 18)); + } if sigs.len() == 15), + "{:?}", + f.signature() + ); } #[test] @@ -243,36 +191,4 @@ mod tests { } } } - - #[test] - fn test_datetime_date_add() { - let f = DateAddFunction; - - let dates = vec![Some(123), None, Some(42), None]; - // Intervals in months - let intervals = vec![1, 2, 3, 1]; - let results = [Some(2678400123), None, Some(7776000042), None]; - - let date_vector = DateTimeVector::from(dates.clone()); - let interval_vector = IntervalYearMonthVector::from_vec(intervals); - let args: Vec = vec![Arc::new(date_vector), Arc::new(interval_vector)]; - let vector = f.eval(FunctionContext::default(), &args).unwrap(); - - assert_eq!(4, vector.len()); - for (i, _t) in dates.iter().enumerate() { - let v = vector.get(i); - let result = results.get(i).unwrap(); - - if result.is_none() { - assert_eq!(Value::Null, v); - continue; - } - match v { - Value::DateTime(date) => { - assert_eq!(date.val(), result.unwrap()); - } - _ => unreachable!(), - } - } - } } diff --git a/src/common/function/src/scalars/date/date_sub.rs b/src/common/function/src/scalars/date/date_sub.rs index b1f87e880ab7..1e00db5331ce 100644 --- a/src/common/function/src/scalars/date/date_sub.rs +++ b/src/common/function/src/scalars/date/date_sub.rs @@ -14,18 +14,19 @@ use std::fmt; -use common_query::error::{InvalidFuncArgsSnafu, Result, UnsupportedInputDataTypeSnafu}; +use common_query::error::{ArrowComputeSnafu, IntoVectorSnafu, InvalidFuncArgsSnafu, Result}; use common_query::prelude::Signature; -use datatypes::data_type::DataType; +use datatypes::arrow::compute::kernels::numeric; use datatypes::prelude::ConcreteDataType; -use datatypes::value::ValueRef; -use datatypes::vectors::VectorRef; -use snafu::ensure; +use datatypes::vectors::{Helper, VectorRef}; +use snafu::{ensure, ResultExt}; use crate::function::{Function, FunctionContext}; use crate::helper; -/// A function subtracts an interval value to Timestamp, Date or DateTime, and return the result. +/// A function subtracts an interval value to Timestamp, Date, and return the result. +/// The implementation of datetime type is based on Date64 which is incorrect so this function +/// doesn't support the datetime type. #[derive(Clone, Debug, Default)] pub struct DateSubFunction; @@ -44,7 +45,6 @@ impl Function for DateSubFunction { helper::one_of_sigs2( vec![ ConcreteDataType::date_datatype(), - ConcreteDataType::datetime_datatype(), ConcreteDataType::timestamp_second_datatype(), ConcreteDataType::timestamp_millisecond_datatype(), ConcreteDataType::timestamp_microsecond_datatype(), @@ -69,65 +69,14 @@ impl Function for DateSubFunction { } ); - let left = &columns[0]; - let right = &columns[1]; + let left = columns[0].to_arrow_array(); + let right = columns[1].to_arrow_array(); - let size = left.len(); - let left_datatype = columns[0].data_type(); - - match left_datatype { - ConcreteDataType::Timestamp(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let ts = left.get(i).as_timestamp(); - let interval = right.get(i).as_interval(); - - let new_ts = match (ts, interval) { - (Some(ts), Some(interval)) => ts.sub_interval(interval), - _ => ts, - }; - - result.push_value_ref(ValueRef::from(new_ts)); - } - - Ok(result.to_vector()) - } - ConcreteDataType::Date(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let date = left.get(i).as_date(); - let interval = right.get(i).as_interval(); - let new_date = match (date, interval) { - (Some(date), Some(interval)) => date.sub_interval(interval), - _ => date, - }; - - result.push_value_ref(ValueRef::from(new_date)); - } - - Ok(result.to_vector()) - } - ConcreteDataType::DateTime(_) => { - let mut result = left_datatype.create_mutable_vector(size); - for i in 0..size { - let datetime = left.get(i).as_datetime(); - let interval = right.get(i).as_interval(); - let new_datetime = match (datetime, interval) { - (Some(datetime), Some(interval)) => datetime.sub_interval(interval), - _ => datetime, - }; - - result.push_value_ref(ValueRef::from(new_datetime)); - } - - Ok(result.to_vector()) - } - _ => UnsupportedInputDataTypeSnafu { - function: NAME, - datatypes: columns.iter().map(|c| c.data_type()).collect::>(), - } - .fail(), - } + let result = numeric::sub(&left, &right).context(ArrowComputeSnafu)?; + let arrow_type = result.data_type().clone(); + Helper::try_into_vector(result).context(IntoVectorSnafu { + data_type: arrow_type, + }) } } @@ -145,8 +94,7 @@ mod tests { use datatypes::prelude::ConcreteDataType; use datatypes::value::Value; use datatypes::vectors::{ - DateTimeVector, DateVector, IntervalDayTimeVector, IntervalYearMonthVector, - TimestampSecondVector, + DateVector, IntervalDayTimeVector, IntervalYearMonthVector, TimestampSecondVector, }; use super::{DateSubFunction, *}; @@ -174,11 +122,15 @@ mod tests { f.return_type(&[ConcreteDataType::datetime_datatype()]) .unwrap() ); - assert!(matches!(f.signature(), + assert!( + matches!(f.signature(), Signature { type_signature: TypeSignature::OneOf(sigs), volatility: Volatility::Immutable - } if sigs.len() == 18)); + } if sigs.len() == 15), + "{:?}", + f.signature() + ); } #[test] @@ -250,42 +202,4 @@ mod tests { } } } - - #[test] - fn test_datetime_date_sub() { - let f = DateSubFunction; - let millis_per_month = 3600 * 24 * 30 * 1000; - - let dates = vec![ - Some(123 * millis_per_month), - None, - Some(42 * millis_per_month), - None, - ]; - // Intervals in months - let intervals = vec![1, 2, 3, 1]; - let results = [Some(316137600000), None, Some(100915200000), None]; - - let date_vector = DateTimeVector::from(dates.clone()); - let interval_vector = IntervalYearMonthVector::from_vec(intervals); - let args: Vec = vec![Arc::new(date_vector), Arc::new(interval_vector)]; - let vector = f.eval(FunctionContext::default(), &args).unwrap(); - - assert_eq!(4, vector.len()); - for (i, _t) in dates.iter().enumerate() { - let v = vector.get(i); - let result = results.get(i).unwrap(); - - if result.is_none() { - assert_eq!(Value::Null, v); - continue; - } - match v { - Value::DateTime(date) => { - assert_eq!(date.val(), result.unwrap()); - } - _ => unreachable!(), - } - } - } } diff --git a/src/common/grpc/src/select.rs b/src/common/grpc/src/select.rs index ba13acf3b7e9..493893f49d0d 100644 --- a/src/common/grpc/src/select.rs +++ b/src/common/grpc/src/select.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use api::helper::{convert_i128_to_interval, convert_to_pb_decimal128}; +use api::helper::{convert_month_day_nano_to_pb, convert_to_pb_decimal128}; use api::v1::column::Values; use common_base::BitVec; use datatypes::types::{IntervalType, TimeType, TimestampType, WrapperType}; @@ -211,7 +211,7 @@ pub fn values(arrays: &[VectorRef]) -> Result { ConcreteDataType::Interval(IntervalType::MonthDayNano(_)), IntervalMonthDayNanoVector, interval_month_day_nano_values, - |x| { convert_i128_to_interval(x.into_native()) } + |x| { convert_month_day_nano_to_pb(x) } ), ( ConcreteDataType::Decimal128(_), diff --git a/src/common/time/src/date.rs b/src/common/time/src/date.rs index 86759d737d41..42749139250d 100644 --- a/src/common/time/src/date.rs +++ b/src/common/time/src/date.rs @@ -14,13 +14,13 @@ use std::fmt::{Display, Formatter, Write}; -use chrono::{Datelike, Days, LocalResult, Months, NaiveDate, NaiveTime, TimeZone}; +use chrono::{Datelike, Days, LocalResult, Months, NaiveDate, NaiveTime, TimeDelta, TimeZone}; use serde::{Deserialize, Serialize}; use serde_json::Value; use snafu::ResultExt; use crate::error::{InvalidDateStrSnafu, ParseDateStrSnafu, Result}; -use crate::interval::Interval; +use crate::interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; use crate::timezone::get_timezone; use crate::util::datetime_to_utc; use crate::Timezone; @@ -134,29 +134,64 @@ impl Date { (self.0 as i64) * 24 * 3600 } - /// Adds given Interval to the current date. - /// Returns None if the resulting date would be out of range. - pub fn add_interval(&self, interval: Interval) -> Option { + // FIXME(yingwen): remove add/sub intervals later + /// Adds given [IntervalYearMonth] to the current date. + pub fn add_year_month(&self, interval: IntervalYearMonth) -> Option { let naive_date = self.to_chrono_date()?; - let (months, days, _) = interval.to_month_day_nano(); + naive_date + .checked_add_months(Months::new(interval.months as u32)) + .map(Into::into) + } + + /// Adds given [IntervalDayTime] to the current date. + pub fn add_day_time(&self, interval: IntervalDayTime) -> Option { + let naive_date = self.to_chrono_date()?; + + naive_date + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::milliseconds(interval.milliseconds as i64)) + .map(Into::into) + } + + /// Adds given [IntervalMonthDayNano] to the current date. + pub fn add_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { + let naive_date = self.to_chrono_date()?; naive_date - .checked_add_months(Months::new(months as u32))? - .checked_add_days(Days::new(days as u64)) + .checked_add_months(Months::new(interval.months as u32))? + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::nanoseconds(interval.nanoseconds)) .map(Into::into) } - /// Subtracts given Interval to the current date. - /// Returns None if the resulting date would be out of range. - pub fn sub_interval(&self, interval: Interval) -> Option { + /// Subtracts given [IntervalYearMonth] to the current date. + pub fn sub_year_month(&self, interval: IntervalYearMonth) -> Option { let naive_date = self.to_chrono_date()?; - let (months, days, _) = interval.to_month_day_nano(); + naive_date + .checked_sub_months(Months::new(interval.months as u32)) + .map(Into::into) + } + + /// Subtracts given [IntervalDayTime] to the current date. + pub fn sub_day_time(&self, interval: IntervalDayTime) -> Option { + let naive_date = self.to_chrono_date()?; + + naive_date + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::milliseconds(interval.milliseconds as i64)) + .map(Into::into) + } + + /// Subtracts given [IntervalMonthDayNano] to the current date. + pub fn sub_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { + let naive_date = self.to_chrono_date()?; naive_date - .checked_sub_months(Months::new(months as u32))? - .checked_sub_days(Days::new(days as u64)) + .checked_sub_months(Months::new(interval.months as u32))? + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::nanoseconds(interval.nanoseconds)) .map(Into::into) } @@ -246,12 +281,12 @@ mod tests { fn test_add_sub_interval() { let date = Date::new(1000); - let interval = Interval::from_year_month(3); + let interval = IntervalYearMonth::new(3); - let new_date = date.add_interval(interval).unwrap(); + let new_date = date.add_year_month(interval).unwrap(); assert_eq!(new_date.val(), 1091); - assert_eq!(date, new_date.sub_interval(interval).unwrap()); + assert_eq!(date, new_date.sub_year_month(interval).unwrap()); } #[test] diff --git a/src/common/time/src/datetime.rs b/src/common/time/src/datetime.rs index 4a60470aebce..abeae4908a11 100644 --- a/src/common/time/src/datetime.rs +++ b/src/common/time/src/datetime.rs @@ -13,16 +13,18 @@ // limitations under the License. use std::fmt::{Display, Formatter, Write}; -use std::time::Duration; -use chrono::{Days, LocalResult, Months, NaiveDateTime, TimeZone as ChronoTimeZone, Utc}; +use chrono::{ + Days, LocalResult, Months, NaiveDateTime, TimeDelta, TimeZone as ChronoTimeZone, Utc, +}; use serde::{Deserialize, Serialize}; use snafu::ResultExt; use crate::error::{InvalidDateStrSnafu, Result}; +use crate::interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; use crate::timezone::{get_timezone, Timezone}; use crate::util::{datetime_to_utc, format_utc_datetime}; -use crate::{Date, Interval}; +use crate::Date; const DATETIME_FORMAT: &str = "%F %H:%M:%S%.f"; const DATETIME_FORMAT_WITH_TZ: &str = "%F %H:%M:%S%.f%z"; @@ -160,32 +162,66 @@ impl DateTime { None => Utc.from_utc_datetime(&v).naive_local(), }) } - /// Adds given Interval to the current datetime. - /// Returns None if the resulting datetime would be out of range. - pub fn add_interval(&self, interval: Interval) -> Option { + + // FIXME(yingwen): remove add/sub intervals later + /// Adds given [IntervalYearMonth] to the current datetime. + pub fn add_year_month(&self, interval: IntervalYearMonth) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + naive_datetime + .checked_add_months(Months::new(interval.months as u32)) + .map(Into::into) + } + + /// Adds given [IntervalDayTime] to the current datetime. + pub fn add_day_time(&self, interval: IntervalDayTime) -> Option { let naive_datetime = self.to_chrono_datetime()?; - let (months, days, nsecs) = interval.to_month_day_nano(); - let naive_datetime = naive_datetime - .checked_add_months(Months::new(months as u32))? - .checked_add_days(Days::new(days as u64))? - + Duration::from_nanos(nsecs as u64); + naive_datetime + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::milliseconds(interval.milliseconds as i64)) + .map(Into::into) + } + + /// Adds given [IntervalMonthDayNano] to the current datetime. + pub fn add_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { + let naive_datetime = self.to_chrono_datetime()?; - Some(naive_datetime.into()) + naive_datetime + .checked_add_months(Months::new(interval.months as u32))? + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::nanoseconds(interval.nanoseconds)) + .map(Into::into) } - /// Subtracts given Interval to the current datetime. - /// Returns None if the resulting datetime would be out of range. - pub fn sub_interval(&self, interval: Interval) -> Option { + /// Subtracts given [IntervalYearMonth] to the current datetime. + pub fn sub_year_month(&self, interval: IntervalYearMonth) -> Option { let naive_datetime = self.to_chrono_datetime()?; - let (months, days, nsecs) = interval.to_month_day_nano(); - let naive_datetime = naive_datetime - .checked_sub_months(Months::new(months as u32))? - .checked_sub_days(Days::new(days as u64))? - - Duration::from_nanos(nsecs as u64); + naive_datetime + .checked_sub_months(Months::new(interval.months as u32)) + .map(Into::into) + } + + /// Subtracts given [IntervalDayTime] to the current datetime. + pub fn sub_day_time(&self, interval: IntervalDayTime) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + naive_datetime + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::milliseconds(interval.milliseconds as i64)) + .map(Into::into) + } + + /// Subtracts given [IntervalMonthDayNano] to the current datetime. + pub fn sub_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { + let naive_datetime = self.to_chrono_datetime()?; - Some(naive_datetime.into()) + naive_datetime + .checked_sub_months(Months::new(interval.months as u32))? + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::nanoseconds(interval.nanoseconds)) + .map(Into::into) } /// Convert to [common_time::date]. @@ -231,12 +267,12 @@ mod tests { fn test_add_sub_interval() { let datetime = DateTime::new(1000); - let interval = Interval::from_day_time(1, 200); + let interval = IntervalDayTime::new(1, 200); - let new_datetime = datetime.add_interval(interval).unwrap(); + let new_datetime = datetime.add_day_time(interval).unwrap(); assert_eq!(new_datetime.val(), 1000 + 3600 * 24 * 1000 + 200); - assert_eq!(datetime, new_datetime.sub_interval(interval).unwrap()); + assert_eq!(datetime, new_datetime.sub_day_time(interval).unwrap()); } #[test] diff --git a/src/common/time/src/interval.rs b/src/common/time/src/interval.rs index cd57028d29f6..0ca40f7d79d8 100644 --- a/src/common/time/src/interval.rs +++ b/src/common/time/src/interval.rs @@ -12,18 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::cmp::Ordering; -use std::default::Default; -use std::fmt::{self, Display, Formatter, Write}; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use arrow::datatypes::IntervalUnit as ArrowIntervalUnit; use serde::{Deserialize, Serialize}; -use serde_json::Value; -use snafu::ResultExt; - -use crate::duration::Duration; -use crate::error::{Result, TimestampOverflowSnafu}; #[derive( Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, @@ -61,268 +53,269 @@ impl From for IntervalUnit { } } -/// Interval Type represents a period of time. -/// It is composed of months, days and nanoseconds. -/// 3 kinds of interval are supported: year-month, day-time and -/// month-day-nano, which will be stored in the following format. -/// Interval data format: -/// | months | days | nsecs | -/// | 4bytes | 4bytes | 8bytes | -#[derive(Debug, Clone, Default, Copy, Serialize, Deserialize)] -pub struct Interval { - months: i32, - days: i32, - nsecs: i64, - unit: IntervalUnit, +// The `Value` type requires Serialize, Deserialize. +#[derive( + Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, +)] +#[repr(C)] +pub struct IntervalYearMonth { + /// Number of months + pub months: i32, } -// Nanosecond convert to other time unit -pub const NANOS_PER_SEC: i64 = 1_000_000_000; -pub const NANOS_PER_MILLI: i64 = 1_000_000; -pub const NANOS_PER_MICRO: i64 = 1_000; -pub const NANOS_PER_HOUR: i64 = 60 * 60 * NANOS_PER_SEC; -pub const NANOS_PER_DAY: i64 = 24 * NANOS_PER_HOUR; -pub const NANOS_PER_MONTH: i64 = 30 * NANOS_PER_DAY; - -pub const DAYS_PER_MONTH: i64 = 30; - -impl Interval { - /// Creates a new interval from months, days and nanoseconds. - /// Precision is nanosecond. - pub fn from_month_day_nano(months: i32, days: i32, nsecs: i64) -> Self { - Interval { - months, - days, - nsecs, - unit: IntervalUnit::MonthDayNano, - } +impl IntervalYearMonth { + pub fn new(months: i32) -> Self { + Self { months } } - /// Creates a new interval from months. - pub fn from_year_month(months: i32) -> Self { - Interval { - months, - days: 0, - nsecs: 0, - unit: IntervalUnit::YearMonth, - } + pub fn to_i32(&self) -> i32 { + self.months } - /// Creates a new interval from days and milliseconds. - pub fn from_day_time(days: i32, millis: i32) -> Self { - Interval { - months: 0, - days, - nsecs: (millis as i64) * NANOS_PER_MILLI, - unit: IntervalUnit::DayTime, + pub fn from_i32(months: i32) -> Self { + Self { months } + } + + pub fn negative(&self) -> Self { + Self::new(-self.months) + } + + pub fn to_iso8601_string(&self) -> String { + IntervalFormat::from(*self).to_iso8601_string() + } +} + +impl From for IntervalFormat { + fn from(interval: IntervalYearMonth) -> Self { + IntervalFormat { + years: interval.months / 12, + months: interval.months % 12, + ..Default::default() } } +} - pub fn to_duration(&self) -> Result { - Ok(Duration::new_nanosecond( - self.to_nanosecond() - .try_into() - .context(TimestampOverflowSnafu)?, - )) +impl From for IntervalYearMonth { + fn from(v: i32) -> Self { + Self::from_i32(v) } +} - /// Return a tuple(months, days, nanoseconds) from the interval. - pub fn to_month_day_nano(&self) -> (i32, i32, i64) { - (self.months, self.days, self.nsecs) +impl From for i32 { + fn from(v: IntervalYearMonth) -> Self { + v.to_i32() } +} - /// Converts the interval to nanoseconds. - pub fn to_nanosecond(&self) -> i128 { - let days = (self.days as i64) + DAYS_PER_MONTH * (self.months as i64); - (self.nsecs as i128) + (NANOS_PER_DAY as i128) * (days as i128) +impl From for serde_json::Value { + fn from(v: IntervalYearMonth) -> Self { + serde_json::Value::from(v.to_i32()) } +} - /// Smallest interval value. - pub const MIN: Self = Self { - months: i32::MIN, - days: i32::MIN, - nsecs: i64::MIN, - unit: IntervalUnit::MonthDayNano, - }; +#[derive( + Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, +)] +#[repr(C)] +pub struct IntervalDayTime { + /// Number of days + pub days: i32, + /// Number of milliseconds + pub milliseconds: i32, +} - /// Largest interval value. - pub const MAX: Self = Self { - months: i32::MAX, - days: i32::MAX, - nsecs: i64::MAX, - unit: IntervalUnit::MonthDayNano, - }; +impl IntervalDayTime { + /// The additive identity i.e. `0`. + pub const ZERO: Self = Self::new(0, 0); - /// Returns the justified interval. - /// allows you to adjust the interval of 30-day as one month and the interval of 24-hour as one day - pub fn justified_interval(&self) -> Self { - let mut result = *self; - let extra_months_d = self.days as i64 / DAYS_PER_MONTH; - let extra_months_nsecs = self.nsecs / NANOS_PER_MONTH; - result.days -= (extra_months_d * DAYS_PER_MONTH) as i32; - result.nsecs -= extra_months_nsecs * NANOS_PER_MONTH; + /// The multiplicative inverse, i.e. `-1`. + pub const MINUS_ONE: Self = Self::new(-1, -1); - let extra_days = self.nsecs / NANOS_PER_DAY; - result.nsecs -= extra_days * NANOS_PER_DAY; + /// The maximum value that can be represented + pub const MAX: Self = Self::new(i32::MAX, i32::MAX); - result.months += extra_months_d as i32 + extra_months_nsecs as i32; - result.days += extra_days as i32; + /// The minimum value that can be represented + pub const MIN: Self = Self::new(i32::MIN, i32::MIN); - result + pub const fn new(days: i32, milliseconds: i32) -> Self { + Self { days, milliseconds } } - /// Convert Interval to nanoseconds, - /// to check whether Interval is positive - pub fn is_positive(&self) -> bool { - self.to_nanosecond() > 0 + pub fn to_i64(&self) -> i64 { + let d = (self.days as u64 & u32::MAX as u64) << 32; + let m = self.milliseconds as u64 & u32::MAX as u64; + (d | m) as i64 } - /// is_zero - pub fn is_zero(&self) -> bool { - self.months == 0 && self.days == 0 && self.nsecs == 0 - } - - /// get unit - pub fn unit(&self) -> IntervalUnit { - self.unit - } - - /// Multiple Interval by an integer with overflow check. - /// Returns justified Interval, or `None` if overflow occurred. - pub fn checked_mul_int(&self, rhs: I) -> Option - where - I: TryInto, - { - let rhs = rhs.try_into().ok()?; - let months = self.months.checked_mul(rhs)?; - let days = self.days.checked_mul(rhs)?; - let nsecs = self.nsecs.checked_mul(rhs as i64)?; - - Some( - Self { - months, - days, - nsecs, - unit: self.unit, - } - .justified_interval(), - ) + pub fn from_i64(value: i64) -> Self { + let days = (value >> 32) as i32; + let milliseconds = value as i32; + Self { days, milliseconds } } - /// Convert Interval to ISO 8601 string - pub fn to_iso8601_string(self) -> String { - IntervalFormat::from(self).to_iso8601_string() + pub fn negative(&self) -> Self { + Self::new(-self.days, -self.milliseconds) } - /// Convert Interval to postgres verbose string - pub fn to_postgres_string(self) -> String { - IntervalFormat::from(self).to_postgres_string() + pub fn to_iso8601_string(&self) -> String { + IntervalFormat::from(*self).to_iso8601_string() } - /// Convert Interval to sql_standard string - pub fn to_sql_standard_string(self) -> String { - IntervalFormat::from(self).to_sql_standard_string() + pub fn as_millis(&self) -> i64 { + self.days as i64 * MS_PER_DAY + self.milliseconds as i64 } +} - /// Interval Type and i128 [IntervalUnit::MonthDayNano] Convert - /// v consists of months(i32) | days(i32) | nsecs(i64) - pub fn from_i128(v: i128) -> Self { - Interval { - nsecs: v as i64, - days: (v >> 64) as i32, - months: (v >> 96) as i32, - unit: IntervalUnit::MonthDayNano, - } +impl From for IntervalDayTime { + fn from(v: i64) -> Self { + Self::from_i64(v) + } +} + +impl From for i64 { + fn from(v: IntervalDayTime) -> Self { + v.to_i64() } +} + +impl From for serde_json::Value { + fn from(v: IntervalDayTime) -> Self { + serde_json::Value::from(v.to_i64()) + } +} + +// Millisecond convert to other time unit +pub const MS_PER_SEC: i64 = 1_000; +pub const MS_PER_MINUTE: i64 = 60 * MS_PER_SEC; +pub const MS_PER_HOUR: i64 = 60 * MS_PER_MINUTE; +pub const MS_PER_DAY: i64 = 24 * MS_PER_HOUR; +pub const NANOS_PER_MILLI: i64 = 1_000_000; - /// `Interval` Type and i64 [IntervalUnit::DayTime] Convert - /// v consists of days(i32) | milliseconds(i32) - pub fn from_i64(v: i64) -> Self { - Interval { - nsecs: ((v as i32) as i64) * NANOS_PER_MILLI, - days: (v >> 32) as i32, - months: 0, - unit: IntervalUnit::DayTime, +impl From for IntervalFormat { + fn from(interval: IntervalDayTime) -> Self { + IntervalFormat { + days: interval.days, + hours: interval.milliseconds as i64 / MS_PER_HOUR, + minutes: (interval.milliseconds as i64 % MS_PER_HOUR) / MS_PER_MINUTE, + seconds: (interval.milliseconds as i64 % MS_PER_MINUTE) / MS_PER_SEC, + microseconds: (interval.milliseconds as i64 % MS_PER_SEC) * MS_PER_SEC, + ..Default::default() } } +} + +#[derive( + Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize, +)] +#[repr(C)] +pub struct IntervalMonthDayNano { + /// Number of months + pub months: i32, + /// Number of days + pub days: i32, + /// Number of nanoseconds + pub nanoseconds: i64, +} + +impl IntervalMonthDayNano { + /// The additive identity i.e. `0`. + pub const ZERO: Self = Self::new(0, 0, 0); - /// `Interval` Type and i32 [IntervalUnit::YearMonth] Convert - /// v consists of months(i32) - pub fn from_i32(v: i32) -> Self { - Interval { - nsecs: 0, - days: 0, - months: v, - unit: IntervalUnit::YearMonth, + /// The multiplicative inverse, i.e. `-1`. + pub const MINUS_ONE: Self = Self::new(-1, -1, -1); + + /// The maximum value that can be represented + pub const MAX: Self = Self::new(i32::MAX, i32::MAX, i64::MAX); + + /// The minimum value that can be represented + pub const MIN: Self = Self::new(i32::MIN, i32::MIN, i64::MIN); + + pub const fn new(months: i32, days: i32, nanoseconds: i64) -> Self { + Self { + months, + days, + nanoseconds, } } pub fn to_i128(&self) -> i128 { - // 128 96 64 0 - // +-------+-------+-------+-------+-------+-------+-------+-------+ - // | months | days | nanoseconds | - // +-------+-------+-------+-------+-------+-------+-------+-------+ - let months = (self.months as u128 & u32::MAX as u128) << 96; - let days = (self.days as u128 & u32::MAX as u128) << 64; - let nsecs = self.nsecs as u128 & u64::MAX as u128; - (months | days | nsecs) as i128 + let m = (self.months as u128 & u32::MAX as u128) << 96; + let d = (self.days as u128 & u32::MAX as u128) << 64; + let n = self.nanoseconds as u128 & u64::MAX as u128; + (m | d | n) as i128 } - pub fn to_i64(&self) -> i64 { - // 64 32 0 - // +-------+-------+-------+-------+-------+-------+-------+-------+ - // | days | milliseconds | - // +-------+-------+-------+-------+-------+-------+-------+-------+ - let days = (self.days as u64 & u32::MAX as u64) << 32; - let milliseconds = (self.nsecs / NANOS_PER_MILLI) as u64 & u32::MAX as u64; - (days | milliseconds) as i64 + pub fn from_i128(value: i128) -> Self { + let months = (value >> 96) as i32; + let days = (value >> 64) as i32; + let nanoseconds = value as i64; + Self { + months, + days, + nanoseconds, + } } - pub fn to_i32(&self) -> i32 { - self.months + pub fn negative(&self) -> Self { + Self::new(-self.months, -self.days, -self.nanoseconds) } - pub fn negative(&self) -> Self { - Self { - months: -self.months, - days: -self.days, - nsecs: -self.nsecs, - unit: self.unit, - } + pub fn to_iso8601_string(&self) -> String { + IntervalFormat::from(*self).to_iso8601_string() } } -impl From for Interval { +impl From for IntervalMonthDayNano { fn from(v: i128) -> Self { Self::from_i128(v) } } -impl From for i128 { - fn from(v: Interval) -> Self { +impl From for i128 { + fn from(v: IntervalMonthDayNano) -> Self { v.to_i128() } } -impl From for serde_json::Value { - fn from(v: Interval) -> Self { - Value::String(v.to_string()) +impl From for serde_json::Value { + fn from(v: IntervalMonthDayNano) -> Self { + serde_json::Value::from(v.to_i128().to_string()) } } -impl Display for Interval { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut s = String::new(); - if self.months != 0 { - write!(s, "{} months ", self.months)?; - } - if self.days != 0 { - write!(s, "{} days ", self.days)?; - } - if self.nsecs != 0 { - write!(s, "{} nsecs", self.nsecs)?; +// Nanosecond convert to other time unit +pub const NS_PER_SEC: i64 = 1_000_000_000; +pub const NS_PER_MINUTE: i64 = 60 * NS_PER_SEC; +pub const NS_PER_HOUR: i64 = 60 * NS_PER_MINUTE; +pub const NS_PER_DAY: i64 = 24 * NS_PER_HOUR; + +impl From for IntervalFormat { + fn from(interval: IntervalMonthDayNano) -> Self { + IntervalFormat { + years: interval.months / 12, + months: interval.months % 12, + days: interval.days, + hours: interval.nanoseconds / NS_PER_HOUR, + minutes: (interval.nanoseconds % NS_PER_HOUR) / NS_PER_MINUTE, + seconds: (interval.nanoseconds % NS_PER_MINUTE) / NS_PER_SEC, + microseconds: (interval.nanoseconds % NS_PER_SEC) / 1_000, } - write!(f, "{}", s.trim()) + } +} + +pub fn interval_year_month_to_month_day_nano(interval: IntervalYearMonth) -> IntervalMonthDayNano { + IntervalMonthDayNano { + months: interval.months, + days: 0, + nanoseconds: 0, + } +} + +pub fn interval_day_time_to_month_day_nano(interval: IntervalDayTime) -> IntervalMonthDayNano { + IntervalMonthDayNano { + months: 0, + days: interval.days, + nanoseconds: interval.milliseconds as i64 * NANOS_PER_MILLI, } } @@ -339,31 +332,6 @@ pub struct IntervalFormat { pub microseconds: i64, } -impl From for IntervalFormat { - fn from(val: Interval) -> IntervalFormat { - let months = val.months; - let days = val.days; - let microseconds = val.nsecs / NANOS_PER_MICRO; - let years = (months - (months % 12)) / 12; - let months = months - years * 12; - let hours = (microseconds - (microseconds % 3_600_000_000)) / 3_600_000_000; - let microseconds = microseconds - hours * 3_600_000_000; - let minutes = (microseconds - (microseconds % 60_000_000)) / 60_000_000; - let microseconds = microseconds - minutes * 60_000_000; - let seconds = (microseconds - (microseconds % 1_000_000)) / 1_000_000; - let microseconds = microseconds - seconds * 1_000_000; - IntervalFormat { - years, - months, - days, - hours, - minutes, - seconds, - microseconds, - } - } -} - impl IntervalFormat { /// All the field in the interval is 0 pub fn is_zero(&self) -> bool { @@ -540,117 +508,37 @@ fn get_time_part( interval } -/// IntervalCompare is used to compare two intervals -/// It makes interval into nanoseconds style. -#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)] -struct IntervalCompare(i128); - -impl From for IntervalCompare { - fn from(interval: Interval) -> Self { - Self(interval.to_nanosecond()) - } -} - -impl Ord for Interval { - fn cmp(&self, other: &Self) -> Ordering { - IntervalCompare::from(*self).cmp(&IntervalCompare::from(*other)) - } -} - -impl PartialOrd for Interval { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Eq for Interval {} - -impl PartialEq for Interval { - fn eq(&self, other: &Self) -> bool { - self.cmp(other).is_eq() - } -} - -impl Hash for Interval { - fn hash(&self, state: &mut H) { - IntervalCompare::from(*self).hash(state) - } -} - #[cfg(test)] mod tests { - use std::collections::HashMap; - use super::*; - use crate::timestamp::TimeUnit; #[test] fn test_from_year_month() { - let interval = Interval::from_year_month(1); + let interval = IntervalYearMonth::new(1); assert_eq!(interval.months, 1); } #[test] fn test_from_date_time() { - let interval = Interval::from_day_time(1, 2); + let interval = IntervalDayTime::new(1, 2); assert_eq!(interval.days, 1); - assert_eq!(interval.nsecs, 2_000_000); + assert_eq!(interval.milliseconds, 2); } #[test] - fn test_to_duration() { - let interval = Interval::from_day_time(1, 2); - - let duration = interval.to_duration().unwrap(); - assert_eq!(86400002000000, duration.value()); - assert_eq!(TimeUnit::Nanosecond, duration.unit()); - - let interval = Interval::from_year_month(12); - - let duration = interval.to_duration().unwrap(); - assert_eq!(31104000000000000, duration.value()); - assert_eq!(TimeUnit::Nanosecond, duration.unit()); - } - - #[test] - fn test_interval_is_positive() { - let interval = Interval::from_year_month(1); - assert!(interval.is_positive()); - let interval = Interval::from_year_month(-1); - assert!(!interval.is_positive()); - - let interval = Interval::from_day_time(1, i32::MIN); - assert!(!interval.is_positive()); - } - - #[test] - fn test_to_nanosecond() { - let interval = Interval::from_year_month(1); - assert_eq!(interval.to_nanosecond(), 2592000000000000); - let interval = Interval::from_day_time(1, 2); - assert_eq!(interval.to_nanosecond(), 86400002000000); - - let max_interval = Interval::from_month_day_nano(i32::MAX, i32::MAX, i64::MAX); - assert_eq!(max_interval.to_nanosecond(), 5751829423496836854775807); - - let min_interval = Interval::from_month_day_nano(i32::MIN, i32::MIN, i64::MIN); - assert_eq!(min_interval.to_nanosecond(), -5751829426175236854775808); - } - - #[test] - fn test_interval_is_zero() { - let interval = Interval::from_month_day_nano(1, 1, 1); - assert!(!interval.is_zero()); - let interval = Interval::from_month_day_nano(0, 0, 0); - assert!(interval.is_zero()); + fn test_from_month_day_nano() { + let interval = IntervalMonthDayNano::new(1, 2, 3); + assert_eq!(interval.months, 1); + assert_eq!(interval.days, 2); + assert_eq!(interval.nanoseconds, 3); } #[test] fn test_interval_i128_convert() { let test_interval_eq = |month, day, nano| { - let interval = Interval::from_month_day_nano(month, day, nano); + let interval = IntervalMonthDayNano::new(month, day, nano); let interval_i128 = interval.to_i128(); - let interval2 = Interval::from_i128(interval_i128); + let interval2 = IntervalMonthDayNano::from_i128(interval_i128); assert_eq!(interval, interval2); }; @@ -666,11 +554,26 @@ mod tests { test_interval_eq(i32::MAX, i32::MIN, i64::MIN); test_interval_eq(i32::MIN, i32::MAX, i64::MIN); test_interval_eq(i32::MIN, i32::MIN, i64::MIN); + + let interval = IntervalMonthDayNano::from_i128(1); + assert_eq!(interval, IntervalMonthDayNano::new(0, 0, 1)); + assert_eq!(1, IntervalMonthDayNano::new(0, 0, 1).to_i128()); + } + + #[test] + fn test_interval_i64_convert() { + let interval = IntervalDayTime::from_i64(1); + assert_eq!(interval, IntervalDayTime::new(0, 1)); + assert_eq!(1, IntervalDayTime::new(0, 1).to_i64()); } #[test] fn test_convert_interval_format() { - let interval = Interval::from_month_day_nano(14, 160, 1000000); + let interval = IntervalMonthDayNano { + months: 14, + days: 160, + nanoseconds: 1000000, + }; let interval_format = IntervalFormat::from(interval); assert_eq!(interval_format.years, 1); assert_eq!(interval_format.months, 2); @@ -681,94 +584,34 @@ mod tests { assert_eq!(interval_format.microseconds, 1000); } - #[test] - fn test_interval_hash() { - let interval = Interval::from_month_day_nano(1, 31, 1); - let interval2 = Interval::from_month_day_nano(2, 1, 1); - let mut map = HashMap::new(); - map.insert(interval, 1); - assert_eq!(map.get(&interval2), Some(&1)); - } - - #[test] - fn test_interval_mul_int() { - let interval = Interval::from_month_day_nano(1, 1, 1); - let interval2 = interval.checked_mul_int(2).unwrap(); - assert_eq!(interval2.months, 2); - assert_eq!(interval2.days, 2); - assert_eq!(interval2.nsecs, 2); - - // test justified interval - let interval = Interval::from_month_day_nano(1, 31, 1); - let interval2 = interval.checked_mul_int(2).unwrap(); - assert_eq!(interval2.months, 4); - assert_eq!(interval2.days, 2); - assert_eq!(interval2.nsecs, 2); - - // test overflow situation - let interval = Interval::from_month_day_nano(i32::MAX, 1, 1); - let interval2 = interval.checked_mul_int(2); - assert!(interval2.is_none()); - } - - #[test] - fn test_display() { - let interval = Interval::from_month_day_nano(1, 1, 1); - assert_eq!(interval.to_string(), "1 months 1 days 1 nsecs"); - - let interval = Interval::from_month_day_nano(14, 31, 10000000000); - assert_eq!(interval.to_string(), "14 months 31 days 10000000000 nsecs"); - } - - #[test] - fn test_interval_justified() { - let interval = Interval::from_month_day_nano(1, 131, 1).justified_interval(); - let interval2 = Interval::from_month_day_nano(5, 11, 1); - assert_eq!(interval, interval2); - - let interval = Interval::from_month_day_nano(1, 1, NANOS_PER_MONTH + 2 * NANOS_PER_DAY) - .justified_interval(); - let interval2 = Interval::from_month_day_nano(2, 3, 0); - assert_eq!(interval, interval2); - } - - #[test] - fn test_serde_json() { - let interval = Interval::from_month_day_nano(1, 1, 1); - let json = serde_json::to_string(&interval).unwrap(); - assert_eq!( - json, - "{\"months\":1,\"days\":1,\"nsecs\":1,\"unit\":\"MonthDayNano\"}" - ); - let interval2: Interval = serde_json::from_str(&json).unwrap(); - assert_eq!(interval, interval2); - } - #[test] fn test_to_iso8601_string() { // Test interval zero - let interval = Interval::from_month_day_nano(0, 0, 0); + let interval = IntervalMonthDayNano::new(0, 0, 0); assert_eq!(interval.to_iso8601_string(), "PT0S"); - let interval = Interval::from_month_day_nano(1, 1, 1); + let interval = IntervalMonthDayNano::new(1, 1, 1); assert_eq!(interval.to_iso8601_string(), "P0Y1M1DT0H0M0S"); - let interval = Interval::from_month_day_nano(14, 31, 10000000000); + let interval = IntervalMonthDayNano::new(14, 31, 10000000000); assert_eq!(interval.to_iso8601_string(), "P1Y2M31DT0H0M10S"); - let interval = Interval::from_month_day_nano(14, 31, 23210200000000); + let interval = IntervalMonthDayNano::new(14, 31, 23210200000000); assert_eq!(interval.to_iso8601_string(), "P1Y2M31DT6H26M50.2S"); } #[test] fn test_to_postgres_string() { // Test interval zero - let interval = Interval::from_month_day_nano(0, 0, 0); - assert_eq!(interval.to_postgres_string(), "00:00:00"); + let interval = IntervalMonthDayNano::new(0, 0, 0); + assert_eq!( + IntervalFormat::from(interval).to_postgres_string(), + "00:00:00" + ); - let interval = Interval::from_month_day_nano(23, 100, 23210200000000); + let interval = IntervalMonthDayNano::new(23, 100, 23210200000000); assert_eq!( - interval.to_postgres_string(), + IntervalFormat::from(interval).to_postgres_string(), "1 year 11 mons 100 days 06:26:50.200000" ); } @@ -776,18 +619,21 @@ mod tests { #[test] fn test_to_sql_standard_string() { // Test zero interval - let interval = Interval::from_month_day_nano(0, 0, 0); - assert_eq!(interval.to_sql_standard_string(), "0"); + let interval = IntervalMonthDayNano::new(0, 0, 0); + assert_eq!(IntervalFormat::from(interval).to_sql_standard_string(), "0"); - let interval = Interval::from_month_day_nano(23, 100, 23210200000000); + let interval = IntervalMonthDayNano::new(23, 100, 23210200000000); assert_eq!( - interval.to_sql_standard_string(), + IntervalFormat::from(interval).to_sql_standard_string(), "+1-11 +100 +6:26:50.200000" ); // Test interval without year, month, day - let interval = Interval::from_month_day_nano(0, 0, 23210200000000); - assert_eq!(interval.to_sql_standard_string(), "6:26:50.200000"); + let interval = IntervalMonthDayNano::new(0, 0, 23210200000000); + assert_eq!( + IntervalFormat::from(interval).to_sql_standard_string(), + "6:26:50.200000" + ); } #[test] diff --git a/src/common/time/src/lib.rs b/src/common/time/src/lib.rs index 770057394c2a..fa025bf661c2 100644 --- a/src/common/time/src/lib.rs +++ b/src/common/time/src/lib.rs @@ -27,7 +27,7 @@ pub mod util; pub use date::Date; pub use datetime::DateTime; pub use duration::Duration; -pub use interval::Interval; +pub use interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; pub use range::RangeMillis; pub use timestamp::Timestamp; pub use timestamp_millis::TimestampMillis; diff --git a/src/common/time/src/timestamp.rs b/src/common/time/src/timestamp.rs index 503c44cf9901..258e9c1a968b 100644 --- a/src/common/time/src/timestamp.rs +++ b/src/common/time/src/timestamp.rs @@ -20,16 +20,17 @@ use std::time::Duration; use arrow::datatypes::TimeUnit as ArrowTimeUnit; use chrono::{ - DateTime, Days, LocalResult, Months, NaiveDate, NaiveDateTime, NaiveTime, + DateTime, Days, LocalResult, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta, TimeZone as ChronoTimeZone, Utc, }; use serde::{Deserialize, Serialize}; use snafu::{OptionExt, ResultExt}; +use crate::error; use crate::error::{ArithmeticOverflowSnafu, ParseTimestampSnafu, Result, TimestampOverflowSnafu}; +use crate::interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; use crate::timezone::{get_timezone, Timezone}; use crate::util::{datetime_to_utc, div_ceil}; -use crate::{error, Interval}; /// Timestamp represents the value of units(seconds/milliseconds/microseconds/nanoseconds) elapsed /// since UNIX epoch. The valid value range of [Timestamp] depends on it's unit (all in UTC timezone): @@ -140,40 +141,77 @@ impl Timestamp { }) } - /// Adds given Interval to the current timestamp. - /// Returns None if the resulting timestamp would be out of range. - pub fn add_interval(&self, interval: Interval) -> Option { + // FIXME(yingwen): remove add/sub intervals later + /// Adds given [IntervalYearMonth] to the current timestamp. + pub fn add_year_month(&self, interval: IntervalYearMonth) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + let naive_datetime = + naive_datetime.checked_add_months(Months::new(interval.months as u32))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) + } + + /// Adds given [IntervalDayTime] to the current timestamp. + pub fn add_day_time(&self, interval: IntervalDayTime) -> Option { let naive_datetime = self.to_chrono_datetime()?; - let (months, days, nsecs) = interval.to_month_day_nano(); let naive_datetime = naive_datetime - .checked_add_months(Months::new(months as u32))? - .checked_add_days(Days::new(days as u64))? - + Duration::from_nanos(nsecs as u64); - - match Timestamp::from_chrono_datetime(naive_datetime) { - // Have to convert the new timestamp by the current unit. - Some(ts) => ts.convert_to(self.unit), - None => None, - } + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::milliseconds(interval.milliseconds as i64))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) } - /// Subtracts given Interval to the current timestamp. - /// Returns None if the resulting timestamp would be out of range. - pub fn sub_interval(&self, interval: Interval) -> Option { + /// Adds given [IntervalMonthDayNano] to the current timestamp. + pub fn add_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { let naive_datetime = self.to_chrono_datetime()?; - let (months, days, nsecs) = interval.to_month_day_nano(); let naive_datetime = naive_datetime - .checked_sub_months(Months::new(months as u32))? - .checked_sub_days(Days::new(days as u64))? - - Duration::from_nanos(nsecs as u64); - - match Timestamp::from_chrono_datetime(naive_datetime) { - // Have to convert the new timestamp by the current unit. - Some(ts) => ts.convert_to(self.unit), - None => None, - } + .checked_add_months(Months::new(interval.months as u32))? + .checked_add_days(Days::new(interval.days as u64))? + .checked_add_signed(TimeDelta::nanoseconds(interval.nanoseconds))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) + } + + /// Subtracts given [IntervalYearMonth] to the current timestamp. + pub fn sub_year_month(&self, interval: IntervalYearMonth) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + let naive_datetime = + naive_datetime.checked_sub_months(Months::new(interval.months as u32))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) + } + + /// Subtracts given [IntervalDayTime] to the current timestamp. + pub fn sub_day_time(&self, interval: IntervalDayTime) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + let naive_datetime = naive_datetime + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::milliseconds(interval.milliseconds as i64))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) + } + + /// Subtracts given [IntervalMonthDayNano] to the current timestamp. + pub fn sub_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option { + let naive_datetime = self.to_chrono_datetime()?; + + let naive_datetime = naive_datetime + .checked_sub_months(Months::new(interval.months as u32))? + .checked_sub_days(Days::new(interval.days as u64))? + .checked_sub_signed(TimeDelta::nanoseconds(interval.nanoseconds))?; + + // Have to convert the new timestamp by the current unit. + Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit)) } /// Subtracts current timestamp with another timestamp, yielding a duration. @@ -688,13 +726,13 @@ mod tests { fn test_add_sub_interval() { let ts = Timestamp::new(1000, TimeUnit::Millisecond); - let interval = Interval::from_day_time(1, 200); + let interval = IntervalDayTime::new(1, 200); - let new_ts = ts.add_interval(interval).unwrap(); + let new_ts = ts.add_day_time(interval).unwrap(); assert_eq!(new_ts.unit(), TimeUnit::Millisecond); assert_eq!(new_ts.value(), 1000 + 3600 * 24 * 1000 + 200); - assert_eq!(ts, new_ts.sub_interval(interval).unwrap()); + assert_eq!(ts, new_ts.sub_day_time(interval).unwrap()); } #[test] diff --git a/src/datatypes/src/interval.rs b/src/datatypes/src/interval.rs index c0969abc4478..b724de802257 100644 --- a/src/datatypes/src/interval.rs +++ b/src/datatypes/src/interval.rs @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common_time::interval::Interval; +use common_time::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; use paste::paste; -use serde::{Deserialize, Serialize}; -use crate::prelude::{Scalar, Value, ValueRef}; +use crate::prelude::Scalar; use crate::scalars::ScalarRef; use crate::types::{ IntervalDayTimeType, IntervalMonthDayNanoType, IntervalYearMonthType, WrapperType, @@ -26,39 +25,6 @@ use crate::vectors::{IntervalDayTimeVector, IntervalMonthDayNanoVector, Interval macro_rules! define_interval_with_unit { ($unit: ident, $native_ty: ty) => { paste! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] - pub struct [](pub Interval); - - impl [] { - pub fn new(val: $native_ty) -> Self { - Self(Interval:: [](val)) - } - } - - impl Default for [] { - fn default() -> Self { - Self::new(0) - } - } - - impl From<[]> for Value { - fn from(t: []) -> Value { - Value::Interval(t.0) - } - } - - impl From<[]> for serde_json::Value { - fn from(t: []) -> Self { - t.0.into() - } - } - - impl From<[]> for ValueRef<'static> { - fn from(t: []) -> Self { - ValueRef::Interval(t.0) - } - } - impl Scalar for [] { type VectorType = []; type RefType<'a> = []; @@ -87,41 +53,11 @@ macro_rules! define_interval_with_unit { type Native = $native_ty; fn from_native(value: Self::Native) -> Self { - Self::new(value) + Self::[](value) } fn into_native(self) -> Self::Native { - self.0.[]() - } - } - - impl From<$native_ty> for [] { - fn from(val: $native_ty) -> Self { - []::from_native(val as $native_ty) - } - } - - impl From<[]> for $native_ty { - fn from(val: []) -> Self { - val.0.[]() - } - } - - impl TryFrom for Option<[]> { - type Error = $crate::error::Error; - - #[inline] - fn try_from(from: Value) -> std::result::Result { - match from { - Value::Interval(v) if v.unit() == common_time::interval::IntervalUnit::$unit => { - Ok(Some([](v))) - }, - Value::Null => Ok(None), - _ => $crate::error::TryFromValueSnafu { - reason: format!("{:?} is not a {}", from, stringify!([])), - } - .fail(), - } + self.[]() } } } @@ -138,17 +74,17 @@ mod tests { #[test] fn test_interval_scalar() { - let interval = IntervalYearMonth::new(1000); + let interval = IntervalYearMonth::from(1000); assert_eq!(interval, interval.as_scalar_ref()); assert_eq!(interval, interval.to_owned_scalar()); assert_eq!(1000, interval.into_native()); - let interval = IntervalDayTime::new(1000); + let interval = IntervalDayTime::from(1000); assert_eq!(interval, interval.as_scalar_ref()); assert_eq!(interval, interval.to_owned_scalar()); assert_eq!(1000, interval.into_native()); - let interval = IntervalMonthDayNano::new(1000); + let interval = IntervalMonthDayNano::from(1000); assert_eq!(interval, interval.as_scalar_ref()); assert_eq!(interval, interval.to_owned_scalar()); assert_eq!(1000, interval.into_native()); @@ -156,15 +92,15 @@ mod tests { #[test] fn test_interval_convert_to_native_type() { - let interval = IntervalMonthDayNano::new(1000); + let interval = IntervalMonthDayNano::from(1000); let native_value: i128 = interval.into(); assert_eq!(native_value, 1000); - let interval = IntervalDayTime::new(1000); + let interval = IntervalDayTime::from(1000); let native_interval: i64 = interval.into(); assert_eq!(native_interval, 1000); - let interval = IntervalYearMonth::new(1000); + let interval = IntervalYearMonth::from(1000); let native_interval: i32 = interval.into(); assert_eq!(native_interval, 1000); } diff --git a/src/datatypes/src/types/interval_type.rs b/src/datatypes/src/types/interval_type.rs index 7ee796498211..77f1b47d6d29 100644 --- a/src/datatypes/src/types/interval_type.rs +++ b/src/datatypes/src/types/interval_type.rs @@ -17,8 +17,9 @@ use arrow::datatypes::{ IntervalMonthDayNanoType as ArrowIntervalMonthDayNanoType, IntervalUnit as ArrowIntervalUnit, IntervalYearMonthType as ArrowIntervalYearMonthType, }; -use common_time::interval::IntervalUnit; -use common_time::Interval; +use common_time::interval::{ + IntervalDayTime, IntervalMonthDayNano, IntervalUnit, IntervalYearMonth, +}; use enum_dispatch::enum_dispatch; use paste::paste; use serde::{Deserialize, Serialize}; @@ -26,7 +27,6 @@ use snafu::OptionExt; use crate::data_type::ConcreteDataType; use crate::error; -use crate::interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth}; use crate::prelude::{ DataType, LogicalTypeId, MutableVector, ScalarVectorBuilder, Value, ValueRef, Vector, }; @@ -75,7 +75,7 @@ macro_rules! impl_data_type_for_interval { } fn default_value(&self) -> Value { - Value::Interval(Interval::from_i128(0)) + Value::[]([]::default()) } fn as_arrow_type(&self) -> ArrowDataType { @@ -124,7 +124,7 @@ macro_rules! impl_data_type_for_interval { fn cast_value_ref(value: ValueRef) -> crate::Result> { match value { ValueRef::Null => Ok(None), - ValueRef::Interval(t) => Ok(Some([](t))), + ValueRef::[](t) => Ok(Some(t)), other => error::CastTypeSnafu { msg: format!("Failed to cast value {:?} to {}", other, stringify!([])), } diff --git a/src/datatypes/src/types/primitive_type.rs b/src/datatypes/src/types/primitive_type.rs index cae71976fd4a..86972bd5ee2e 100644 --- a/src/datatypes/src/types/primitive_type.rs +++ b/src/datatypes/src/types/primitive_type.rs @@ -16,7 +16,6 @@ use std::cmp::Ordering; use std::fmt; use arrow::datatypes::{ArrowNativeType, ArrowPrimitiveType, DataType as ArrowDataType}; -use common_time::interval::IntervalUnit; use common_time::{Date, DateTime}; use serde::{Deserialize, Serialize}; use snafu::OptionExt; @@ -30,6 +29,7 @@ use crate::types::{DateTimeType, DateType}; use crate::value::{Value, ValueRef}; use crate::vectors::{MutableVector, PrimitiveVector, PrimitiveVectorBuilder, Vector}; +// TODO(yingwen): Can we remove `Into`? /// Represents the wrapper type that wraps a native type using the `newtype pattern`, /// such as [Date](`common_time::Date`) is a wrapper type for the underlying native /// type `i32`. @@ -364,11 +364,7 @@ impl DataType for Int64Type { Value::DateTime(v) => Some(Value::Int64(v.val())), Value::Timestamp(v) => Some(Value::Int64(v.value())), Value::Time(v) => Some(Value::Int64(v.value())), - Value::Interval(v) => match v.unit() { - IntervalUnit::DayTime => Some(Value::Int64(v.to_i64())), - IntervalUnit::YearMonth => None, - IntervalUnit::MonthDayNano => None, - }, + // We don't allow casting interval type to int. _ => None, } } @@ -410,11 +406,7 @@ impl DataType for Int32Type { Value::Float64(v) => num::cast::cast(v).map(Value::Int32), Value::String(v) => v.as_utf8().parse::().map(Value::Int32).ok(), Value::Date(v) => Some(Value::Int32(v.val())), - Value::Interval(v) => match v.unit() { - IntervalUnit::YearMonth => Some(Value::Int32(v.to_i32())), - IntervalUnit::DayTime => None, - IntervalUnit::MonthDayNano => None, - }, + // We don't allow casting interval type to int. _ => None, } } diff --git a/src/datatypes/src/types/string_type.rs b/src/datatypes/src/types/string_type.rs index 38045a600adb..06a5e7c7f6bd 100644 --- a/src/datatypes/src/types/string_type.rs +++ b/src/datatypes/src/types/string_type.rs @@ -78,7 +78,15 @@ impl DataType for StringType { Value::DateTime(v) => Some(Value::String(StringBytes::from(v.to_string()))), Value::Timestamp(v) => Some(Value::String(StringBytes::from(v.to_iso8601_string()))), Value::Time(v) => Some(Value::String(StringBytes::from(v.to_iso8601_string()))), - Value::Interval(v) => Some(Value::String(StringBytes::from(v.to_iso8601_string()))), + Value::IntervalYearMonth(v) => { + Some(Value::String(StringBytes::from(v.to_iso8601_string()))) + } + Value::IntervalDayTime(v) => { + Some(Value::String(StringBytes::from(v.to_iso8601_string()))) + } + Value::IntervalMonthDayNano(v) => { + Some(Value::String(StringBytes::from(v.to_iso8601_string()))) + } Value::Duration(v) => Some(Value::String(StringBytes::from(v.to_string()))), Value::Decimal128(v) => Some(Value::String(StringBytes::from(v.to_string()))), diff --git a/src/datatypes/src/value.rs b/src/datatypes/src/value.rs index a8e59da51355..b973a3156b03 100644 --- a/src/datatypes/src/value.rs +++ b/src/datatypes/src/value.rs @@ -28,7 +28,7 @@ use common_time::datetime::DateTime; use common_time::interval::IntervalUnit; use common_time::time::Time; use common_time::timestamp::{TimeUnit, Timestamp}; -use common_time::{Duration, Interval, Timezone}; +use common_time::{Duration, IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth, Timezone}; use datafusion_common::ScalarValue; use greptime_proto::v1::value::ValueData; pub use ordered_float::OrderedFloat; @@ -78,7 +78,10 @@ pub enum Value { Timestamp(Timestamp), Time(Time), Duration(Duration), - Interval(Interval), + // Interval types: + IntervalYearMonth(IntervalYearMonth), + IntervalDayTime(IntervalDayTime), + IntervalMonthDayNano(IntervalMonthDayNano), List(ListValue), } @@ -111,7 +114,15 @@ impl Display for Value { Value::DateTime(v) => write!(f, "{v}"), Value::Timestamp(v) => write!(f, "{}", v.to_iso8601_string()), Value::Time(t) => write!(f, "{}", t.to_iso8601_string()), - Value::Interval(v) => write!(f, "{}", v.to_iso8601_string()), + Value::IntervalYearMonth(v) => { + write!(f, "{}", v.to_iso8601_string()) + } + Value::IntervalDayTime(v) => { + write!(f, "{}", v.to_iso8601_string()) + } + Value::IntervalMonthDayNano(v) => { + write!(f, "{}", v.to_iso8601_string()) + } Value::Duration(d) => write!(f, "{d}"), Value::List(v) => { let items = v @@ -153,7 +164,15 @@ macro_rules! define_data_type_func { $struct::DateTime(_) => ConcreteDataType::datetime_datatype(), $struct::Time(t) => ConcreteDataType::time_datatype(*t.unit()), $struct::Timestamp(v) => ConcreteDataType::timestamp_datatype(v.unit()), - $struct::Interval(v) => ConcreteDataType::interval_datatype(v.unit()), + $struct::IntervalYearMonth(_) => { + ConcreteDataType::interval_datatype(IntervalUnit::YearMonth) + } + $struct::IntervalDayTime(_) => { + ConcreteDataType::interval_datatype(IntervalUnit::DayTime) + } + $struct::IntervalMonthDayNano(_) => { + ConcreteDataType::interval_datatype(IntervalUnit::MonthDayNano) + } $struct::List(list) => ConcreteDataType::list_datatype(list.datatype().clone()), $struct::Duration(d) => ConcreteDataType::duration_datatype(d.unit()), $struct::Decimal128(d) => { @@ -206,7 +225,9 @@ impl Value { Value::List(v) => ValueRef::List(ListValueRef::Ref { val: v }), Value::Timestamp(v) => ValueRef::Timestamp(*v), Value::Time(v) => ValueRef::Time(*v), - Value::Interval(v) => ValueRef::Interval(*v), + Value::IntervalYearMonth(v) => ValueRef::IntervalYearMonth(*v), + Value::IntervalDayTime(v) => ValueRef::IntervalDayTime(*v), + Value::IntervalMonthDayNano(v) => ValueRef::IntervalMonthDayNano(*v), Value::Duration(v) => ValueRef::Duration(*v), Value::Decimal128(v) => ValueRef::Decimal128(*v), } @@ -220,14 +241,6 @@ impl Value { } } - /// Cast Value to Interval. Return None if value is not a valid interval data type. - pub fn as_interval(&self) -> Option { - match self { - Value::Interval(i) => Some(*i), - _ => None, - } - } - /// Cast Value to utf8 String. Return None if value is not a valid string data type. pub fn as_string(&self) -> Option { match self { @@ -255,12 +268,35 @@ impl Value { /// Cast Value to [Time]. Return None if value is not a valid time data type. pub fn as_time(&self) -> Option