[CALCITE-1601] DateRangeRules loses OR filters
Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/095acb10 Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/095acb10 Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/095acb10 Branch: refs/heads/master Commit: 095acb1004c4432b6eb11390f61227ee58dd78db Parents: ee289e4 Author: Julian Hyde <[email protected]> Authored: Tue Feb 21 14:13:19 2017 -0800 Committer: Julian Hyde <[email protected]> Committed: Wed Feb 22 22:17:37 2017 -0800 ---------------------------------------------------------------------- .../calcite/rel/rules/DateRangeRules.java | 41 +++++++++++++++++++- .../calcite/rel/rules/DateRangeRulesTest.java | 24 ++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/095acb10/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java index 9fc71b8..a052140 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java @@ -39,6 +39,7 @@ import org.apache.calcite.util.Bug; import com.google.common.base.Predicate; import com.google.common.collect.BoundType; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableRangeSet; import com.google.common.collect.ImmutableSet; @@ -47,8 +48,10 @@ import com.google.common.collect.RangeSet; import com.google.common.collect.TreeRangeSet; import java.math.BigDecimal; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Calendar; +import java.util.Deque; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -189,6 +192,7 @@ public abstract class DateRangeRules { private final RexBuilder rexBuilder; private final TimeUnitRange timeUnit; private final Map<String, RangeSet<Calendar>> operandRanges; + private final Deque<RexCall> calls = new ArrayDeque<>(); public ExtractShuttle(RexBuilder rexBuilder, TimeUnitRange timeUnit, Map<String, RangeSet<Calendar>> operandRanges) { @@ -222,8 +226,43 @@ public abstract class DateRangeRules { (RexLiteral) op1); } } + default: + calls.push(call); + try { + return super.visitCall(call); + } finally { + calls.pop(); + } + } + } + + @Override protected List<RexNode> visitList(List<? extends RexNode> exprs, + boolean[] update) { + if (exprs.isEmpty()) { + return ImmutableList.of(); // a bit more efficient + } + switch (calls.peek().getKind()) { + case AND: + return super.visitList(exprs, update); + default: + final Map<String, RangeSet<Calendar>> save = + ImmutableMap.copyOf(operandRanges); + final ImmutableList.Builder<RexNode> clonedOperands = + ImmutableList.builder(); + for (RexNode operand : exprs) { + RexNode clonedOperand = operand.accept(this); + if ((clonedOperand != operand) && (update != null)) { + update[0] = true; + } + clonedOperands.add(clonedOperand); + + // Restore the state. For an operator such as "OR", an argument + // cannot inherit the previous argument's state. + operandRanges.clear(); + operandRanges.putAll(save); + } + return clonedOperands.build(); } - return super.visitCall(call); } boolean isExtractCall(RexNode e) { http://git-wip-us.apache.org/repos/asf/calcite/blob/095acb10/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java index 6ef898e..63a84f1 100644 --- a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java @@ -95,6 +95,30 @@ public class DateRangeRulesTest { + " >=($8, 2014-06-01), <($8, 2014-07-01))")); } + /** Test case for + * <a href="https://issues.apache.org/jira/browse/CALCITE-1601">[CALCITE-1601] + * DateRangeRules loses OR filters</a>. */ + @Test public void testExtractYearAndMonthFromDateColumn2() { + final Fixture2 f = new Fixture2(); + final String s1 = "AND(" + + "AND(>=($8, 2000-01-01), <($8, 2001-01-01))," + + " OR(" + + "AND(>=($8, 2000-02-01), <($8, 2000-03-01)), " + + "AND(>=($8, 2000-03-01), <($8, 2000-04-01)), " + + "AND(>=($8, 2000-05-01), <($8, 2000-06-01))))"; + final String s2 = "AND(>=($8, 2000-01-01), <($8, 2001-01-01)," + + " OR(" + + "AND(>=($8, 2000-02-01), <($8, 2000-03-01)), " + + "AND(>=($8, 2000-03-01), <($8, 2000-04-01)), " + + "AND(>=($8, 2000-05-01), <($8, 2000-06-01))))"; + final RexNode e = + f.and(f.eq(f.exYear, f.literal(2000)), + f.or(f.eq(f.exMonth, f.literal(2)), + f.eq(f.exMonth, f.literal(3)), + f.eq(f.exMonth, f.literal(5)))); + checkDateRange(f, e, is(s1), is(s2)); + } + @Test public void testExtractYearAndDayFromDateColumn() { final Fixture2 f = new Fixture2(); checkDateRange(f,
