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/10/02 21:00:09 UTC

[09/15] calcite git commit: [CALCITE-1987] Implement EXTRACT for JDBC (Pavel Gubin)

[CALCITE-1987] Implement EXTRACT for JDBC (Pavel Gubin)

Remove EXTRACT_DATE function (it's all just EXTRACTi now),
and revise Druid adapter.

Close apache/calcite#539


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

Branch: refs/heads/master
Commit: 796a28f9a9d49a16971135074f315d536eb929cf
Parents: 8441e79
Author: pavelgubin <pa...@contiamo.com>
Authored: Thu Sep 14 14:53:41 2017 +0200
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 2 11:13:43 2017 -0700

----------------------------------------------------------------------
 .../calcite/adapter/enumerable/RexImpTable.java | 163 ++++++++++++++++++-
 .../calcite/sql/fun/SqlStdOperatorTable.java    |   5 -
 .../sql2rel/StandardConvertletTable.java        | 154 +-----------------
 .../calcite/rel/rules/DateRangeRulesTest.java   | 118 ++++++--------
 .../java/org/apache/calcite/test/JdbcTest.java  |  24 +++
 .../apache/calcite/test/SqlValidatorTest.java   |   1 -
 .../org/apache/calcite/test/RelOptRulesTest.xml |  20 +--
 .../org/apache/calcite/test/DruidAdapterIT.java |  64 ++++----
 .../calcite/test/DruidDateRangeRulesTest.java   |  24 +--
 9 files changed, 283 insertions(+), 290 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
index 0b3aa84..3f99182 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java
@@ -125,7 +125,7 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.DIVIDE_INTEGER;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.ELEMENT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EQUALS;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXP;
-import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXTRACT_DATE;
+import static org.apache.calcite.sql.fun.SqlStdOperatorTable.EXTRACT;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FIRST_VALUE;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.FLOOR;
 import static org.apache.calcite.sql.fun.SqlStdOperatorTable.GREATER_THAN;
@@ -323,8 +323,8 @@ public class RexImpTable {
         new DatetimeArithmeticImplementor(), false);
     defineImplementor(MINUS_DATE, NullPolicy.STRICT,
         new DatetimeArithmeticImplementor(), false);
-    defineMethod(EXTRACT_DATE, BuiltInMethod.UNIX_DATE_EXTRACT.method,
-        NullPolicy.STRICT);
+    defineImplementor(EXTRACT, NullPolicy.STRICT,
+        new ExtractImplementor(), false);
     defineImplementor(FLOOR, NullPolicy.STRICT,
         new FloorImplementor(BuiltInMethod.FLOOR.method.getName(),
             BuiltInMethod.UNIX_TIMESTAMP_FLOOR.method,
@@ -1889,6 +1889,163 @@ public class RexImpTable {
     }
   }
 
+  /** Implementor for the {@code EXTRACT(unit FROM datetime)} function. */
+  private static class ExtractImplementor implements NotNullImplementor {
+    public Expression implement(RexToLixTranslator translator, RexCall call,
+        List<Expression> translatedOperands) {
+      final TimeUnitRange timeUnitRange =
+          (TimeUnitRange) ((ConstantExpression) translatedOperands.get(0)).value;
+      final TimeUnit unit = timeUnitRange.startUnit;
+      Expression operand = translatedOperands.get(1);
+      final SqlTypeName sqlTypeName =
+          call.operands.get(1).getType().getSqlTypeName();
+      switch (unit) {
+      case MILLENNIUM:
+      case CENTURY:
+      case YEAR:
+      case QUARTER:
+      case MONTH:
+      case DAY:
+      case DOW:
+      case DOY:
+      case WEEK:
+        switch (sqlTypeName) {
+        case INTERVAL_YEAR:
+        case INTERVAL_YEAR_MONTH:
+        case INTERVAL_MONTH:
+        case INTERVAL_DAY:
+        case INTERVAL_DAY_HOUR:
+        case INTERVAL_DAY_MINUTE:
+        case INTERVAL_DAY_SECOND:
+        case INTERVAL_HOUR:
+        case INTERVAL_HOUR_MINUTE:
+        case INTERVAL_HOUR_SECOND:
+        case INTERVAL_MINUTE:
+        case INTERVAL_MINUTE_SECOND:
+        case INTERVAL_SECOND:
+          break;
+        case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+          operand = Expressions.call(
+              BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+              operand,
+              Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot()));
+          // fall through
+        case TIMESTAMP:
+          operand = Expressions.divide(operand,
+              Expressions.constant(TimeUnit.DAY.multiplier.longValue()));
+          // fall through
+        case DATE:
+          return Expressions.call(BuiltInMethod.UNIX_DATE_EXTRACT.method,
+              translatedOperands.get(0), operand);
+        default:
+          throw new AssertionError("unexpected " + sqlTypeName);
+        }
+        break;
+      case DECADE:
+        switch (sqlTypeName) {
+        case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+          operand = Expressions.call(
+              BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+              operand,
+              Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot()));
+          // fall through
+        case TIMESTAMP:
+          operand = Expressions.divide(operand,
+              Expressions.constant(TimeUnit.DAY.multiplier.longValue()));
+          // fall through
+        case DATE:
+          operand = Expressions.call(
+              BuiltInMethod.UNIX_DATE_EXTRACT.method,
+              Expressions.constant(TimeUnitRange.YEAR), operand);
+          return Expressions.divide(operand,
+              Expressions.constant(
+                  unit.multiplier.divideToIntegralValue(TimeUnit.YEAR.multiplier)
+                      .longValue()));
+        }
+        break;
+      case EPOCH:
+        switch (sqlTypeName) {
+        case DATE:
+          // convert to milliseconds
+          operand = Expressions.multiply(operand,
+              Expressions.constant(TimeUnit.DAY.multiplier.longValue()));
+          // fall through
+        case TIMESTAMP:
+          // convert to seconds
+          return Expressions.divide(operand,
+              Expressions.constant(TimeUnit.SECOND.multiplier.longValue()));
+        case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+          operand = Expressions.call(
+              BuiltInMethod.TIMESTAMP_WITH_LOCAL_TIME_ZONE_TO_TIMESTAMP.method,
+              operand,
+              Expressions.call(BuiltInMethod.TIME_ZONE.method, translator.getRoot()));
+          return Expressions.divide(operand,
+              Expressions.constant(TimeUnit.SECOND.multiplier.longValue()));
+        case INTERVAL_YEAR:
+        case INTERVAL_YEAR_MONTH:
+        case INTERVAL_MONTH:
+        case INTERVAL_DAY:
+        case INTERVAL_DAY_HOUR:
+        case INTERVAL_DAY_MINUTE:
+        case INTERVAL_DAY_SECOND:
+        case INTERVAL_HOUR:
+        case INTERVAL_HOUR_MINUTE:
+        case INTERVAL_HOUR_SECOND:
+        case INTERVAL_MINUTE:
+        case INTERVAL_MINUTE_SECOND:
+        case INTERVAL_SECOND:
+          // no convertlet conversion, pass it as extract
+          throw new AssertionError("unexpected " + sqlTypeName);
+        }
+        break;
+      }
+
+      operand = mod(operand, getFactor(unit));
+      if (unit == TimeUnit.QUARTER) {
+        operand = Expressions.subtract(operand, Expressions.constant(1L));
+      }
+      operand = Expressions.divide(operand,
+          Expressions.constant(unit.multiplier.longValue()));
+      if (unit == TimeUnit.QUARTER) {
+        operand = Expressions.add(operand, Expressions.constant(1L));
+      }
+      return operand;
+    }
+
+  }
+
+  private static Expression mod(Expression operand, long factor) {
+    if (factor == 1L) {
+      return operand;
+    } else {
+      return Expressions.modulo(operand, Expressions.constant(factor));
+    }
+  }
+
+  private static long getFactor(TimeUnit unit) {
+    switch (unit) {
+    case DAY:
+      return 1L;
+    case HOUR:
+      return TimeUnit.DAY.multiplier.longValue();
+    case MINUTE:
+      return TimeUnit.HOUR.multiplier.longValue();
+    case SECOND:
+      return TimeUnit.MINUTE.multiplier.longValue();
+    case MONTH:
+      return TimeUnit.YEAR.multiplier.longValue();
+    case QUARTER:
+      return TimeUnit.YEAR.multiplier.longValue();
+    case YEAR:
+    case DECADE:
+    case CENTURY:
+    case MILLENNIUM:
+      return 1L;
+    default:
+      throw Util.unexpected(unit);
+    }
+  }
+
   /** Implementor for the SQL {@code CASE} operator. */
   private static class CaseImplementor implements CallImplementor {
     public Expression implement(RexToLixTranslator translator, RexCall call,

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 7b6b771..c8adf5e 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -1235,11 +1235,6 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
         }
       };
 
-  /** Internal operator that extracts time periods (year, month, date) from a
-   * date in internal format (number of days since epoch). */
-  public static final SqlSpecialOperator EXTRACT_DATE =
-      new SqlSpecialOperator("EXTRACT_DATE", SqlKind.EXTRACT);
-
   //-------------------------------------------------------------
   //                   FUNCTIONS
   //-------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index 14bff94..4c45716 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -18,7 +18,6 @@ package org.apache.calcite.sql2rel;
 
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnit;
-import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.type.RelDataType;
@@ -635,158 +634,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       SqlRexContext cx,
       SqlExtractFunction op,
       SqlCall call) {
-    final RexBuilder rexBuilder = cx.getRexBuilder();
-    final List<SqlNode> operands = call.getOperandList();
-    final List<RexNode> exprs = convertExpressionList(cx, operands,
-        SqlOperandTypeChecker.Consistency.NONE);
-
-    // TODO: Will need to use decimal type for seconds with precision
-    RelDataType resType =
-        cx.getTypeFactory().createSqlType(SqlTypeName.BIGINT);
-    resType =
-        cx.getTypeFactory().createTypeWithNullability(
-            resType,
-            exprs.get(1).getType().isNullable());
-    RexNode res = rexBuilder.makeReinterpretCast(
-        resType, exprs.get(1), rexBuilder.makeLiteral(false));
-
-    final TimeUnit unit =
-        ((SqlIntervalQualifier) operands.get(0)).getStartUnit();
-    final SqlTypeName sqlTypeName = exprs.get(1).getType().getSqlTypeName();
-    switch (unit) {
-    case MILLENNIUM:
-    case CENTURY:
-    case YEAR:
-    case QUARTER:
-    case MONTH:
-    case DAY:
-    case DOW:
-    case DOY:
-    case WEEK:
-      switch (sqlTypeName) {
-      case INTERVAL_YEAR:
-      case INTERVAL_YEAR_MONTH:
-      case INTERVAL_MONTH:
-      case INTERVAL_DAY:
-      case INTERVAL_DAY_HOUR:
-      case INTERVAL_DAY_MINUTE:
-      case INTERVAL_DAY_SECOND:
-      case INTERVAL_HOUR:
-      case INTERVAL_HOUR_MINUTE:
-      case INTERVAL_HOUR_SECOND:
-      case INTERVAL_MINUTE:
-      case INTERVAL_MINUTE_SECOND:
-      case INTERVAL_SECOND:
-        break;
-      case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
-        RelDataType type =
-            cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
-        type = cx.getTypeFactory().createTypeWithNullability(
-            type,
-            exprs.get(1).getType().isNullable());
-        res = rexBuilder.makeCast(type, res);
-        // fall through
-      case TIMESTAMP:
-        res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
-        // fall through
-      case DATE:
-        return rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE,
-            ImmutableList.of(exprs.get(0), res));
-      default:
-        throw new AssertionError("unexpected " + sqlTypeName);
-      }
-      break;
-    case DECADE:
-      switch (sqlTypeName) {
-      case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
-        RelDataType type =
-            cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
-        type = cx.getTypeFactory().createTypeWithNullability(
-            type,
-            exprs.get(1).getType().isNullable());
-        res = rexBuilder.makeCast(type, res);
-        // fall through
-      case TIMESTAMP:
-        res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
-        // fall through
-      case DATE:
-        res = rexBuilder.makeCall(resType, SqlStdOperatorTable.EXTRACT_DATE,
-            ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), res));
-        return divide(rexBuilder, res, unit.multiplier.divide(TimeUnit.YEAR.multiplier));
-      }
-      break;
-    case EPOCH:
-      switch (sqlTypeName) {
-      case DATE:
-        // convert to milliseconds
-        res = rexBuilder.makeCall(resType, SqlStdOperatorTable.MULTIPLY,
-            ImmutableList.of(res, rexBuilder.makeExactLiteral(TimeUnit.DAY.multiplier)));
-        // fall through
-      case TIMESTAMP:
-        // convert to seconds
-        return divide(rexBuilder, res, TimeUnit.SECOND.multiplier);
-      case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
-        RelDataType type =
-            cx.getTypeFactory().createSqlType(SqlTypeName.TIMESTAMP);
-        type = cx.getTypeFactory().createTypeWithNullability(
-            type,
-            exprs.get(1).getType().isNullable());
-        return divide(
-            rexBuilder,
-            rexBuilder.makeCast(type, res),
-            TimeUnit.SECOND.multiplier);
-      case INTERVAL_YEAR:
-      case INTERVAL_YEAR_MONTH:
-      case INTERVAL_MONTH:
-      case INTERVAL_DAY:
-      case INTERVAL_DAY_HOUR:
-      case INTERVAL_DAY_MINUTE:
-      case INTERVAL_DAY_SECOND:
-      case INTERVAL_HOUR:
-      case INTERVAL_HOUR_MINUTE:
-      case INTERVAL_HOUR_SECOND:
-      case INTERVAL_MINUTE:
-      case INTERVAL_MINUTE_SECOND:
-      case INTERVAL_SECOND:
-        // no convertlet conversion, pass it as extract
-        return convertFunction(cx, (SqlFunction) call.getOperator(), call);
-      }
-      break;
-    }
-
-    res = mod(rexBuilder, resType, res, getFactor(unit));
-    if (unit == TimeUnit.QUARTER) {
-      res = minus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE));
-    }
-    res = divide(rexBuilder, res, unit.multiplier);
-    if (unit == TimeUnit.QUARTER) {
-      res = plus(rexBuilder, res, rexBuilder.makeExactLiteral(BigDecimal.ONE));
-    }
-    return res;
-  }
-
-  private static BigDecimal getFactor(TimeUnit unit) {
-    switch (unit) {
-    case DAY:
-      return BigDecimal.ONE;
-    case HOUR:
-      return TimeUnit.DAY.multiplier;
-    case MINUTE:
-      return TimeUnit.HOUR.multiplier;
-    case SECOND:
-      return TimeUnit.MINUTE.multiplier;
-    case MONTH:
-      return TimeUnit.YEAR.multiplier;
-    case QUARTER:
-      return TimeUnit.YEAR.multiplier;
-    case YEAR:
-    case DECADE:
-    case CENTURY:
-    case MILLENNIUM:
-      return BigDecimal.ONE;
-    default:
-      throw Util.unexpected(unit);
-    }
+    return convertFunction(cx, (SqlFunction) call.getOperator(), call);
   }
 
   private RexNode mod(RexBuilder rexBuilder, RelDataType resType, RexNode res,

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/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 ea7b58b..5fd746d 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
@@ -53,34 +53,34 @@ public class DateRangeRulesTest {
     assertThat(DateRangeRules.extractTimeUnits(f.literal(1)), is(set()));
 
     // extract YEAR from a DATE column
-    checkDateRange(f, e, is("AND(>=($8, 2014-01-01), <($8, 2015-01-01))"));
+    checkDateRange(f, e, is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))"));
     checkDateRange(f, f.eq(f.exYear, f.literal(2014)),
-        is("AND(>=($8, 2014-01-01), <($8, 2015-01-01))"));
+        is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))"));
     checkDateRange(f, f.ge(f.exYear, f.literal(2014)),
-        is(">=($8, 2014-01-01)"));
+        is(">=($9, 2014-01-01)"));
     checkDateRange(f, f.gt(f.exYear, f.literal(2014)),
-        is(">=($8, 2015-01-01)"));
+        is(">=($9, 2015-01-01)"));
     checkDateRange(f, f.lt(f.exYear, f.literal(2014)),
-        is("<($8, 2014-01-01)"));
+        is("<($9, 2014-01-01)"));
     checkDateRange(f, f.le(f.exYear, f.literal(2014)),
-        is("<($8, 2015-01-01)"));
+        is("<($9, 2015-01-01)"));
     checkDateRange(f, f.ne(f.exYear, f.literal(2014)),
-        is("<>(EXTRACT_DATE(FLAG(YEAR), $8), 2014)"));
+        is("<>(EXTRACT(FLAG(YEAR), $9), 2014)"));
   }
 
   @Test public void testExtractYearFromTimestampColumn() {
     final Fixture2 f = new Fixture2();
-    checkDateRange(f, f.eq(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.eq(f.exYear, f.literal(2014)),
         is("AND(>=($9, 2014-01-01), <($9, 2015-01-01))"));
-    checkDateRange(f, f.ge(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.ge(f.exYear, f.literal(2014)),
         is(">=($9, 2014-01-01)"));
-    checkDateRange(f, f.gt(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.gt(f.exYear, f.literal(2014)),
         is(">=($9, 2015-01-01)"));
-    checkDateRange(f, f.lt(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.lt(f.exYear, f.literal(2014)),
         is("<($9, 2014-01-01)"));
-    checkDateRange(f, f.le(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.le(f.exYear, f.literal(2014)),
         is("<($9, 2015-01-01)"));
-    checkDateRange(f, f.ne(f.exYearTs, f.literal(2014)),
+    checkDateRange(f, f.ne(f.exYear, f.literal(2014)),
         is("<>(EXTRACT(FLAG(YEAR), $9), 2014)"));
   }
 
@@ -88,10 +88,10 @@ public class DateRangeRulesTest {
     final Fixture2 f = new Fixture2();
     checkDateRange(f,
         f.and(f.eq(f.exYear, f.literal(2014)), f.eq(f.exMonth, f.literal(6))),
-        is("AND(AND(>=($8, 2014-01-01), <($8, 2015-01-01)),"
-            + " AND(>=($8, 2014-06-01), <($8, 2014-07-01)))"),
-        is("AND(>=($8, 2014-01-01), <($8, 2015-01-01),"
-            + " >=($8, 2014-06-01), <($8, 2014-07-01))"));
+        is("AND(AND(>=($9, 2014-01-01), <($9, 2015-01-01)),"
+            + " AND(>=($9, 2014-06-01), <($9, 2014-07-01)))"),
+        is("AND(>=($9, 2014-01-01), <($9, 2015-01-01),"
+            + " >=($9, 2014-06-01), <($9, 2014-07-01))"));
   }
 
   /** Test case for
@@ -100,16 +100,16 @@ public class DateRangeRulesTest {
   @Test public void testExtractYearAndMonthFromDateColumn2() {
     final Fixture2 f = new Fixture2();
     final String s1 = "AND("
-        + "AND(>=($8, 2000-01-01), <($8, 2001-01-01)),"
+        + "AND(>=($9, 2000-01-01), <($9, 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),"
+        + "AND(>=($9, 2000-02-01), <($9, 2000-03-01)), "
+        + "AND(>=($9, 2000-03-01), <($9, 2000-04-01)), "
+        + "AND(>=($9, 2000-05-01), <($9, 2000-06-01))))";
+    final String s2 = "AND(>=($9, 2000-01-01), <($9, 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))))";
+        + "AND(>=($9, 2000-02-01), <($9, 2000-03-01)), "
+        + "AND(>=($9, 2000-03-01), <($9, 2000-04-01)), "
+        + "AND(>=($9, 2000-05-01), <($9, 2000-06-01))))";
     final RexNode e =
         f.and(f.eq(f.exYear, f.literal(2000)),
             f.or(f.eq(f.exMonth, f.literal(2)),
@@ -122,14 +122,14 @@ public class DateRangeRulesTest {
     final Fixture2 f = new Fixture2();
     checkDateRange(f,
         f.and(f.eq(f.exYear, f.literal(2010)), f.eq(f.exDay, f.literal(31))),
-        is("AND(AND(>=($8, 2010-01-01), <($8, 2011-01-01)),"
-            + " OR(AND(>=($8, 2010-01-31), <($8, 2010-02-01)),"
-            + " AND(>=($8, 2010-03-31), <($8, 2010-04-01)),"
-            + " AND(>=($8, 2010-05-31), <($8, 2010-06-01)),"
-            + " AND(>=($8, 2010-07-31), <($8, 2010-08-01)),"
-            + " AND(>=($8, 2010-08-31), <($8, 2010-09-01)),"
-            + " AND(>=($8, 2010-10-31), <($8, 2010-11-01)),"
-            + " AND(>=($8, 2010-12-31), <($8, 2011-01-01))))"));
+        is("AND(AND(>=($9, 2010-01-01), <($9, 2011-01-01)),"
+            + " OR(AND(>=($9, 2010-01-31), <($9, 2010-02-01)),"
+            + " AND(>=($9, 2010-03-31), <($9, 2010-04-01)),"
+            + " AND(>=($9, 2010-05-31), <($9, 2010-06-01)),"
+            + " AND(>=($9, 2010-07-31), <($9, 2010-08-01)),"
+            + " AND(>=($9, 2010-08-31), <($9, 2010-09-01)),"
+            + " AND(>=($9, 2010-10-31), <($9, 2010-11-01)),"
+            + " AND(>=($9, 2010-12-31), <($9, 2011-01-01))))"));
 
   }
 
@@ -139,32 +139,32 @@ public class DateRangeRulesTest {
     // namely 29th February 2012 and 2016.
     //
     // Currently there are redundant conditions, e.g.
-    // "AND(>=($8, 2011-01-01), <($8, 2020-01-01))". We should remove them by
+    // "AND(>=($9, 2011-01-01), <($9, 2020-01-01))". We should remove them by
     // folding intervals.
     checkDateRange(f,
         f.and(f.gt(f.exYear, f.literal(2010)), f.lt(f.exYear, f.literal(2020)),
             f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))),
-        is("AND(>=($8, 2011-01-01),"
-            + " AND(>=($8, 2011-01-01), <($8, 2020-01-01)),"
-            + " OR(AND(>=($8, 2011-02-01), <($8, 2011-03-01)),"
-            + " AND(>=($8, 2012-02-01), <($8, 2012-03-01)),"
-            + " AND(>=($8, 2013-02-01), <($8, 2013-03-01)),"
-            + " AND(>=($8, 2014-02-01), <($8, 2014-03-01)),"
-            + " AND(>=($8, 2015-02-01), <($8, 2015-03-01)),"
-            + " AND(>=($8, 2016-02-01), <($8, 2016-03-01)),"
-            + " AND(>=($8, 2017-02-01), <($8, 2017-03-01)),"
-            + " AND(>=($8, 2018-02-01), <($8, 2018-03-01)),"
-            + " AND(>=($8, 2019-02-01), <($8, 2019-03-01))),"
-            + " OR(AND(>=($8, 2012-02-29), <($8, 2012-03-01)),"
-            + " AND(>=($8, 2016-02-29), <($8, 2016-03-01))))"));
+        is("AND(>=($9, 2011-01-01),"
+            + " AND(>=($9, 2011-01-01), <($9, 2020-01-01)),"
+            + " OR(AND(>=($9, 2011-02-01), <($9, 2011-03-01)),"
+            + " AND(>=($9, 2012-02-01), <($9, 2012-03-01)),"
+            + " AND(>=($9, 2013-02-01), <($9, 2013-03-01)),"
+            + " AND(>=($9, 2014-02-01), <($9, 2014-03-01)),"
+            + " AND(>=($9, 2015-02-01), <($9, 2015-03-01)),"
+            + " AND(>=($9, 2016-02-01), <($9, 2016-03-01)),"
+            + " AND(>=($9, 2017-02-01), <($9, 2017-03-01)),"
+            + " AND(>=($9, 2018-02-01), <($9, 2018-03-01)),"
+            + " AND(>=($9, 2019-02-01), <($9, 2019-03-01))),"
+            + " OR(AND(>=($9, 2012-02-29), <($9, 2012-03-01)),"
+            + " AND(>=($9, 2016-02-29), <($9, 2016-03-01))))"));
   }
 
   @Test public void testExtractYearMonthDayFromTimestampColumn() {
     final Fixture2 f = new Fixture2();
     checkDateRange(f,
-        f.and(f.gt(f.exYearTs, f.literal(2010)),
-            f.lt(f.exYearTs, f.literal(2020)),
-            f.eq(f.exMonthTs, f.literal(2)), f.eq(f.exDayTs, f.literal(29))),
+        f.and(f.gt(f.exYear, f.literal(2010)),
+            f.lt(f.exYear, f.literal(2020)),
+            f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))),
         is("AND(>=($9, 2011-01-01),"
             + " AND(>=($9, 2011-01-01), <($9, 2020-01-01)),"
             + " OR(AND(>=($9, 2011-02-01), <($9, 2011-03-01)),"
@@ -212,26 +212,14 @@ public class DateRangeRulesTest {
     private final RexNode exYear;
     private final RexNode exMonth;
     private final RexNode exDay;
-    private final RexNode exYearTs;
-    private final RexNode exMonthTs;
-    private final RexNode exDayTs;
 
     Fixture2() {
-      exYear = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), dt));
-      exMonth = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), dt));
-      exDay = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), dt));
-      exYearTs = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT,
+      exYear = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), ts));
-      exMonthTs = rexBuilder.makeCall(intRelDataType,
+      exMonth = rexBuilder.makeCall(intRelDataType,
           SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), ts));
-      exDayTs = rexBuilder.makeCall(intRelDataType,
+      exDay = rexBuilder.makeCall(intRelDataType,
           SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), ts));
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 2282037..7d722cb 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -1516,6 +1516,30 @@ public class JdbcTest {
             });
   }
 
+  @Test public void testExtractMonthFromTimestamp() {
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.JDBC_FOODMART)
+        .query("select extract(month from \"birth_date\") as c \n"
+            + "from \"foodmart\".\"employee\" where \"employee_id\"=1")
+        .returns("C=8\n");
+  }
+
+  @Test public void testExtractYearFromTimestamp() {
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.JDBC_FOODMART)
+        .query("select extract(year from \"birth_date\") as c \n"
+            + "from \"foodmart\".\"employee\" where \"employee_id\"=1")
+        .returns("C=1961\n");
+  }
+
+  @Test public void testExtractFromInterval() {
+    CalciteAssert.that()
+        .with(CalciteAssert.Config.JDBC_FOODMART)
+        .query("select extract(month from interval '2-3' year to month) as c \n"
+            + "from \"foodmart\".\"employee\" where \"employee_id\"=1")
+        .returns("C=3\n");
+  }
+
   @Test public void testFloorDate() {
     CalciteAssert.that()
         .with(CalciteAssert.Config.JDBC_FOODMART)

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 95c47fc..570c7a0 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -8575,7 +8575,6 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
         + "UNION ALL left\n"
         + "\n"
         + "$throw -\n"
-        + "EXTRACT_DATE -\n"
         + "FILTER left\n"
         + "Reinterpret -\n"
         + "TABLE pre\n"

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index f575271..ecf1e46 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -18,11 +18,9 @@ limitations under the License.
 <Root>
     <TestCase name="testReduceNot">
         <Resource name="sql">
-            <![CDATA[select sal
-from emp
-where case when (sal = 1000) then
-(case when sal = 1000 then null else 1 end is null) else
-(case when sal = 2000 then null else 1 end is null) end is true]]>
+            <![CDATA[select *
+from (select (case when sal > 1000 then null else false end) as caseCol from emp)
+where NOT(caseCol)]]>
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
@@ -656,7 +654,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[$SUM0($2)], EXPR$2=[SUM($1)])
     </TestCase>
     <TestCase name="testDistinctNonDistinctTwoAggregatesWithGrouping">
         <Resource name="sql">
-            <![CDATA[SELECT deptno, sum(comm), min(comm), SUM(DISTINCT sal)
+            <![CDATA[SELECT deptno, SUM(comm), MIN(comm), SUM(DISTINCT sal)
 FROM emp
 GROUP BY deptno]]>
         </Resource>
@@ -678,7 +676,7 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($2)], EXPR$2=[MIN($3)], EXPR$3=[SUM($1
     </TestCase>
     <TestCase name="testDistinctWithGrouping">
         <Resource name="sql">
-            <![CDATA[SELECT sal, sum(comm), min(comm), SUM(DISTINCT sal)
+            <![CDATA[SELECT sal, SUM(comm), MIN(comm), SUM(DISTINCT sal)
 FROM emp
 GROUP BY sal]]>
         </Resource>
@@ -2331,14 +2329,14 @@ where extract(year from birthdate) = 2014and extract(month from birthdate) = 4]]
         <Resource name="planBefore">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9])
-  LogicalFilter(condition=[AND(=(EXTRACT_DATE(FLAG(YEAR), Reinterpret($9)), 2014), =(EXTRACT_DATE(FLAG(MONTH), Reinterpret($9)), 4))])
+  LogicalFilter(condition=[AND(=(EXTRACT(FLAG(YEAR), $9), 2014), =(EXTRACT(FLAG(MONTH), $9), 4))])
     LogicalTableScan(table=[[CATALOG, SALES, EMP_B]])
 ]]>
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9])
-  LogicalFilter(condition=[AND(>=(Reinterpret($9), 2014-01-01), <(Reinterpret($9), 2015-01-01), >=(Reinterpret($9), 2014-04-01), <(Reinterpret($9), 2014-05-01))])
+  LogicalFilter(condition=[AND(>=($9, 2014-04-01), <($9, 2014-05-01))])
     LogicalTableScan(table=[[CATALOG, SALES, EMP_B]])
 ]]>
         </Resource>
@@ -2352,14 +2350,14 @@ where extract(year from birthdate) = 2014]]>
         <Resource name="planBefore">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9])
-  LogicalFilter(condition=[=(EXTRACT_DATE(FLAG(YEAR), Reinterpret($9)), 2014)])
+  LogicalFilter(condition=[=(EXTRACT(FLAG(YEAR), $9), 2014)])
     LogicalTableScan(table=[[CATALOG, SALES, EMP_B]])
 ]]>
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], BIRTHDATE=[$9])
-  LogicalFilter(condition=[AND(>=(Reinterpret($9), 2014-01-01), <(Reinterpret($9), 2015-01-01))])
+  LogicalFilter(condition=[AND(>=($9, 2014-01-01), <($9, 2015-01-01))])
     LogicalTableScan(table=[[CATALOG, SALES, EMP_B]])
 ]]>
         </Resource>

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
----------------------------------------------------------------------
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
index 1a0d3d3..c167e06 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -1378,10 +1378,9 @@ public class DruidAdapterIT {
         + "where extract(year from \"timestamp\") = 1997\n"
         + "and extract(month from \"timestamp\") in (4, 6)\n";
     final String explain = "DruidQuery(table=[[foodmart, foodmart]], "
-        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[AND(="
-        + "(EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 1997), OR(=(EXTRACT_DATE"
-        + "(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 4), =(EXTRACT_DATE(FLAG(MONTH), "
-        + "/INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 6)))], groups=[{}], aggs=[[COUNT()]])";
+        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+        + "filter=[AND(=(EXTRACT(FLAG(YEAR), $0), 1997), OR(=(EXTRACT(FLAG(MONTH), $0), 4), "
+        + "=(EXTRACT(FLAG(MONTH), $0), 6)))], groups=[{}], aggs=[[COUNT()]])";
     sql(sql)
         .explainContains(explain)
         .returnsUnordered("C=13500");
@@ -1586,10 +1585,9 @@ public class DruidAdapterIT {
                     + "'timeZone':'UTC','locale':'en-US'}}"))
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
-            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)"
-            + "], projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), "
-            + "EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), EXTRACT_DATE(FLAG"
-            + "(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n")
+            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], "
+            + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), EXTRACT(FLAG(MONTH), $0), "
+            + "EXTRACT(FLAG(YEAR), $0), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n")
         .returnsUnordered("day=2; month=1; year=1997; product_id=1016",
             "day=10; month=1; year=1997; product_id=1016",
             "day=13; month=1; year=1997; product_id=1016",
@@ -1620,10 +1618,9 @@ public class DruidAdapterIT {
                     + "'timeZone':'UTC','locale':'en-US'}}"))
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
-            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)"
-            + "], projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), "
-            + "EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), EXTRACT_DATE(FLAG"
-            + "(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n")
+            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], "
+            + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), EXTRACT(FLAG(MONTH), $0), "
+            + "EXTRACT(FLAG(YEAR), $0), $1]], groups=[{0, 1, 2, 3}], aggs=[[]])\n")
         .returnsUnordered("EXPR$0=2; EXPR$1=1; EXPR$2=1997; product_id=1016",
             "EXPR$0=10; EXPR$1=1; EXPR$2=1997; product_id=1016",
             "EXPR$0=13; EXPR$1=1; EXPR$2=1997; product_id=1016",
@@ -1647,8 +1644,8 @@ public class DruidAdapterIT {
                     + "'timeZone':'UTC','locale':'en-US'}}"))
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
-            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], filter=[=($1, 1016)], "
-            + "projects=[[EXTRACT_DATE(FLAG(DAY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1]], "
+            + "intervals=[[1997-01-01T00:00:00.001/1997-01-20T00:00:00.000]], "
+            + "filter=[=($1, 1016)], projects=[[EXTRACT(FLAG(DAY), $0), $1]], "
             + "groups=[{0, 1}], aggs=[[]])\n")
         .returnsUnordered("EXPR$0=2; dayOfMonth=1016", "EXPR$0=10; dayOfMonth=1016",
             "EXPR$0=13; dayOfMonth=1016", "EXPR$0=16; dayOfMonth=1016");
@@ -1675,10 +1672,10 @@ public class DruidAdapterIT {
     sql(sql)
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
-            + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[AND(>=(CAST"
-            + "($11):BIGINT, 8), <=(CAST($11):BIGINT, 10), <(CAST($10):BIGINT, 15), =(EXTRACT_DATE"
-            + "(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), 1997))], groups=[{}], "
-            + "aggs=[[SUM($90)]])")
+            + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+            + "filter=[AND(>=(CAST($11):BIGINT, 8), <=(CAST($11):BIGINT, 10), "
+            + "<(CAST($10):BIGINT, 15), =(EXTRACT(FLAG(YEAR), $0), 1997))], groups=[{}], "
+            + "aggs=[[SUM($90)]])\n")
         .queryContains(druidChecker(druidQuery))
         .returnsUnordered("EXPR$0=75364.09998679161");
   }
@@ -1824,10 +1821,10 @@ public class DruidAdapterIT {
             + "'intervals':['1900-01-09T00:00:00.000/2992-01-10T00:00:00.000']}"))
         .explainContains("PLAN=EnumerableInterpreter\n"
             + "  DruidQuery(table=[[foodmart, foodmart]], "
-            + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)"
-            + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), "
-            + "86400000)), $1, $89]], groups=[{0, 1}], aggs=[[SUM($2)]], sort0=[0], sort1=[2], "
-            + "sort2=[1], dir0=[ASC], dir1=[ASC], dir2=[ASC])");
+            + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+            + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(MONTH), $0), $1, $89]], "
+            + "groups=[{0, 1}], aggs=[[SUM($2)]], sort0=[0], sort1=[2], sort2=[1], "
+            + "dir0=[ASC], dir1=[ASC], dir2=[ASC])");
   }
 
 
@@ -1870,10 +1867,10 @@ public class DruidAdapterIT {
         + " by y DESC, m ASC, s DESC, \"product_id\" LIMIT 3";
     final String expectedPlan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], "
-        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)"
-        + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)),"
-        + " EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1, $89]], groups=[{0, 1,"
-        + " 2}], aggs=[[SUM($3)]], sort0=[0], sort1=[1], sort2=[3], sort3=[2], dir0=[DESC], "
+        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+        + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(YEAR), $0), "
+        + "EXTRACT(FLAG(MONTH), $0), $1, $89]], groups=[{0, 1, 2}], aggs=[[SUM($3)]], sort0=[0], "
+        + "sort1=[1], sort2=[3], sort3=[2], dir0=[DESC], "
         + "dir1=[ASC], dir2=[DESC], dir3=[ASC], fetch=[3])";
     final String expectedDruidQuery = "{'queryType':'groupBy','dataSource':'foodmart',"
         + "'granularity':'all','dimensions':[{'type':'extraction',"
@@ -1906,11 +1903,10 @@ public class DruidAdapterIT {
         + " by s DESC, m DESC, \"product_id\" LIMIT 3";
     final String expectedPlan = "PLAN=EnumerableInterpreter\n"
         + "  DruidQuery(table=[[foodmart, foodmart]], "
-        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[>=(CAST($1)"
-        + ":BIGINT, 1558)], projects=[[EXTRACT_DATE(FLAG(YEAR), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)),"
-        + " EXTRACT_DATE(FLAG(MONTH), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000)), $1, $89]], groups=[{0, 1,"
-        + " 2}], aggs=[[SUM($3)]], sort0=[3], sort1=[1], sort2=[2], dir0=[DESC], dir1=[DESC], "
-        + "dir2=[ASC], fetch=[3])";
+        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+        + "filter=[>=(CAST($1):BIGINT, 1558)], projects=[[EXTRACT(FLAG(YEAR), $0), "
+        + "EXTRACT(FLAG(MONTH), $0), $1, $89]], groups=[{0, 1, 2}], aggs=[[SUM($3)]], "
+        + "sort0=[3], sort1=[1], sort2=[2], dir0=[DESC], dir1=[DESC], dir2=[ASC], fetch=[3])";
     final String expectedDruidQuery = "{'queryType':'groupBy','dataSource':'foodmart',"
         + "'granularity':'all','dimensions':[{'type':'extraction',"
         + "'dimension':'__time','outputName':'extract_year',"
@@ -2040,10 +2036,10 @@ public class DruidAdapterIT {
         + "\"product_id\" = 1558 group by extract(CENTURY from \"timestamp\")";
     final String plan = "PLAN=EnumerableInterpreter\n"
         + "  BindableAggregate(group=[{0}])\n"
-        + "    BindableProject(EXPR$0=[EXTRACT_DATE(FLAG(CENTURY), /INT(CAST(Reinterpret($0)):TIMESTAMP(0), 86400000))])\n"
+        + "    BindableProject(EXPR$0=[EXTRACT(FLAG(CENTURY), $0)])\n"
         + "      DruidQuery(table=[[foodmart, foodmart]], "
-        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], filter=[=($1, 1558)], "
-        + "projects=[[$0]])";
+        + "intervals=[[1900-01-09T00:00:00.000/2992-01-10T00:00:00.000]], "
+        + "filter=[=($1, 1558)], projects=[[$0]])\n";
     sql(sql).explainContains(plan).queryContains(druidChecker("'queryType':'select'"))
         .returnsUnordered("EXPR$0=20");
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/796a28f9/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 0e1948d..f993a53 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
@@ -112,9 +112,9 @@ public class DruidDateRangeRulesTest {
     //     OR(AND(>=($9, 2012-02-29), <($9, 2012-03-01)),"
     //        AND(>=($9, 2016-02-29), <($9, 2016-03-01))))
     checkDateRange(f,
-        f.and(f.gt(f.exYearTs, f.literal(2010)),
-            f.lt(f.exYearTs, f.literal(2020)),
-            f.eq(f.exMonthTs, f.literal(2)), f.eq(f.exDayTs, f.literal(29))),
+        f.and(f.gt(f.exYear, f.literal(2010)),
+            f.lt(f.exYear, f.literal(2020)),
+            f.eq(f.exMonth, f.literal(2)), f.eq(f.exDay, f.literal(29))),
         is("[2012-02-29T00:00:00.000/2012-03-01T00:00:00.000, "
             + "2016-02-29T00:00:00.000/2016-03-01T00:00:00.000]"));
   }
@@ -190,26 +190,14 @@ public class DruidDateRangeRulesTest {
     private final RexNode exYear;
     private final RexNode exMonth;
     private final RexNode exDay;
-    private final RexNode exYearTs;
-    private final RexNode exMonthTs;
-    private final RexNode exDayTs;
 
     Fixture2() {
-      exYear = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), dt));
-      exMonth = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), dt));
-      exDay = rexBuilder.makeCall(intRelDataType,
-          SqlStdOperatorTable.EXTRACT_DATE,
-          ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), dt));
-      exYearTs = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT,
+      exYear = rexBuilder.makeCall(SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.YEAR), ts));
-      exMonthTs = rexBuilder.makeCall(intRelDataType,
+      exMonth = rexBuilder.makeCall(intRelDataType,
           SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.MONTH), ts));
-      exDayTs = rexBuilder.makeCall(intRelDataType,
+      exDay = rexBuilder.makeCall(intRelDataType,
           SqlStdOperatorTable.EXTRACT,
           ImmutableList.of(rexBuilder.makeFlag(TimeUnitRange.DAY), ts));
     }