Skip to content

Commit

Permalink
Add additional expr boolean simplification rules (#4200)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jefffrey committed Nov 14, 2022
1 parent d2814c9 commit 9de893e
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
56 changes: 56 additions & 0 deletions datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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));
Expand Down
5 changes: 5 additions & 0 deletions datafusion/optimizer/src/simplify_expressions/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>> {
Expand Down

0 comments on commit 9de893e

Please sign in to comment.