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

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


The following commit(s) were added to refs/heads/master by this push:
     new bae8562  fix: not do boolean folding on NULL and/or expr (#1245)
bae8562 is described below

commit bae8562c74ff5e29d8f33e7f471316f13f1cd4dd
Author: Nga Tran <[email protected]>
AuthorDate: Fri Nov 5 11:13:29 2021 -0400

    fix: not do boolean folding on NULL and/or expr (#1245)
    
    * fix: not do boolean folding on NULL and/or expr
    
    * refactor: address review comments
---
 datafusion/src/optimizer/constant_folding.rs | 186 +++++++++++++++++----------
 1 file changed, 118 insertions(+), 68 deletions(-)

diff --git a/datafusion/src/optimizer/constant_folding.rs 
b/datafusion/src/optimizer/constant_folding.rs
index dace622..7249160 100644
--- a/datafusion/src/optimizer/constant_folding.rs
+++ b/datafusion/src/optimizer/constant_folding.rs
@@ -135,6 +135,94 @@ impl<'a> Simplifier<'a> {
 
         false
     }
+
+    fn boolean_folding_for_or(
+        const_bool: &Option<bool>,
+        bool_expr: Box<Expr>,
+        left_right_order: bool,
+    ) -> Expr {
+        // See if we can fold 'const_bool OR bool_expr' to a constant boolean
+        match const_bool {
+            // TRUE or expr (including NULL) = TRUE
+            Some(true) => Expr::Literal(ScalarValue::Boolean(Some(true))),
+            // FALSE or expr (including NULL) = expr
+            Some(false) => *bool_expr,
+            None => match *bool_expr {
+                // NULL or TRUE = TRUE
+                Expr::Literal(ScalarValue::Boolean(Some(true))) => {
+                    Expr::Literal(ScalarValue::Boolean(Some(true)))
+                }
+                // NULL or FALSE = NULL
+                Expr::Literal(ScalarValue::Boolean(Some(false))) => {
+                    Expr::Literal(ScalarValue::Boolean(None))
+                }
+                // NULL or NULL = NULL
+                Expr::Literal(ScalarValue::Boolean(None)) => {
+                    Expr::Literal(ScalarValue::Boolean(None))
+                }
+                // NULL or expr can be either NULL or TRUE
+                // So let us not rewrite it
+                _ => {
+                    let mut left =
+                        
Box::new(Expr::Literal(ScalarValue::Boolean(*const_bool)));
+                    let mut right = bool_expr;
+                    if !left_right_order {
+                        std::mem::swap(&mut left, &mut right);
+                    }
+
+                    Expr::BinaryExpr {
+                        left,
+                        op: Operator::Or,
+                        right,
+                    }
+                }
+            },
+        }
+    }
+
+    fn boolean_folding_for_and(
+        const_bool: &Option<bool>,
+        bool_expr: Box<Expr>,
+        left_right_order: bool,
+    ) -> Expr {
+        // See if we can fold 'const_bool AND bool_expr' to a constant boolean
+        match const_bool {
+            // TRUE and expr (including NULL) = expr
+            Some(true) => *bool_expr,
+            // FALSE and expr (including NULL) = FALSE
+            Some(false) => Expr::Literal(ScalarValue::Boolean(Some(false))),
+            None => match *bool_expr {
+                // NULL and TRUE = NULL
+                Expr::Literal(ScalarValue::Boolean(Some(true))) => {
+                    Expr::Literal(ScalarValue::Boolean(None))
+                }
+                // NULL and FALSE = FALSE
+                Expr::Literal(ScalarValue::Boolean(Some(false))) => {
+                    Expr::Literal(ScalarValue::Boolean(Some(false)))
+                }
+                // NULL and NULL = NULL
+                Expr::Literal(ScalarValue::Boolean(None)) => {
+                    Expr::Literal(ScalarValue::Boolean(None))
+                }
+                // NULL and expr can either be NULL or FALSE
+                // So let us not rewrite it
+                _ => {
+                    let mut left =
+                        
Box::new(Expr::Literal(ScalarValue::Boolean(*const_bool)));
+                    let mut right = bool_expr;
+                    if !left_right_order {
+                        std::mem::swap(&mut left, &mut right);
+                    }
+
+                    Expr::BinaryExpr {
+                        left,
+                        op: Operator::And,
+                        right,
+                    }
+                }
+            },
+        }
+    }
 }
 
 impl<'a> ExprRewriter for Simplifier<'a> {
@@ -214,46 +302,12 @@ impl<'a> ExprRewriter for Simplifier<'a> {
                     (Expr::Literal(ScalarValue::Boolean(b)), _)
                         if self.is_boolean_type(&right) =>
                     {
-                        match b {
-                            Some(true) => 
Expr::Literal(ScalarValue::Boolean(Some(true))),
-                            Some(false) => match *right {
-                                Expr::Literal(ScalarValue::Boolean(None)) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                _ => *right,
-                            },
-                            None => match *right {
-                                
Expr::Literal(ScalarValue::Boolean(Some(true))) => {
-                                    
Expr::Literal(ScalarValue::Boolean(Some(true)))
-                                }
-                                
Expr::Literal(ScalarValue::Boolean(Some(false))) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                _ => *right,
-                            },
-                        }
+                        Self::boolean_folding_for_or(b, right, true)
                     }
                     (_, Expr::Literal(ScalarValue::Boolean(b)))
                         if self.is_boolean_type(&left) =>
                     {
-                        match b {
-                            Some(true) => 
Expr::Literal(ScalarValue::Boolean(Some(true))),
-                            Some(false) => match *left {
-                                Expr::Literal(ScalarValue::Boolean(None)) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                _ => *left,
-                            },
-                            None => match *left {
-                                
Expr::Literal(ScalarValue::Boolean(Some(true))) => {
-                                    
Expr::Literal(ScalarValue::Boolean(Some(true)))
-                                }
-                                
Expr::Literal(ScalarValue::Boolean(Some(false))) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                _ => *left,
-                            },
-                        }
+                        Self::boolean_folding_for_or(b, left, false)
                     }
                     _ => Expr::BinaryExpr {
                         left,
@@ -265,42 +319,12 @@ impl<'a> ExprRewriter for Simplifier<'a> {
                     (Expr::Literal(ScalarValue::Boolean(b)), _)
                         if self.is_boolean_type(&right) =>
                     {
-                        // match b {
-                        //     Some(false) => {
-                        //         
Expr::Literal(ScalarValue::Boolean(Some(false)))
-                        //     }
-                        //     _ => *right,
-                        // }
-                        match b {
-                            Some(true) => match *right {
-                                Expr::Literal(ScalarValue::Boolean(None)) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                _ => *right,
-                            },
-                            Some(false) => {
-                                
Expr::Literal(ScalarValue::Boolean(Some(false)))
-                            }
-                            None => match *right {
-                                
Expr::Literal(ScalarValue::Boolean(Some(true))) => {
-                                    Expr::Literal(ScalarValue::Boolean(None))
-                                }
-                                
Expr::Literal(ScalarValue::Boolean(Some(false))) => {
-                                    
Expr::Literal(ScalarValue::Boolean(Some(false)))
-                                }
-                                _ => *right,
-                            },
-                        }
+                        Self::boolean_folding_for_and(b, right, true)
                     }
                     (_, Expr::Literal(ScalarValue::Boolean(b)))
                         if self.is_boolean_type(&left) =>
                     {
-                        match b {
-                            Some(false) => {
-                                
Expr::Literal(ScalarValue::Boolean(Some(false)))
-                            }
-                            _ => *left,
-                        }
+                        Self::boolean_folding_for_and(b, left, false)
                     }
                     _ => Expr::BinaryExpr {
                         left,
@@ -962,6 +986,19 @@ mod tests {
             lit(ScalarValue::Boolean(None)),
         );
 
+        // ( c1 BETWEEN Int32(0) AND Int32(10) ) OR Boolean(NULL)
+        // it can be either NULL or  TRUE depending on the value of `c1 
BETWEEN Int32(0) AND Int32(10)`
+        // and should not be rewritten
+        let expr = Expr::Between {
+            expr: Box::new(col("c1")),
+            negated: false,
+            low: Box::new(lit(0)),
+            high: Box::new(lit(10)),
+        };
+        let expr = expr.or(Expr::Literal(ScalarValue::Boolean(None)));
+        let result = expr.clone().rewrite(&mut rewriter)?;
+        assert_eq!(expr, result);
+
         Ok(())
     }
     #[test]
@@ -1016,6 +1053,19 @@ mod tests {
             lit(ScalarValue::Boolean(Some(false))),
         );
 
+        // c1 BETWEEN Int32(0) AND Int32(10) AND Boolean(NULL)
+        // it can be either NULL or FALSE depending on the value of `c1 
BETWEEN Int32(0) AND Int32(10`
+        // and should not be rewritten
+        let expr = Expr::Between {
+            expr: Box::new(col("c1")),
+            negated: false,
+            low: Box::new(lit(0)),
+            high: Box::new(lit(10)),
+        };
+        let expr = expr.and(Expr::Literal(ScalarValue::Boolean(None)));
+        let result = expr.clone().rewrite(&mut rewriter)?;
+        assert_eq!(expr, result);
+
         Ok(())
     }
 }

Reply via email to