Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,11 @@ impl<'a, S: SimplifyInfo> ExprRewriter for Simplifier<'a, S> {
//
Expr::Not(inner) => negate_clause(*inner),

//
// Rules for Negative
//
Expr::Negative(inner) => distribute_negation(*inner),

//
// Rules for Case
//
Expand Down Expand Up @@ -2122,6 +2127,37 @@ mod tests {
assert_eq!(simplify(expr), expected);
}

#[test]
fn test_simplify_by_de_morgan_laws() {
// Laws with logical operations
// !(c3 AND c4) --> !c3 OR !c4
let expr = and(col("c3"), col("c4")).not();
let expected = or(col("c3").not(), col("c4").not());
assert_eq!(simplify(expr), expected);
// !(c3 OR c4) --> !c3 AND !c4
let expr = or(col("c3"), col("c4")).not();
let expected = and(col("c3").not(), col("c4").not());
assert_eq!(simplify(expr), expected);
// !(!c3) --> c3
let expr = col("c3").not().not();
let expected = col("c3");
assert_eq!(simplify(expr), expected);

// Laws with bitwise operations
// !(c3 & c4) --> !c3 | !c4
let expr = -bitwise_and(col("c3"), col("c4"));
let expected = bitwise_or(-col("c3"), -col("c4"));
assert_eq!(simplify(expr), expected);
// !(c3 | c4) --> !c3 & !c4
let expr = -bitwise_or(col("c3"), col("c4"));
let expected = bitwise_and(-col("c3"), -col("c4"));
assert_eq!(simplify(expr), expected);
// !(!c3) --> c3
let expr = -(-col("c3"));
let expected = col("c3");
assert_eq!(simplify(expr), expected);
}

#[test]
fn test_simplify_null_and_false() {
let expr = and(lit_bool_null(), lit(false));
Expand Down Expand Up @@ -2425,11 +2461,6 @@ mod tests {
)
}

#[test]
fn simplify_expr_not_not() {
assert_eq!(simplify(col("c2").not().not().not()), col("c2").not(),);
}

#[test]
fn simplify_expr_null_comparison() {
// x = null is always null
Expand Down
41 changes: 40 additions & 1 deletion datafusion/optimizer/src/simplify_expressions/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use datafusion_common::{DataFusionError, Result, ScalarValue};
use datafusion_expr::{
expr::{Between, BinaryExpr},
expr_fn::{and, concat_ws, or},
expr_fn::{and, bitwise_and, bitwise_or, concat_ws, or},
lit, BuiltinScalarFunction, Expr, Like, Operator,
};

Expand Down Expand Up @@ -311,6 +311,45 @@ pub fn negate_clause(expr: Expr) -> Expr {
}
}

/// bitwise negate a Negative clause
/// input is the clause to be bitwise negated.(args for Negative clause)
/// For BinaryExpr:
/// ~(A & B) ===> ~A | ~B
/// ~(A | B) ===> ~A & ~B
/// For Negative:
/// ~(~A) ===> A
/// For others, use Negative clause
pub fn distribute_negation(expr: Expr) -> Expr {
match expr {
Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
match op {
// ~(A & B) ===> ~A | ~B
Operator::BitwiseAnd => {
let left = distribute_negation(*left);
let right = distribute_negation(*right);

bitwise_or(left, right)
}
// ~(A | B) ===> ~A & ~B
Operator::BitwiseOr => {
let left = distribute_negation(*left);
let right = distribute_negation(*right);

bitwise_and(left, right)
}
// use negative clause
_ => Expr::Negative(Box::new(Expr::BinaryExpr(BinaryExpr::new(
left, op, right,
)))),
}
}
// ~(~A) ===> A
Expr::Negative(expr) => *expr,
// use negative clause
_ => Expr::Negative(Box::new(expr)),
}
}

/// Simplify the `concat` function by
/// 1. filtering out all `null` literals
/// 2. concatenating contiguous literal arguments
Expand Down