diff --git a/src/datatypes/src/types.rs b/src/datatypes/src/types.rs index d01822a3b9e9..8a3cd9ad55aa 100644 --- a/src/datatypes/src/types.rs +++ b/src/datatypes/src/types.rs @@ -14,6 +14,7 @@ mod binary_type; mod boolean_type; +pub mod cast; mod date_type; mod datetime_type; mod dictionary_type; @@ -27,6 +28,7 @@ mod timestamp_type; pub use binary_type::BinaryType; pub use boolean_type::BooleanType; +pub use cast::can_cast_type; pub use date_type::DateType; pub use datetime_type::DateTimeType; pub use dictionary_type::DictionaryType; diff --git a/src/datatypes/src/types/binary_type.rs b/src/datatypes/src/types/binary_type.rs index a315d82e7872..17f421162aa2 100644 --- a/src/datatypes/src/types/binary_type.rs +++ b/src/datatypes/src/types/binary_type.rs @@ -58,7 +58,10 @@ impl DataType for BinaryType { false } - fn cast(&self, _: Value) -> Option { - unimplemented!() + fn cast(&self, from: Value) -> Option { + match from { + Value::Binary(v) => Some(Value::Binary(v)), + _ => None, + } } } diff --git a/src/datatypes/src/types/boolean_type.rs b/src/datatypes/src/types/boolean_type.rs index a2528b5d1a2f..b51d62fed374 100644 --- a/src/datatypes/src/types/boolean_type.rs +++ b/src/datatypes/src/types/boolean_type.rs @@ -71,6 +71,7 @@ impl DataType for BooleanType { Value::Int64(v) => numeric_to_bool(v), Value::Float32(v) => numeric_to_bool(v), Value::Float64(v) => numeric_to_bool(v), + Value::String(v) => v.as_utf8().parse::().ok().map(Value::Boolean), _ => None, } } diff --git a/src/datatypes/src/types/cast.rs b/src/datatypes/src/types/cast.rs new file mode 100644 index 000000000000..35ee99c030a6 --- /dev/null +++ b/src/datatypes/src/types/cast.rs @@ -0,0 +1,314 @@ +// Copyright 2023 Greptime Team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::data_type::ConcreteDataType; +use crate::types::{IntervalType, TimeType}; +use crate::value::Value; + +// Return true if the src_value can be casted to dest_type, +// Otherwise, return false. +pub fn can_cast_type(src_value: &Value, dest_type: ConcreteDataType) -> bool { + use ConcreteDataType::*; + use IntervalType::*; + use TimeType::*; + let src_type = src_value.data_type(); + + if src_type == dest_type { + return true; + } + + match (src_type, dest_type) { + (_, Null(_)) => true, + // numeric types + ( + Boolean(_), + UInt8(_) | UInt16(_) | UInt32(_) | UInt64(_) | Int8(_) | Int16(_) | Int32(_) | Int64(_) + | Float32(_) | Float64(_) | String(_), + ) => true, + ( + UInt8(_), + Boolean(_) | UInt16(_) | UInt32(_) | UInt64(_) | Int16(_) | Int32(_) | Int64(_) + | Float32(_) | Float64(_) | String(_), + ) => true, + ( + UInt16(_), + Boolean(_) | UInt8(_) | UInt32(_) | UInt64(_) | Int32(_) | Int64(_) | Float32(_) + | Float64(_) | String(_), + ) => true, + (UInt32(_), Boolean(_) | UInt64(_) | Int64(_) | Float64(_) | String(_)) => true, + (UInt64(_), Boolean(_) | String(_)) => true, + ( + Int8(_), + Boolean(_) | Int16(_) | Int32(_) | Int64(_) | Float32(_) | Float64(_) | String(_), + ) => true, + (Int16(_), Boolean(_) | Int32(_) | Int64(_) | Float32(_) | Float64(_) | String(_)) => true, + (Int32(_), Boolean(_) | Int64(_) | Float32(_) | Float64(_) | String(_) | Date(_)) => true, + (Int64(_), Boolean(_) | Float64(_) | String(_) | DateTime(_) | Timestamp(_) | Time(_)) => { + true + } + ( + Float32(_), + Boolean(_) | UInt8(_) | UInt16(_) | UInt32(_) | UInt64(_) | Int8(_) | Int16(_) + | Int32(_) | Int64(_) | Float64(_) | String(_), + ) => true, + ( + Float64(_), + Boolean(_) | UInt8(_) | UInt16(_) | UInt32(_) | UInt64(_) | Int8(_) | Int16(_) + | Int32(_) | Int64(_) | String(_), + ) => true, + ( + String(_), + Boolean(_) | UInt8(_) | UInt16(_) | UInt32(_) | UInt64(_) | Int8(_) | Int16(_) + | Int32(_) | Int64(_) | Float32(_) | Float64(_) | Date(_) | DateTime(_) | Timestamp(_) + | Time(_) | Interval(_), + ) => true, + // temporal types + (Date(_), Int32(_) | Timestamp(_) | String(_)) => true, + (DateTime(_), Int64(_) | Timestamp(_) | String(_)) => true, + (Timestamp(_), Int64(_) | Date(_) | DateTime(_) | String(_)) => true, + (Time(_), String(_)) => true, + (Time(Second(_)), Int32(_)) => true, + (Time(Millisecond(_)), Int32(_)) => true, + (Time(Microsecond(_)), Int64(_)) => true, + (Time(Nanosecond(_)), Int64(_)) => true, + (Interval(_), String(_)) => true, + (Interval(YearMonth(_)), Int32(_)) => true, + (Interval(DayTime(_)), Int64(_)) => true, + (Interval(MonthDayNano(_)), _) => false, + // other situations return false + (_, _) => false, + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use common_base::bytes::StringBytes; + use common_time::time::Time; + use common_time::{Date, DateTime, Interval, Timestamp}; + use ordered_float::OrderedFloat; + + use super::*; + + macro_rules! test_can_cast { + ($src_value: expr, $($dest_type: ident),*) => { + $( + let val = $src_value; + let t = ConcreteDataType::$dest_type(); + assert_eq!(can_cast_type(&val, t), true); + )* + }; + } + + #[test] + fn test_can_cast_type() { + // uint8 -> other types + test_can_cast!( + Value::UInt8(0), + null_datatype, + uint8_datatype, + uint16_datatype, + uint32_datatype, + uint64_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype + ); + + // uint16 -> other types + test_can_cast!( + Value::UInt16(0), + null_datatype, + uint8_datatype, + uint16_datatype, + uint32_datatype, + uint64_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype + ); + + // uint32 -> other types + test_can_cast!( + Value::UInt32(0), + null_datatype, + uint32_datatype, + uint64_datatype, + int64_datatype, + float64_datatype, + string_datatype + ); + + // uint64 -> other types + test_can_cast!( + Value::UInt64(0), + null_datatype, + uint64_datatype, + string_datatype + ); + + // int8 -> other types + test_can_cast!( + Value::Int8(0), + null_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype + ); + + // int16 -> other types + test_can_cast!( + Value::Int16(0), + null_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype + ); + + // int32 -> other types + test_can_cast!( + Value::Int32(0), + null_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype, + date_datatype + ); + + // int64 -> other types + test_can_cast!( + Value::Int64(0), + null_datatype, + int64_datatype, + float64_datatype, + string_datatype, + datetime_datatype, + timestamp_second_datatype, + time_second_datatype + ); + + // float32 -> other types + test_can_cast!( + Value::Float32(OrderedFloat(0.0)), + null_datatype, + uint8_datatype, + uint16_datatype, + uint32_datatype, + uint64_datatype, + int8_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype + ); + + // float64 -> other types + test_can_cast!( + Value::Float64(OrderedFloat(0.0)), + null_datatype, + uint8_datatype, + uint16_datatype, + uint32_datatype, + uint64_datatype, + int8_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float64_datatype, + string_datatype + ); + + // string -> other types + test_can_cast!( + Value::String(StringBytes::from("0")), + null_datatype, + uint8_datatype, + uint16_datatype, + uint32_datatype, + uint64_datatype, + int8_datatype, + int16_datatype, + int32_datatype, + int64_datatype, + float32_datatype, + float64_datatype, + string_datatype, + date_datatype, + datetime_datatype, + timestamp_second_datatype, + time_second_datatype, + interval_year_month_datatype, + interval_day_time_datatype, + interval_month_day_nano_datatype + ); + + // date -> other types + test_can_cast!( + Value::Date(Date::from_str("2021-01-01").unwrap()), + null_datatype, + int32_datatype, + timestamp_second_datatype, + string_datatype + ); + + // datetime -> other types + test_can_cast!( + Value::DateTime(DateTime::from_str("2021-01-01 00:00:00").unwrap()), + null_datatype, + int64_datatype, + timestamp_second_datatype, + string_datatype + ); + + // timestamp -> other types + test_can_cast!( + Value::Timestamp(Timestamp::from_str("2021-01-01 00:00:00").unwrap()), + null_datatype, + int64_datatype, + date_datatype, + datetime_datatype, + string_datatype + ); + + // time -> other types + test_can_cast!( + Value::Time(Time::new_second(0)), + null_datatype, + string_datatype + ); + + // interval -> other types + test_can_cast!( + Value::Interval(Interval::from_year_month(0)), + null_datatype, + string_datatype + ); + } +} diff --git a/src/datatypes/src/types/interval_type.rs b/src/datatypes/src/types/interval_type.rs index 1fc7d52b0846..a29610e2381e 100644 --- a/src/datatypes/src/types/interval_type.rs +++ b/src/datatypes/src/types/interval_type.rs @@ -91,7 +91,7 @@ macro_rules! impl_data_type_for_interval { } fn cast(&self, _: Value) -> Option { - unimplemented!() + unimplemented!("interval type cast not implemented yet") } } diff --git a/src/datatypes/src/types/list_type.rs b/src/datatypes/src/types/list_type.rs index 38c5d244b326..e15bef4f586e 100644 --- a/src/datatypes/src/types/list_type.rs +++ b/src/datatypes/src/types/list_type.rs @@ -80,8 +80,11 @@ impl DataType for ListType { false } - fn cast(&self, _: Value) -> Option { - unimplemented!() + fn cast(&self, from: Value) -> Option { + match from { + Value::List(v) => Some(Value::List(v)), + _ => None, + } } } diff --git a/src/datatypes/src/types/null_type.rs b/src/datatypes/src/types/null_type.rs index 04fe98daf5a6..8192db168192 100644 --- a/src/datatypes/src/types/null_type.rs +++ b/src/datatypes/src/types/null_type.rs @@ -56,7 +56,8 @@ impl DataType for NullType { false } - fn cast(&self, _: Value) -> Option { - unimplemented!() + // Unconditional cast other type to Value::Null + fn cast(&self, _from: Value) -> Option { + Some(Value::Null) } } diff --git a/src/datatypes/src/types/primitive_type.rs b/src/datatypes/src/types/primitive_type.rs index 7ad3a4a8d38e..65cced40ca6d 100644 --- a/src/datatypes/src/types/primitive_type.rs +++ b/src/datatypes/src/types/primitive_type.rs @@ -300,7 +300,9 @@ define_non_timestamp_primitive!( u64, UInt64, UInt64Type, UInt64Type, UInt8, UInt16, UInt32, UInt64, Float32, Float64 ); define_non_timestamp_primitive!(i8, Int8, Int8Type, Int64Type, Int8, Float32, Float64); -define_non_timestamp_primitive!(i16, Int16, Int16Type, Int64Type, Int8, Int16, Float32, Float64); +define_non_timestamp_primitive!( + i16, Int16, Int16Type, Int64Type, Int8, Int16, UInt8, Float32, Float64 +); define_non_timestamp_primitive!( f32, @@ -308,26 +310,22 @@ define_non_timestamp_primitive!( Float32Type, Float64Type, Float32, - Float64, UInt8, UInt16, - UInt32, - UInt64, Int8, Int16, - Int32, - Int64 + Int32 ); define_non_timestamp_primitive!( f64, Float64, Float64Type, Float64Type, + Float32, Float64, UInt8, UInt16, UInt32, - UInt64, Int8, Int16, Int32, @@ -371,6 +369,9 @@ impl DataType for Int64Type { Value::Int16(v) => num::cast::cast(v).map(Value::Int64), Value::Int32(v) => num::cast::cast(v).map(Value::Int64), Value::Int64(v) => Some(Value::Int64(v)), + Value::UInt8(v) => num::cast::cast(v).map(Value::Int64), + Value::UInt16(v) => num::cast::cast(v).map(Value::Int64), + Value::UInt32(v) => num::cast::cast(v).map(Value::Int64), Value::Float32(v) => num::cast::cast(v).map(Value::Int64), Value::Float64(v) => num::cast::cast(v).map(Value::Int64), Value::String(v) => v.as_utf8().parse::().map(Value::Int64).ok(), @@ -425,6 +426,8 @@ impl DataType for Int32Type { Value::Int8(v) => num::cast::cast(v).map(Value::Int32), Value::Int16(v) => num::cast::cast(v).map(Value::Int32), Value::Int32(v) => Some(Value::Int32(v)), + Value::UInt8(v) => num::cast::cast(v).map(Value::Int32), + Value::UInt16(v) => num::cast::cast(v).map(Value::Int32), Value::Float32(v) => num::cast::cast(v).map(Value::Int32), Value::Float64(v) => num::cast::cast(v).map(Value::Int32), Value::String(v) => v.as_utf8().parse::().map(Value::Int32).ok(), @@ -577,16 +580,6 @@ mod tests { ConcreteDataType::float32_datatype(), Value::Float32(OrderedFloat(12.0)) ); - assert_primitive_cast!( - Value::UInt32(12), - ConcreteDataType::float32_datatype(), - Value::Float32(OrderedFloat(12.0)) - ); - assert_primitive_cast!( - Value::UInt64(12), - ConcreteDataType::float32_datatype(), - Value::Float32(OrderedFloat(12.0)) - ); assert_primitive_cast!( Value::Int8(12), ConcreteDataType::float32_datatype(), @@ -602,11 +595,6 @@ mod tests { ConcreteDataType::float32_datatype(), Value::Float32(OrderedFloat(12.0)) ); - assert_primitive_cast!( - Value::Int64(12), - ConcreteDataType::float32_datatype(), - Value::Float32(OrderedFloat(12.0)) - ); // cast to Float64 assert_primitive_cast!( @@ -624,11 +612,6 @@ mod tests { ConcreteDataType::float64_datatype(), Value::Float64(OrderedFloat(12.0)) ); - assert_primitive_cast!( - Value::UInt64(12), - ConcreteDataType::float64_datatype(), - Value::Float64(OrderedFloat(12.0)) - ); assert_primitive_cast!( Value::Int8(12), ConcreteDataType::float64_datatype(),