You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2022/11/14 21:16:36 UTC

[arrow-datafusion] branch master updated: Add additional expr boolean simplification rules (#4200)

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 9de893e54 Add additional expr boolean simplification rules (#4200)
9de893e54 is described below

commit 9de893e54bba2c70782f4e684da70653b9241499
Author: Jeffrey <22...@users.noreply.github.com>
AuthorDate: Tue Nov 15 08:16:30 2022 +1100

    Add additional expr boolean simplification rules (#4200)
---
 .../src/simplify_expressions/expr_simplifier.rs    | 56 ++++++++++++++++++++++
 .../optimizer/src/simplify_expressions/utils.rs    |  5 ++
 2 files changed, 61 insertions(+)

diff --git a/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs b/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
index 4fe284bee..40285eedc 100644
--- a/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
+++ b/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
@@ -470,6 +470,22 @@ impl<'a, S: SimplifyInfo> ExprRewriter for Simplifier<'a, S> {
                 op: Or,
                 right,
             }) if is_false(&right) => *left,
+            // A OR !A ---> true (if A not nullable)
+            Expr::BinaryExpr(BinaryExpr {
+                left,
+                op: Or,
+                right,
+            }) if is_not_of(&right, &left) && !info.nullable(&left)? => {
+                Expr::Literal(ScalarValue::Boolean(Some(true)))
+            }
+            // !A OR A ---> true (if A not nullable)
+            Expr::BinaryExpr(BinaryExpr {
+                left,
+                op: Or,
+                right,
+            }) if is_not_of(&left, &right) && !info.nullable(&right)? => {
+                Expr::Literal(ScalarValue::Boolean(Some(true)))
+            }
             // (..A..) OR A --> (..A..)
             Expr::BinaryExpr(BinaryExpr {
                 left,
@@ -523,6 +539,22 @@ impl<'a, S: SimplifyInfo> ExprRewriter for Simplifier<'a, S> {
                 op: And,
                 right,
             }) if is_false(&right) => *right,
+            // A AND !A ---> false (if A not nullable)
+            Expr::BinaryExpr(BinaryExpr {
+                left,
+                op: And,
+                right,
+            }) if is_not_of(&right, &left) && !info.nullable(&left)? => {
+                Expr::Literal(ScalarValue::Boolean(Some(false)))
+            }
+            // !A AND A ---> false (if A not nullable)
+            Expr::BinaryExpr(BinaryExpr {
+                left,
+                op: And,
+                right,
+            }) if is_not_of(&left, &right) && !info.nullable(&right)? => {
+                Expr::Literal(ScalarValue::Boolean(Some(false)))
+            }
             // (..A..) AND A --> (..A..)
             Expr::BinaryExpr(BinaryExpr {
                 left,
@@ -1077,6 +1109,18 @@ mod tests {
         assert_eq!(simplify(expr), expected);
     }
 
+    #[test]
+    fn test_simplify_or_not_self() {
+        // A OR !A if A is not nullable --> true
+        // !A OR A if A is not nullable --> true
+        let expr_a = col("c2_non_null").or(col("c2_non_null").not());
+        let expr_b = col("c2_non_null").not().or(col("c2_non_null"));
+        let expected = lit(true);
+
+        assert_eq!(simplify(expr_a), expected);
+        assert_eq!(simplify(expr_b), expected);
+    }
+
     #[test]
     fn test_simplify_and_false() {
         let expr_a = lit(false).and(col("c2"));
@@ -1105,6 +1149,18 @@ mod tests {
         assert_eq!(simplify(expr_b), expected);
     }
 
+    #[test]
+    fn test_simplify_and_not_self() {
+        // A AND !A if A is not nullable --> false
+        // !A AND A if A is not nullable --> false
+        let expr_a = col("c2_non_null").and(col("c2_non_null").not());
+        let expr_b = col("c2_non_null").not().and(col("c2_non_null"));
+        let expected = lit(false);
+
+        assert_eq!(simplify(expr_a), expected);
+        assert_eq!(simplify(expr_b), expected);
+    }
+
     #[test]
     fn test_simplify_multiply_by_one() {
         let expr_a = binary_expr(col("c2"), Operator::Multiply, lit(1));
diff --git a/datafusion/optimizer/src/simplify_expressions/utils.rs b/datafusion/optimizer/src/simplify_expressions/utils.rs
index d9314e329..4df3f507d 100644
--- a/datafusion/optimizer/src/simplify_expressions/utils.rs
+++ b/datafusion/optimizer/src/simplify_expressions/utils.rs
@@ -152,6 +152,11 @@ pub fn is_op_with(target_op: Operator, haystack: &Expr, needle: &Expr) -> bool {
     matches!(haystack, Expr::BinaryExpr(BinaryExpr { left, op, right }) if op == &target_op && (needle == left.as_ref() || needle == right.as_ref()))
 }
 
+/// returns true if `not_expr` is !`expr`
+pub fn is_not_of(not_expr: &Expr, expr: &Expr) -> bool {
+    matches!(not_expr, Expr::Not(inner) if expr == inner.as_ref())
+}
+
 /// returns the contained boolean value in `expr` as
 /// `Expr::Literal(ScalarValue::Boolean(v))`.
 pub fn as_bool_lit(expr: Expr) -> Result<Option<bool>> {