This is an automated email from the ASF dual-hosted git repository.
comphead pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new eb25e8d965 Refactor binary.rs tests into modular submodules under
`binary/tests` (#16782)
eb25e8d965 is described below
commit eb25e8d965fad653a05b22a97e9cfb73f7cb0e0b
Author: kosiew <[email protected]>
AuthorDate: Sun Jul 20 13:07:42 2025 +0800
Refactor binary.rs tests into modular submodules under `binary/tests`
(#16782)
* refactor(binary): move tests into dedicated modules
move test module into binary/tests hierarchy
split tests into arithmetic, comparison, null, and dictionary modules
* Add license headers to binary tests for compliance
* Enhance test documentation for binary coercion macros with usage examples
---
datafusion/expr-common/src/type_coercion/binary.rs | 1096 +-------------------
.../src/type_coercion/binary/tests/arithmetic.rs | 250 +++++
.../src/type_coercion/binary/tests/comparison.rs | 699 +++++++++++++
.../src/type_coercion/binary/tests/dictionary.rs | 72 ++
.../src/type_coercion/binary/tests/mod.rs | 79 ++
.../type_coercion/binary/tests/null_coercion.rs | 72 ++
6 files changed, 1173 insertions(+), 1095 deletions(-)
diff --git a/datafusion/expr-common/src/type_coercion/binary.rs
b/datafusion/expr-common/src/type_coercion/binary.rs
index 7e0bc80e5a..9264a2940d 100644
--- a/datafusion/expr-common/src/type_coercion/binary.rs
+++ b/datafusion/expr-common/src/type_coercion/binary.rs
@@ -1544,1098 +1544,4 @@ fn null_coercion(lhs_type: &DataType, rhs_type:
&DataType) -> Option<DataType> {
}
#[cfg(test)]
-mod tests {
- use super::*;
-
- use datafusion_common::assert_contains;
-
- #[test]
- fn test_coercion_error() -> Result<()> {
- let coercer =
- BinaryTypeCoercer::new(&DataType::Float32, &Operator::Plus,
&DataType::Utf8);
- let result_type = coercer.get_input_types();
-
- let e = result_type.unwrap_err();
- assert_eq!(e.strip_backtrace(), "Error during planning: Cannot coerce
arithmetic expression Float32 + Utf8 to valid types");
- Ok(())
- }
-
- #[test]
- fn test_decimal_binary_comparison_coercion() -> Result<()> {
- let input_decimal = DataType::Decimal128(20, 3);
- let input_types = [
- DataType::Int8,
- DataType::Int16,
- DataType::Int32,
- DataType::Int64,
- DataType::Float32,
- DataType::Float64,
- DataType::Decimal128(38, 10),
- DataType::Decimal128(20, 8),
- DataType::Null,
- ];
- let result_types = [
- DataType::Decimal128(20, 3),
- DataType::Decimal128(20, 3),
- DataType::Decimal128(20, 3),
- DataType::Decimal128(23, 3),
- DataType::Decimal128(24, 7),
- DataType::Decimal128(32, 15),
- DataType::Decimal128(38, 10),
- DataType::Decimal128(25, 8),
- DataType::Decimal128(20, 3),
- ];
- let comparison_op_types = [
- Operator::NotEq,
- Operator::Eq,
- Operator::Gt,
- Operator::GtEq,
- Operator::Lt,
- Operator::LtEq,
- ];
- for (i, input_type) in input_types.iter().enumerate() {
- let expect_type = &result_types[i];
- for op in comparison_op_types {
- let (lhs, rhs) = BinaryTypeCoercer::new(&input_decimal, &op,
input_type)
- .get_input_types()?;
- assert_eq!(expect_type, &lhs);
- assert_eq!(expect_type, &rhs);
- }
- }
- // negative test
- let result_type =
- BinaryTypeCoercer::new(&input_decimal, &Operator::Eq,
&DataType::Boolean)
- .get_input_types();
- assert!(result_type.is_err());
- Ok(())
- }
-
- #[test]
- fn test_decimal_mathematics_op_type() {
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Int8).unwrap(),
- DataType::Decimal128(3, 0)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Int16).unwrap(),
- DataType::Decimal128(5, 0)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Int32).unwrap(),
- DataType::Decimal128(10, 0)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Int64).unwrap(),
- DataType::Decimal128(20, 0)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Float16).unwrap(),
- DataType::Decimal128(6, 3)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Float32).unwrap(),
- DataType::Decimal128(14, 7)
- );
- assert_eq!(
- coerce_numeric_type_to_decimal(&DataType::Float64).unwrap(),
- DataType::Decimal128(30, 15)
- );
- }
-
- #[test]
- fn test_dictionary_type_coercion() {
- use DataType::*;
-
- let lhs_type = Dictionary(Box::new(Int8), Box::new(Int32));
- let rhs_type = Dictionary(Box::new(Int8), Box::new(Int16));
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
- Some(Int32)
- );
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
- Some(Int32)
- );
-
- // Since we can coerce values of Int16 to Utf8 can support this
- let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
- let rhs_type = Dictionary(Box::new(Int8), Box::new(Int16));
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
- Some(Utf8)
- );
-
- // Since we can coerce values of Utf8 to Binary can support this
- let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
- let rhs_type = Dictionary(Box::new(Int8), Box::new(Binary));
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
- Some(Binary)
- );
-
- let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
- let rhs_type = Utf8;
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
- Some(Utf8)
- );
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
- Some(lhs_type.clone())
- );
-
- let lhs_type = Utf8;
- let rhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
- Some(Utf8)
- );
- assert_eq!(
- dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
- Some(rhs_type.clone())
- );
- }
-
- /// Test coercion rules for binary operators
- ///
- /// Applies coercion rules for `$LHS_TYPE $OP $RHS_TYPE` and asserts that
- /// the result type is `$RESULT_TYPE`
- macro_rules! test_coercion_binary_rule {
- ($LHS_TYPE:expr, $RHS_TYPE:expr, $OP:expr, $RESULT_TYPE:expr) => {{
- let (lhs, rhs) =
- BinaryTypeCoercer::new(&$LHS_TYPE, &$OP,
&$RHS_TYPE).get_input_types()?;
- assert_eq!(lhs, $RESULT_TYPE);
- assert_eq!(rhs, $RESULT_TYPE);
- }};
- }
-
- /// Test coercion rules for binary operators
- ///
- /// Applies coercion rules for each RHS_TYPE in $RHS_TYPES such that
- /// `$LHS_TYPE $OP RHS_TYPE` and asserts that the result type is
`$RESULT_TYPE`.
- /// Also tests that the inverse `RHS_TYPE $OP $LHS_TYPE` is true
- macro_rules! test_coercion_binary_rule_multiple {
- ($LHS_TYPE:expr, $RHS_TYPES:expr, $OP:expr, $RESULT_TYPE:expr) => {{
- for rh_type in $RHS_TYPES {
- let (lhs, rhs) = BinaryTypeCoercer::new(&$LHS_TYPE, &$OP,
&rh_type)
- .get_input_types()?;
- assert_eq!(lhs, $RESULT_TYPE);
- assert_eq!(rhs, $RESULT_TYPE);
-
- BinaryTypeCoercer::new(&rh_type, &$OP,
&$LHS_TYPE).get_input_types()?;
- assert_eq!(lhs, $RESULT_TYPE);
- assert_eq!(rhs, $RESULT_TYPE);
- }
- }};
- }
-
- /// Test coercion rules for like
- ///
- /// Applies coercion rules for both
- /// * `$LHS_TYPE LIKE $RHS_TYPE`
- /// * `$RHS_TYPE LIKE $LHS_TYPE`
- ///
- /// And asserts the result type is `$RESULT_TYPE`
- macro_rules! test_like_rule {
- ($LHS_TYPE:expr, $RHS_TYPE:expr, $RESULT_TYPE:expr) => {{
- println!("Coercing {} LIKE {}", $LHS_TYPE, $RHS_TYPE);
- let result = like_coercion(&$LHS_TYPE, &$RHS_TYPE);
- assert_eq!(result, $RESULT_TYPE);
- // reverse the order
- let result = like_coercion(&$RHS_TYPE, &$LHS_TYPE);
- assert_eq!(result, $RESULT_TYPE);
- }};
- }
-
- #[test]
- fn test_date_timestamp_arithmetic_error() -> Result<()> {
- let (lhs, rhs) = BinaryTypeCoercer::new(
- &DataType::Timestamp(TimeUnit::Nanosecond, None),
- &Operator::Minus,
- &DataType::Timestamp(TimeUnit::Millisecond, None),
- )
- .get_input_types()?;
- assert_eq!(lhs.to_string(), "Timestamp(Millisecond, None)");
- assert_eq!(rhs.to_string(), "Timestamp(Millisecond, None)");
-
- let err =
- BinaryTypeCoercer::new(&DataType::Date32, &Operator::Plus,
&DataType::Date64)
- .get_input_types()
- .unwrap_err()
- .to_string();
-
- assert_contains!(
- &err,
- "Cannot get result type for temporal operation Date64 + Date64"
- );
-
- Ok(())
- }
-
- #[test]
- fn test_like_coercion() {
- // string coerce to strings
- test_like_rule!(DataType::Utf8, DataType::Utf8, Some(DataType::Utf8));
- test_like_rule!(
- DataType::LargeUtf8,
- DataType::Utf8,
- Some(DataType::LargeUtf8)
- );
- test_like_rule!(
- DataType::Utf8,
- DataType::LargeUtf8,
- Some(DataType::LargeUtf8)
- );
- test_like_rule!(
- DataType::LargeUtf8,
- DataType::LargeUtf8,
- Some(DataType::LargeUtf8)
- );
-
- // Also coerce binary to strings
- test_like_rule!(DataType::Binary, DataType::Utf8,
Some(DataType::Utf8));
- test_like_rule!(
- DataType::LargeBinary,
- DataType::Utf8,
- Some(DataType::LargeUtf8)
- );
- test_like_rule!(
- DataType::Binary,
- DataType::LargeUtf8,
- Some(DataType::LargeUtf8)
- );
- test_like_rule!(
- DataType::LargeBinary,
- DataType::LargeUtf8,
- Some(DataType::LargeUtf8)
- );
- }
-
- #[test]
- fn test_type_coercion() -> Result<()> {
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Date32,
- Operator::Eq,
- DataType::Date32
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Date64,
- Operator::Lt,
- DataType::Date64
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Time32(TimeUnit::Second),
- Operator::Eq,
- DataType::Time32(TimeUnit::Second)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Time32(TimeUnit::Millisecond),
- Operator::Eq,
- DataType::Time32(TimeUnit::Millisecond)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Time64(TimeUnit::Microsecond),
- Operator::Eq,
- DataType::Time64(TimeUnit::Microsecond)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Time64(TimeUnit::Nanosecond),
- Operator::Eq,
- DataType::Time64(TimeUnit::Nanosecond)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Timestamp(TimeUnit::Second, None),
- Operator::Lt,
- DataType::Timestamp(TimeUnit::Nanosecond, None)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Timestamp(TimeUnit::Millisecond, None),
- Operator::Lt,
- DataType::Timestamp(TimeUnit::Nanosecond, None)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Timestamp(TimeUnit::Microsecond, None),
- Operator::Lt,
- DataType::Timestamp(TimeUnit::Nanosecond, None)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Timestamp(TimeUnit::Nanosecond, None),
- Operator::Lt,
- DataType::Timestamp(TimeUnit::Nanosecond, None)
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8,
- Operator::RegexMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8View,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8View,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8,
- Operator::RegexNotMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8View,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8View,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8,
- Operator::RegexNotIMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Utf8View,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Utf8View,
- DataType::Utf8View,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8,
- Operator::RegexMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8View,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8View,
- Operator::RegexMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8,
- Operator::RegexIMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8,
- Operator::RegexIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8View,
- Operator::RegexIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8View,
- Operator::RegexIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8,
- Operator::RegexNotMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8View,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8View,
- Operator::RegexNotMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8,
- Operator::RegexNotIMatch,
- DataType::Utf8
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8.into()),
- DataType::Utf8View,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
- DataType::Utf8View,
- Operator::RegexNotIMatch,
- DataType::Utf8View
- );
- test_coercion_binary_rule!(
- DataType::Int16,
- DataType::Int64,
- Operator::BitwiseAnd,
- DataType::Int64
- );
- test_coercion_binary_rule!(
- DataType::UInt64,
- DataType::UInt64,
- Operator::BitwiseAnd,
- DataType::UInt64
- );
- test_coercion_binary_rule!(
- DataType::Int8,
- DataType::UInt32,
- Operator::BitwiseAnd,
- DataType::Int64
- );
- test_coercion_binary_rule!(
- DataType::UInt32,
- DataType::Int32,
- Operator::BitwiseAnd,
- DataType::Int64
- );
- test_coercion_binary_rule!(
- DataType::UInt16,
- DataType::Int16,
- Operator::BitwiseAnd,
- DataType::Int32
- );
- test_coercion_binary_rule!(
- DataType::UInt32,
- DataType::UInt32,
- Operator::BitwiseAnd,
- DataType::UInt32
- );
- test_coercion_binary_rule!(
- DataType::UInt16,
- DataType::UInt32,
- Operator::BitwiseAnd,
- DataType::UInt32
- );
- Ok(())
- }
-
- #[test]
- fn test_type_coercion_arithmetic() -> Result<()> {
- use DataType::*;
-
- // (Float64, _) | (_, Float64) => Some(Float64),
- test_coercion_binary_rule_multiple!(
- Float64,
- [
- Float64, Float32, Float16, Int64, UInt64, Int32, UInt32,
Int16, UInt16,
- Int8, UInt8
- ],
- Operator::Plus,
- Float64
- );
- // (_, Float32) | (Float32, _) => Some(Float32),
- test_coercion_binary_rule_multiple!(
- Float32,
- [
- Float32, Float16, Int64, UInt64, Int32, UInt32, Int16, UInt16,
Int8,
- UInt8
- ],
- Operator::Plus,
- Float32
- );
- // (_, Float16) | (Float16, _) => Some(Float16),
- test_coercion_binary_rule_multiple!(
- Float16,
- [Float16, Int64, UInt64, Int32, UInt32, Int16, UInt16, Int8,
UInt8],
- Operator::Plus,
- Float16
- );
- // (UInt64, Int64 | Int32 | Int16 | Int8) | (Int64 | Int32 | Int16 |
Int8, UInt64) => Some(Decimal128(20, 0)),
- test_coercion_binary_rule_multiple!(
- UInt64,
- [Int64, Int32, Int16, Int8],
- Operator::Divide,
- Decimal128(20, 0)
- );
- // (UInt64, _) | (_, UInt64) => Some(UInt64),
- test_coercion_binary_rule_multiple!(
- UInt64,
- [UInt64, UInt32, UInt16, UInt8],
- Operator::Modulo,
- UInt64
- );
- // (Int64, _) | (_, Int64) => Some(Int64),
- test_coercion_binary_rule_multiple!(
- Int64,
- [Int64, Int32, UInt32, Int16, UInt16, Int8, UInt8],
- Operator::Modulo,
- Int64
- );
- // (UInt32, Int32 | Int16 | Int8) | (Int32 | Int16 | Int8, UInt32) =>
Some(Int64)
- test_coercion_binary_rule_multiple!(
- UInt32,
- [Int32, Int16, Int8],
- Operator::Modulo,
- Int64
- );
- // (UInt32, _) | (_, UInt32) => Some(UInt32),
- test_coercion_binary_rule_multiple!(
- UInt32,
- [UInt32, UInt16, UInt8],
- Operator::Modulo,
- UInt32
- );
- // (Int32, _) | (_, Int32) => Some(Int32),
- test_coercion_binary_rule_multiple!(
- Int32,
- [Int32, Int16, Int8],
- Operator::Modulo,
- Int32
- );
- // (UInt16, Int16 | Int8) | (Int16 | Int8, UInt16) => Some(Int32)
- test_coercion_binary_rule_multiple!(
- UInt16,
- [Int16, Int8],
- Operator::Minus,
- Int32
- );
- // (UInt16, _) | (_, UInt16) => Some(UInt16),
- test_coercion_binary_rule_multiple!(
- UInt16,
- [UInt16, UInt8, UInt8],
- Operator::Plus,
- UInt16
- );
- // (Int16, _) | (_, Int16) => Some(Int16),
- test_coercion_binary_rule_multiple!(Int16, [Int16, Int8],
Operator::Plus, Int16);
- // (UInt8, Int8) | (Int8, UInt8) => Some(Int16)
- test_coercion_binary_rule!(Int8, UInt8, Operator::Minus, Int16);
- test_coercion_binary_rule!(UInt8, Int8, Operator::Multiply, Int16);
- // (UInt8, _) | (_, UInt8) => Some(UInt8),
- test_coercion_binary_rule!(UInt8, UInt8, Operator::Minus, UInt8);
- // (Int8, _) | (_, Int8) => Some(Int8),
- test_coercion_binary_rule!(Int8, Int8, Operator::Plus, Int8);
-
- Ok(())
- }
-
- fn test_math_decimal_coercion_rule(
- lhs_type: DataType,
- rhs_type: DataType,
- expected_lhs_type: DataType,
- expected_rhs_type: DataType,
- ) {
- // The coerced types for lhs and rhs, if any of them is not decimal
- let (lhs_type, rhs_type) = math_decimal_coercion(&lhs_type,
&rhs_type).unwrap();
- assert_eq!(lhs_type, expected_lhs_type);
- assert_eq!(rhs_type, expected_rhs_type);
- }
-
- #[test]
- fn test_coercion_arithmetic_decimal() -> Result<()> {
- test_math_decimal_coercion_rule(
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::Int32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::Int32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::Int32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::Int32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::Int32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
-
- test_math_decimal_coercion_rule(
- DataType::UInt32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- DataType::Decimal128(10, 2),
- );
- test_math_decimal_coercion_rule(
- DataType::Decimal128(10, 2),
- DataType::UInt32,
- DataType::Decimal128(10, 2),
- DataType::Decimal128(10, 0),
- );
-
- Ok(())
- }
-
- #[test]
- fn test_type_coercion_compare() -> Result<()> {
- // boolean
- test_coercion_binary_rule!(
- DataType::Boolean,
- DataType::Boolean,
- Operator::Eq,
- DataType::Boolean
- );
- // float
- test_coercion_binary_rule!(
- DataType::Float16,
- DataType::Int64,
- Operator::Eq,
- DataType::Float16
- );
- test_coercion_binary_rule!(
- DataType::Float16,
- DataType::Float64,
- Operator::Eq,
- DataType::Float64
- );
- test_coercion_binary_rule!(
- DataType::Float32,
- DataType::Int64,
- Operator::Eq,
- DataType::Float32
- );
- test_coercion_binary_rule!(
- DataType::Float32,
- DataType::Float64,
- Operator::GtEq,
- DataType::Float64
- );
- // signed integer
- test_coercion_binary_rule!(
- DataType::Int8,
- DataType::Int32,
- Operator::LtEq,
- DataType::Int32
- );
- test_coercion_binary_rule!(
- DataType::Int64,
- DataType::Int32,
- Operator::LtEq,
- DataType::Int64
- );
- // unsigned integer
- test_coercion_binary_rule!(
- DataType::UInt32,
- DataType::UInt8,
- Operator::Gt,
- DataType::UInt32
- );
- test_coercion_binary_rule!(
- DataType::UInt64,
- DataType::UInt8,
- Operator::Eq,
- DataType::UInt64
- );
- test_coercion_binary_rule!(
- DataType::UInt64,
- DataType::Int64,
- Operator::Eq,
- DataType::Decimal128(20, 0)
- );
- // numeric/decimal
- test_coercion_binary_rule!(
- DataType::Int64,
- DataType::Decimal128(10, 0),
- Operator::Eq,
- DataType::Decimal128(20, 0)
- );
- test_coercion_binary_rule!(
- DataType::Int64,
- DataType::Decimal128(10, 2),
- Operator::Lt,
- DataType::Decimal128(22, 2)
- );
- test_coercion_binary_rule!(
- DataType::Float64,
- DataType::Decimal128(10, 3),
- Operator::Gt,
- DataType::Decimal128(30, 15)
- );
- test_coercion_binary_rule!(
- DataType::Int64,
- DataType::Decimal128(10, 0),
- Operator::Eq,
- DataType::Decimal128(20, 0)
- );
- test_coercion_binary_rule!(
- DataType::Decimal128(14, 2),
- DataType::Decimal128(10, 3),
- Operator::GtEq,
- DataType::Decimal128(15, 3)
- );
- test_coercion_binary_rule!(
- DataType::UInt64,
- DataType::Decimal128(20, 0),
- Operator::Eq,
- DataType::Decimal128(20, 0)
- );
-
- // Binary
- test_coercion_binary_rule!(
- DataType::Binary,
- DataType::Binary,
- Operator::Eq,
- DataType::Binary
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::Binary,
- Operator::Eq,
- DataType::Binary
- );
- test_coercion_binary_rule!(
- DataType::Binary,
- DataType::Utf8,
- Operator::Eq,
- DataType::Binary
- );
-
- // LargeBinary
- test_coercion_binary_rule!(
- DataType::LargeBinary,
- DataType::LargeBinary,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::Binary,
- DataType::LargeBinary,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::LargeBinary,
- DataType::Binary,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::Utf8,
- DataType::LargeBinary,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::LargeBinary,
- DataType::Utf8,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::LargeUtf8,
- DataType::LargeBinary,
- Operator::Eq,
- DataType::LargeBinary
- );
- test_coercion_binary_rule!(
- DataType::LargeBinary,
- DataType::LargeUtf8,
- Operator::Eq,
- DataType::LargeBinary
- );
-
- // Timestamps
- let utc: Option<Arc<str>> = Some("UTC".into());
- test_coercion_binary_rule!(
- DataType::Timestamp(TimeUnit::Second, utc.clone()),
- DataType::Timestamp(TimeUnit::Second, utc.clone()),
- Operator::Eq,
- DataType::Timestamp(TimeUnit::Second, utc.clone())
- );
- test_coercion_binary_rule!(
- DataType::Timestamp(TimeUnit::Second, utc.clone()),
- DataType::Timestamp(TimeUnit::Second,
Some("Europe/Brussels".into())),
- Operator::Eq,
- DataType::Timestamp(TimeUnit::Second, utc.clone())
- );
- test_coercion_binary_rule!(
- DataType::Timestamp(TimeUnit::Second,
Some("America/New_York".into())),
- DataType::Timestamp(TimeUnit::Second,
Some("Europe/Brussels".into())),
- Operator::Eq,
- DataType::Timestamp(TimeUnit::Second,
Some("America/New_York".into()))
- );
- test_coercion_binary_rule!(
- DataType::Timestamp(TimeUnit::Second,
Some("Europe/Brussels".into())),
- DataType::Timestamp(TimeUnit::Second, utc),
- Operator::Eq,
- DataType::Timestamp(TimeUnit::Second,
Some("Europe/Brussels".into()))
- );
-
- // list
- let inner_field = Arc::new(Field::new_list_field(DataType::Int64,
true));
- test_coercion_binary_rule!(
- DataType::List(Arc::clone(&inner_field)),
- DataType::List(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::List(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::List(Arc::clone(&inner_field)),
- DataType::LargeList(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::LargeList(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::LargeList(Arc::clone(&inner_field)),
- DataType::List(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::LargeList(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::LargeList(Arc::clone(&inner_field)),
- DataType::LargeList(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::LargeList(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- Operator::Eq,
- DataType::FixedSizeList(Arc::clone(&inner_field), 10)
- );
- test_coercion_binary_rule!(
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- DataType::LargeList(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::LargeList(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::LargeList(Arc::clone(&inner_field)),
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- Operator::Eq,
- DataType::LargeList(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::List(Arc::clone(&inner_field)),
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- Operator::Eq,
- DataType::List(Arc::clone(&inner_field))
- );
- test_coercion_binary_rule!(
- DataType::FixedSizeList(Arc::clone(&inner_field), 10),
- DataType::List(Arc::clone(&inner_field)),
- Operator::Eq,
- DataType::List(Arc::clone(&inner_field))
- );
-
- // Negative test: inner_timestamp_field and inner_field are not
compatible because their inner types are not compatible
- let inner_timestamp_field = Arc::new(Field::new_list_field(
- DataType::Timestamp(TimeUnit::Microsecond, None),
- true,
- ));
- let result_type = BinaryTypeCoercer::new(
- &DataType::List(Arc::clone(&inner_field)),
- &Operator::Eq,
- &DataType::List(Arc::clone(&inner_timestamp_field)),
- )
- .get_input_types();
- assert!(result_type.is_err());
-
- // TODO add other data type
- Ok(())
- }
-
- #[test]
- fn test_list_coercion() {
- let lhs_type = DataType::List(Arc::new(Field::new("lhs",
DataType::Int8, false)));
-
- let rhs_type = DataType::List(Arc::new(Field::new("rhs",
DataType::Int64, true)));
-
- let coerced_type = list_coercion(&lhs_type, &rhs_type).unwrap();
- assert_eq!(
- coerced_type,
- DataType::List(Arc::new(Field::new("lhs", DataType::Int64, true)))
- ); // nullable because the RHS is nullable
- }
-
- #[test]
- fn test_type_coercion_logical_op() -> Result<()> {
- test_coercion_binary_rule!(
- DataType::Boolean,
- DataType::Boolean,
- Operator::And,
- DataType::Boolean
- );
-
- test_coercion_binary_rule!(
- DataType::Boolean,
- DataType::Boolean,
- Operator::Or,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Boolean,
- DataType::Null,
- Operator::And,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Boolean,
- DataType::Null,
- Operator::Or,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Null,
- DataType::Null,
- Operator::Or,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Null,
- DataType::Null,
- Operator::And,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Null,
- DataType::Boolean,
- Operator::And,
- DataType::Boolean
- );
- test_coercion_binary_rule!(
- DataType::Null,
- DataType::Boolean,
- Operator::Or,
- DataType::Boolean
- );
- Ok(())
- }
-
- #[test]
- fn test_map_coercion() -> Result<()> {
- let lhs = Field::new_map(
- "lhs",
- "entries",
- Arc::new(Field::new("keys", DataType::Utf8, false)),
- Arc::new(Field::new("values", DataType::LargeUtf8, false)),
- true,
- false,
- );
- let rhs = Field::new_map(
- "rhs",
- "kvp",
- Arc::new(Field::new("k", DataType::Utf8, false)),
- Arc::new(Field::new("v", DataType::Utf8, true)),
- false,
- true,
- );
-
- let expected = Field::new_map(
- "expected",
- "entries", // struct coercion takes lhs name
- Arc::new(Field::new(
- "keys", // struct coercion takes lhs name
- DataType::Utf8,
- false,
- )),
- Arc::new(Field::new(
- "values", // struct coercion takes lhs name
- DataType::LargeUtf8, // lhs is large string
- true, // rhs is nullable
- )),
- false, // both sides must be sorted
- true, // rhs is nullable
- );
-
- test_coercion_binary_rule!(
- lhs.data_type(),
- rhs.data_type(),
- Operator::Eq,
- expected.data_type().clone()
- );
- Ok(())
- }
-}
+mod tests;
diff --git
a/datafusion/expr-common/src/type_coercion/binary/tests/arithmetic.rs
b/datafusion/expr-common/src/type_coercion/binary/tests/arithmetic.rs
new file mode 100644
index 0000000000..fdd41ae2bb
--- /dev/null
+++ b/datafusion/expr-common/src/type_coercion/binary/tests/arithmetic.rs
@@ -0,0 +1,250 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 super::*;
+use datafusion_common::assert_contains;
+
+#[test]
+fn test_coercion_error() -> Result<()> {
+ let coercer =
+ BinaryTypeCoercer::new(&DataType::Float32, &Operator::Plus,
&DataType::Utf8);
+ let result_type = coercer.get_input_types();
+
+ let e = result_type.unwrap_err();
+ assert_eq!(e.strip_backtrace(), "Error during planning: Cannot coerce
arithmetic expression Float32 + Utf8 to valid types");
+ Ok(())
+}
+
+#[test]
+fn test_date_timestamp_arithmetic_error() -> Result<()> {
+ let (lhs, rhs) = BinaryTypeCoercer::new(
+ &DataType::Timestamp(TimeUnit::Nanosecond, None),
+ &Operator::Minus,
+ &DataType::Timestamp(TimeUnit::Millisecond, None),
+ )
+ .get_input_types()?;
+ assert_eq!(lhs.to_string(), "Timestamp(Millisecond, None)");
+ assert_eq!(rhs.to_string(), "Timestamp(Millisecond, None)");
+
+ let err =
+ BinaryTypeCoercer::new(&DataType::Date32, &Operator::Plus,
&DataType::Date64)
+ .get_input_types()
+ .unwrap_err()
+ .to_string();
+
+ assert_contains!(
+ &err,
+ "Cannot get result type for temporal operation Date64 + Date64"
+ );
+
+ Ok(())
+}
+
+#[test]
+fn test_decimal_mathematics_op_type() {
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Int8).unwrap(),
+ DataType::Decimal128(3, 0)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Int16).unwrap(),
+ DataType::Decimal128(5, 0)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Int32).unwrap(),
+ DataType::Decimal128(10, 0)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Int64).unwrap(),
+ DataType::Decimal128(20, 0)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Float16).unwrap(),
+ DataType::Decimal128(6, 3)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Float32).unwrap(),
+ DataType::Decimal128(14, 7)
+ );
+ assert_eq!(
+ coerce_numeric_type_to_decimal(&DataType::Float64).unwrap(),
+ DataType::Decimal128(30, 15)
+ );
+}
+
+#[test]
+fn test_type_coercion_arithmetic() -> Result<()> {
+ use DataType::*;
+
+ // (Float64, _) | (_, Float64) => Some(Float64)
+ test_coercion_binary_rule_multiple!(
+ Float64,
+ [
+ Float64, Float32, Float16, Int64, UInt64, Int32, UInt32, Int16,
UInt16, Int8,
+ UInt8
+ ],
+ Operator::Plus,
+ Float64
+ );
+ // (_, Float32) | (Float32, _) => Some(Float32)
+ test_coercion_binary_rule_multiple!(
+ Float32,
+ [Float32, Float16, Int64, UInt64, Int32, UInt32, Int16, UInt16, Int8,
UInt8],
+ Operator::Plus,
+ Float32
+ );
+ // (_, Float16) | (Float16, _) => Some(Float16)
+ test_coercion_binary_rule_multiple!(
+ Float16,
+ [Float16, Int64, UInt64, Int32, UInt32, Int16, UInt16, Int8, UInt8],
+ Operator::Plus,
+ Float16
+ );
+ // (UInt64, Int64 | Int32 | Int16 | Int8) | (Int64 | Int32 | Int16 | Int8,
UInt64) => Some(Decimal128(20, 0))
+ test_coercion_binary_rule_multiple!(
+ UInt64,
+ [Int64, Int32, Int16, Int8],
+ Operator::Divide,
+ Decimal128(20, 0)
+ );
+ // (UInt64, _) | (_, UInt64) => Some(UInt64)
+ test_coercion_binary_rule_multiple!(
+ UInt64,
+ [UInt64, UInt32, UInt16, UInt8],
+ Operator::Modulo,
+ UInt64
+ );
+ // (Int64, _) | (_, Int64) => Some(Int64)
+ test_coercion_binary_rule_multiple!(
+ Int64,
+ [Int64, Int32, UInt32, Int16, UInt16, Int8, UInt8],
+ Operator::Modulo,
+ Int64
+ );
+ // (UInt32, Int32 | Int16 | Int8) | (Int32 | Int16 | Int8, UInt32) =>
Some(Int64)
+ test_coercion_binary_rule_multiple!(
+ UInt32,
+ [Int32, Int16, Int8],
+ Operator::Modulo,
+ Int64
+ );
+ // (UInt32, _) | (_, UInt32) => Some(UInt32)
+ test_coercion_binary_rule_multiple!(
+ UInt32,
+ [UInt32, UInt16, UInt8],
+ Operator::Modulo,
+ UInt32
+ );
+ // (Int32, _) | (_, Int32) => Some(Int32)
+ test_coercion_binary_rule_multiple!(
+ Int32,
+ [Int32, Int16, Int8],
+ Operator::Modulo,
+ Int32
+ );
+ // (UInt16, Int16 | Int8) | (Int16 | Int8, UInt16) => Some(Int32)
+ test_coercion_binary_rule_multiple!(UInt16, [Int16, Int8],
Operator::Minus, Int32);
+ // (UInt16, _) | (_, UInt16) => Some(UInt16)
+ test_coercion_binary_rule_multiple!(
+ UInt16,
+ [UInt16, UInt8, UInt8],
+ Operator::Plus,
+ UInt16
+ );
+ // (Int16, _) | (_, Int16) => Some(Int16)
+ test_coercion_binary_rule_multiple!(Int16, [Int16, Int8], Operator::Plus,
Int16);
+ // (UInt8, Int8) | (Int8, UInt8) => Some(Int16)
+ test_coercion_binary_rule!(Int8, UInt8, Operator::Minus, Int16);
+ test_coercion_binary_rule!(UInt8, Int8, Operator::Multiply, Int16);
+ // (UInt8, _) | (_, UInt8) => Some(UInt8)
+ test_coercion_binary_rule!(UInt8, UInt8, Operator::Minus, UInt8);
+ // (Int8, _) | (_, Int8) => Some(Int8)
+ test_coercion_binary_rule!(Int8, Int8, Operator::Plus, Int8);
+
+ Ok(())
+}
+
+fn test_math_decimal_coercion_rule(
+ lhs_type: DataType,
+ rhs_type: DataType,
+ expected_lhs_type: DataType,
+ expected_rhs_type: DataType,
+) {
+ let (lhs_type, rhs_type) = math_decimal_coercion(&lhs_type,
&rhs_type).unwrap();
+ assert_eq!(lhs_type, expected_lhs_type);
+ assert_eq!(rhs_type, expected_rhs_type);
+}
+
+#[test]
+fn test_coercion_arithmetic_decimal() -> Result<()> {
+ test_math_decimal_coercion_rule(
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::Int32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::Int32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::Int32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::Int32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::Int32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+
+ test_math_decimal_coercion_rule(
+ DataType::UInt32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ DataType::Decimal128(10, 2),
+ );
+ test_math_decimal_coercion_rule(
+ DataType::Decimal128(10, 2),
+ DataType::UInt32,
+ DataType::Decimal128(10, 2),
+ DataType::Decimal128(10, 0),
+ );
+
+ Ok(())
+}
diff --git
a/datafusion/expr-common/src/type_coercion/binary/tests/comparison.rs
b/datafusion/expr-common/src/type_coercion/binary/tests/comparison.rs
new file mode 100644
index 0000000000..208edae4ff
--- /dev/null
+++ b/datafusion/expr-common/src/type_coercion/binary/tests/comparison.rs
@@ -0,0 +1,699 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 super::*;
+
+#[test]
+fn test_decimal_binary_comparison_coercion() -> Result<()> {
+ let input_decimal = DataType::Decimal128(20, 3);
+ let input_types = [
+ DataType::Int8,
+ DataType::Int16,
+ DataType::Int32,
+ DataType::Int64,
+ DataType::Float32,
+ DataType::Float64,
+ DataType::Decimal128(38, 10),
+ DataType::Decimal128(20, 8),
+ DataType::Null,
+ ];
+ let result_types = [
+ DataType::Decimal128(20, 3),
+ DataType::Decimal128(20, 3),
+ DataType::Decimal128(20, 3),
+ DataType::Decimal128(23, 3),
+ DataType::Decimal128(24, 7),
+ DataType::Decimal128(32, 15),
+ DataType::Decimal128(38, 10),
+ DataType::Decimal128(25, 8),
+ DataType::Decimal128(20, 3),
+ ];
+ let comparison_op_types = [
+ Operator::NotEq,
+ Operator::Eq,
+ Operator::Gt,
+ Operator::GtEq,
+ Operator::Lt,
+ Operator::LtEq,
+ ];
+ for (i, input_type) in input_types.iter().enumerate() {
+ let expect_type = &result_types[i];
+ for op in comparison_op_types {
+ let (lhs, rhs) = BinaryTypeCoercer::new(&input_decimal, &op,
input_type)
+ .get_input_types()?;
+ assert_eq!(expect_type, &lhs);
+ assert_eq!(expect_type, &rhs);
+ }
+ }
+ // negative test
+ let result_type =
+ BinaryTypeCoercer::new(&input_decimal, &Operator::Eq,
&DataType::Boolean)
+ .get_input_types();
+ assert!(result_type.is_err());
+ Ok(())
+}
+
+#[test]
+fn test_like_coercion() {
+ // string coerce to strings
+ test_like_rule!(DataType::Utf8, DataType::Utf8, Some(DataType::Utf8));
+ test_like_rule!(
+ DataType::LargeUtf8,
+ DataType::Utf8,
+ Some(DataType::LargeUtf8)
+ );
+ test_like_rule!(
+ DataType::Utf8,
+ DataType::LargeUtf8,
+ Some(DataType::LargeUtf8)
+ );
+ test_like_rule!(
+ DataType::LargeUtf8,
+ DataType::LargeUtf8,
+ Some(DataType::LargeUtf8)
+ );
+
+ // Also coerce binary to strings
+ test_like_rule!(DataType::Binary, DataType::Utf8, Some(DataType::Utf8));
+ test_like_rule!(
+ DataType::LargeBinary,
+ DataType::Utf8,
+ Some(DataType::LargeUtf8)
+ );
+ test_like_rule!(
+ DataType::Binary,
+ DataType::LargeUtf8,
+ Some(DataType::LargeUtf8)
+ );
+ test_like_rule!(
+ DataType::LargeBinary,
+ DataType::LargeUtf8,
+ Some(DataType::LargeUtf8)
+ );
+}
+
+#[test]
+fn test_type_coercion() -> Result<()> {
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Date32,
+ Operator::Eq,
+ DataType::Date32
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Date64,
+ Operator::Lt,
+ DataType::Date64
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Time32(TimeUnit::Second),
+ Operator::Eq,
+ DataType::Time32(TimeUnit::Second)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Time32(TimeUnit::Millisecond),
+ Operator::Eq,
+ DataType::Time32(TimeUnit::Millisecond)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Time64(TimeUnit::Microsecond),
+ Operator::Eq,
+ DataType::Time64(TimeUnit::Microsecond)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Time64(TimeUnit::Nanosecond),
+ Operator::Eq,
+ DataType::Time64(TimeUnit::Nanosecond)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Timestamp(TimeUnit::Second, None),
+ Operator::Lt,
+ DataType::Timestamp(TimeUnit::Nanosecond, None)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Timestamp(TimeUnit::Millisecond, None),
+ Operator::Lt,
+ DataType::Timestamp(TimeUnit::Nanosecond, None)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Timestamp(TimeUnit::Microsecond, None),
+ Operator::Lt,
+ DataType::Timestamp(TimeUnit::Nanosecond, None)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Timestamp(TimeUnit::Nanosecond, None),
+ Operator::Lt,
+ DataType::Timestamp(TimeUnit::Nanosecond, None)
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8,
+ Operator::RegexMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8View,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8View,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8,
+ Operator::RegexNotMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8View,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8View,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8,
+ Operator::RegexNotIMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Utf8View,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8View,
+ DataType::Utf8View,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8,
+ Operator::RegexMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8View,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8View,
+ Operator::RegexMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8,
+ Operator::RegexIMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8,
+ Operator::RegexIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8View,
+ Operator::RegexIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8View,
+ Operator::RegexIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8,
+ Operator::RegexNotMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8View,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8View,
+ Operator::RegexNotMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8,
+ Operator::RegexNotIMatch,
+ DataType::Utf8
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(), DataType::Utf8.into()),
+ DataType::Utf8View,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Dictionary(DataType::Int32.into(),
DataType::Utf8View.into()),
+ DataType::Utf8View,
+ Operator::RegexNotIMatch,
+ DataType::Utf8View
+ );
+ test_coercion_binary_rule!(
+ DataType::Int16,
+ DataType::Int64,
+ Operator::BitwiseAnd,
+ DataType::Int64
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt64,
+ DataType::UInt64,
+ Operator::BitwiseAnd,
+ DataType::UInt64
+ );
+ test_coercion_binary_rule!(
+ DataType::Int8,
+ DataType::UInt32,
+ Operator::BitwiseAnd,
+ DataType::Int64
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt32,
+ DataType::Int32,
+ Operator::BitwiseAnd,
+ DataType::Int64
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt16,
+ DataType::Int16,
+ Operator::BitwiseAnd,
+ DataType::Int32
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt32,
+ DataType::UInt32,
+ Operator::BitwiseAnd,
+ DataType::UInt32
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt16,
+ DataType::UInt32,
+ Operator::BitwiseAnd,
+ DataType::UInt32
+ );
+ Ok(())
+}
+
+#[test]
+fn test_type_coercion_compare() -> Result<()> {
+ // boolean
+ test_coercion_binary_rule!(
+ DataType::Boolean,
+ DataType::Boolean,
+ Operator::Eq,
+ DataType::Boolean
+ );
+ // float
+ test_coercion_binary_rule!(
+ DataType::Float16,
+ DataType::Int64,
+ Operator::Eq,
+ DataType::Float16
+ );
+ test_coercion_binary_rule!(
+ DataType::Float16,
+ DataType::Float64,
+ Operator::Eq,
+ DataType::Float64
+ );
+ test_coercion_binary_rule!(
+ DataType::Float32,
+ DataType::Int64,
+ Operator::Eq,
+ DataType::Float32
+ );
+ test_coercion_binary_rule!(
+ DataType::Float32,
+ DataType::Float64,
+ Operator::GtEq,
+ DataType::Float64
+ );
+ // signed integer
+ test_coercion_binary_rule!(
+ DataType::Int8,
+ DataType::Int32,
+ Operator::LtEq,
+ DataType::Int32
+ );
+ test_coercion_binary_rule!(
+ DataType::Int64,
+ DataType::Int32,
+ Operator::LtEq,
+ DataType::Int64
+ );
+ // unsigned integer
+ test_coercion_binary_rule!(
+ DataType::UInt32,
+ DataType::UInt8,
+ Operator::Gt,
+ DataType::UInt32
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt64,
+ DataType::UInt8,
+ Operator::Eq,
+ DataType::UInt64
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt64,
+ DataType::Int64,
+ Operator::Eq,
+ DataType::Decimal128(20, 0)
+ );
+ // numeric/decimal
+ test_coercion_binary_rule!(
+ DataType::Int64,
+ DataType::Decimal128(10, 0),
+ Operator::Eq,
+ DataType::Decimal128(20, 0)
+ );
+ test_coercion_binary_rule!(
+ DataType::Int64,
+ DataType::Decimal128(10, 2),
+ Operator::Lt,
+ DataType::Decimal128(22, 2)
+ );
+ test_coercion_binary_rule!(
+ DataType::Float64,
+ DataType::Decimal128(10, 3),
+ Operator::Gt,
+ DataType::Decimal128(30, 15)
+ );
+ test_coercion_binary_rule!(
+ DataType::Int64,
+ DataType::Decimal128(10, 0),
+ Operator::Eq,
+ DataType::Decimal128(20, 0)
+ );
+ test_coercion_binary_rule!(
+ DataType::Decimal128(14, 2),
+ DataType::Decimal128(10, 3),
+ Operator::GtEq,
+ DataType::Decimal128(15, 3)
+ );
+ test_coercion_binary_rule!(
+ DataType::UInt64,
+ DataType::Decimal128(20, 0),
+ Operator::Eq,
+ DataType::Decimal128(20, 0)
+ );
+
+ // Binary
+ test_coercion_binary_rule!(
+ DataType::Binary,
+ DataType::Binary,
+ Operator::Eq,
+ DataType::Binary
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::Binary,
+ Operator::Eq,
+ DataType::Binary
+ );
+ test_coercion_binary_rule!(
+ DataType::Binary,
+ DataType::Utf8,
+ Operator::Eq,
+ DataType::Binary
+ );
+
+ // LargeBinary
+ test_coercion_binary_rule!(
+ DataType::LargeBinary,
+ DataType::LargeBinary,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::Binary,
+ DataType::LargeBinary,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeBinary,
+ DataType::Binary,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::Utf8,
+ DataType::LargeBinary,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeBinary,
+ DataType::Utf8,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeUtf8,
+ DataType::LargeBinary,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeBinary,
+ DataType::LargeUtf8,
+ Operator::Eq,
+ DataType::LargeBinary
+ );
+
+ // Timestamps
+ let utc: Option<Arc<str>> = Some("UTC".into());
+ test_coercion_binary_rule!(
+ DataType::Timestamp(TimeUnit::Second, utc.clone()),
+ DataType::Timestamp(TimeUnit::Second, utc.clone()),
+ Operator::Eq,
+ DataType::Timestamp(TimeUnit::Second, utc.clone())
+ );
+ test_coercion_binary_rule!(
+ DataType::Timestamp(TimeUnit::Second, utc.clone()),
+ DataType::Timestamp(TimeUnit::Second, Some("Europe/Brussels".into())),
+ Operator::Eq,
+ DataType::Timestamp(TimeUnit::Second, utc.clone())
+ );
+ test_coercion_binary_rule!(
+ DataType::Timestamp(TimeUnit::Second, Some("America/New_York".into())),
+ DataType::Timestamp(TimeUnit::Second, Some("Europe/Brussels".into())),
+ Operator::Eq,
+ DataType::Timestamp(TimeUnit::Second, Some("America/New_York".into()))
+ );
+ test_coercion_binary_rule!(
+ DataType::Timestamp(TimeUnit::Second, Some("Europe/Brussels".into())),
+ DataType::Timestamp(TimeUnit::Second, utc),
+ Operator::Eq,
+ DataType::Timestamp(TimeUnit::Second, Some("Europe/Brussels".into()))
+ );
+
+ // list
+ let inner_field = Arc::new(Field::new_list_field(DataType::Int64, true));
+ test_coercion_binary_rule!(
+ DataType::List(Arc::clone(&inner_field)),
+ DataType::List(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::List(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::List(Arc::clone(&inner_field)),
+ DataType::LargeList(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::LargeList(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeList(Arc::clone(&inner_field)),
+ DataType::List(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::LargeList(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeList(Arc::clone(&inner_field)),
+ DataType::LargeList(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::LargeList(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ Operator::Eq,
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10)
+ );
+ test_coercion_binary_rule!(
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ DataType::LargeList(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::LargeList(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::LargeList(Arc::clone(&inner_field)),
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ Operator::Eq,
+ DataType::LargeList(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::List(Arc::clone(&inner_field)),
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ Operator::Eq,
+ DataType::List(Arc::clone(&inner_field))
+ );
+ test_coercion_binary_rule!(
+ DataType::FixedSizeList(Arc::clone(&inner_field), 10),
+ DataType::List(Arc::clone(&inner_field)),
+ Operator::Eq,
+ DataType::List(Arc::clone(&inner_field))
+ );
+
+ let inner_timestamp_field = Arc::new(Field::new_list_field(
+ DataType::Timestamp(TimeUnit::Microsecond, None),
+ true,
+ ));
+ let result_type = BinaryTypeCoercer::new(
+ &DataType::List(Arc::clone(&inner_field)),
+ &Operator::Eq,
+ &DataType::List(Arc::clone(&inner_timestamp_field)),
+ )
+ .get_input_types();
+ assert!(result_type.is_err());
+
+ Ok(())
+}
+
+#[test]
+fn test_list_coercion() {
+ let lhs_type = DataType::List(Arc::new(Field::new("lhs", DataType::Int8,
false)));
+
+ let rhs_type = DataType::List(Arc::new(Field::new("rhs", DataType::Int64,
true)));
+
+ let coerced_type = list_coercion(&lhs_type, &rhs_type).unwrap();
+ assert_eq!(
+ coerced_type,
+ DataType::List(Arc::new(Field::new("lhs", DataType::Int64, true)))
+ );
+}
+
+#[test]
+fn test_map_coercion() -> Result<()> {
+ let lhs = Field::new_map(
+ "lhs",
+ "entries",
+ Arc::new(Field::new("keys", DataType::Utf8, false)),
+ Arc::new(Field::new("values", DataType::LargeUtf8, false)),
+ true,
+ false,
+ );
+ let rhs = Field::new_map(
+ "rhs",
+ "kvp",
+ Arc::new(Field::new("k", DataType::Utf8, false)),
+ Arc::new(Field::new("v", DataType::Utf8, true)),
+ false,
+ true,
+ );
+
+ let expected = Field::new_map(
+ "expected",
+ "entries",
+ Arc::new(Field::new("keys", DataType::Utf8, false)),
+ Arc::new(Field::new("values", DataType::LargeUtf8, true)),
+ false,
+ true,
+ );
+
+ test_coercion_binary_rule!(
+ lhs.data_type(),
+ rhs.data_type(),
+ Operator::Eq,
+ expected.data_type().clone()
+ );
+ Ok(())
+}
diff --git
a/datafusion/expr-common/src/type_coercion/binary/tests/dictionary.rs
b/datafusion/expr-common/src/type_coercion/binary/tests/dictionary.rs
new file mode 100644
index 0000000000..0fb56a4a2c
--- /dev/null
+++ b/datafusion/expr-common/src/type_coercion/binary/tests/dictionary.rs
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 super::*;
+
+#[test]
+fn test_dictionary_type_coercion() {
+ use DataType::*;
+
+ let lhs_type = Dictionary(Box::new(Int8), Box::new(Int32));
+ let rhs_type = Dictionary(Box::new(Int8), Box::new(Int16));
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
+ Some(Int32)
+ );
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
+ Some(Int32)
+ );
+
+ // Since we can coerce values of Int16 to Utf8 can support this
+ let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
+ let rhs_type = Dictionary(Box::new(Int8), Box::new(Int16));
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
+ Some(Utf8)
+ );
+
+ // Since we can coerce values of Utf8 to Binary can support this
+ let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
+ let rhs_type = Dictionary(Box::new(Int8), Box::new(Binary));
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
+ Some(Binary)
+ );
+
+ let lhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
+ let rhs_type = Utf8;
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
+ Some(Utf8)
+ );
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
+ Some(lhs_type.clone())
+ );
+
+ let lhs_type = Utf8;
+ let rhs_type = Dictionary(Box::new(Int8), Box::new(Utf8));
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, false),
+ Some(Utf8)
+ );
+ assert_eq!(
+ dictionary_comparison_coercion(&lhs_type, &rhs_type, true),
+ Some(rhs_type.clone())
+ );
+}
diff --git a/datafusion/expr-common/src/type_coercion/binary/tests/mod.rs
b/datafusion/expr-common/src/type_coercion/binary/tests/mod.rs
new file mode 100644
index 0000000000..6d21d795e4
--- /dev/null
+++ b/datafusion/expr-common/src/type_coercion/binary/tests/mod.rs
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 super::*;
+
+// Common test macros
+
+/// Tests that coercion for a binary operator between two types yields the
expected result type for both sides.
+///
+/// Usage: test_coercion_binary_rule!(lhs_type, rhs_type, op, expected_type)
+/// - lhs_type: The left-hand side data type
+/// - rhs_type: The right-hand side data type
+/// - op: The binary operator (e.g., "+", "-", etc.)
+/// - expected_type: The type both sides should be coerced to
+macro_rules! test_coercion_binary_rule {
+ ($LHS_TYPE:expr, $RHS_TYPE:expr, $OP:expr, $RESULT_TYPE:expr) => {{
+ let (lhs, rhs) =
+ BinaryTypeCoercer::new(&$LHS_TYPE, &$OP,
&$RHS_TYPE).get_input_types()?;
+ assert_eq!(lhs, $RESULT_TYPE);
+ assert_eq!(rhs, $RESULT_TYPE);
+ }};
+}
+
+/// Tests that coercion for a binary operator between one type and multiple
right-hand side types
+/// yields the expected result type for both sides, in both lhs/rhs and
rhs/lhs order.
+///
+/// Usage: test_coercion_binary_rule_multiple!(lhs_type, rhs_types, op,
expected_type)
+/// - lhs_type: The left-hand side data type
+/// - rhs_types: An iterable of right-hand side data types
+/// - op: The binary operator
+/// - expected_type: The type both sides should be coerced to
+macro_rules! test_coercion_binary_rule_multiple {
+ ($LHS_TYPE:expr, $RHS_TYPES:expr, $OP:expr, $RESULT_TYPE:expr) => {{
+ for rh_type in $RHS_TYPES {
+ let (lhs, rhs) =
+ BinaryTypeCoercer::new(&$LHS_TYPE, &$OP,
&rh_type).get_input_types()?;
+ assert_eq!(lhs, $RESULT_TYPE);
+ assert_eq!(rhs, $RESULT_TYPE);
+
+ BinaryTypeCoercer::new(&rh_type, &$OP,
&$LHS_TYPE).get_input_types()?;
+ assert_eq!(lhs, $RESULT_TYPE);
+ assert_eq!(rhs, $RESULT_TYPE);
+ }
+ }};
+}
+
+/// Tests that the like_coercion function returns the expected result type for
both lhs/rhs and rhs/lhs order.
+///
+/// Usage: test_like_rule!(lhs_type, rhs_type, expected_type)
+/// - lhs_type: The left-hand side data type
+/// - rhs_type: The right-hand side data type
+/// - expected_type: The expected result type from like_coercion
+macro_rules! test_like_rule {
+ ($LHS_TYPE:expr, $RHS_TYPE:expr, $RESULT_TYPE:expr) => {{
+ let result = like_coercion(&$LHS_TYPE, &$RHS_TYPE);
+ assert_eq!(result, $RESULT_TYPE);
+ let result = like_coercion(&$RHS_TYPE, &$LHS_TYPE);
+ assert_eq!(result, $RESULT_TYPE);
+ }};
+}
+
+mod arithmetic;
+mod comparison;
+mod dictionary;
+mod null_coercion;
diff --git
a/datafusion/expr-common/src/type_coercion/binary/tests/null_coercion.rs
b/datafusion/expr-common/src/type_coercion/binary/tests/null_coercion.rs
new file mode 100644
index 0000000000..91c826b563
--- /dev/null
+++ b/datafusion/expr-common/src/type_coercion/binary/tests/null_coercion.rs
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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 super::*;
+
+#[test]
+fn test_type_coercion_logical_op() -> Result<()> {
+ test_coercion_binary_rule!(
+ DataType::Boolean,
+ DataType::Boolean,
+ Operator::And,
+ DataType::Boolean
+ );
+
+ test_coercion_binary_rule!(
+ DataType::Boolean,
+ DataType::Boolean,
+ Operator::Or,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Boolean,
+ DataType::Null,
+ Operator::And,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Boolean,
+ DataType::Null,
+ Operator::Or,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Null,
+ DataType::Null,
+ Operator::Or,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Null,
+ DataType::Null,
+ Operator::And,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Null,
+ DataType::Boolean,
+ Operator::And,
+ DataType::Boolean
+ );
+ test_coercion_binary_rule!(
+ DataType::Null,
+ DataType::Boolean,
+ Operator::Or,
+ DataType::Boolean
+ );
+ Ok(())
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]