You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/04/20 18:40:48 UTC

calcite git commit: [CALCITE-1738] Push CAST of literals to Druid (Remus Rusanu)

Repository: calcite
Updated Branches:
  refs/heads/master cc8398742 -> 495fd1dc7


[CALCITE-1738] Push CAST of literals to Druid (Remus Rusanu)

Close apache/calcite#430


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/495fd1dc
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/495fd1dc
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/495fd1dc

Branch: refs/heads/master
Commit: 495fd1dc7b0c1805834964a98fc042e12c76d7a7
Parents: cc83987
Author: Remus Rusanu <re...@apache.org>
Authored: Mon Apr 17 05:05:59 2017 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Apr 20 10:19:38 2017 -0700

----------------------------------------------------------------------
 .../calcite/test/RexImplicationCheckerTest.java |  4 ++
 .../adapter/druid/DruidDateTimeUtils.java       | 24 ++++++++++-
 .../calcite/test/DruidDateRangeRulesTest.java   | 45 ++++++++++++++++++++
 3 files changed, 71 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/495fd1dc/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index f321551..c027164 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -501,6 +501,10 @@ public class RexImplicationCheckerTest {
           calendar, timeDataType.getPrecision());
     }
 
+    public RexNode cast(RelDataType type, RexNode exp) {
+      return rexBuilder.makeCast(type, exp, true);
+    }
+
     void checkImplies(RexNode node1, RexNode node2) {
       final String message =
           node1 + " does not imply " + node2 + " when it should";

http://git-wip-us.apache.org/repos/asf/calcite/blob/495fd1dc/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
----------------------------------------------------------------------
diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
index 1312783..e3e86c3 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
@@ -243,12 +244,31 @@ public class DruidDateTimeUtils {
   }
 
   private static Calendar literalValue(RexNode node) {
-    if (node instanceof RexLiteral) {
+    switch (node.getKind()) {
+    case LITERAL:
+      assert node instanceof RexLiteral;
       Object value = ((RexLiteral) node).getValue();
       if (value instanceof  Calendar) {
         return (Calendar) value;
       }
-      return null;
+      break;
+    case CAST:
+      // Normally all CASTs are eliminated by now by constant reduction.
+      // But when HiveExecutor is used there may be a cast that changes only
+      // nullability, from TIMESTAMP NOT NULL literal to TIMESTAMP literal.
+      // We can handle that case by traversing the dummy CAST.
+      assert node instanceof RexCall;
+      final RexCall call = (RexCall) node;
+      final RexNode operand = call.getOperands().get(0);
+      final RelDataType callType = call.getType();
+      final RelDataType operandType = operand.getType();
+      if (operand.getKind() == SqlKind.LITERAL
+          && callType.getSqlTypeName() == SqlTypeName.TIMESTAMP
+          && callType.isNullable()
+          && operandType.getSqlTypeName() == SqlTypeName.TIMESTAMP
+          && !operandType.isNullable()) {
+        return literalValue(operand);
+      }
     }
     return null;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/495fd1dc/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
----------------------------------------------------------------------
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
index 8273130..b2cf321 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rel.rules.DateRangeRules;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.test.RexImplicationCheckerTest.Fixture;
+import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
@@ -37,6 +38,7 @@ import java.util.List;
 import java.util.Map;
 
 import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.notNullValue;
 import static org.junit.Assert.assertThat;
 
 /** Unit tests for {@link DateRangeRules} algorithms. */
@@ -116,6 +118,49 @@ public class DruidDateRangeRulesTest {
             + "2016-02-29T00:00:00.000/2016-03-01T00:00:00.000]"));
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-1738">[CALCITE-1738]
+   * Push CAST of literals to Druid</a>. */
+  @Test public void testFilterWithCast() {
+    final Fixture2 f = new Fixture2();
+    Calendar from = Util.calendar();
+    from.clear();
+    from.set(2010, Calendar.JANUARY, 1);
+    Calendar to = Util.calendar();
+    to.clear();
+    to.set(2011, Calendar.JANUARY, 1);
+
+    // dt >= 2010-01-01 AND dt < 2011-01-01
+    checkDateRangeNoSimplify(f,
+        f.and(
+            f.ge(f.dt, f.cast(f.timeStampDataType, f.timestampLiteral(from))),
+            f.lt(f.dt, f.cast(f.timeStampDataType, f.timestampLiteral(to)))),
+        is("[2010-01-01T00:00:00.000/2011-01-01T00:00:00.000]"));
+  }
+
+  // For testFilterWithCast we need to no simplify the expression, which would
+  // remove the CAST, in order to match the way expressions are presented when
+  // HiveRexExecutorImpl is used in Hive
+  private void checkDateRangeNoSimplify(Fixture f, RexNode e,
+      Matcher<String> intervalMatcher) {
+    final Map<String, RangeSet<Calendar>> operandRanges = new HashMap<>();
+    // We rely on the collection being sorted (so YEAR comes before MONTH
+    // before HOUR) and unique. A predicate on MONTH is not useful if there is
+    // no predicate on YEAR. Then when we apply the predicate on DAY it doesn't
+    // generate hundreds of ranges we'll later throw away.
+    final List<TimeUnitRange> timeUnits =
+        Ordering.natural().sortedCopy(DateRangeRules.extractTimeUnits(e));
+    for (TimeUnitRange timeUnit : timeUnits) {
+      e = e.accept(
+          new DateRangeRules.ExtractShuttle(f.rexBuilder, timeUnit,
+              operandRanges));
+    }
+    final List<LocalInterval> intervals =
+        DruidDateTimeUtils.createInterval(f.timeStampDataType, e);
+    assertThat(intervals, notNullValue());
+    assertThat(intervals.toString(), intervalMatcher);
+  }
+
   private void checkDateRange(Fixture f, RexNode e, Matcher<String> intervalMatcher) {
     final Map<String, RangeSet<Calendar>> operandRanges = new HashMap<>();
     // We rely on the collection being sorted (so YEAR comes before MONTH