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>> {