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

alamb 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 ecd9f36628 FIX : Incorrect NULL handling in BETWEEN expression (#14007)
ecd9f36628 is described below

commit ecd9f3662865f67fb710f323e903fa623e33e2d6
Author: Namgung Chan <[email protected]>
AuthorDate: Mon Jan 6 03:06:00 2025 +0900

    FIX : Incorrect NULL handling in BETWEEN expression (#14007)
    
    * submodule update
    
    * FIX : Incorrect NULL handling in BETWEEN expression
    
    * Revert "submodule update"
    
    This reverts commit 72431aadeaf33a27775a88c41931572a0b66bae3.
    
    * fix incorrect unit test
    
    * move sqllogictest to expr
---
 datafusion/optimizer/src/analyzer/type_coercion.rs  | 15 +++++++++++++--
 datafusion/optimizer/tests/optimizer_integration.rs |  5 +++--
 datafusion/sqllogictest/test_files/expr.slt         | 17 +++++++++++++++++
 3 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/datafusion/optimizer/src/analyzer/type_coercion.rs 
b/datafusion/optimizer/src/analyzer/type_coercion.rs
index 89dd4ca60a..70bcd553a9 100644
--- a/datafusion/optimizer/src/analyzer/type_coercion.rs
+++ b/datafusion/optimizer/src/analyzer/type_coercion.rs
@@ -426,7 +426,7 @@ impl TreeNodeRewriter for TypeCoercionRewriter<'_> {
                         ))
                     })?;
                 let high_type = high.get_type(self.schema)?;
-                let high_coerced_type = comparison_coercion(&expr_type, 
&low_type)
+                let high_coerced_type = comparison_coercion(&expr_type, 
&high_type)
                     .ok_or_else(|| {
                         DataFusionError::Internal(format!(
                             "Failed to coerce types {expr_type} and 
{high_type} in BETWEEN expression"
@@ -1458,7 +1458,7 @@ mod test {
         let empty = empty_with_type(Utf8);
         let plan = LogicalPlan::Filter(Filter::try_new(expr, empty)?);
         let expected =
-            "Filter: a BETWEEN Utf8(\"2002-05-08\") AND 
CAST(CAST(Utf8(\"2002-05-08\") AS Date32) + IntervalYearMonth(\"1\") AS Utf8)\
+            "Filter: CAST(a AS Date32) BETWEEN CAST(Utf8(\"2002-05-08\") AS 
Date32) AND CAST(Utf8(\"2002-05-08\") AS Date32) + IntervalYearMonth(\"1\")\
             \n  EmptyRelation";
         assert_analyzed_plan_eq(Arc::new(TypeCoercion::new()), plan, expected)
     }
@@ -1480,6 +1480,17 @@ mod test {
         assert_analyzed_plan_eq(Arc::new(TypeCoercion::new()), plan, expected)
     }
 
+    #[test]
+    fn between_null() -> Result<()> {
+        let expr = lit(ScalarValue::Null).between(lit(ScalarValue::Null), 
lit(2i64));
+        let empty = empty();
+        let plan = LogicalPlan::Filter(Filter::try_new(expr, empty)?);
+        let expected =
+            "Filter: CAST(NULL AS Int64) BETWEEN CAST(NULL AS Int64) AND 
Int64(2)\
+            \n  EmptyRelation";
+        assert_analyzed_plan_eq(Arc::new(TypeCoercion::new()), plan, expected)
+    }
+
     #[test]
     fn is_bool_for_type_coercion() -> Result<()> {
         // is true
diff --git a/datafusion/optimizer/tests/optimizer_integration.rs 
b/datafusion/optimizer/tests/optimizer_integration.rs
index 2361679857..29fac5cc3d 100644
--- a/datafusion/optimizer/tests/optimizer_integration.rs
+++ b/datafusion/optimizer/tests/optimizer_integration.rs
@@ -76,8 +76,9 @@ fn subquery_filter_with_cast() -> Result<()> {
     \n    SubqueryAlias: __scalar_sq_1\
     \n      Aggregate: groupBy=[[]], aggr=[[avg(CAST(test.col_int32 AS 
Float64))]]\
     \n        Projection: test.col_int32\
-    \n          Filter: test.col_utf8 >= Utf8(\"2002-05-08\") AND 
test.col_utf8 <= Utf8(\"2002-05-13\")\
-    \n            TableScan: test projection=[col_int32, col_utf8]";
+    \n          Filter: __common_expr_5 >= Date32(\"2002-05-08\") AND 
__common_expr_5 <= Date32(\"2002-05-13\")\
+    \n            Projection: CAST(test.col_utf8 AS Date32) AS 
__common_expr_5, test.col_int32\
+    \n              TableScan: test projection=[col_int32, col_utf8]";
     assert_eq!(expected, format!("{plan}"));
     Ok(())
 }
diff --git a/datafusion/sqllogictest/test_files/expr.slt 
b/datafusion/sqllogictest/test_files/expr.slt
index 577c7ede90..1647d61bf7 100644
--- a/datafusion/sqllogictest/test_files/expr.slt
+++ b/datafusion/sqllogictest/test_files/expr.slt
@@ -1963,3 +1963,20 @@ drop table t;
 
 statement ok
 set datafusion.sql_parser.dialect = 'Generic';
+
+# test between expression with null
+query I
+select 1 where null between null and null;
+----
+
+query T
+select 'A' where null between null and null;
+----
+
+query I
+select 1 where null between null and 2;
+----
+
+query T
+select 'A' where null between 2 and null;
+---


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to