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 2016/10/18 19:04:47 UTC

[2/3] calcite git commit: [CALCITE-1417] In RelBuilder, simplify "CAST(literal TO type)" to a literal when possible

[CALCITE-1417] In RelBuilder, simplify "CAST(literal TO type)" to a literal when possible

This allows us to simplify logic that the Druid adapter uses to push
down time ranges. For example, CAST('2016-01-23' AS DATE) will already
be a DATE value.

You can turn off simplification (mainly for testing purposes) by
setting Hook.REL_BUILDER_SIMPLIFY. This the first time we have a
allowed a Hook to act like a property.

Add a test case (disabled) for [CALCITE-1439].

Allow QuidemTest to accept test script names as command-line
arguments.

Use RexExecutor for constant reduction (although not necessarily the
same one that will be used later in planning).


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

Branch: refs/heads/master
Commit: 54556b82c0599012f2e7fefaae3a9868cb68f879
Parents: d9e9103
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Oct 9 16:21:47 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Oct 18 10:20:28 2016 -0700

----------------------------------------------------------------------
 .../java/org/apache/calcite/rex/RexBuilder.java |  11 +-
 .../java/org/apache/calcite/rex/RexUtil.java    |  81 ++++-
 .../java/org/apache/calcite/runtime/Hook.java   |  14 +
 .../apache/calcite/sql/fun/SqlCastFunction.java |  90 ++----
 .../org/apache/calcite/tools/RelBuilder.java    |  14 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   |  36 ++-
 .../org/apache/calcite/test/QuidemTest.java     |  11 +-
 .../apache/calcite/test/RelMetadataTest.java    |   3 +-
 .../apache/calcite/test/RelOptRulesTest.java    |  56 +++-
 .../org/apache/calcite/test/RelOptTestBase.java |  65 +++-
 .../org/apache/calcite/test/RexProgramTest.java | 116 ++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml |  13 +-
 .../calcite/test/SqlToRelConverterTest.xml      | 178 +++++++----
 core/src/test/resources/sql/dummy.iq            |  15 +-
 core/src/test/resources/sql/misc.iq             | 220 ++++++++++++++
 .../adapter/druid/DruidDateTimeUtils.java       | 295 +++++--------------
 .../calcite/adapter/druid/DruidRules.java       |  22 +-
 17 files changed, 838 insertions(+), 402 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index 73ef60d..87c84e3 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -52,6 +52,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
 import java.math.BigDecimal;
+import java.math.MathContext;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -577,7 +578,7 @@ public class RexBuilder {
     }
   }
 
-  private boolean canRemoveCastFromLiteral(RelDataType toType, Comparable value,
+  boolean canRemoveCastFromLiteral(RelDataType toType, Comparable value,
       SqlTypeName fromTypeName) {
     final SqlTypeName sqlType = toType.getSqlTypeName();
     if (!RexLiteral.valueMatchesType(value, sqlType, false)) {
@@ -1375,12 +1376,18 @@ public class RexBuilder {
       }
       return new BigDecimal(((Number) o).longValue());
     case FLOAT:
+      if (o instanceof BigDecimal) {
+        return o;
+      }
+      return new BigDecimal(((Number) o).doubleValue(), MathContext.DECIMAL32)
+          .stripTrailingZeros();
     case REAL:
     case DOUBLE:
       if (o instanceof BigDecimal) {
         return o;
       }
-      return new BigDecimal(((Number) o).doubleValue());
+      return new BigDecimal(((Number) o).doubleValue(), MathContext.DECIMAL64)
+          .stripTrailingZeros();
     case CHAR:
     case VARCHAR:
       if (o instanceof NlsString) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index d2a95fa..fd971bd 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -18,6 +18,7 @@ package org.apache.calcite.rex;
 
 import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.linq4j.function.Predicate1;
+import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
@@ -29,6 +30,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFamily;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
@@ -43,6 +45,7 @@ import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
@@ -104,6 +107,11 @@ public class RexUtil {
         }
       };
 
+  /** Executor for a bit of constant reduction. Ideally we'd use the user's
+   * preferred executor, but that isn't available. */
+  private static final RelOptPlanner.Executor EXECUTOR =
+      new RexExecutorImpl(Schemas.createDataContext(null));
+
   private RexUtil() {
   }
 
@@ -1386,6 +1394,24 @@ public class RexUtil {
     return e1 == e2 || e1.toString().equals(e2.toString());
   }
 
+  /** Simplifies a boolean expression, always preserving its type and its
+   * nullability.
+   *
+   * <p>This is useful if you are simplifying expressions in a
+   * {@link Project}. */
+  public static RexNode simplifyPreservingType(RexBuilder rexBuilder,
+      RexNode e) {
+    final RexNode e2 = simplify(rexBuilder, e, false);
+    if (e2.getType() == e.getType()) {
+      return e2;
+    }
+    final RexNode e3 = rexBuilder.makeCast(e.getType(), e2, true);
+    if (e3.equals(e)) {
+      return e;
+    }
+    return e3;
+  }
+
   /**
    * Simplifies a boolean expression.
    *
@@ -1412,23 +1438,37 @@ public class RexUtil {
       return simplifyNot(rexBuilder, (RexCall) e);
     case CASE:
       return simplifyCase(rexBuilder, (RexCall) e, unknownAsFalse);
+    case CAST:
+      return simplifyCast(rexBuilder, (RexCall) e);
     case IS_NULL:
-      return ((RexCall) e).getOperands().get(0).getType().isNullable()
-          ? e : rexBuilder.makeLiteral(false);
     case IS_NOT_NULL:
-      return ((RexCall) e).getOperands().get(0).getType().isNullable()
-          ? e : rexBuilder.makeLiteral(true);
     case IS_TRUE:
     case IS_NOT_TRUE:
     case IS_FALSE:
     case IS_NOT_FALSE:
       assert e instanceof RexCall;
       return simplifyIs(rexBuilder, (RexCall) e);
+    case EQUALS:
+    case GREATER_THAN:
+    case GREATER_THAN_OR_EQUAL:
+    case LESS_THAN:
+    case LESS_THAN_OR_EQUAL:
+    case NOT_EQUALS:
+      return simplifyCall(rexBuilder, (RexCall) e);
     default:
       return e;
     }
   }
 
+  private static RexNode simplifyCall(RexBuilder rexBuilder, RexCall e) {
+    final List<RexNode> operands = new ArrayList<>(e.operands);
+    simplifyList(rexBuilder, operands);
+    if (operands.equals(e.operands)) {
+      return e;
+    }
+    return rexBuilder.makeCall(e.op, operands);
+  }
+
   /**
    * Simplifies a conjunction of boolean expressions.
    */
@@ -2074,6 +2114,39 @@ public class RexUtil {
         && (call.operands.size() - i) % 2 == 1;
   }
 
+  private static RexNode simplifyCast(RexBuilder rexBuilder, RexCall e) {
+    final RexNode operand = e.getOperands().get(0);
+    switch (operand.getKind()) {
+    case LITERAL:
+      final RexLiteral literal = (RexLiteral) operand;
+      final Comparable value = literal.getValue();
+      final SqlTypeName typeName = literal.getTypeName();
+
+      // First, try to remove the cast without changing the value.
+      // makeCast and canRemoveCastFromLiteral have the same logic, so we are
+      // sure to be able to remove the cast.
+      if (rexBuilder.canRemoveCastFromLiteral(e.getType(), value, typeName)) {
+        return rexBuilder.makeCast(e.getType(), operand);
+      }
+
+      // Next, try to convert the value to a different type,
+      // e.g. CAST('123' as integer)
+      switch (literal.getTypeName()) {
+      case TIME:
+        switch (e.getType().getSqlTypeName()) {
+        case TIMESTAMP:
+          return e;
+        }
+      }
+      final List<RexNode> reducedValues = new ArrayList<>();
+      EXECUTOR.reduce(rexBuilder, ImmutableList.<RexNode>of(e), reducedValues);
+      return Preconditions.checkNotNull(
+          Iterables.getOnlyElement(reducedValues));
+    default:
+      return e;
+    }
+  }
+
   /** Returns a function that applies NOT to its argument. */
   public static Function<RexNode, RexNode> notFn(final RexBuilder rexBuilder) {
     return new Function<RexNode, RexNode>() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/main/java/org/apache/calcite/runtime/Hook.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/Hook.java b/core/src/main/java/org/apache/calcite/runtime/Hook.java
index 2d10b31..a97a406 100644
--- a/core/src/main/java/org/apache/calcite/runtime/Hook.java
+++ b/core/src/main/java/org/apache/calcite/runtime/Hook.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.runtime;
 
+import org.apache.calcite.util.Holder;
+
 import com.google.common.base.Function;
 
 import java.util.ArrayList;
@@ -33,6 +35,10 @@ public enum Hook {
    * in tests. */
   CURRENT_TIME,
 
+  /** Returns a boolean value, whether RelBuilder should simplify expressions.
+   * Default true. */
+  REL_BUILDER_SIMPLIFY,
+
   /** Called with the SQL string and parse tree, in an array. */
   PARSE_TREE,
 
@@ -129,6 +135,14 @@ public enum Hook {
     }
   }
 
+  /** Returns the value of a property hook.
+   * (Property hooks take a {@link Holder} as an argument.) */
+  public <V> V get(V defaultValue) {
+    final Holder<V> holder = Holder.of(defaultValue);
+    run(holder);
+    return holder.get();
+  }
+
   /** Removes a Hook after use.
    *
    * <p>Note: Although it would be convenient, this interface cannot extend

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
index 3742c8e..a502a01 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
@@ -38,10 +38,8 @@ import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 
-import com.google.common.collect.ImmutableSet;
-
-import java.util.Objects;
-import java.util.Set;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
@@ -54,8 +52,22 @@ import static org.apache.calcite.util.Static.RESOURCE;
 public class SqlCastFunction extends SqlFunction {
   //~ Instance fields --------------------------------------------------------
 
-  private final Set<TypeFamilyCast> nonMonotonicPreservingCasts =
-      createNonMonotonicPreservingCasts();
+  /** Map of all casts that do not preserve monotonicity. */
+  private final SetMultimap<SqlTypeFamily, SqlTypeFamily> nonMonotonicCasts =
+      ImmutableSetMultimap.<SqlTypeFamily, SqlTypeFamily>builder()
+          .put(SqlTypeFamily.EXACT_NUMERIC, SqlTypeFamily.CHARACTER)
+          .put(SqlTypeFamily.NUMERIC, SqlTypeFamily.CHARACTER)
+          .put(SqlTypeFamily.APPROXIMATE_NUMERIC, SqlTypeFamily.CHARACTER)
+          .put(SqlTypeFamily.DATETIME_INTERVAL, SqlTypeFamily.CHARACTER)
+          .put(SqlTypeFamily.CHARACTER, SqlTypeFamily.EXACT_NUMERIC)
+          .put(SqlTypeFamily.CHARACTER, SqlTypeFamily.NUMERIC)
+          .put(SqlTypeFamily.CHARACTER, SqlTypeFamily.APPROXIMATE_NUMERIC)
+          .put(SqlTypeFamily.CHARACTER, SqlTypeFamily.DATETIME_INTERVAL)
+          .put(SqlTypeFamily.DATETIME, SqlTypeFamily.TIME)
+          .put(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.TIME)
+          .put(SqlTypeFamily.TIME, SqlTypeFamily.DATETIME)
+          .put(SqlTypeFamily.TIME, SqlTypeFamily.TIMESTAMP)
+          .build();
 
   //~ Constructors -----------------------------------------------------------
 
@@ -71,38 +83,6 @@ public class SqlCastFunction extends SqlFunction {
 
   //~ Methods ----------------------------------------------------------------
 
-  /**
-   * List all casts that do not preserve monotonicity.
-   */
-  private Set<TypeFamilyCast> createNonMonotonicPreservingCasts() {
-    ImmutableSet.Builder<TypeFamilyCast> builder = ImmutableSet.builder();
-    add(builder, SqlTypeFamily.EXACT_NUMERIC, SqlTypeFamily.CHARACTER);
-    add(builder, SqlTypeFamily.NUMERIC, SqlTypeFamily.CHARACTER);
-    add(builder, SqlTypeFamily.APPROXIMATE_NUMERIC, SqlTypeFamily.CHARACTER);
-    add(builder, SqlTypeFamily.DATETIME_INTERVAL, SqlTypeFamily.CHARACTER);
-    add(builder, SqlTypeFamily.CHARACTER, SqlTypeFamily.EXACT_NUMERIC);
-    add(builder, SqlTypeFamily.CHARACTER, SqlTypeFamily.NUMERIC);
-    add(builder, SqlTypeFamily.CHARACTER, SqlTypeFamily.APPROXIMATE_NUMERIC);
-    add(builder, SqlTypeFamily.CHARACTER, SqlTypeFamily.DATETIME_INTERVAL);
-    add(builder, SqlTypeFamily.DATETIME, SqlTypeFamily.TIME);
-    add(builder, SqlTypeFamily.TIMESTAMP, SqlTypeFamily.TIME);
-    add(builder, SqlTypeFamily.TIME, SqlTypeFamily.DATETIME);
-    add(builder, SqlTypeFamily.TIME, SqlTypeFamily.TIMESTAMP);
-    return builder.build();
-  }
-
-  private void add(ImmutableSet.Builder<TypeFamilyCast> result,
-      SqlTypeFamily from, SqlTypeFamily to) {
-    result.add(new TypeFamilyCast(from, to));
-  }
-
-  private boolean isMonotonicPreservingCast(
-      RelDataTypeFamily castFrom,
-      RelDataTypeFamily castTo) {
-    return !nonMonotonicPreservingCasts.contains(
-        new TypeFamilyCast(castFrom, castTo));
-  }
-
   public RelDataType inferReturnType(
       SqlOperatorBinding opBinding) {
     assert opBinding.getOperandCount() == 2;
@@ -202,36 +182,12 @@ public class SqlCastFunction extends SqlFunction {
   @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     RelDataTypeFamily castFrom = call.getOperandType(0).getFamily();
     RelDataTypeFamily castTo = call.getOperandType(1).getFamily();
-    if (isMonotonicPreservingCast(castFrom, castTo)) {
-      return call.getOperandMonotonicity(0);
-    } else {
+    if (castFrom instanceof SqlTypeFamily
+        && castTo instanceof SqlTypeFamily
+        && nonMonotonicCasts.containsEntry(castFrom, castTo)) {
       return SqlMonotonicity.NOT_MONOTONIC;
-    }
-  }
-
-  //~ Inner Classes ----------------------------------------------------------
-
-  /** Pair of source-target type families. */
-  private class TypeFamilyCast {
-    private final RelDataTypeFamily castFrom;
-    private final RelDataTypeFamily castTo;
-
-    public TypeFamilyCast(
-        RelDataTypeFamily castFrom,
-        RelDataTypeFamily castTo) {
-      this.castFrom = castFrom;
-      this.castTo = castTo;
-    }
-
-    @Override public boolean equals(Object o) {
-      return o == this
-          || o instanceof TypeFamilyCast
-          && castFrom.equals(((TypeFamilyCast) o).castFrom)
-          && castTo.equals(((TypeFamilyCast) o).castTo);
-    }
-
-    @Override public int hashCode() {
-      return Objects.hash(castFrom, castTo);
+    } else {
+      return call.getOperandMonotonicity(0);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 554e777..2973a2f 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -45,6 +45,7 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SemiJoinType;
@@ -123,6 +124,7 @@ public class RelBuilder {
   private final RelFactories.ValuesFactory valuesFactory;
   private final RelFactories.TableScanFactory scanFactory;
   private final Deque<Frame> stack = new ArrayDeque<>();
+  private final boolean simplify;
 
   protected RelBuilder(Context context, RelOptCluster cluster,
       RelOptSchema relOptSchema) {
@@ -131,6 +133,7 @@ public class RelBuilder {
     if (context == null) {
       context = Contexts.EMPTY_CONTEXT;
     }
+    this.simplify = Hook.REL_BUILDER_SIMPLIFY.get(true);
     this.aggregateFactory =
         Util.first(context.unwrap(RelFactories.AggregateFactory.class),
             RelFactories.DEFAULT_AGGREGATE_FACTORY);
@@ -825,12 +828,17 @@ public class RelBuilder {
       Iterable<String> fieldNames,
       boolean force) {
     final List<String> names = new ArrayList<>();
-    final List<RexNode> exprList = Lists.newArrayList(nodes);
+    final List<RexNode> exprList = new ArrayList<>();
+    for (RexNode node : nodes) {
+      if (simplify) {
+        node = RexUtil.simplifyPreservingType(getRexBuilder(), node);
+      }
+      exprList.add(node);
+    }
     final Iterator<String> nameIterator = fieldNames.iterator();
     for (RexNode node : nodes) {
       final String name = nameIterator.hasNext() ? nameIterator.next() : null;
-      final String name2 = inferAlias(exprList, node);
-      names.add(Util.first(name, name2));
+      names.add(name != null ? name : inferAlias(exprList, node));
     }
     final RelDataType inputRowType = peek().getRowType();
     if (!force && RexUtil.isIdentity(exprList, inputRowType)) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 3488e2a..0c3acc6 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -665,9 +665,6 @@ public abstract class SqlOperatorBaseTest {
             true);
       }
 
-      if (!enable) {
-        return;
-      }
       // Convert from string to type
       checkCastToScalarOkay(
           "'" + MAX_NUMERIC_STRINGS[i] + "'",
@@ -1138,6 +1135,22 @@ public abstract class SqlOperatorBaseTest {
     tester.checkNull("cast(null as boolean)");
   }
 
+  @Ignore("[CALCITE-1439] Handling errors during constant reduction")
+  @Test public void testCastInvalid() {
+    // Constant reduction kicks in and generates Java constants that throw
+    // when the class is loaded, thus ExceptionInInitializerError. We don't have
+    // a fix yet.
+    tester.checkScalarExact("cast('15' as integer)", "INTEGER NOT NULL", "15");
+    tester.checkFails("cast('15.4' as integer)", "xxx", true);
+    tester.checkFails("cast('15.6' as integer)", "xxx", true);
+    tester.checkFails("cast('ue' as boolean)", "xxx", true);
+    tester.checkFails("cast('' as boolean)", "xxx", true);
+    tester.checkFails("cast('' as integer)", "xxx", true);
+    tester.checkFails("cast('' as real)", "xxx", true);
+    tester.checkFails("cast('' as double)", "xxx", true);
+    tester.checkFails("cast('' as smallint)", "xxx", true);
+  }
+
   @Test public void testCastDateTime() {
     // Test cast for date/time/timestamp
     tester.setFor(SqlStdOperatorTable.CAST);
@@ -1261,6 +1274,15 @@ public abstract class SqlOperatorBaseTest {
     tester.checkFails(
         "cast('12:54:78' as TIME)", BAD_DATETIME_MESSAGE,
         true);
+    tester.checkFails(
+        "cast('12:34:5' as TIME)", BAD_DATETIME_MESSAGE,
+        true);
+    tester.checkFails(
+        "cast('12:3:45' as TIME)", BAD_DATETIME_MESSAGE,
+        true);
+    tester.checkFails(
+        "cast('1:23:45' as TIME)", BAD_DATETIME_MESSAGE,
+        true);
 
     // timestamp <-> string
     checkCastToString(
@@ -1311,6 +1333,9 @@ public abstract class SqlOperatorBaseTest {
     tester.checkFails(
         "cast('1945-01-24 25:42:25.34' as TIMESTAMP)", BAD_DATETIME_MESSAGE,
         true);
+    tester.checkFails(
+        "cast('1945-1-24 12:23:34.454' as TIMESTAMP)", BAD_DATETIME_MESSAGE,
+        true);
 
     // date <-> string
     checkCastToString("DATE '1945-02-24'", null, "1945-02-24");
@@ -1321,6 +1346,10 @@ public abstract class SqlOperatorBaseTest {
         "1945-02-24",
         "DATE NOT NULL");
     tester.checkScalar(
+        "cast(' 1945-2-4 ' as DATE)",
+        "1945-02-04",
+        "DATE NOT NULL");
+    tester.checkScalar(
         "cast('  1945-02-24  ' as DATE)",
         "1945-02-24",
         "DATE NOT NULL");
@@ -1395,6 +1424,7 @@ public abstract class SqlOperatorBaseTest {
     tester.checkBoolean("cast('true' as boolean)", Boolean.TRUE);
     tester.checkBoolean("cast('false' as boolean)", Boolean.FALSE);
     tester.checkBoolean("cast('  trUe' as boolean)", Boolean.TRUE);
+    tester.checkBoolean("cast('  tr' || 'Ue' as boolean)", Boolean.TRUE);
     tester.checkBoolean("cast('  fALse' as boolean)", Boolean.FALSE);
     tester.checkFails(
         "cast('unknown' as boolean)", INVALID_CHAR_MESSAGE,

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/test/QuidemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/QuidemTest.java b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
index 2e8675c..a3dafba 100644
--- a/core/src/test/java/org/apache/calcite/test/QuidemTest.java
+++ b/core/src/test/java/org/apache/calcite/test/QuidemTest.java
@@ -67,10 +67,15 @@ public class QuidemTest {
     this.method = findMethod(path);
   }
 
-  /** Run a test from the command line. */
+  /** Runs a test from the command line.
+   *
+   * <p>For example:
+   *
+   * <blockquote><code>java QuidemTest sql/dummy.iq</code></blockquote> */
   public static void main(String[] args) throws Exception {
-    final String path = "sql/lateral.iq";
-    new QuidemTest(path).test();
+    for (String arg : args) {
+      new QuidemTest(arg).test();
+    }
   }
 
   private Method findMethod(String path) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index 562286a..5a12335 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -1350,8 +1350,7 @@ public class RelMetadataTest extends SqlToRelTestBase {
     final RelMetadataQuery mq = RelMetadataQuery.instance();
     RelOptPredicateList list = mq.getPulledUpPredicates(rel);
     assertThat(list.pulledUpPredicates,
-        sortsAs("[<($0, 10), =($3, 'y'), =($4, CAST('1'):INTEGER NOT NULL), "
-            + "IS NULL($1), IS NULL($2)]"));
+        sortsAs("[<($0, 10), =($3, 'y'), =($4, 1), IS NULL($1), IS NULL($2)]"));
   }
 
   @Test public void testPullUpPredicatesOnNullableConstant() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 09b9110..221dca2 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -87,6 +87,7 @@ import org.apache.calcite.rel.rules.ValuesReduceRule;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
@@ -848,12 +849,15 @@ public class RelOptRulesTest extends RelOptTestBase {
 
     // There is "CAST(2 AS INTEGER)" in the plan because 2 has type "INTEGER NOT
     // NULL" and we need "INTEGER".
-    checkPlanning(program,
-        "select 1+2, d.deptno+(3+4), (5+6)+d.deptno, cast(null as integer),"
-            + " coalesce(2,null), row(7+8)"
-            + " from dept d inner join emp e"
-            + " on d.deptno = e.deptno + (5-5)"
-            + " where d.deptno=(7+8) and d.deptno=(8+7) and d.deptno=coalesce(2,null)");
+    final String sql = "select"
+        + " 1+2, d.deptno+(3+4), (5+6)+d.deptno, cast(null as integer),"
+        + " coalesce(2,null), row(7+8)"
+        + " from dept d inner join emp e"
+        + " on d.deptno = e.deptno + (5-5)"
+        + " where d.deptno=(7+8) and d.deptno=(8+7) and d.deptno=coalesce(2,null)";
+    sql(sql).with(program)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   /** Test case for
@@ -1241,7 +1245,7 @@ public class RelOptRulesTest extends RelOptTestBase {
             + " where a - b < 21");
   }
 
-  @Test public void testReduceCase() throws Exception {
+  @Ignore @Test public void testReduceCase() throws Exception {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)
         .build();
@@ -1250,7 +1254,9 @@ public class RelOptRulesTest extends RelOptTestBase {
         + "  case when false then cast(2.1 as float)\n"
         + "   else cast(1 as integer) end as newcol\n"
         + "from emp";
-    checkPlanning(program, sql);
+    sql(sql).with(program)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   @Test public void testReduceConstantsIsNull() throws Exception {
@@ -1447,6 +1453,20 @@ public class RelOptRulesTest extends RelOptTestBase {
             + "where cast(e.job as varchar(1)) = 'Manager'");
   }
 
+  /** Tests that a cast from a TIME to a TIMESTAMP is not reduced. It is not
+   * constant because the result depends upon the current date. */
+  @Test public void testReduceCastTimeUnchanged() throws Exception {
+    HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.JOIN_INSTANCE)
+        .build();
+
+    sql("select cast(time '12:34:56' as timestamp) from emp as e")
+        .with(program)
+        .checkUnchanged();
+  }
+
   @Test public void testReduceCastAndConsts() throws Exception {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
@@ -2262,7 +2282,9 @@ public class RelOptRulesTest extends RelOptTestBase {
     final String sql = "select empno,\n"
         + "  deptno in (select deptno from sales.emp where empno < 20) as d\n"
         + "from sales.emp";
-    checkSubQuery(sql).check();
+    checkSubQuery(sql)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   @Test public void testExpandProjectInNullable() throws Exception {
@@ -2272,21 +2294,27 @@ public class RelOptRulesTest extends RelOptTestBase {
         + "select empno,\n"
         + "  deptno in (select deptno from e2 where empno < 20) as d\n"
         + "from e2";
-    checkSubQuery(sql).check();
+    checkSubQuery(sql)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   @Test public void testExpandProjectInComposite() throws Exception {
     final String sql = "select empno, (empno, deptno) in (\n"
         + "    select empno, deptno from sales.emp where empno < 20) as d\n"
         + "from sales.emp";
-    checkSubQuery(sql).check();
+    checkSubQuery(sql)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   @Test public void testExpandProjectExists() throws Exception {
     final String sql = "select empno,\n"
         + "  exists (select deptno from sales.emp where empno < 20) as d\n"
         + "from sales.emp";
-    checkSubQuery(sql).check();
+    checkSubQuery(sql)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   @Test public void testExpandFilterScalar() throws Exception {
@@ -2326,7 +2354,9 @@ public class RelOptRulesTest extends RelOptTestBase {
         + "   when false then 20\n"
         + "   else 30\n"
         + "   end";
-    checkSubQuery(sql).check();
+    checkSubQuery(sql)
+        .withProperty(Hook.REL_BUILDER_SIMPLIFY, false)
+        .check();
   }
 
   /** An EXISTS filter that can be converted into true/false. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
index 637ddef..1556094 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -27,10 +27,16 @@ import org.apache.calcite.rel.RelRoot;
 import org.apache.calcite.rel.metadata.ChainedRelMetadataProvider;
 import org.apache.calcite.rel.metadata.DefaultRelMetadataProvider;
 import org.apache.calcite.rel.metadata.RelMetadataProvider;
+import org.apache.calcite.runtime.Hook;
+import org.apache.calcite.util.Holder;
 
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -171,7 +177,7 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
 
   /** Sets the SQL statement for a test. */
   Sql sql(String sql) {
-    return new Sql(sql, null, true);
+    return new Sql(sql, null, true, ImmutableMap.<Hook, Function>of());
   }
 
   /** Allows fluent testing. */
@@ -179,27 +185,74 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
     private final String sql;
     private final HepPlanner hepPlanner;
     private final boolean expand;
+    private final ImmutableMap<Hook, Function> hooks;
 
-    public Sql(String sql, HepPlanner hepPlanner, boolean expand) {
+    Sql(String sql, HepPlanner hepPlanner, boolean expand,
+        ImmutableMap<Hook, Function> hooks) {
       this.sql = sql;
       this.hepPlanner = hepPlanner;
       this.expand = expand;
+      this.hooks = hooks;
     }
 
     public Sql with(HepPlanner hepPlanner) {
-      return new Sql(sql, hepPlanner, expand);
+      return new Sql(sql, hepPlanner, expand, hooks);
     }
 
     public Sql with(HepProgram program) {
-      return new Sql(sql, new HepPlanner(program), expand);
+      return new Sql(sql, new HepPlanner(program), expand, hooks);
+    }
+
+    /** Adds a hook and a handler for that hook. Calcite will create a thread
+     * hook (by calling {@link Hook#addThread(com.google.common.base.Function)})
+     * just before running the query, and remove the hook afterwards. */
+    public <T> Sql withHook(Hook hook, Function<T, Void> handler) {
+      return new Sql(sql, hepPlanner, expand,
+          ImmutableMap.<Hook, Function>builder().putAll(hooks)
+              .put(hook, handler).build());
+    }
+
+    /** Returns a function that, when a hook is called, will "return" a given
+     * value. (Because of the way hooks work, it "returns" the value by writing
+     * into a {@link Holder}. */
+    private <V> Function<Holder<V>, Void> propertyHook(final V v) {
+      return new Function<Holder<V>, Void>() {
+        public Void apply(Holder<V> holder) {
+          holder.set(v);
+          return null;
+        }
+      };
+    }
+
+    public <V> Sql withProperty(Hook hook, V value) {
+      return withHook(hook, propertyHook(value));
     }
 
     public Sql expand(boolean expand) {
-      return new Sql(sql, hepPlanner, expand);
+      return new Sql(sql, hepPlanner, expand, hooks);
     }
 
     public void check() {
-      checkPlanning(tester.withExpand(expand), null, hepPlanner, sql);
+      check(false);
+    }
+
+    public void checkUnchanged() {
+      check(true);
+    }
+
+    private void check(boolean unchanged) {
+      final List<Hook.Closeable> closeables = new ArrayList<>();
+      try {
+        for (Map.Entry<Hook, Function> entry : hooks.entrySet()) {
+          closeables.add(entry.getKey().addThread(entry.getValue()));
+        }
+        checkPlanning(tester.withExpand(expand), null, hepPlanner, sql,
+            unchanged);
+      } finally {
+        for (Hook.Closeable closeable : closeables) {
+          closeable.close();
+        }
+      }
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index 015ddda..9481d2f 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -17,6 +17,8 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.avatica.util.ByteString;
+import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
 import org.apache.calcite.plan.Strong;
 import org.apache.calcite.rel.type.RelDataType;
@@ -34,19 +36,25 @@ import org.apache.calcite.rex.RexProgramBuilder;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeAssignmentRules;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.TestUtil;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
 
 import org.junit.Before;
 import org.junit.Test;
 
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.List;
 
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -1070,6 +1078,114 @@ public class RexProgramTest {
     assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
   }
 
+  @Test public void testSimplifyCastLiteral() {
+    final List<RexLiteral> literals = new ArrayList<>();
+    literals.add(
+        rexBuilder.makeExactLiteral(BigDecimal.ONE,
+            typeFactory.createSqlType(SqlTypeName.INTEGER)));
+    literals.add(
+        rexBuilder.makeExactLiteral(BigDecimal.valueOf(2),
+            typeFactory.createSqlType(SqlTypeName.BIGINT)));
+    literals.add(
+        rexBuilder.makeExactLiteral(BigDecimal.valueOf(3),
+            typeFactory.createSqlType(SqlTypeName.SMALLINT)));
+    literals.add(
+        rexBuilder.makeExactLiteral(BigDecimal.valueOf(4),
+            typeFactory.createSqlType(SqlTypeName.TINYINT)));
+    literals.add(
+        rexBuilder.makeExactLiteral(new BigDecimal("1234"),
+            typeFactory.createSqlType(SqlTypeName.DECIMAL, 4, 0)));
+    literals.add(
+        rexBuilder.makeExactLiteral(new BigDecimal("123.45"),
+            typeFactory.createSqlType(SqlTypeName.DECIMAL, 5, 2)));
+    literals.add(
+        rexBuilder.makeApproxLiteral(new BigDecimal("3.1415"),
+            typeFactory.createSqlType(SqlTypeName.REAL)));
+    literals.add(
+        rexBuilder.makeApproxLiteral(BigDecimal.valueOf(Math.E),
+            typeFactory.createSqlType(SqlTypeName.FLOAT)));
+    literals.add(
+        rexBuilder.makeApproxLiteral(BigDecimal.valueOf(Math.PI),
+            typeFactory.createSqlType(SqlTypeName.DOUBLE)));
+    literals.add(rexBuilder.makeLiteral(true));
+    literals.add(rexBuilder.makeLiteral(false));
+    literals.add(rexBuilder.makeLiteral("hello world"));
+    literals.add(rexBuilder.makeLiteral("1969-07-20 12:34:56"));
+    literals.add(rexBuilder.makeLiteral("1969-07-20"));
+    literals.add(rexBuilder.makeLiteral("12:34:45"));
+    literals.add((RexLiteral)
+        rexBuilder.makeLiteral(new ByteString(new byte[] {1, 2, -34, 0, -128}),
+            typeFactory.createSqlType(SqlTypeName.BINARY, 5), false));
+    literals.add(
+        rexBuilder.makeDateLiteral(cal(1974, Calendar.AUGUST, 9, 0, 0, 0)));
+    literals.add(rexBuilder.makeTimeLiteral(cal(0, 0, 0, 1, 23, 45), 0));
+    literals.add(
+        rexBuilder.makeTimestampLiteral(
+            cal(1974, Calendar.AUGUST, 9, 1, 23, 45), 0));
+
+    final Multimap<SqlTypeName, RexLiteral> map = LinkedHashMultimap.create();
+    for (RexLiteral literal : literals) {
+      map.put(literal.getTypeName(), literal);
+    }
+
+    final List<RelDataType> types = new ArrayList<>();
+    types.add(typeFactory.createSqlType(SqlTypeName.INTEGER));
+    types.add(typeFactory.createSqlType(SqlTypeName.BIGINT));
+    types.add(typeFactory.createSqlType(SqlTypeName.SMALLINT));
+    types.add(typeFactory.createSqlType(SqlTypeName.TINYINT));
+    types.add(typeFactory.createSqlType(SqlTypeName.REAL));
+    types.add(typeFactory.createSqlType(SqlTypeName.FLOAT));
+    types.add(typeFactory.createSqlType(SqlTypeName.DOUBLE));
+    types.add(typeFactory.createSqlType(SqlTypeName.BOOLEAN));
+    types.add(typeFactory.createSqlType(SqlTypeName.VARCHAR, 10));
+    types.add(typeFactory.createSqlType(SqlTypeName.CHAR, 5));
+    types.add(typeFactory.createSqlType(SqlTypeName.VARBINARY, 60));
+    types.add(typeFactory.createSqlType(SqlTypeName.BINARY, 3));
+    types.add(typeFactory.createSqlType(SqlTypeName.TIMESTAMP));
+    types.add(typeFactory.createSqlType(SqlTypeName.TIME));
+    types.add(typeFactory.createSqlType(SqlTypeName.DATE));
+
+    for (RelDataType fromType : types) {
+      for (RelDataType toType : types) {
+        if (SqlTypeAssignmentRules.instance().canCastFrom(
+            toType.getSqlTypeName(), fromType.getSqlTypeName(), false)) {
+          for (RexLiteral literal : map.get(fromType.getSqlTypeName())) {
+            final RexNode cast = rexBuilder.makeCast(toType, literal);
+            if (cast instanceof RexLiteral) {
+              assertThat(cast.getType(), is(toType));
+              continue; // makeCast already simplified
+            }
+            final RexNode simplified = RexUtil.simplify(rexBuilder, cast);
+            boolean expectedSimplify =
+                literal.getTypeName() != toType.getSqlTypeName()
+                || (literal.getTypeName() == SqlTypeName.CHAR
+                    && ((NlsString) literal.getValue()).getValue().length()
+                        > toType.getPrecision())
+                || (literal.getTypeName() == SqlTypeName.BINARY
+                    && ((ByteString) literal.getValue()).length()
+                        > toType.getPrecision());
+            boolean couldSimplify = !cast.equals(simplified);
+            final String reason = (expectedSimplify
+                ? "expected to simplify, but could not: "
+                : "simplified, but did not expect to: ")
+                + cast + " --> " + simplified;
+            assertThat(reason, couldSimplify, is(expectedSimplify));
+          }
+        }
+      }
+    }
+  }
+
+  private Calendar cal(int y, int m, int d, int h, int mm, int s) {
+    final Calendar c = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
+    c.set(Calendar.YEAR, y);
+    c.set(Calendar.MONTH, m);
+    c.set(Calendar.DAY_OF_MONTH, d);
+    c.set(Calendar.HOUR_OF_DAY, h);
+    c.set(Calendar.MINUTE, mm);
+    c.set(Calendar.SECOND, s);
+    return c;
+  }
 }
 
 // End RexProgramTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/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 8edbd44..d830b95 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -2592,7 +2592,7 @@ LogicalAggregate(group=[{1}], EXPR$1=[$SUM0($2)])
             <![CDATA[
 LogicalAggregate(group=[{1}], EXPR$1=[$SUM0($2)])
   LogicalAggregate(group=[{5, 7}], EXPR$1=[COUNT()])
-    LogicalFilter(condition=[>(CAST($5):BIGINT NOT NULL, CAST('12'):BIGINT NOT NULL)])
+    LogicalFilter(condition=[>(CAST($5):BIGINT NOT NULL, 12)])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -3868,6 +3868,17 @@ LogicalProject(NEWCOL=[1E0])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testReduceCastTimeUnchanged">
+        <Resource name="sql">
+            <![CDATA[select cast(time '12:34:56' as timestamp) from emp as e]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EXPR$0=[CAST(12:34:56):TIMESTAMP(0) NOT NULL])
+  LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testReduceConstantsRequiresExecutor">
         <Resource name="sql">
             <![CDATA[select * from (values (1,2)) where 1 + 2 > 3 + CAST(NULL AS INTEGER)]]>

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 92f6ed8..371c20c 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -61,7 +61,9 @@ LogicalProject(EXPR$0=[+($0, 4)], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[*(2, $3)])
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select deptno + 4, sum(sal), sum(3 + sal), 2 * count(sal) from emp group by deptno]]>
+            <![CDATA[select
+  deptno + 4, sum(sal), sum(3 + sal), 2 * count(sal)
+from emp group by deptno]]>
         </Resource>
     </TestCase>
     <TestCase name="testHaving">
@@ -102,7 +104,10 @@ LogicalProject(NAME=[$1], FOO=[$2])
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select name, foo from (select deptno, name, count(deptno) as foo from dept group by name, deptno, name)]]>
+            <![CDATA[select name, foo from (
+select deptno, name, count(deptno) as foo
+from dept
+group by name, deptno, name)]]>
         </Resource>
     </TestCase>
     <TestCase name="testAggDistinct">
@@ -114,7 +119,9 @@ LogicalAggregate(group=[{0}], EXPR$1=[SUM($1)], EXPR$2=[SUM(DISTINCT $1)], EXPR$
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select deptno, sum(sal), sum(distinct sal), count(*) from emp group by deptno]]>
+            <![CDATA[select deptno, sum(sal), sum(distinct sal), count(*)
+from emp
+group by deptno]]>
         </Resource>
     </TestCase>
     <TestCase name="testCollectionTableWithLateral">
@@ -323,7 +330,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select*from emp where exists (select 1 from dept where deptno=55)]]>
+            <![CDATA[select*from emp
+where exists (select 1 from dept where deptno=55)]]>
         </Resource>
     </TestCase>
     <TestCase name="testExistsCorrelated">
@@ -341,7 +349,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select*from emp where exists (select 1 from dept where emp.deptno=dept.deptno)]]>
+            <![CDATA[select*from emp where exists (
+  select 1 from dept where emp.deptno=dept.deptno)]]>
         </Resource>
     </TestCase>
     <TestCase name="testUnnestSelect">
@@ -374,7 +383,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
 ]]>
         </Resource>
         <Resource name="sql">
-            <![CDATA[select * from emp, LATERAL (select * from dept where emp.deptno=dept.deptno)]]>
+            <![CDATA[select * from emp,
+  LATERAL (select * from dept where emp.deptno=dept.deptno)]]>
         </Resource>
     </TestCase>
     <TestCase name="testElement">
@@ -580,7 +590,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testIntervalLiteralYearToMonth">
         <Resource name="sql">
-            <![CDATA[select cast(empno as Integer) * (INTERVAL '1-1' YEAR TO MONTH)
+            <![CDATA[select
+  cast(empno as Integer) * (INTERVAL '1-1' YEAR TO MONTH)
 from emp]]>
         </Resource>
         <Resource name="plan">
@@ -592,7 +603,8 @@ LogicalProject(EXPR$0=[*(CAST($0):INTEGER NOT NULL, 13)])
     </TestCase>
     <TestCase name="testIntervalLiteralHourToMinute">
         <Resource name="sql">
-            <![CDATA[select cast(empno as Integer) * (INTERVAL '1:1' HOUR TO MINUTE)
+            <![CDATA[select
+ cast(empno as Integer) * (INTERVAL '1:1' HOUR TO MINUTE)
 from emp]]>
         </Resource>
         <Resource name="plan">
@@ -808,7 +820,8 @@ ProjectRel(EMPNO=[$0], Y=[$1])
     </TestCase>
     <TestCase name="testOrderByAliasInExpr">
         <Resource name="sql">
-            <![CDATA[select empno + 1 as x, empno - 2 as y from emp order by y + 3]]>
+            <![CDATA[select empno + 1 as x, empno - 2 as y
+from emp order by y + 3]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -821,7 +834,8 @@ LogicalProject(X=[$0], Y=[$1])
     </TestCase>
     <TestCase name="testOrderByAliasOverrides">
         <Resource name="sql">
-            <![CDATA[select empno + 1 as empno, empno - 2 as y from emp order by empno + 3]]>
+            <![CDATA[select empno + 1 as empno, empno - 2 as y
+from emp order by empno + 3]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -834,7 +848,10 @@ LogicalProject(EMPNO=[$0], Y=[$1])
     </TestCase>
     <TestCase name="testOrderUnion">
         <Resource name="sql">
-            <![CDATA[select empno, sal from emp union all select deptno, deptno from dept order by sal desc, empno asc]]>
+            <![CDATA[select empno, sal from emp
+union all
+select deptno, deptno from dept
+order by sal desc, empno asc]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -850,7 +867,10 @@ LogicalSort(sort0=[$1], sort1=[$0], dir0=[DESC], dir1=[ASC])
     </TestCase>
     <TestCase name="testOrderUnionExprs">
         <Resource name="sql">
-            <![CDATA[select empno, sal from emp union all select deptno, deptno from dept order by empno * sal + 2]]>
+            <![CDATA[select empno, sal from emp
+union all
+select deptno, deptno from dept
+order by empno * sal + 2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -867,7 +887,10 @@ LogicalProject(EMPNO=[$0], SAL=[$1])
     </TestCase>
     <TestCase name="testOrderGroup">
         <Resource name="sql">
-            <![CDATA[select deptno, count(*) from emp group by deptno order by deptno * sum(sal) desc, min(empno)]]>
+            <![CDATA[select deptno, count(*)
+from emp
+group by deptno
+order by deptno * sum(sal) desc, min(empno)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -882,7 +905,8 @@ LogicalProject(DEPTNO=[$0], EXPR$1=[$1])
     </TestCase>
     <TestCase name="testOrderDistinct">
         <Resource name="sql">
-            <![CDATA[select distinct empno, deptno + 1 from emp order by deptno + 1 + empno]]>
+            <![CDATA[select distinct empno, deptno + 1
+from emp order by deptno + 1 + empno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -896,7 +920,8 @@ LogicalProject(EMPNO=[$0], EXPR$1=[$1])
     </TestCase>
     <TestCase name="testOrderBySameExpr">
         <Resource name="sql">
-            <![CDATA[select empno from emp, dept order by sal + empno desc, sal * empno, sal + empno]]>
+            <![CDATA[select empno from emp, dept
+order by sal + empno desc, sal * empno, sal + empno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -911,7 +936,10 @@ LogicalProject(EMPNO=[$0])
     </TestCase>
     <TestCase name="testOrderUnionOrdinal">
         <Resource name="sql">
-            <![CDATA[select empno, sal from emp union all select deptno, deptno from dept order by 2]]>
+            <![CDATA[select empno, sal from emp
+union all
+select deptno, deptno from dept
+order by 2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -971,7 +999,8 @@ LogicalProject(EXPR$0=[LAST_VALUE($7) OVER (ORDER BY $0 RANGE BETWEEN UNBOUNDED
     </TestCase>
     <TestCase name="testOverOrderFollowingWindow">
         <Resource name="sql">
-            <![CDATA[select last_value(deptno) over (order by empno rows 2 following)
+            <![CDATA[select
+  last_value(deptno) over (order by empno rows 2 following)
 from emp
 ]]>
         </Resource>
@@ -1037,7 +1066,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testJoinOn">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp JOIN dept on emp.deptno = dept.deptno]]>
+            <![CDATA[SELECT * FROM emp
+JOIN dept on emp.deptno = dept.deptno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1197,7 +1227,9 @@ LogicalProject(A=[$0], B=[$1], C=[$2], DEPTNO=[$3], NAME=[$4])
     </TestCase>
     <TestCase name="testJoinWithUnion">
         <Resource name="sql">
-            <![CDATA[select grade from (select empno from emp union select deptno from dept), salgrade]]>
+            <![CDATA[select grade
+from (select empno from emp union select deptno from dept),
+  salgrade]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1227,7 +1259,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testJoinNaturalNoCommonColumn">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp NATURAL JOIN (SELECT deptno AS foo, name FROM dept) AS d]]>
+            <![CDATA[SELECT *
+FROM emp NATURAL JOIN (SELECT deptno AS foo, name FROM dept) AS d]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1241,7 +1274,9 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testJoinNaturalMultipleCommonColumn">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp NATURAL JOIN (SELECT deptno, name AS ename FROM dept) AS d]]>
+            <![CDATA[SELECT *
+FROM emp
+NATURAL JOIN (SELECT deptno, name AS ename FROM dept) AS d]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1255,7 +1290,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testOrderOffsetFetch">
         <Resource name="sql">
-            <![CDATA[select empno from emp order by empno offset 10 rows fetch next 5 rows only]]>
+            <![CDATA[select empno from emp
+order by empno offset 10 rows fetch next 5 rows only]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1279,7 +1315,8 @@ LogicalSort(fetch=[5])
     </TestCase>
     <TestCase name="testOffsetFetch">
         <Resource name="sql">
-            <![CDATA[select empno from emp offset 10 rows fetch next 5 rows only]]>
+            <![CDATA[select empno from emp
+offset 10 rows fetch next 5 rows only]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1336,7 +1373,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testJoinOnExpression">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp JOIN dept on emp.deptno + 1 = dept.deptno - 2]]>
+            <![CDATA[SELECT * FROM emp
+JOIN dept on emp.deptno + 1 = dept.deptno - 2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1379,7 +1417,9 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     <TestCase name="testWithUnion">
         <Resource name="sql">
             <![CDATA[with emp2 as (select * from emp where deptno > 10)
-select empno from emp2 where deptno < 30 union all select deptno from emp]]>
+select empno from emp2 where deptno < 30
+union all
+select deptno from emp]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1451,7 +1491,8 @@ LogicalAggregate(group=[{}], EXPR$0=[SUM($0)])
     </TestCase>
     <TestCase name="testConditionOffByOneReversed">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp JOIN dept on dept.deptno = emp.deptno + 0]]>
+            <![CDATA[SELECT * FROM emp
+JOIN dept on dept.deptno = emp.deptno + 0]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1466,7 +1507,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testConditionOffByOne">
         <Resource name="sql">
-            <![CDATA[SELECT * FROM emp JOIN dept on emp.deptno + 0 = dept.deptno]]>
+            <![CDATA[SELECT * FROM emp
+JOIN dept on emp.deptno + 0 = dept.deptno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -1500,7 +1542,8 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
     </TestCase>
     <TestCase name="testNestedCorrelations">
         <Resource name="sql">
-            <![CDATA[select * from (select 2+deptno d2, 3+deptno d3 from emp) e
+            <![CDATA[select *
+from (select 2+deptno d2, 3+deptno d3 from emp) e
  where exists (select 1 from (select deptno+1 d1 from dept) d
  where d1=e.d2 and exists (select 2 from (select deptno+4 d4, deptno+5 d5, deptno+6 d6 from dept)
  where d4=d.d1 and d5=d.d1 and d6=e.d3))]]>
@@ -1713,7 +1756,8 @@ LogicalProject(EXPR$0=[CAST(/(SUM(+(+($1, *(2, $2)), *(3, $3))) OVER (PARTITION
     </TestCase>
     <TestCase name="testWithAlias">
         <Resource name="sql">
-            <![CDATA[with w(x, y) as (select * from dept where deptno > 10)
+            <![CDATA[with w(x, y) as
+  (select * from dept where deptno > 10)
 select x from w where x < 30 union all select deptno from dept]]>
         </Resource>
         <Resource name="plan">
@@ -1774,18 +1818,18 @@ from dept]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
-LogicalProject(NAME=[$1], EXPR$1=[CASE(=($2, 0), false, IS NOT NULL($6), true, IS NULL($4), null, <($3, $2), null, false)])
+LogicalProject(NAME=[$1], EXPR$1=[CASE(=($2, 0), false, IS NOT NULL($6), true, <($3, $2), null, false)])
   LogicalJoin(condition=[=($4, $5)], joinType=[left])
     LogicalProject($f0=[$0], $f1=[$1], $f2=[$2], $f3=[$3], $f4=[$0])
       LogicalJoin(condition=[true], joinType=[inner])
         LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
         LogicalAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0)])
           LogicalProject($f0=[$0], $f1=[true])
-            LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+            LogicalProject(EXPR$0=[CAST($7):INTEGER])
               LogicalTableScan(table=[[CATALOG, SALES, EMP]])
     LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
       LogicalProject($f0=[$0], $f1=[true])
-        LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+        LogicalProject(EXPR$0=[CAST($7):INTEGER])
           LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
         </Resource>
@@ -1805,11 +1849,11 @@ LogicalProject(EMPNO=[$0], EXPR$1=[NOT(CASE(=($9, 0), false, IS NOT NULL($13), t
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
         LogicalAggregate(group=[{}], agg#0=[COUNT()], agg#1=[COUNT($0)])
           LogicalProject($f0=[$0], $f1=[true])
-            LogicalProject(EXPR$0=[CASE(true, CAST($0):INTEGER, null)])
+            LogicalProject(EXPR$0=[CAST($0):INTEGER])
               LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
     LogicalAggregate(group=[{0}], agg#0=[MIN($1)])
       LogicalProject($f0=[$0], $f1=[true])
-        LogicalProject(EXPR$0=[CASE(true, CAST($0):INTEGER, null)])
+        LogicalProject(EXPR$0=[CAST($0):INTEGER])
           LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
         </Resource>
@@ -1958,7 +2002,8 @@ LogicalProject(EXPR$0=[$6])
     </TestCase>
     <TestCase name="testGroupingSetsCartesianProduct">
         <Resource name="sql">
-            <![CDATA[select 1 from (values (1, 2, 3, 4)) as t(a, b, c, d)
+            <![CDATA[select 1
+from (values (1, 2, 3, 4)) as t(a, b, c, d)
 group by grouping sets (a, b), grouping sets (c, d)]]>
         </Resource>
         <Resource name="plan">
@@ -1972,7 +2017,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testGroupingSetsCartesianProduct2">
         <Resource name="sql">
-            <![CDATA[select 1 from (values (1, 2, 3, 4)) as t(a, b, c, d)
+            <![CDATA[select 1
+from (values (1, 2, 3, 4)) as t(a, b, c, d)
 group by grouping sets (a, (a, b)), grouping sets (c), d]]>
         </Resource>
         <Resource name="plan">
@@ -1986,7 +2032,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testRollup">
         <Resource name="sql">
-            <![CDATA[select 1 from (values (1, 2, 3, 4)) as t(a, b, c, d)
+            <![CDATA[select 1
+from (values (1, 2, 3, 4)) as t(a, b, c, d)
 group by rollup(a, b), rollup(c, d)]]>
         </Resource>
         <Resource name="plan">
@@ -2000,7 +2047,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testCube">
         <Resource name="sql">
-            <![CDATA[select 1 from (values (1, 2, 3, 4)) as t(a, b, c, d)
+            <![CDATA[select 1
+from (values (1, 2, 3, 4)) as t(a, b, c, d)
 group by cube(a, b)]]>
         </Resource>
         <Resource name="plan">
@@ -2015,7 +2063,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testRollupTuples">
         <Resource name="sql">
-            <![CDATA[select 1 from (values (1, 2, 3, 4)) as t(a, b, c, d)
+            <![CDATA[select 1
+from (values (1, 2, 3, 4)) as t(a, b, c, d)
 group by rollup(b, (a, d))]]>
         </Resource>
         <Resource name="plan">
@@ -2061,7 +2110,9 @@ LogicalProject(A=[$0], B=[$1], C=[$4])
     </TestCase>
     <TestCase name="testGroupByExpression">
         <Resource name="sql">
-            <![CDATA[select count(*) from emp group by substring(ename FROM 1 FOR 1)]]>
+            <![CDATA[select count(*)
+from emp
+group by substring(ename FROM 1 FOR 1)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2089,7 +2140,8 @@ LogicalProject(EXPR$0=[1])
     </TestCase>
     <TestCase name="testGroupingFunctionWithGroupBy">
         <Resource name="sql">
-            <![CDATA[select deptno, grouping(deptno), count(*), grouping(empno)
+            <![CDATA[select
+  deptno, grouping(deptno), count(*), grouping(empno)
 from emp
 group by empno, deptno
 order by 2]]>
@@ -2106,7 +2158,8 @@ LogicalSort(sort0=[$1], dir0=[ASC])
     </TestCase>
     <TestCase name="testGroupingFunction">
         <Resource name="sql">
-            <![CDATA[select deptno, grouping(deptno), count(*), grouping(empno)
+            <![CDATA[select
+  deptno, grouping(deptno), count(*), grouping(empno)
 from emp
 group by rollup(empno, deptno)]]>
         </Resource>
@@ -2147,8 +2200,10 @@ LogicalAggregate(group=[{0}])
     </TestCase>
     <TestCase name="testAggNoDuplicateColumnNames">
         <Resource name="sql">
-            <![CDATA[SELECT empno, EXPR$2, COUNT(empno) FROM (SELECT empno, deptno AS EXPR$2
-FROM emp) GROUP BY empno, EXPR$2]]>
+            <![CDATA[SELECT  empno, EXPR$2, COUNT(empno) FROM (
+    SELECT empno, deptno AS EXPR$2
+    FROM emp)
+GROUP BY empno, EXPR$2]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2218,7 +2273,8 @@ LogicalDelta
     </TestCase>
     <TestCase name="testStreamGroupBy">
         <Resource name="sql">
-            <![CDATA[select stream floor(rowtime to second) as rowtime, count(*) as c
+            <![CDATA[select stream
+ floor(rowtime to second) as rowtime, count(*) as c
 from orders
 group by floor(rowtime to second)]]>
         </Resource>
@@ -2249,7 +2305,8 @@ LogicalDelta
     </TestCase>
     <TestCase name="testGroupByCaseIn">
         <Resource name="sql">
-            <![CDATA[select (CASE WHEN (deptno IN (10, 20)) THEN 0 ELSE deptno END),
+            <![CDATA[select
+ (CASE WHEN (deptno IN (10, 20)) THEN 0 ELSE deptno END),
  min(empno) from EMP
 group by (CASE WHEN (deptno IN (10, 20)) THEN 0 ELSE deptno END)]]>
         </Resource>
@@ -2263,7 +2320,10 @@ LogicalAggregate(group=[{0}], EXPR$1=[MIN($1)])
     </TestCase>
     <TestCase name="testAggFilter">
         <Resource name="sql">
-            <![CDATA[select deptno, sum(sal * 2) filter (where empno < 10), count(*) from emp group by deptno]]>
+            <![CDATA[select
+  deptno, sum(sal * 2) filter (where empno < 10), count(*)
+from emp
+group by deptno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2614,7 +2674,8 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
     </TestCase>
     <TestCase name="testWindowAggInSubQueryJoin">
         <Resource name="sql">
-            <![CDATA[select T.x, T.y, T.z, emp.empno from (select min(deptno) as x,
+            <![CDATA[select T.x, T.y, T.z, emp.empno
+from (select min(deptno) as x,
    rank() over (order by empno) as y,
    max(empno) over (partition by deptno) as z
    from emp group by deptno, empno) as T
@@ -2637,8 +2698,7 @@ LogicalProject(X=[$0], Y=[$1], Z=[$2], EMPNO=[$3])
     <TestCase name="testOrderByOver">
         <Resource name="sql">
             <![CDATA[select deptno, rank() over(partition by empno order by deptno)
-   from emp order by row_number() over(partition by empno order by deptno)
-]]>
+from emp order by row_number() over(partition by empno order by deptno)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2736,7 +2796,8 @@ LogicalProject(EMPNO=[$0])
     </TestCase>
     <TestCase name="testCorrelationNotExistsAndFilter">
         <Resource name="sql">
-            <![CDATA[SELECT e1.empno FROM emp e1, dept d1 where e1.deptno = d1.deptno
+            <![CDATA[SELECT e1.empno
+FROM emp e1, dept d1 where e1.deptno = d1.deptno
 and e1.deptno < 10 and d1.deptno < 15
 and not exists (select * from emp e2 where e1.empno = e2.empno)]]>
         </Resource>
@@ -2922,7 +2983,7 @@ from dept]]>
         <Resource name="plan">
             <![CDATA[
 LogicalProject(NAME=[$1], EXPR$1=[IN($0, {
-LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+LogicalProject(EXPR$0=[CAST($7):INTEGER])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 })])
   LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
@@ -2969,7 +3030,7 @@ from emp]]>
         <Resource name="plan">
             <![CDATA[
 LogicalProject(EMPNO=[$0], EXPR$1=[NOT(IN($7, {
-LogicalProject(EXPR$0=[CASE(true, CAST($0):INTEGER, null)])
+LogicalProject(EXPR$0=[CAST($0):INTEGER])
   LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 }))])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -3076,7 +3137,7 @@ and deptno in (
             <![CDATA[
 LogicalProject(S=[$1])
   LogicalFilter(condition=[AND(>($2, 2), IN($0, {
-LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+LogicalProject(EXPR$0=[CAST($7):INTEGER])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 }))])
     LogicalAggregate(group=[{0}], S=[SUM($1)], agg#1=[COUNT()])
@@ -3098,7 +3159,7 @@ order by (select case when true then deptno else null end from emp) desc,
 LogicalProject(S=[$0])
   LogicalSort(sort0=[$1], sort1=[$2], dir0=[DESC], dir1=[ASC])
     LogicalProject(S=[$1], EXPR$1=[$SCALAR_QUERY({
-LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+LogicalProject(EXPR$0=[CAST($7):INTEGER])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 })], EXPR$2=[$2])
       LogicalAggregate(group=[{0}], S=[SUM($1)], agg#1=[COUNT()])
@@ -3119,7 +3180,7 @@ order by (select case when true then deptno else null end from emp) desc,
 LogicalProject(ENAME=[$0])
   LogicalSort(sort0=[$1], sort1=[$0], dir0=[DESC], dir1=[ASC])
     LogicalProject(ENAME=[$1], EXPR$1=[$SCALAR_QUERY({
-LogicalProject(EXPR$0=[CASE(true, CAST($7):INTEGER, null)])
+LogicalProject(EXPR$0=[CAST($7):INTEGER])
   LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 })])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
@@ -3545,7 +3606,8 @@ LogicalAggregate(group=[{0}])
     </TestCase>
     <TestCase name="testDynStarInExistSubQ">
         <Resource name="sql">
-            <![CDATA[select * from SALES.REGION where exists (select * from SALES.NATION)]]>
+            <![CDATA[select *
+from SALES.REGION where exists (select * from SALES.NATION)]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -3575,7 +3637,7 @@ LogicalProject(**=[$0])
     </TestCase>
     <TestCase name="testInToSemiJoin">
         <Resource name="sql">
-            <![CDATA[SELECT * from SALES.NATION order by n_nationkey]]>
+            <![CDATA[SELECT empno FROM emp AS e WHERE cast(e.empno as bigint) in (130, 131, 132, 133, 134)]]>
         </Resource>
         <Resource name="planNotConverted">
             <![CDATA[

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/resources/sql/dummy.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/dummy.iq b/core/src/test/resources/sql/dummy.iq
index 166e1b0..a70271c 100644
--- a/core/src/test/resources/sql/dummy.iq
+++ b/core/src/test/resources/sql/dummy.iq
@@ -16,8 +16,17 @@
 # limitations under the License.
 #
 !use post
-values 1;
-EXPR$0
-1
+!set outputformat mysql
+values cast('-123.45' as double);
++---------+
+| EXPR$0  |
++---------+
+| -123.45 |
++---------+
+(1 row)
+
 !ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[-1.2345E2], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
 # End dummy.iq

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/core/src/test/resources/sql/misc.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq
index 1509a3c..068736b 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -1310,4 +1310,224 @@ select (case when (true) then 1 end) from (values(1));
 EXPR$0 INTEGER(10)
 !type
 
+# Cast an character literal to a timestamp; note: the plan does not contain CAST
+values cast('1969-07-21 12:34:56' as timestamp);
++---------------------+
+| EXPR$0              |
++---------------------+
+| 1969-07-21 12:34:56 |
++---------------------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[1969-07-21 12:34:56], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Cast a character literal to a date; note: the plan does not contain CAST
+values cast('1969-07-21' as date);
++------------+
+| EXPR$0     |
++------------+
+| 1969-07-21 |
++------------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[1969-07-21], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Slightly different format
+# (Incidentally, this format is not allowed in date literals, per the standard)
+values cast('1989-7-4' as date);
++------------+
+| EXPR$0     |
++------------+
+| 1989-07-04 |
++------------+
+(1 row)
+
+!ok
+
+# Cast a character literal to an integer; note: the plan does not contain CAST
+values cast('196907' as integer);
++--------+
+| EXPR$0 |
++--------+
+| 196907 |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[196907], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Cast an integer literal to a bigint; note: the plan does not contain CAST
+values cast(123 as bigint);
++--------+
+| EXPR$0 |
++--------+
+|    123 |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[123], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Cast an integer literal to a decimal; note: the plan does not contain CAST
+values cast('123.45' as decimal(4, 2));
++--------+
+| EXPR$0 |
++--------+
+| 123.45 |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[123.45], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Cast a character literal to a decimal; note: the plan does not contain CAST
+values cast('123.45' as decimal(4, 2));
++--------+
+| EXPR$0 |
++--------+
+| 123.45 |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[123.45], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+# Cast a character literal to a double; note: the plan does not contain CAST
+values cast('-123.45' as double);
++---------+
+| EXPR$0  |
++---------+
+| -123.45 |
++---------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[-1.2345E2], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+values cast('false' as boolean);
++--------+
+| EXPR$0 |
++--------+
+| false  |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[false], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+values cast('TRUE' as boolean);
++--------+
+| EXPR$0 |
++--------+
+| true   |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=[true], EXPR$0=[$t1])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+values cast('TR' || 'UE' as boolean);
++--------+
+| EXPR$0 |
++--------+
+| true   |
++--------+
+(1 row)
+
+!ok
+EnumerableCalc(expr#0=[{inputs}], expr#1=['TR'], expr#2=['UE'], expr#3=[||($t1, $t2)], expr#4=[CAST($t3):BOOLEAN NOT NULL], EXPR$0=[$t4])
+  EnumerableValues(tuples=[[{ 0 }]])
+!plan
+
+!if (fixed.calcite1439) {
+values cast('null' as boolean);
+!error
+!plan
+
+values cast('' as date);
+!error
+
+values cast('' as timestamp);
+!error
+
+values cast('' as integer);
+!error
+
+values cast('' as boolean);
+!error
+
+values cast('' as double);
+!error
+
+# Postgres fails:
+#  ERROR:  invalid input syntax for integer: "1.56"
+values cast('15.6' as integer);
+!error
+
+# Postgres fails:
+#  ERROR:  invalid input syntax for integer: " - 5 "
+values cast(' - 5 ' as double);
+!error
+
+# Out of TINYINT range (max 127)
+values cast('200' as tinyint);
+!error
+
+# Out of SMALLINT range (max 32767)
+values cast('50000' as smallint);
+!error
+
+# Out of INTEGER range (max 2.1e9)
+values cast('4567891234' as integer);
+!error
+
+# Out of BIGINT range (max 9.2e18)
+values cast('12345678901234567890' as bigint);
+!error
+
+# Out of REAL range
+values cast('12.34e56' as real);
+!error
+
+# Out of FLOAT range
+values cast('12.34e5678' as float);
+!error
+
+# Out of DOUBLE range
+values cast('12.34e5678' as double);
+!error
+
+!}
+
+# Postgres succeeds
+values cast(' -5 ' as double);
++--------+
+| EXPR$0 |
++--------+
+|   -5.0 |
++--------+
+(1 row)
+
+!ok
+
 # End misc.iq

http://git-wip-us.apache.org/repos/asf/calcite/blob/54556b82/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 65ade8e..4c81b60 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
@@ -16,7 +16,6 @@
  */
 package org.apache.calcite.adapter.druid;
 
-import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexCall;
@@ -24,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.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
 import com.google.common.base.Function;
@@ -38,10 +38,7 @@ import org.joda.time.chrono.ISOChronology;
 
 import org.slf4j.Logger;
 
-import java.sql.Date;
-import java.sql.Timestamp;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 import java.util.regex.Pattern;
@@ -67,7 +64,7 @@ public class DruidDateTimeUtils {
    * reference a single column: the timestamp column.
    */
   public static List<Interval> createInterval(RelDataType type, RexNode e) {
-    final List<Range> ranges = extractRanges(type, e, false);
+    final List<Range<Calendar>> ranges = extractRanges(e, false);
     if (ranges == null) {
       // We did not succeed, bail out
       return null;
@@ -82,32 +79,37 @@ public class DruidDateTimeUtils {
     return toInterval(ImmutableList.<Range>copyOf(condensedRanges.asRanges()));
   }
 
-  protected static List<Interval> toInterval(List<Range> ranges) {
-    List<Interval> intervals = Lists.transform(ranges, new Function<Range, Interval>() {
-      @Override public Interval apply(Range range) {
-        if (!range.hasLowerBound() && !range.hasUpperBound()) {
-          return DruidTable.DEFAULT_INTERVAL;
-        }
-        long start = range.hasLowerBound() ? toLong(range.lowerEndpoint())
-            : DruidTable.DEFAULT_INTERVAL.getStartMillis();
-        long end = range.hasUpperBound() ? toLong(range.upperEndpoint())
-            : DruidTable.DEFAULT_INTERVAL.getEndMillis();
-        if (range.hasLowerBound() && range.lowerBoundType() == BoundType.OPEN) {
-          start++;
-        }
-        if (range.hasUpperBound() && range.upperBoundType() == BoundType.CLOSED) {
-          end++;
-        }
-        return new Interval(start, end, ISOChronology.getInstanceUTC());
-      }
-    });
+  protected static List<Interval> toInterval(List<Range<Calendar>> ranges) {
+    List<Interval> intervals = Lists.transform(ranges,
+        new Function<Range<Calendar>, Interval>() {
+          @Override public Interval apply(Range<Calendar> range) {
+            if (!range.hasLowerBound() && !range.hasUpperBound()) {
+              return DruidTable.DEFAULT_INTERVAL;
+            }
+            long start = range.hasLowerBound()
+                ? range.lowerEndpoint().getTime().getTime()
+                : DruidTable.DEFAULT_INTERVAL.getStartMillis();
+            long end = range.hasUpperBound()
+                ? range.upperEndpoint().getTime().getTime()
+                : DruidTable.DEFAULT_INTERVAL.getEndMillis();
+            if (range.hasLowerBound()
+                && range.lowerBoundType() == BoundType.OPEN) {
+              start++;
+            }
+            if (range.hasUpperBound()
+                && range.upperBoundType() == BoundType.CLOSED) {
+              end++;
+            }
+            return new Interval(start, end, ISOChronology.getInstanceUTC());
+          }
+        });
     if (LOGGER.isInfoEnabled()) {
       LOGGER.info("Converted time ranges " + ranges + " to interval " + intervals);
     }
     return intervals;
   }
 
-  protected static List<Range> extractRanges(RelDataType type, RexNode node,
+  protected static List<Range<Calendar>> extractRanges(RexNode node,
       boolean withNot) {
     switch (node.getKind()) {
     case EQUALS:
@@ -117,16 +119,16 @@ public class DruidDateTimeUtils {
     case GREATER_THAN_OR_EQUAL:
     case BETWEEN:
     case IN:
-      return leafToRanges(type, (RexCall) node, withNot);
+      return leafToRanges((RexCall) node, withNot);
 
     case NOT:
-      return extractRanges(type, ((RexCall) node).getOperands().get(0), !withNot);
+      return extractRanges(((RexCall) node).getOperands().get(0), !withNot);
 
     case OR: {
       RexCall call = (RexCall) node;
-      List<Range> intervals = Lists.newArrayList();
+      List<Range<Calendar>> intervals = Lists.newArrayList();
       for (RexNode child : call.getOperands()) {
-        List<Range> extracted = extractRanges(type, child, withNot);
+        List<Range<Calendar>> extracted = extractRanges(child, withNot);
         if (extracted != null) {
           intervals.addAll(extracted);
         }
@@ -136,9 +138,9 @@ public class DruidDateTimeUtils {
 
     case AND: {
       RexCall call = (RexCall) node;
-      List<Range> ranges = new ArrayList<>();
+      List<Range<Calendar>> ranges = new ArrayList<>();
       for (RexNode child : call.getOperands()) {
-        List<Range> extractedRanges = extractRanges(type, child, false);
+        List<Range<Calendar>> extractedRanges = extractRanges(child, false);
         if (extractedRanges == null || extractedRanges.isEmpty()) {
           // We could not extract, we bail out
           return null;
@@ -147,7 +149,7 @@ public class DruidDateTimeUtils {
           ranges.addAll(extractedRanges);
           continue;
         }
-        List<Range> overlapped = Lists.newArrayList();
+        List<Range<Calendar>> overlapped = new ArrayList<>();
         for (Range current : ranges) {
           for (Range interval : extractedRanges) {
             if (current.isConnected(interval)) {
@@ -165,7 +167,7 @@ public class DruidDateTimeUtils {
     }
   }
 
-  protected static List<Range> leafToRanges(RelDataType type, RexCall call,
+  protected static List<Range<Calendar>> leafToRanges(RexCall call,
       boolean withNot) {
     switch (call.getKind()) {
     case EQUALS:
@@ -174,246 +176,81 @@ public class DruidDateTimeUtils {
     case GREATER_THAN:
     case GREATER_THAN_OR_EQUAL:
     {
-      RexLiteral literal = null;
+      final Calendar value;
       if (call.getOperands().get(0) instanceof RexInputRef
-          && call.getOperands().get(1) instanceof RexLiteral) {
-        literal = extractLiteral(call.getOperands().get(1));
-      } else if (call.getOperands().get(0) instanceof RexInputRef
-          && call.getOperands().get(1).getKind() == SqlKind.CAST) {
-        literal = extractLiteral(call.getOperands().get(1));
-      } else if (call.getOperands().get(1) instanceof RexInputRef
-          && call.getOperands().get(0) instanceof RexLiteral) {
-        literal = extractLiteral(call.getOperands().get(0));
+          && literalValue(call.getOperands().get(1)) != null) {
+        value = literalValue(call.getOperands().get(1));
       } else if (call.getOperands().get(1) instanceof RexInputRef
-          && call.getOperands().get(0).getKind() == SqlKind.CAST) {
-        literal = extractLiteral(call.getOperands().get(0));
-      }
-      if (literal == null) {
-        return null;
-      }
-      Comparable value = literalToType(literal, type);
-      if (value == null) {
+          && literalValue(call.getOperands().get(0)) != null) {
+        value = literalValue(call.getOperands().get(0));
+      } else {
         return null;
       }
       switch (call.getKind()) {
       case LESS_THAN:
-        return Arrays.<Range>asList(withNot ? Range.atLeast(value) : Range.lessThan(value));
+        return ImmutableList.of(withNot ? Range.atLeast(value) : Range.lessThan(value));
       case LESS_THAN_OR_EQUAL:
-        return Arrays.<Range>asList(withNot ? Range.greaterThan(value) : Range.atMost(value));
+        return ImmutableList.of(withNot ? Range.greaterThan(value) : Range.atMost(value));
       case GREATER_THAN:
-        return Arrays.<Range>asList(withNot ? Range.atMost(value) : Range.greaterThan(value));
+        return ImmutableList.of(withNot ? Range.atMost(value) : Range.greaterThan(value));
       case GREATER_THAN_OR_EQUAL:
-        return Arrays.<Range>asList(withNot ? Range.lessThan(value) : Range.atLeast(value));
+        return ImmutableList.of(withNot ? Range.lessThan(value) : Range.atLeast(value));
       default:
         if (!withNot) {
-          return Arrays.<Range>asList(Range.closed(value, value));
+          return ImmutableList.of(Range.closed(value, value));
         }
-        return Arrays.<Range>asList(Range.lessThan(value), Range.greaterThan(value));
+        return ImmutableList.of(Range.lessThan(value), Range.greaterThan(value));
       }
     }
     case BETWEEN:
     {
-      RexLiteral literal1 = extractLiteral(call.getOperands().get(2));
-      if (literal1 == null) {
-        return null;
-      }
-      RexLiteral literal2 = extractLiteral(call.getOperands().get(3));
-      if (literal2 == null) {
-        return null;
-      }
-      Comparable value1 = literalToType(literal1, type);
-      Comparable value2 = literalToType(literal2, type);
-      if (value1 == null || value2 == null) {
+      final Calendar value1;
+      final Calendar value2;
+      if (literalValue(call.getOperands().get(2)) != null
+          && literalValue(call.getOperands().get(3)) != null) {
+        value1 = literalValue(call.getOperands().get(2));
+        value2 = literalValue(call.getOperands().get(3));
+      } else {
         return null;
       }
+
       boolean inverted = value1.compareTo(value2) > 0;
       if (!withNot) {
-        return Arrays.<Range>asList(
+        return ImmutableList.of(
             inverted ? Range.closed(value2, value1) : Range.closed(value1, value2));
       }
-      return Arrays.<Range>asList(Range.lessThan(inverted ? value2 : value1),
+      return ImmutableList.of(Range.lessThan(inverted ? value2 : value1),
           Range.greaterThan(inverted ? value1 : value2));
     }
     case IN:
     {
-      List<Range> ranges = Lists.newArrayList();
-      for (int i = 1; i < call.getOperands().size(); i++) {
-        RexLiteral literal = extractLiteral(call.getOperands().get(i));
-        if (literal == null) {
-          return null;
-        }
-        Comparable element = literalToType(literal, type);
+      ImmutableList.Builder<Range<Calendar>> ranges = ImmutableList.builder();
+      for (RexNode operand : Util.skip(call.operands)) {
+        final Calendar element = literalValue(operand);
         if (element == null) {
           return null;
         }
         if (withNot) {
-          ranges.addAll(
-              Arrays.<Range>asList(Range.lessThan(element), Range.greaterThan(element)));
+          ranges.add(Range.lessThan(element));
+          ranges.add(Range.greaterThan(element));
         } else {
           ranges.add(Range.closed(element, element));
         }
       }
-      return ranges;
+      return ranges.build();
     }
     default:
       return null;
     }
   }
 
-  @SuppressWarnings("incomplete-switch")
-  protected static Comparable literalToType(RexLiteral literal, RelDataType type) {
-    // Extract
-    Object value = null;
-    switch (literal.getType().getSqlTypeName()) {
-    case DATE:
-    case TIME:
-    case TIMESTAMP:
-    case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY:
-      value = literal.getValue();
-      break;
-    case TINYINT:
-    case SMALLINT:
-    case INTEGER:
-    case BIGINT:
-    case DOUBLE:
-    case DECIMAL:
-    case FLOAT:
-    case REAL:
-    case VARCHAR:
-    case CHAR:
-    case BOOLEAN:
-      value = literal.getValue3();
-    }
-    if (value == null) {
-      return null;
-    }
-
-    // Convert
-    switch (type.getSqlTypeName()) {
-    case BIGINT:
-      return toLong(value);
-    case INTEGER:
-      return toInt(value);
-    case FLOAT:
-      return toFloat(value);
-    case DOUBLE:
-      return toDouble(value);
-    case VARCHAR:
-    case CHAR:
-      return String.valueOf(value);
-    case TIMESTAMP:
-      return toTimestamp(value);
-    }
-    return null;
-  }
-
-  private static RexLiteral extractLiteral(RexNode node) {
-    RexNode target = node;
-    if (node.getKind() == SqlKind.CAST) {
-      target = ((RexCall) node).getOperands().get(0);
-    }
-    if (!(target instanceof RexLiteral)) {
-      return null;
-    }
-    return (RexLiteral) target;
-  }
-
-  private static Comparable toTimestamp(Object literal) {
-    if (literal instanceof Timestamp) {
-      return (Timestamp) literal;
-    }
-    final Long v = toLong(literal);
-    if (v != null) {
-      return new Timestamp(v);
-    }
-    return null;
-  }
-
-  private static Long toLong(Object literal) {
-    if (literal instanceof Number) {
-      return ((Number) literal).longValue();
-    }
-    if (literal instanceof Date) {
-      return ((Date) literal).getTime();
-    }
-    if (literal instanceof Timestamp) {
-      return ((Timestamp) literal).getTime();
-    }
-    if (literal instanceof Calendar) {
-      return ((Calendar) literal).getTime().getTime();
-    }
-    if (literal instanceof String) {
-      final String s = (String) literal;
-      try {
-        return Long.valueOf(s);
-      } catch (NumberFormatException e) {
-        // ignore
-      }
-      if (TIMESTAMP_PATTERN.matcher(s).matches()) {
-        return DateTimeUtils.timestampStringToUnixDate(s);
-      }
-    }
-    return null;
-  }
-
-
-  private static Integer toInt(Object literal) {
-    if (literal instanceof Number) {
-      return ((Number) literal).intValue();
-    }
-    if (literal instanceof String) {
-      try {
-        return Integer.valueOf((String) literal);
-      } catch (NumberFormatException e) {
-        // ignore
-      }
-    }
-    return null;
-  }
-
-  private static Float toFloat(Object literal) {
-    if (literal instanceof Number) {
-      return ((Number) literal).floatValue();
-    }
-    if (literal instanceof String) {
-      try {
-        return Float.valueOf((String) literal);
-      } catch (NumberFormatException e) {
-        // ignore
-      }
+  private static Calendar literalValue(RexNode node) {
+    if (node instanceof RexLiteral) {
+      return (Calendar) ((RexLiteral) node).getValue();
     }
     return null;
   }
 
-  private static Double toDouble(Object literal) {
-    if (literal instanceof Number) {
-      return ((Number) literal).doubleValue();
-    }
-    if (literal instanceof String) {
-      try {
-        return Double.valueOf((String) literal);
-      } catch (NumberFormatException e) {
-        // ignore
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Extract the total time span covered by these intervals. It does not check
-   * if the intervals overlap.
-   * @param intervals list of intervals
-   * @return total time span covered by these intervals
-   */
-  public static long extractTotalTime(List<Interval> intervals) {
-    long totalTime = 0;
-    for (Interval interval : intervals) {
-      totalTime += interval.getEndMillis() - interval.getStartMillis();
-    }
-    return totalTime;
-  }
-
   /**
    * Extracts granularity from a call {@code FLOOR(<time> TO <timeunit>)}.
    * Timeunit specifies the granularity. Returns null if it cannot