Skip to content

Commit

Permalink
fix(optimizer): fix filter pushdown and range fold (#842)
Browse files Browse the repository at this point in the history
related to #794 #834 , add some new rules and change scan's default
filter to true(this make it match with the "filter-scan" rule)

Signed-off-by: kysshsy <[email protected]>
  • Loading branch information
kysshsy authored Apr 12, 2024
1 parent b391b48 commit 85f50ed
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 9 deletions.
101 changes: 101 additions & 0 deletions src/planner/rules/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,18 @@ pub fn rules() -> Vec<Rewrite> { vec![
rw!("and-null"; "(and null ?a)" => "null"),
rw!("and-comm"; "(and ?a ?b)" => "(and ?b ?a)"),
rw!("and-assoc"; "(and ?a (and ?b ?c))" => "(and (and ?a ?b) ?c)"),

rw!("and-gt-gt-fold"; "(and (> ?x ?a) (> ?x ?b))" => "(> ?x ?a)" if is_greater_than_or_equal("?a", "?b")),
rw!("and-ge-ge-fold"; "(and (>= ?x ?a) (>= ?x ?b))" => "(>= ?x ?a)" if is_greater_than_or_equal("?a", "?b")),
rw!("and-gt-ge-fold"; "(and (> ?x ?a) (>= ?x ?b))" => "(> ?x ?a)" if is_greater_than_or_equal("?a", "?b")),
rw!("and-ge-gt-fold"; "(and (>= ?x ?a) (> ?x ?b))" => "(>= ?x ?a)" if is_greater_than("?a", "?b")),

rw!("and-lt-lt-fold"; "(and (< ?x ?a) (< ?x ?b))" => "(< ?x ?a)" if is_less_than_or_equal("?a", "?b")),
rw!("and-le-le-fold"; "(and (<= ?x ?a) (<= ?x ?b))" => "(<= ?x ?a)" if is_less_than_or_equal("?a", "?b")),
rw!("and-lt-le-fold"; "(and (< ?x ?a) (<= ?x ?b))" => "(< ?x ?a)" if is_less_than_or_equal("?a", "?b")),
rw!("and-le-lt-fold"; "(and (<= ?x ?a) (< ?x ?b))" => "(<= ?x ?a)" if is_less_than("?a", "?b")),

rw!("and-gt-lt-conflict"; "(and (> ?x ?a) (< ?x ?b))" => "false" if is_greater_than_or_equal("?a", "?b")),

rw!("or-false"; "(or false ?a)" => "?a"),
rw!("or-true"; "(or true ?a)" => "true"),
Expand Down Expand Up @@ -172,6 +184,41 @@ fn is_not_zero(var: &str) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
value_is(var, |v| !v.is_zero())
}

fn is_greater_than_or_equal(var1: &str, var2: &str) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
value_cmp(var1, var2, |d1, d2| d1.ge(d2))
}

fn is_greater_than(var1: &str, var2: &str) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
value_cmp(var1, var2, |d1, d2| d1.gt(d2))
}

fn is_less_than_or_equal(var1: &str, var2: &str) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
value_cmp(var1, var2, |d1, d2| d1.le(d2))
}

fn is_less_than(var1: &str, var2: &str) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
value_cmp(var1, var2, |d1, d2| d1.lt(d2))
}

fn value_cmp(
v1: &str,
v2: &str,
f: impl Fn(&DataValue, &DataValue) -> bool,
) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
let v1 = var(v1);
let v2 = var(v2);

move |egraph, _, subst| match (
&egraph[subst[v1]].data.constant,
&egraph[subst[v2]].data.constant,
) {
(Some(d1), Some(d2)) => {
(std::mem::discriminant(d1) == std::mem::discriminant(d2)) && f(d1, d2)
}
_ => false,
}
}

fn value_is(v: &str, f: impl Fn(&DataValue) -> bool) -> impl Fn(&mut EGraph, Id, &Subst) -> bool {
let v = var(v);
move |egraph, _, subst| {
Expand Down Expand Up @@ -217,4 +264,58 @@ mod tests {
rules(),
"(isnull 1)" => "false",
}

egg::test_fn! {
constant_gt_gt_fold,
rules(),
"(and (> a 1) (> a 2))" => "(> a 2)",
}

egg::test_fn! {
constant_ge_ge_fold,
rules(),
"(and (>= a 1) (>= a 2))" => "(>= a 2)",
}

egg::test_fn! {
constant_gt_ge_fold,
rules(),
"(and (> a 2) (>= a 2))" => "(> a 2)",
}

egg::test_fn! {
constant_ge_gt_fold,
rules(),
"(and (> a 1) (>= a 2))" => "(>= a 2)",
}

egg::test_fn! {
constant_lt_lt_fold,
rules(),
"(and (< a 1) (< a 2))" => "(< a 1)",
}

egg::test_fn! {
constant_le_le_fold,
rules(),
"(and (<= a 1) (<= a 2))" => "(<= a 1)",
}

egg::test_fn! {
constant_lt_le_fold,
rules(),
"(and (< a 2) (<= a 2))" => "(< a 2)",
}

egg::test_fn! {
constant_le_lt_fold,
rules(),
"(and (< a 2) (<= a 1))" => "(<= a 1)",
}

egg::test_fn! {
constant_gt_lt_conflict,
rules(),
"(and (> a 2) (< a 2))" => "false",
}
}
12 changes: 3 additions & 9 deletions tests/planner_test/storage-pushdown.planner.sql
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,14 @@ Filter { cond: > { lhs: b, rhs: 1 }, cost: 16.05, rows: 2.5 }
explain select * from t1 where a > 1 and a < 0 and b > 1;

/*
Filter { cond: > { lhs: b, rhs: 1 }, cost: 16.05, rows: 2.5 }
└── Scan
├── table: t1
├── list: [ a, b ]
├── filter: and { lhs: > { lhs: 0, rhs: a }, rhs: > { lhs: a, rhs: 1 } }
├── cost: 10
└── rows: 5
Scan { table: t1, list: [ a, b ], filter: false, cost: 10, rows: 5 }
*/

-- use storage filter for a combination of primary key (could be eliminated) and other keys
explain select * from t1 where a > 1 and a > 3 and b > 1;

/*
Filter { cond: and { lhs: > { lhs: b, rhs: 1 }, rhs: > { lhs: a, rhs: 3 } }, cost: 15.1, rows: 1.25 }
└── Scan { table: t1, list: [ a, b ], filter: > { lhs: a, rhs: 1 }, cost: 10, rows: 5 }
Filter { cond: > { lhs: b, rhs: 1 }, cost: 16.05, rows: 2.5 }
└── Scan { table: t1, list: [ a, b ], filter: > { lhs: a, rhs: 3 }, cost: 10, rows: 5 }
*/

0 comments on commit 85f50ed

Please sign in to comment.