Skip to content

Commit b7bf0d3

Browse files
author
ZENOTME
committed
fix rewrite_not to process complex nested not
1 parent 425db3f commit b7bf0d3

File tree

4 files changed

+926
-23
lines changed

4 files changed

+926
-23
lines changed

crates/iceberg/src/expr/predicate.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ use itertools::Itertools;
2828
use serde::{Deserialize, Serialize};
2929

3030
use crate::error::Result;
31+
use crate::expr::visitors::predicate_visitor::visit;
32+
use crate::expr::visitors::rewrite_not::RewriteNotVisitor;
3133
use crate::expr::{Bind, BoundReference, PredicateOperator, Reference};
3234
use crate::spec::{Datum, PrimitiveLiteral, SchemaRef};
3335
use crate::{Error, ErrorKind};
@@ -652,29 +654,8 @@ impl Predicate {
652654
/// assert_eq!(&format!("{result}"), "a >= 5");
653655
/// ```
654656
pub fn rewrite_not(self) -> Predicate {
655-
match self {
656-
Predicate::And(expr) => {
657-
let [left, right] = expr.inputs;
658-
let new_left = Box::new(left.rewrite_not());
659-
let new_right = Box::new(right.rewrite_not());
660-
Predicate::And(LogicalExpression::new([new_left, new_right]))
661-
}
662-
Predicate::Or(expr) => {
663-
let [left, right] = expr.inputs;
664-
let new_left = Box::new(left.rewrite_not());
665-
let new_right = Box::new(right.rewrite_not());
666-
Predicate::Or(LogicalExpression::new([new_left, new_right]))
667-
}
668-
Predicate::Not(expr) => {
669-
let [inner] = expr.inputs;
670-
inner.negate()
671-
}
672-
Predicate::Unary(expr) => Predicate::Unary(expr),
673-
Predicate::Binary(expr) => Predicate::Binary(expr),
674-
Predicate::Set(expr) => Predicate::Set(expr),
675-
Predicate::AlwaysTrue => Predicate::AlwaysTrue,
676-
Predicate::AlwaysFalse => Predicate::AlwaysFalse,
677-
}
657+
visit(&mut RewriteNotVisitor::new(), &self)
658+
.expect("RewriteNotVisitor guarantees always success")
678659
}
679660
}
680661

@@ -1466,4 +1447,29 @@ mod tests {
14661447
assert_eq!(&format!("{bound_expr}"), r#"True"#);
14671448
test_bound_predicate_serialize_diserialize(bound_expr);
14681449
}
1450+
1451+
#[test]
1452+
fn test_rewrite_not_deeply_nested() {
1453+
// Test nested expression: not((not((not(ref(name="bar") < 40) and ref(name="bar") < 40)) and ref(name="bar") < 40))
1454+
// Expected rewrite not result: ((bar >= 40) AND (bar < 40)) OR (bar >= 40)
1455+
let complex_expression = Reference::new("bar")
1456+
.less_than(Datum::int(40))
1457+
.not()
1458+
.and(Reference::new("bar").less_than(Datum::int(40)))
1459+
.not()
1460+
.and(Reference::new("bar").less_than(Datum::int(40)))
1461+
.not();
1462+
1463+
let expected = Reference::new("bar")
1464+
.greater_than_or_equal_to(Datum::int(40))
1465+
.and(Reference::new("bar").less_than(Datum::int(40)))
1466+
.or(Reference::new("bar").greater_than_or_equal_to(Datum::int(40)));
1467+
1468+
let result = complex_expression.rewrite_not();
1469+
1470+
assert_eq!(result, expected);
1471+
1472+
let result_str = format!("{result}");
1473+
assert_eq!(&result_str, "((bar >= 40) AND (bar < 40)) OR (bar >= 40)");
1474+
}
14691475
}

crates/iceberg/src/expr/visitors/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub(crate) mod inclusive_metrics_evaluator;
2121
pub(crate) mod inclusive_projection;
2222
pub(crate) mod manifest_evaluator;
2323
pub(crate) mod page_index_evaluator;
24+
pub(crate) mod predicate_visitor;
25+
pub(crate) mod rewrite_not;
2426
pub(crate) mod row_group_metrics_evaluator;
2527
pub(crate) mod strict_metrics_evaluator;
2628
pub(crate) mod strict_projection;

0 commit comments

Comments
 (0)