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