Skip to content

Commit 8ea0df9

Browse files
committed
[CALCITE-6878] Implement FilterSortTransposeRule
1 parent 48648b3 commit 8ea0df9

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

core/src/main/java/org/apache/calcite/rel/rules/CoreRules.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ private CoreRules() {}
293293
public static final FilterTableScanRule FILTER_SCAN =
294294
FilterTableScanRule.Config.DEFAULT.toRule();
295295

296+
/** Rule that transforms a {@link Filter} on top of a {@link Sort}
297+
* into a {@link Sort} on top of a {@link Filter}. */
298+
public static final FilterSortTransposeRule FILTER_SORT_TRANSPOSE =
299+
FilterSortTransposeRule.Config.DEFAULT.toRule();
300+
296301
/** Rule that matches a {@link Filter} on an
297302
* {@link org.apache.calcite.adapter.enumerable.EnumerableInterpreter} on a
298303
* {@link TableScan}. */
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.calcite.rel.rules;
18+
19+
import org.apache.calcite.plan.RelOptRuleCall;
20+
import org.apache.calcite.plan.RelRule;
21+
import org.apache.calcite.rel.RelNode;
22+
import org.apache.calcite.rel.core.Filter;
23+
import org.apache.calcite.rel.core.Sort;
24+
import org.apache.calcite.rex.RexNode;
25+
import org.apache.calcite.tools.RelBuilder;
26+
import org.apache.calcite.tools.RelBuilderFactory;
27+
28+
import org.immutables.value.Value;
29+
30+
/**
31+
* Rule that transforms a {@link Filter} on top of a {@link Sort}
32+
* into a {@link Sort} on top of a {@link Filter}.
33+
*/
34+
@Value.Enclosing
35+
public class FilterSortTransposeRule
36+
extends RelRule<FilterSortTransposeRule.Config>
37+
implements TransformationRule {
38+
protected FilterSortTransposeRule(FilterSortTransposeRule.Config config) {
39+
super(config);
40+
}
41+
42+
@Deprecated // to be removed before 2.0
43+
public FilterSortTransposeRule(RelBuilderFactory relBuilderFactory) {
44+
this(FilterSortTransposeRule.Config.DEFAULT.withRelBuilderFactory(relBuilderFactory)
45+
.as(FilterSortTransposeRule.Config.class));
46+
}
47+
48+
@Override public void onMatch(RelOptRuleCall call) {
49+
final Filter filter = call.rel(0);
50+
final Sort sort = call.rel(1);
51+
final RelBuilder builder = call.builder();
52+
53+
final RexNode condition = filter.getCondition();
54+
55+
RelNode newSort = builder.push(sort.getInput())
56+
.filter(condition)
57+
.sort(sort.getCollation())
58+
.build();
59+
60+
call.transformTo(newSort);
61+
}
62+
63+
/** Rule configuration. */
64+
@Value.Immutable
65+
public interface Config extends RelRule.Config {
66+
Config DEFAULT = ImmutableFilterSortTransposeRule.Config.of()
67+
.withOperandSupplier(f ->
68+
f.operand(Filter.class)
69+
.oneInput(s ->
70+
s.operand(Sort.class).anyInputs()));
71+
72+
@Override default FilterSortTransposeRule toRule() {
73+
return new FilterSortTransposeRule(this);
74+
}
75+
}
76+
}

core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,19 @@ private static boolean skipItem(RexNode expr) {
574574
.check();
575575
}
576576

577+
/** Test case for
578+
* <a href="https://issues.apache.org/jira/browse/CALCITE-6878">[CALCITE-6878]
579+
* Add the planner rule that pushes the Filter past a Sort</a>. */
580+
@Test void testFilterSortTranspose() {
581+
final Function<RelBuilder, RelNode> relFn = b -> b
582+
.scan("EMP")
583+
.project(b.field(0))
584+
.sort(b.field(0))
585+
.filter(b.lessThan(b.field(0), b.literal(10)))
586+
.build();
587+
relFn(relFn).withRule(CoreRules.FILTER_SORT_TRANSPOSE).check();
588+
}
589+
577590
@Test void testReduceOrCaseWhen() {
578591
HepProgramBuilder builder = new HepProgramBuilder();
579592
builder.addRuleClass(ReduceExpressionsRule.class);

core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5391,6 +5391,24 @@ LogicalProject(DEPTNO=[$7])
53915391
Sample(mode=[system], rate=[0.5], repeatableSeed=[10])
53925392
LogicalFilter(condition=[>($7, 10)])
53935393
LogicalTableScan(table=[[CATALOG, SALES, EMP]])
5394+
]]>
5395+
</Resource>
5396+
</TestCase>
5397+
<TestCase name="testFilterSortTranspose">
5398+
<Resource name="planBefore">
5399+
<![CDATA[
5400+
LogicalFilter(condition=[<($0, 10)])
5401+
LogicalSort(sort0=[$0], dir0=[ASC])
5402+
LogicalProject(EMPNO=[$0])
5403+
LogicalTableScan(table=[[scott, EMP]])
5404+
]]>
5405+
</Resource>
5406+
<Resource name="planAfter">
5407+
<![CDATA[
5408+
LogicalSort(sort0=[$0], dir0=[ASC])
5409+
LogicalFilter(condition=[<($0, 10)])
5410+
LogicalProject(EMPNO=[$0])
5411+
LogicalTableScan(table=[[scott, EMP]])
53945412
]]>
53955413
</Resource>
53965414
</TestCase>

0 commit comments

Comments
 (0)