This is an automated email from the ASF dual-hosted git repository.

jakevin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 93771052c5 fix: add condition check for BinaryExpr Date/Time +/- 
Interval (#5932)
93771052c5 is described below

commit 93771052c5ac31f2cf22b8c25bf938656afe1047
Author: jakevin <[email protected]>
AuthorDate: Tue Apr 11 17:29:13 2023 +0800

    fix: add condition check for BinaryExpr Date/Time +/- Interval (#5932)
---
 .../tests/sqllogictests/test_files/timestamps.slt  |  4 +-
 datafusion/expr/src/type_coercion/binary.rs        | 46 +++++++++++-----------
 datafusion/optimizer/src/analyzer/type_coercion.rs | 11 +++---
 3 files changed, 31 insertions(+), 30 deletions(-)

diff --git a/datafusion/core/tests/sqllogictests/test_files/timestamps.slt 
b/datafusion/core/tests/sqllogictests/test_files/timestamps.slt
index 3bea8cb6c9..3887fc84ad 100644
--- a/datafusion/core/tests/sqllogictests/test_files/timestamps.slt
+++ b/datafusion/core/tests/sqllogictests/test_files/timestamps.slt
@@ -656,7 +656,7 @@ SELECT ts1 + i FROM foo;
 2003-07-12T01:31:15.000123463
 
 # Timestamp + Timestamp => error
-statement error DataFusion error: Error during planning: 
Timestamp\(Nanosecond, None\) Timestamp\(Nanosecond, None\) is an unsupported 
operation. addition/subtraction on dates/timestamps only supported with 
interval types
+statement error DataFusion error: Error during planning: 
Timestamp\(Nanosecond, None\) \+ Timestamp\(Nanosecond, None\) can't be 
evaluated because there isn't a common type to coerce the types to
 SELECT ts1 + ts2
 FROM foo;
 
@@ -690,4 +690,4 @@ SELECT
   '2000-01-01T00:00:00'::timestamp::timestamptz <= 
'2000-01-01T00:00:00'::timestamp
 ;
 ----
-true false true true
\ No newline at end of file
+true false true true
diff --git a/datafusion/expr/src/type_coercion/binary.rs 
b/datafusion/expr/src/type_coercion/binary.rs
index 99a5efb4fd..33ec5e4365 100644
--- a/datafusion/expr/src/type_coercion/binary.rs
+++ b/datafusion/expr/src/type_coercion/binary.rs
@@ -125,7 +125,7 @@ pub fn coerce_types(
                     || !is_timestamp(rhs_type)
                     || *op != Operator::Minus) =>
         {
-            temporal_add_sub_coercion(lhs_type, rhs_type, op)?
+            temporal_add_sub_coercion(lhs_type, rhs_type, op)
         }
         // for math expressions, the final value of the coercion is also the 
return type
         // because coercion favours higher information types
@@ -217,29 +217,33 @@ pub fn temporal_add_sub_coercion(
     lhs_type: &DataType,
     rhs_type: &DataType,
     op: &Operator,
-) -> Result<Option<DataType>> {
+) -> Option<DataType> {
     match (lhs_type, rhs_type, op) {
         // if an interval is being added/subtracted from a date/timestamp, 
return the date/timestamp data type
         (lhs, rhs, _) if is_interval(lhs) && (is_date(rhs) || 
is_timestamp(rhs)) => {
-            Ok(Some(rhs.clone()))
+            Some(rhs.clone())
         }
         (lhs, rhs, _) if is_interval(rhs) && (is_date(lhs) || 
is_timestamp(lhs)) => {
-            Ok(Some(lhs.clone()))
+            Some(lhs.clone())
         }
         // if two timestamps are being subtracted, check their time units and 
return the corresponding interval data type
         (lhs, rhs, Operator::Minus) if is_timestamp(lhs) && is_timestamp(rhs) 
=> {
             handle_timestamp_minus(lhs, rhs)
         }
         // if two intervals are being added/subtracted, check their interval 
units and return the corresponding interval data type
-        (lhs, rhs, _) if is_interval(lhs) && is_interval(rhs) => 
handle_interval_addition(lhs, rhs),
+        (lhs, rhs, _) if is_interval(lhs) && is_interval(rhs) => {
+            handle_interval_addition(lhs, rhs)
+        }
         // if two date/timestamp are being added/subtracted, return an error 
indicating that the operation is not supported
-        (lhs, rhs, _) if (is_date(lhs) || is_timestamp(lhs)) && (is_date(rhs) 
|| is_timestamp(rhs)) => {
-            Err(DataFusionError::Plan(format!(
-                "{lhs_type:?} {rhs_type:?} is an unsupported operation. 
addition/subtraction on dates/timestamps only supported with interval types"
-            )))
+        (lhs, rhs, Operator::Minus)
+            if (is_date(lhs) || is_timestamp(lhs))
+                && (is_date(rhs) || is_timestamp(rhs)) =>
+        {
+            // TODO: support Minus
+            None
         }
         // return None if no coercion is possible
-        _ => Ok(None),
+        _ => None,
     }
 }
 
@@ -247,19 +251,19 @@ pub fn temporal_add_sub_coercion(
 // representing the sum of them. If the two interval data types have different 
units, it returns an interval data type
 // with "IntervalUnit::MonthDayNano". If the two interval data types are 
already "IntervalUnit::YearMonth" or "IntervalUnit::DayTime",
 // it returns an interval data type with the same unit as the operands.
-fn handle_interval_addition(lhs: &DataType, rhs: &DataType) -> 
Result<Option<DataType>> {
+fn handle_interval_addition(lhs: &DataType, rhs: &DataType) -> 
Option<DataType> {
     match (lhs, rhs) {
         // operation with the same types
         (
             DataType::Interval(IntervalUnit::YearMonth),
             DataType::Interval(IntervalUnit::YearMonth),
-        ) => Ok(Some(DataType::Interval(IntervalUnit::YearMonth))),
+        ) => Some(DataType::Interval(IntervalUnit::YearMonth)),
         (
             DataType::Interval(IntervalUnit::DayTime),
             DataType::Interval(IntervalUnit::DayTime),
-        ) => Ok(Some(DataType::Interval(IntervalUnit::DayTime))),
+        ) => Some(DataType::Interval(IntervalUnit::DayTime)),
         // operation with MonthDayNano's or different types
-        (_, _) => Ok(Some(DataType::Interval(IntervalUnit::MonthDayNano))),
+        (_, _) => Some(DataType::Interval(IntervalUnit::MonthDayNano)),
     }
 }
 
@@ -267,7 +271,7 @@ fn handle_interval_addition(lhs: &DataType, rhs: &DataType) 
-> Result<Option<Dat
 // representing the difference between them, either "IntervalUnit::DayTime" if 
the time unit is second or millisecond,
 // or "IntervalUnit::MonthDayNano" if the time unit is microsecond or 
nanosecond. If the two timestamp data types have
 // different time units, it returns an error indicating that "The timestamps 
have different types".
-fn handle_timestamp_minus(lhs: &DataType, rhs: &DataType) -> 
Result<Option<DataType>> {
+fn handle_timestamp_minus(lhs: &DataType, rhs: &DataType) -> Option<DataType> {
     match (lhs, rhs) {
         (
             DataType::Timestamp(TimeUnit::Second, _),
@@ -276,7 +280,7 @@ fn handle_timestamp_minus(lhs: &DataType, rhs: &DataType) 
-> Result<Option<DataT
         | (
             DataType::Timestamp(TimeUnit::Millisecond, _),
             DataType::Timestamp(TimeUnit::Millisecond, _),
-        ) => Ok(Some(DataType::Interval(IntervalUnit::DayTime))),
+        ) => Some(DataType::Interval(IntervalUnit::DayTime)),
         (
             DataType::Timestamp(TimeUnit::Microsecond, _),
             DataType::Timestamp(TimeUnit::Microsecond, _),
@@ -284,10 +288,8 @@ fn handle_timestamp_minus(lhs: &DataType, rhs: &DataType) 
-> Result<Option<DataT
         | (
             DataType::Timestamp(TimeUnit::Nanosecond, _),
             DataType::Timestamp(TimeUnit::Nanosecond, _),
-        ) => Ok(Some(DataType::Interval(IntervalUnit::MonthDayNano))),
-        (_, _) => Err(DataFusionError::Plan(
-            "The timestamps have different types".to_string(),
-        )),
+        ) => Some(DataType::Interval(IntervalUnit::MonthDayNano)),
+        (_, _) => None,
     }
 }
 
@@ -1003,12 +1005,12 @@ mod tests {
         )
         .unwrap_err()
         .to_string();
-        assert_contains!(&err, "The timestamps have different types");
+        assert_contains!(&err, "Timestamp(Nanosecond, None) - 
Timestamp(Millisecond, None) can't be evaluated because there isn't a common 
type to coerce the types to");
 
         let err = coerce_types(&DataType::Date32, &Operator::Plus, 
&DataType::Date64)
             .unwrap_err()
             .to_string();
-        assert_contains!(&err, "Date32 Date64 is an unsupported operation. 
addition/subtraction on dates/timestamps only supported with interval types");
+        assert_contains!(&err, "Date32 + Date64 can't be evaluated because 
there isn't a common type to coerce the types to");
 
         Ok(())
     }
diff --git a/datafusion/optimizer/src/analyzer/type_coercion.rs 
b/datafusion/optimizer/src/analyzer/type_coercion.rs
index 952cc04b0b..9a210601f6 100644
--- a/datafusion/optimizer/src/analyzer/type_coercion.rs
+++ b/datafusion/optimizer/src/analyzer/type_coercion.rs
@@ -242,20 +242,19 @@ impl TreeNodeRewriter for TypeCoercionRewriter {
                 op,
                 ref right,
             }) => {
+                // this is a workaround for 
https://github.com/apache/arrow-datafusion/issues/3419
                 let left_type = left.get_type(&self.schema)?;
                 let right_type = right.get_type(&self.schema)?;
                 match (&left_type, &right_type) {
+                    // Handle some case about Interval.
                     (
                         DataType::Date32 | DataType::Date64 | 
DataType::Timestamp(_, _),
                         &DataType::Interval(_),
-                    )
-                    | (
+                    ) if matches!(op, Operator::Plus | Operator::Minus) => 
Ok(expr),
+                    (
                         &DataType::Interval(_),
                         DataType::Date32 | DataType::Date64 | 
DataType::Timestamp(_, _),
-                    ) => {
-                        // this is a workaround for 
https://github.com/apache/arrow-datafusion/issues/3419
-                        Ok(expr.clone())
-                    }
+                    ) if matches!(op, Operator::Plus) => Ok(expr),
                     (DataType::Timestamp(_, _), DataType::Timestamp(_, _))
                         if op.is_numerical_operators() =>
                     {

Reply via email to