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/07/01 19:18:09 UTC

calcite git commit: [CALCITE-1302] Create SqlTypeName values for each interval range, e.g. YEAR_MONTH

Repository: calcite
Updated Branches:
  refs/heads/master 5511253b5 -> ac9c8c7af


[CALCITE-1302] Create SqlTypeName values for each interval range, e.g. YEAR_MONTH

As a result, we don't need to use SqlIntervalQualifier as often. Also,
the JDBC client gets more information from the type.

Change the CalciteAssert.checkResultCount API.


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

Branch: refs/heads/master
Commit: ac9c8c7af020a0532e3e7e31b4216f69d9f0b39f
Parents: 5511253
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jun 27 23:57:41 2016 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Jul 1 11:11:10 2016 -0700

----------------------------------------------------------------------
 .../calcite/adapter/enumerable/RexImpTable.java |  36 +++-
 .../adapter/enumerable/RexToLixTranslator.java  |  42 ++++-
 .../calcite/jdbc/JavaTypeFactoryImpl.java       |  13 +-
 .../calcite/prepare/CalcitePrepareImpl.java     |  21 ++-
 .../apache/calcite/rel/metadata/RelMdSize.java  |  30 +++-
 .../calcite/rel/type/RelDataTypeSystemImpl.java |  52 +++++-
 .../java/org/apache/calcite/rex/RexBuilder.java |  67 ++++++--
 .../java/org/apache/calcite/rex/RexLiteral.java |  39 ++++-
 .../calcite/sql/SqlIntervalQualifier.java       |  46 +++++-
 .../java/org/apache/calcite/sql/SqlLiteral.java |  44 +++--
 .../calcite/sql/type/IntervalSqlType.java       |  27 +--
 .../sql/type/MatchReturnTypeInference.java      |   8 +-
 .../sql/type/SqlTypeAssignmentRules.java        | 111 +++++--------
 .../sql/type/SqlTypeExplicitPrecedenceList.java |  39 ++++-
 .../calcite/sql/type/SqlTypeFactoryImpl.java    |   4 +-
 .../apache/calcite/sql/type/SqlTypeFamily.java  |   8 +-
 .../apache/calcite/sql/type/SqlTypeName.java    | 164 ++++++++++++++++++-
 .../apache/calcite/sql/type/SqlTypeUtil.java    |   3 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |  13 +-
 .../sql2rel/SqlNodeToRexConverterImpl.java      |  13 +-
 .../sql2rel/StandardConvertletTable.java        |  73 ++++++++-
 .../main/java/org/apache/calcite/util/Util.java |   3 +-
 .../calcite/jdbc/CalciteRemoteDriverTest.java   |   2 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   |  24 +++
 .../org/apache/calcite/test/CalciteAssert.java  |  12 +-
 .../apache/calcite/test/SqlValidatorTest.java   |  31 +---
 26 files changed, 710 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 2ac0dc9..22f2249 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
@@ -45,7 +45,6 @@ import org.apache.calcite.schema.ImplementableFunction;
 import org.apache.calcite.schema.impl.AggregateFunctionImpl;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlBinaryOperator;
-import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlTrimFunction;
@@ -1962,7 +1961,16 @@ public class RexImpTable {
       switch (operand0.getType().getSqlTypeName()) {
       case DATE:
         switch (typeName1) {
-        case INTERVAL_DAY_TIME:
+        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:
           trop1 =
               Expressions.convert_(
                   Expressions.divide(trop1,
@@ -1974,16 +1982,26 @@ public class RexImpTable {
         trop1 = Expressions.convert_(trop1, int.class);
         break;
       }
-      final SqlIntervalQualifier interval = call.getType().getIntervalQualifier();
       switch (typeName1) {
+      case INTERVAL_YEAR:
       case INTERVAL_YEAR_MONTH:
+      case INTERVAL_MONTH:
         switch (call.getKind()) {
         case MINUS:
           trop1 = Expressions.negate(trop1);
         }
         return Expressions.call(BuiltInMethod.ADD_MONTHS.method, trop0, trop1);
 
-      case INTERVAL_DAY_TIME:
+      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:
         switch (call.getKind()) {
         case MINUS:
           return Expressions.subtract(trop0, trop1);
@@ -1994,17 +2012,19 @@ public class RexImpTable {
       default:
         switch (call.getKind()) {
         case MINUS:
-          Class targetType = interval.isYearMonth() ? int.class : long.class;
-          if (interval.isYearMonth()) {
+          switch (call.getType().getSqlTypeName()) {
+          case INTERVAL_YEAR:
+          case INTERVAL_YEAR_MONTH:
+          case INTERVAL_MONTH:
             return Expressions.call(BuiltInMethod.SUBTRACT_MONTHS.method,
                 trop0, trop1);
           }
           TimeUnit fromUnit =
               typeName1 == SqlTypeName.DATE ? TimeUnit.DAY : TimeUnit.MILLISECOND;
-          TimeUnit toUnit = interval.isYearMonth() ? TimeUnit.MONTH : TimeUnit.MILLISECOND;
+          TimeUnit toUnit = TimeUnit.MILLISECOND;
           return multiplyDivide(
               Expressions.convert_(Expressions.subtract(trop0, trop1),
-                  targetType),
+                  (Class) long.class),
               fromUnit.multiplier, toUnit.multiplier);
         default:
           return Expressions.add(trop0, trop1);

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 2a93c0a..333e183 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -323,7 +323,9 @@ public class RexToLixTranslator {
                 BuiltInMethod.UNIX_TIMESTAMP_TO_STRING.method,
                 operand));
         break;
+      case INTERVAL_YEAR:
       case INTERVAL_YEAR_MONTH:
+      case INTERVAL_MONTH:
         convert = RexImpTable.optimize2(
             operand,
             Expressions.call(
@@ -331,7 +333,16 @@ public class RexToLixTranslator {
                 operand,
                 Expressions.constant(interval.timeUnitRange)));
         break;
-      case INTERVAL_DAY_TIME:
+      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:
         convert = RexImpTable.optimize2(
             operand,
             Expressions.call(
@@ -413,12 +424,22 @@ public class RexToLixTranslator {
                     (long) Math.pow(10, 3 - targetScale)));
       }
       break;
-    case INTERVAL_DAY_TIME:
+    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:
       switch (sourceType.getSqlTypeName().getFamily()) {
       case NUMERIC:
-        final SqlIntervalQualifier interval = targetType.getIntervalQualifier();
-        final BigDecimal multiplier = interval.getUnit().multiplier;
+        final BigDecimal multiplier = targetType.getSqlTypeName().getEndUnit().multiplier;
         final BigDecimal divider = BigDecimal.ONE;
         convert = RexImpTable.multiplyDivide(convert, multiplier, divider);
       }
@@ -614,11 +635,22 @@ public class RexToLixTranslator {
       value2 = ((Calendar) value).getTimeInMillis();
       javaClass = long.class;
       break;
-    case INTERVAL_DAY_TIME:
+    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:
       value2 = ((BigDecimal) value).longValue();
       javaClass = long.class;
       break;
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
       value2 = ((BigDecimal) value).intValue();
       javaClass = int.class;
       break;

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
index 45e935f..a1f6e3f 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
@@ -176,11 +176,22 @@ public class JavaTypeFactoryImpl
       case DATE:
       case TIME:
       case INTEGER:
+      case INTERVAL_YEAR:
       case INTERVAL_YEAR_MONTH:
+      case INTERVAL_MONTH:
         return type.isNullable() ? Integer.class : int.class;
       case TIMESTAMP:
       case BIGINT:
-      case INTERVAL_DAY_TIME:
+      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:
         return type.isNullable() ? Long.class : long.class;
       case SMALLINT:
         return type.isNullable() ? Short.class : short.class;

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 60a76bb..bfc1ce2 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -912,18 +912,27 @@ public class CalcitePrepareImpl implements CalcitePrepare {
   private static String getTypeName(RelDataType type) {
     final SqlTypeName sqlTypeName = type.getSqlTypeName();
     switch (sqlTypeName) {
-    case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
-      // e.g. "INTERVAL_MONTH" or "INTERVAL_YEAR_MONTH"
-      return "INTERVAL_"
-          + type.getIntervalQualifier().toString().replace(' ', '_');
     case ARRAY:
     case MULTISET:
     case MAP:
     case ROW:
       return type.toString(); // e.g. "INTEGER ARRAY"
+    case INTERVAL_YEAR_MONTH:
+      return "INTERVAL_YEAR_TO_MONTH";
+    case INTERVAL_DAY_HOUR:
+      return "INTERVAL_DAY_TO_HOUR";
+    case INTERVAL_DAY_MINUTE:
+      return "INTERVAL_DAY_TO_MINUTE";
+    case INTERVAL_DAY_SECOND:
+      return "INTERVAL_DAY_TO_SECOND";
+    case INTERVAL_HOUR_MINUTE:
+      return "INTERVAL_HOUR_TO_MINUTE";
+    case INTERVAL_HOUR_SECOND:
+      return "INTERVAL_HOUR_TO_SECOND";
+    case INTERVAL_MINUTE_SECOND:
+      return "INTERVAL_MINUTE_TO_SECOND";
     default:
-      return sqlTypeName.getName(); // e.g. "DECIMAL"
+      return sqlTypeName.getName(); // e.g. "DECIMAL", "INTERVAL_YEAR_MONTH"
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
index 0fd808e..744d241 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
@@ -280,13 +280,24 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
     case DECIMAL:
     case DATE:
     case TIME:
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
       return 4d;
     case BIGINT:
     case DOUBLE:
     case FLOAT: // sic
     case TIMESTAMP:
-    case INTERVAL_DAY_TIME:
-    case INTERVAL_YEAR_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:
       return 8d;
     case BINARY:
       return (double) type.getPrecision();
@@ -327,12 +338,23 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
     case REAL:
     case DATE:
     case TIME:
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
       return 4d;
     case BIGINT:
     case DOUBLE:
     case TIMESTAMP:
-    case INTERVAL_DAY_TIME:
-    case INTERVAL_YEAR_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:
       return 8d;
     case BINARY:
     case VARBINARY:

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
index c34c2e6..677173f 100644
--- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
+++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeSystemImpl.java
@@ -37,8 +37,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
     switch (typeName) {
     case DECIMAL:
       return getMaxNumericScale();
-    case INTERVAL_DAY_TIME:
+    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:
       return SqlTypeName.MAX_INTERVAL_FRACTIONAL_SECOND_PRECISION;
     default:
       return -1;
@@ -55,8 +66,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
       return 1;
     case DECIMAL:
       return getMaxNumericPrecision();
-    case INTERVAL_DAY_TIME:
+    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:
       return SqlTypeName.DEFAULT_INTERVAL_START_PRECISION;
     case BOOLEAN:
       return 1;
@@ -99,8 +121,19 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
     case TIME:
     case TIMESTAMP:
       return SqlTypeName.MAX_DATETIME_PRECISION;
-    case INTERVAL_DAY_TIME:
+    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:
       return SqlTypeName.MAX_INTERVAL_START_PRECISION;
     default:
       return getDefaultPrecision(typeName);
@@ -125,9 +158,20 @@ public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
       return isPrefix ? "x'" : "'";
     case TIMESTAMP:
       return isPrefix ? "TIMESTAMP '" : "'";
-    case INTERVAL_DAY_TIME:
+    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:
       return isPrefix ? "INTERVAL '" : "' DAY";
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
       return isPrefix ? "INTERVAL '" : "' YEAR TO MONTH";
     case TIME:
       return isPrefix ? "TIME '" : "'";

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 825fdb9..a062ba5 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -38,7 +38,6 @@ import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.fun.SqlCountAggFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.ArraySqlType;
-import org.apache.calcite.sql.type.IntervalSqlType;
 import org.apache.calcite.sql.type.MapSqlType;
 import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeFamily;
@@ -73,7 +72,8 @@ public class RexBuilder {
    */
   public static final SqlSpecialOperator GET_OPERATOR =
       new SqlSpecialOperator("_get", SqlKind.OTHER_FUNCTION);
-  public static final Function<RelDataTypeField, RexInputRef> TO_INPUT_REF =
+
+  private static final Function<RelDataTypeField, RexInputRef> TO_INPUT_REF =
       new Function<RelDataTypeField, RexInputRef>() {
         public RexInputRef apply(RelDataTypeField input) {
           return new RexInputRef(input.getIndex(), input.getType());
@@ -509,7 +509,16 @@ public class RexBuilder {
                   calendar.getTimeInMillis(),
                   DateTimeUtils.powerX(10, 3 - scale)));
           break;
-        case INTERVAL_DAY_TIME:
+        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:
           assert value instanceof BigDecimal;
           typeName = type.getSqlTypeName();
           switch (typeName) {
@@ -522,9 +531,9 @@ public class RexBuilder {
           case DECIMAL:
             BigDecimal value2 = (BigDecimal) value;
             final BigDecimal multiplier =
-                baseUnit(literal.getType().getIntervalQualifier().getUnit()).multiplier;
+                baseUnit(literal.getTypeName()).multiplier;
             final BigDecimal divider =
-                literal.getType().getIntervalQualifier().getUnit().multiplier;
+                literal.getTypeName().getEndUnit().multiplier;
             value = value2.multiply(multiplier)
                 .divide(divider, 0, BigDecimal.ROUND_HALF_DOWN);
           }
@@ -560,8 +569,8 @@ public class RexBuilder {
   /** Returns the lowest granularity unit for the given unit.
    * YEAR and MONTH intervals are stored as months;
    * HOUR, MINUTE, SECOND intervals are stored as milliseconds. */
-  protected static TimeUnit baseUnit(TimeUnit unit) {
-    if (unit.yearMonth) {
+  protected static TimeUnit baseUnit(SqlTypeName unit) {
+    if (unit.isYearMonth()) {
       return TimeUnit.MONTH;
     } else {
       return TimeUnit.MILLISECOND;
@@ -624,9 +633,8 @@ public class RexBuilder {
   }
 
   private RexNode makeCastIntervalToExact(RelDataType toType, RexNode exp) {
-    final IntervalSqlType intervalType = (IntervalSqlType) exp.getType();
-    final TimeUnit endUnit = intervalType.getIntervalQualifier().getUnit();
-    final TimeUnit baseUnit = baseUnit(endUnit);
+    final TimeUnit endUnit = exp.getType().getSqlTypeName().getEndUnit();
+    final TimeUnit baseUnit = baseUnit(exp.getType().getSqlTypeName());
     final BigDecimal multiplier = baseUnit.multiplier;
     final int scale = 0;
     BigDecimal divider = endUnit.multiplier.scaleByPowerOfTen(-scale);
@@ -636,14 +644,14 @@ public class RexBuilder {
       RelDataType decimalType =
           getTypeFactory().createSqlType(
               SqlTypeName.DECIMAL,
-              scale + intervalType.getPrecision(),
+              scale + exp.getType().getPrecision(),
               scale);
       value = encodeIntervalOrDecimal(value, decimalType, false);
     }
     return ensureType(toType, value, false);
   }
 
-  private RexNode multiplyDivide(RexNode e, BigDecimal multiplier,
+  public RexNode multiplyDivide(RexNode e, BigDecimal multiplier,
       BigDecimal divider) {
     assert multiplier.signum() > 0;
     assert divider.signum() > 0;
@@ -1063,7 +1071,8 @@ public class RexBuilder {
   }
 
   /**
-   * Creates an interval literal.
+   * Creates a literal representing an interval type, for example
+   * {@code YEAR TO MONTH} or {@code DOW}.
    */
   public RexLiteral makeIntervalLiteral(
       SqlIntervalQualifier intervalQualifier) {
@@ -1072,7 +1081,8 @@ public class RexBuilder {
   }
 
   /**
-   * Creates an interval literal.
+   * Creates a literal representing an interval value, for example
+   * {@code INTERVAL '3-7' YEAR TO MONTH}.
    */
   public RexLiteral makeIntervalLiteral(
       BigDecimal v,
@@ -1080,8 +1090,7 @@ public class RexBuilder {
     return makeLiteral(
         v,
         typeFactory.createSqlIntervalType(intervalQualifier),
-        intervalQualifier.isYearMonth() ? SqlTypeName.INTERVAL_YEAR_MONTH
-            : SqlTypeName.INTERVAL_DAY_TIME);
+        intervalQualifier.typeName());
   }
 
   /**
@@ -1257,8 +1266,19 @@ public class RexBuilder {
       return makeDateLiteral((Calendar) value);
     case TIMESTAMP:
       return makeTimestampLiteral((Calendar) value, type.getPrecision());
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
+    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:
       return makeIntervalLiteral((BigDecimal) value,
           type.getIntervalQualifier());
     case MAP:
@@ -1330,8 +1350,19 @@ public class RexBuilder {
     case INTEGER:
     case BIGINT:
     case DECIMAL:
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
+    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:
       if (o instanceof BigDecimal) {
         return o;
       }

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index 8af8a06..c9ffc1b 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -215,8 +215,19 @@ public class RexLiteral extends RexNode {
     case TIME:
     case TIMESTAMP:
       return value instanceof Calendar;
-    case INTERVAL_DAY_TIME:
+    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:
       // The value of a DAY-TIME interval (whatever the start and end units,
       // even say HOUR TO MINUTE) is in milliseconds (perhaps fractional
       // milliseconds). The value of a YEAR-MONTH interval is in months.
@@ -386,8 +397,19 @@ public class RexLiteral extends RexNode {
     case TIMESTAMP:
       printDatetime(pw, new ZonelessTimestamp(), value);
       break;
-    case INTERVAL_DAY_TIME:
+    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:
       if (value instanceof BigDecimal) {
         pw.print(value.toString());
       } else {
@@ -469,13 +491,24 @@ public class RexLiteral extends RexNode {
       return new RexLiteral(new ByteString(bytes), type, typeName);
     case NULL:
       return new RexLiteral(null, type, typeName);
-    case INTERVAL_DAY_TIME:
+    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:
       long millis =
           SqlParserUtil.intervalToMillis(
               literal,
               type.getIntervalQualifier());
       return new RexLiteral(BigDecimal.valueOf(millis), type, typeName);
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
       long months =
           SqlParserUtil.intervalToMonths(
               literal,

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
index 5255047..9be154c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
@@ -107,6 +107,9 @@ public class SqlIntervalQualifier extends SqlNode {
       int fractionalSecondPrecision,
       SqlParserPos pos) {
     super(pos);
+    if (endUnit == startUnit) {
+      endUnit = null;
+    }
     this.timeUnitRange =
         TimeUnitRange.of(Preconditions.checkNotNull(startUnit), endUnit);
     this.startPrecision = startPrecision;
@@ -128,9 +131,46 @@ public class SqlIntervalQualifier extends SqlNode {
   //~ Methods ----------------------------------------------------------------
 
   public SqlTypeName typeName() {
-    return isYearMonth()
-        ? SqlTypeName.INTERVAL_YEAR_MONTH
-        : SqlTypeName.INTERVAL_DAY_TIME;
+    switch (timeUnitRange) {
+    case YEAR:
+    case CENTURY:
+    case DECADE:
+    case MILLENNIUM:
+      return SqlTypeName.INTERVAL_YEAR;
+    case YEAR_TO_MONTH:
+      return SqlTypeName.INTERVAL_YEAR_MONTH;
+    case MONTH:
+    case QUARTER:
+      return SqlTypeName.INTERVAL_MONTH;
+    case DOW:
+    case DOY:
+    case DAY:
+    case WEEK:
+      return SqlTypeName.INTERVAL_DAY;
+    case DAY_TO_HOUR:
+      return SqlTypeName.INTERVAL_DAY_HOUR;
+    case DAY_TO_MINUTE:
+      return SqlTypeName.INTERVAL_DAY_MINUTE;
+    case DAY_TO_SECOND:
+      return SqlTypeName.INTERVAL_DAY_SECOND;
+    case HOUR:
+      return SqlTypeName.INTERVAL_HOUR;
+    case HOUR_TO_MINUTE:
+      return SqlTypeName.INTERVAL_HOUR_MINUTE;
+    case HOUR_TO_SECOND:
+      return SqlTypeName.INTERVAL_HOUR_SECOND;
+    case MINUTE:
+      return SqlTypeName.INTERVAL_MINUTE;
+    case MINUTE_TO_SECOND:
+      return SqlTypeName.INTERVAL_MINUTE_SECOND;
+    case SECOND:
+    case MILLISECOND:
+    case EPOCH:
+    case MICROSECOND:
+      return SqlTypeName.INTERVAL_SECOND;
+    default:
+      throw new AssertionError(timeUnitRange);
+    }
   }
 
   public void validate(

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index 347ea1a..95b1bc3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -129,7 +129,8 @@ import static org.apache.calcite.util.Static.RESOURCE;
  * <td>An {@link Enum}</td>
  * </tr>
  * <tr>
- * <td>{@link SqlTypeName#INTERVAL_DAY_TIME}</td>
+ * <td>{@link SqlTypeName#INTERVAL_YEAR}
+ *     .. {@link SqlTypeName#INTERVAL_SECOND}</td>
  * <td>Interval, for example <code>INTERVAL '1:34' HOUR</code>.</td>
  * <td>{@link SqlIntervalLiteral.IntervalValue}.</td>
  * </tr>
@@ -197,8 +198,19 @@ public class SqlLiteral extends SqlNode {
     case TIME:
     case TIMESTAMP:
       return value instanceof Calendar;
-    case INTERVAL_DAY_TIME:
+    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:
       return value instanceof SqlIntervalLiteral.IntervalValue;
     case BINARY:
       return value instanceof BitString;
@@ -281,10 +293,10 @@ public class SqlLiteral extends SqlNode {
    * <li>If the node is a {@link SqlIntervalQualifier},
    * returns its {@link TimeUnitRange}.
    *
-   * <li>If the node is INTERVAL_DAY_TIME in {@link SqlTypeFamily},
+   * <li>If the node is INTERVAL_DAY_TIME_ in {@link SqlTypeFamily},
    * returns its sign multiplied by its millisecond equivalent value
    *
-   * <li>If the node is INTERVAL_YEAR_MONTH in {@link SqlTypeFamily},
+   * <li>If the node is INTERVAL_YEAR_MONTH_ in {@link SqlTypeFamily},
    * returns its sign multiplied by its months equivalent value
    *
    * <li>Otherwise the behavior is not specified.
@@ -632,8 +644,19 @@ public class SqlLiteral extends SqlNode {
               collation);
       return type;
 
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
+    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:
       SqlIntervalLiteral.IntervalValue intervalValue =
           (SqlIntervalLiteral.IntervalValue) value;
       return typeFactory.createSqlIntervalType(
@@ -684,15 +707,8 @@ public class SqlLiteral extends SqlNode {
       String intervalStr,
       SqlIntervalQualifier intervalQualifier,
       SqlParserPos pos) {
-    SqlTypeName typeName =
-        intervalQualifier.isYearMonth() ? SqlTypeName.INTERVAL_YEAR_MONTH
-            : SqlTypeName.INTERVAL_DAY_TIME;
-    return new SqlIntervalLiteral(
-        sign,
-        intervalStr,
-        intervalQualifier,
-        typeName,
-        pos);
+    return new SqlIntervalLiteral(sign, intervalStr, intervalQualifier,
+        intervalQualifier.typeName(), pos);
   }
 
   public static SqlNumericLiteral createNegative(

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java b/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java
index 6111c7b..d4b2284 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/IntervalSqlType.java
@@ -46,11 +46,7 @@ public class IntervalSqlType extends AbstractSqlType {
   public IntervalSqlType(RelDataTypeSystem typeSystem,
       SqlIntervalQualifier intervalQualifier,
       boolean isNullable) {
-    super(intervalQualifier.isYearMonth()
-            ? SqlTypeName.INTERVAL_YEAR_MONTH
-            : SqlTypeName.INTERVAL_DAY_TIME,
-        isNullable,
-        null);
+    super(intervalQualifier.typeName(), isNullable, null);
     this.typeSystem = Preconditions.checkNotNull(typeSystem);
     this.intervalQualifier = Preconditions.checkNotNull(intervalQualifier);
     computeDigest();
@@ -85,24 +81,17 @@ public class IntervalSqlType extends AbstractSqlType {
   public IntervalSqlType combine(
       RelDataTypeFactoryImpl typeFactory,
       IntervalSqlType that) {
-    assert this.intervalQualifier.isYearMonth()
-        == that.intervalQualifier.isYearMonth();
+    assert this.typeName.isYearMonth() == that.typeName.isYearMonth();
     boolean nullable = isNullable || that.isNullable;
-    TimeUnit thisStart =
-        this.intervalQualifier.getStartUnit();
-    TimeUnit thisEnd =
-        this.intervalQualifier.getEndUnit();
-    TimeUnit thatStart =
-        that.intervalQualifier.getStartUnit();
-    TimeUnit thatEnd =
-        that.intervalQualifier.getEndUnit();
-
-    assert null != thisStart;
-    assert null != thatStart;
+    TimeUnit thisStart = Preconditions.checkNotNull(typeName.getStartUnit());
+    TimeUnit thisEnd = typeName.getEndUnit();
+    final TimeUnit thatStart =
+        Preconditions.checkNotNull(that.typeName.getStartUnit());
+    final TimeUnit thatEnd = that.typeName.getEndUnit();
 
     int secondPrec =
         this.intervalQualifier.getStartPrecisionPreservingDefault();
-    int fracPrec =
+    final int fracPrec =
         SqlIntervalQualifier.combineFractionalSecondPrecisionPreservingDefault(
             typeSystem,
             this.intervalQualifier,

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java b/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java
index 5c60187..2eadcd8 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/MatchReturnTypeInference.java
@@ -19,6 +19,7 @@ package org.apache.calcite.sql.type;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.sql.SqlOperatorBinding;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
@@ -49,12 +50,11 @@ public class MatchReturnTypeInference implements SqlReturnTypeInference {
    * Returns the first type matching any type in typeNames at or after
    * position start (zero based).
    */
-  public MatchReturnTypeInference(int start, List<SqlTypeName> typeNames) {
-    assert start >= 0;
-    assert null != typeNames;
-    assert typeNames.size() > 0;
+  public MatchReturnTypeInference(int start, Iterable<SqlTypeName> typeNames) {
+    Preconditions.checkArgument(start >= 0);
     this.start = start;
     this.typeNames = ImmutableList.copyOf(typeNames);
+    Preconditions.checkArgument(!this.typeNames.isEmpty());
   }
 
   //~ Methods ----------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
index 8ed26b8..efe2bb7 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeAssignmentRules.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.type;
 
 import org.apache.calcite.util.Util;
 
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -40,45 +41,39 @@ public class SqlTypeAssignmentRules {
   //~ Constructors -----------------------------------------------------------
 
   private SqlTypeAssignmentRules() {
-    rules = new HashMap<SqlTypeName, Set<SqlTypeName>>();
+    rules = new HashMap<>();
 
     Set<SqlTypeName> rule;
 
     // IntervalYearMonth is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.INTERVAL_YEAR_MONTH);
-    rules.put(SqlTypeName.INTERVAL_YEAR_MONTH, rule);
-
-    // IntervalDayTime is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.INTERVAL_DAY_TIME);
-    rules.put(SqlTypeName.INTERVAL_DAY_TIME, rule);
+    for (SqlTypeName interval : SqlTypeName.YEAR_INTERVAL_TYPES) {
+      rules.put(interval, SqlTypeName.YEAR_INTERVAL_TYPES);
+    }
+    for (SqlTypeName interval : SqlTypeName.DAY_INTERVAL_TYPES) {
+      rules.put(interval, SqlTypeName.DAY_INTERVAL_TYPES);
+    }
 
     // Multiset is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.MULTISET);
-    rules.put(SqlTypeName.MULTISET, rule);
+    rules.put(SqlTypeName.MULTISET, EnumSet.of(SqlTypeName.MULTISET));
 
     // Tinyint is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.TINYINT);
-    rules.put(SqlTypeName.TINYINT, rule);
+    rules.put(SqlTypeName.TINYINT, EnumSet.of(SqlTypeName.TINYINT));
 
     // Smallint is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rules.put(SqlTypeName.SMALLINT, rule);
 
     // Int is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
     rules.put(SqlTypeName.INTEGER, rule);
 
     // BigInt is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -86,7 +81,7 @@ public class SqlTypeAssignmentRules {
     rules.put(SqlTypeName.BIGINT, rule);
 
     // Float is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -96,7 +91,7 @@ public class SqlTypeAssignmentRules {
     rules.put(SqlTypeName.FLOAT, rule);
 
     // Real is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -107,7 +102,7 @@ public class SqlTypeAssignmentRules {
     rules.put(SqlTypeName.REAL, rule);
 
     // Double is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -119,7 +114,7 @@ public class SqlTypeAssignmentRules {
     rules.put(SqlTypeName.DOUBLE, rule);
 
     // Decimal is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -130,52 +125,46 @@ public class SqlTypeAssignmentRules {
     rules.put(SqlTypeName.DECIMAL, rule);
 
     // VarBinary is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.VARBINARY);
     rule.add(SqlTypeName.BINARY);
     rules.put(SqlTypeName.VARBINARY, rule);
 
     // Char is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.CHAR);
-    rules.put(SqlTypeName.CHAR, rule);
+    rules.put(SqlTypeName.CHAR, EnumSet.of(SqlTypeName.CHAR));
 
     // VarChar is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.CHAR);
     rule.add(SqlTypeName.VARCHAR);
     rules.put(SqlTypeName.VARCHAR, rule);
 
     // Boolean is assignable from...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.BOOLEAN);
-    rules.put(SqlTypeName.BOOLEAN, rule);
+    rules.put(SqlTypeName.BOOLEAN, EnumSet.of(SqlTypeName.BOOLEAN));
 
     // Binary is assignable from...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.BINARY);
     rule.add(SqlTypeName.VARBINARY);
     rules.put(SqlTypeName.BINARY, rule);
 
     // Date is assignable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.DATE);
     rule.add(SqlTypeName.TIMESTAMP);
     rules.put(SqlTypeName.DATE, rule);
 
     // Time is assignable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TIME);
     rule.add(SqlTypeName.TIMESTAMP);
     rules.put(SqlTypeName.TIME, rule);
 
     // Timestamp is assignable from ...
-    rule = new HashSet<SqlTypeName>();
-    rule.add(SqlTypeName.TIMESTAMP);
-    rules.put(SqlTypeName.TIMESTAMP, rule);
+    rules.put(SqlTypeName.TIMESTAMP, EnumSet.of(SqlTypeName.TIMESTAMP));
 
     // Any is assignable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -193,7 +182,7 @@ public class SqlTypeAssignmentRules {
 
     // Make numbers symmetrical and
     // make varchar/char castable to/from numbers
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TINYINT);
     rule.add(SqlTypeName.SMALLINT);
     rule.add(SqlTypeName.INTEGER);
@@ -240,27 +229,19 @@ public class SqlTypeAssignmentRules {
     // Exact Numerics are castable from intervals
     for (SqlTypeName exactType : SqlTypeName.EXACT_TYPES) {
       rule = coerceRules.get(exactType);
-      rule.add(SqlTypeName.INTERVAL_DAY_TIME);
-      rule.add(SqlTypeName.INTERVAL_YEAR_MONTH);
+      rule.addAll(SqlTypeName.INTERVAL_TYPES);
     }
 
     // intervals are castable from Exact Numeric
-    rule = coerceRules.get(SqlTypeName.INTERVAL_DAY_TIME);
-    rule.add(SqlTypeName.TINYINT);
-    rule.add(SqlTypeName.SMALLINT);
-    rule.add(SqlTypeName.INTEGER);
-    rule.add(SqlTypeName.BIGINT);
-    rule.add(SqlTypeName.DECIMAL);
-    rule.add(SqlTypeName.VARCHAR);
-
-    // intervals  castable from Exact Numeric
-    rule = coerceRules.get(SqlTypeName.INTERVAL_YEAR_MONTH);
-    rule.add(SqlTypeName.TINYINT);
-    rule.add(SqlTypeName.SMALLINT);
-    rule.add(SqlTypeName.INTEGER);
-    rule.add(SqlTypeName.BIGINT);
-    rule.add(SqlTypeName.DECIMAL);
-    rule.add(SqlTypeName.VARCHAR);
+    for (SqlTypeName typeName : SqlTypeName.INTERVAL_TYPES) {
+      rule = coerceRules.get(typeName);
+      rule.add(SqlTypeName.TINYINT);
+      rule.add(SqlTypeName.SMALLINT);
+      rule.add(SqlTypeName.INTEGER);
+      rule.add(SqlTypeName.BIGINT);
+      rule.add(SqlTypeName.DECIMAL);
+      rule.add(SqlTypeName.VARCHAR);
+    }
 
     // varchar is castable from Boolean, Date, time, timestamp, numbers and
     // intervals
@@ -269,8 +250,7 @@ public class SqlTypeAssignmentRules {
     rule.add(SqlTypeName.DATE);
     rule.add(SqlTypeName.TIME);
     rule.add(SqlTypeName.TIMESTAMP);
-    rule.add(SqlTypeName.INTERVAL_DAY_TIME);
-    rule.add(SqlTypeName.INTERVAL_YEAR_MONTH);
+    rule.addAll(SqlTypeName.INTERVAL_TYPES);
 
     // char is castable from Boolean, Date, time and timestamp and numbers
     rule = coerceRules.get(SqlTypeName.CHAR);
@@ -278,8 +258,7 @@ public class SqlTypeAssignmentRules {
     rule.add(SqlTypeName.DATE);
     rule.add(SqlTypeName.TIME);
     rule.add(SqlTypeName.TIMESTAMP);
-    rule.add(SqlTypeName.INTERVAL_DAY_TIME);
-    rule.add(SqlTypeName.INTERVAL_YEAR_MONTH);
+    rule.addAll(SqlTypeName.INTERVAL_TYPES);
 
     // Boolean is castable from char and varchar
     rule = coerceRules.get(SqlTypeName.BOOLEAN);
@@ -289,7 +268,7 @@ public class SqlTypeAssignmentRules {
     // Date, time, and timestamp are castable from
     // char and varchar
     // Date is castable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.DATE);
     rule.add(SqlTypeName.TIMESTAMP);
     rule.add(SqlTypeName.CHAR);
@@ -297,7 +276,7 @@ public class SqlTypeAssignmentRules {
     coerceRules.put(SqlTypeName.DATE, rule);
 
     // Time is castable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TIME);
     rule.add(SqlTypeName.TIMESTAMP);
     rule.add(SqlTypeName.CHAR);
@@ -305,7 +284,7 @@ public class SqlTypeAssignmentRules {
     coerceRules.put(SqlTypeName.TIME, rule);
 
     // Timestamp is castable from ...
-    rule = new HashSet<SqlTypeName>();
+    rule = new HashSet<>();
     rule.add(SqlTypeName.TIMESTAMP);
     rule.add(SqlTypeName.DATE);
     rule.add(SqlTypeName.TIME);
@@ -333,9 +312,9 @@ public class SqlTypeAssignmentRules {
     Map<SqlTypeName, Set<SqlTypeName>> ruleset =
         coerce ? coerceRules : rules;
 
-    if (to.equals(SqlTypeName.NULL)) {
+    if (to == SqlTypeName.NULL) {
       return false;
-    } else if (from.equals(SqlTypeName.NULL)) {
+    } else if (from == SqlTypeName.NULL) {
       return true;
     }
 
@@ -352,7 +331,7 @@ public class SqlTypeAssignmentRules {
 
   @SuppressWarnings("unchecked")
   private static <K, V> Map<K, V> copy(Map<K, V> map) {
-    Map<K, V> copy = new HashMap<K, V>();
+    Map<K, V> copy = new HashMap<>();
     for (Map.Entry<K, V> e : map.entrySet()) {
       if (e.getValue() instanceof Set) {
         copy.put(e.getKey(), (V) copy((Set) e.getValue()));

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java
index 4fe315b..1fc7c9b 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeExplicitPrecedenceList.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -86,10 +87,32 @@ public class SqlTypeExplicitPrecedenceList
           .put(SqlTypeName.DATE, list(SqlTypeName.DATE))
           .put(SqlTypeName.TIME, list(SqlTypeName.TIME))
           .put(SqlTypeName.TIMESTAMP, list(SqlTypeName.TIMESTAMP))
+          .put(SqlTypeName.INTERVAL_YEAR,
+              list(SqlTypeName.YEAR_INTERVAL_TYPES))
           .put(SqlTypeName.INTERVAL_YEAR_MONTH,
-              list(SqlTypeName.INTERVAL_YEAR_MONTH))
-          .put(SqlTypeName.INTERVAL_DAY_TIME,
-              list(SqlTypeName.INTERVAL_DAY_TIME))
+              list(SqlTypeName.YEAR_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_MONTH,
+              list(SqlTypeName.YEAR_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_DAY,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_DAY_HOUR,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_DAY_MINUTE,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_DAY_SECOND,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_HOUR,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_HOUR_MINUTE,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_HOUR_SECOND,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_MINUTE,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_MINUTE_SECOND,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
+          .put(SqlTypeName.INTERVAL_SECOND,
+              list(SqlTypeName.DAY_INTERVAL_TYPES))
           .build();
 
   //~ Instance fields --------------------------------------------------------
@@ -98,14 +121,18 @@ public class SqlTypeExplicitPrecedenceList
 
   //~ Constructors -----------------------------------------------------------
 
-  public SqlTypeExplicitPrecedenceList(List<SqlTypeName> typeNames) {
+  public SqlTypeExplicitPrecedenceList(Iterable<SqlTypeName> typeNames) {
     this.typeNames = ImmutableNullableList.copyOf(typeNames);
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  private static SqlTypeExplicitPrecedenceList list(SqlTypeName... array) {
-    return new SqlTypeExplicitPrecedenceList(ImmutableList.copyOf(array));
+  private static SqlTypeExplicitPrecedenceList list(SqlTypeName... typeNames) {
+    return list(Arrays.asList(typeNames));
+  }
+
+  private static SqlTypeExplicitPrecedenceList list(Iterable<SqlTypeName> typeNames) {
+    return new SqlTypeExplicitPrecedenceList(typeNames);
   }
 
   private static SqlTypeExplicitPrecedenceList numeric(SqlTypeName typeName) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
index 57378cc..92c3313 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
@@ -208,9 +208,7 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
     assert typeName != null;
     assert typeName != SqlTypeName.MULTISET
         : "use createMultisetType() instead";
-    assert typeName != SqlTypeName.INTERVAL_DAY_TIME
-        : "use createSqlIntervalType() instead";
-    assert typeName != SqlTypeName.INTERVAL_YEAR_MONTH
+    assert !SqlTypeName.INTERVAL_TYPES.contains(typeName)
         : "use createSqlIntervalType() instead";
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
index ce3fd6e..4543b00 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFamily.java
@@ -23,7 +23,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 import java.sql.Types;
-import java.util.List;
+import java.util.Collection;
 import java.util.Map;
 
 /**
@@ -118,7 +118,7 @@ public enum SqlTypeFamily implements RelDataTypeFamily {
   /**
    * @return collection of {@link SqlTypeName}s included in this family
    */
-  public List<SqlTypeName> getTypeNames() {
+  public Collection<SqlTypeName> getTypeNames() {
     switch (this) {
     case CHARACTER:
       return SqlTypeName.CHAR_TYPES;
@@ -135,9 +135,9 @@ public enum SqlTypeFamily implements RelDataTypeFamily {
     case BOOLEAN:
       return SqlTypeName.BOOLEAN_TYPES;
     case INTERVAL_YEAR_MONTH:
-      return ImmutableList.of(SqlTypeName.INTERVAL_YEAR_MONTH);
+      return SqlTypeName.YEAR_INTERVAL_TYPES;
     case INTERVAL_DAY_TIME:
-      return ImmutableList.of(SqlTypeName.INTERVAL_DAY_TIME);
+      return SqlTypeName.DAY_INTERVAL_TYPES;
     case STRING:
       return SqlTypeName.STRING_TYPES;
     case APPROXIMATE_NUMERIC:

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
index b43850c..f55f9b9 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
@@ -17,12 +17,15 @@
 package org.apache.calcite.sql.type;
 
 import org.apache.calcite.avatica.util.DateTimeUtils;
+import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
 
 import java.math.BigDecimal;
 import java.sql.Types;
@@ -30,6 +33,7 @@ import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Enumeration of the type names which can be used to construct a SQL type.
@@ -59,9 +63,31 @@ public enum SqlTypeName {
       SqlTypeFamily.TIME),
   TIMESTAMP(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.TIMESTAMP,
       SqlTypeFamily.TIMESTAMP),
+  INTERVAL_YEAR(PrecScale.NO_NO, false, Types.OTHER,
+      SqlTypeFamily.INTERVAL_YEAR_MONTH),
   INTERVAL_YEAR_MONTH(PrecScale.NO_NO, false, Types.OTHER,
       SqlTypeFamily.INTERVAL_YEAR_MONTH),
-  INTERVAL_DAY_TIME(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+  INTERVAL_MONTH(PrecScale.NO_NO, false, Types.OTHER,
+      SqlTypeFamily.INTERVAL_YEAR_MONTH),
+  INTERVAL_DAY(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_DAY_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_DAY_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_DAY_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_HOUR(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_HOUR_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_HOUR_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_MINUTE(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_MINUTE_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
+      false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
+  INTERVAL_SECOND(PrecScale.NO_NO | PrecScale.YES_NO | PrecScale.YES_YES,
       false, Types.OTHER, SqlTypeFamily.INTERVAL_DAY_TIME),
   CHAR(PrecScale.NO_NO | PrecScale.YES_NO, false, Types.CHAR,
       SqlTypeFamily.CHARACTER),
@@ -114,7 +140,11 @@ public enum SqlTypeName {
       ImmutableList.of(
           BOOLEAN, INTEGER, VARCHAR, DATE, TIME, TIMESTAMP, NULL, DECIMAL,
           ANY, CHAR, BINARY, VARBINARY, TINYINT, SMALLINT, BIGINT, REAL,
-          DOUBLE, SYMBOL, INTERVAL_YEAR_MONTH, INTERVAL_DAY_TIME,
+          DOUBLE, SYMBOL, INTERVAL_YEAR, INTERVAL_YEAR_MONTH, INTERVAL_MONTH,
+          INTERVAL_DAY, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
+          INTERVAL_DAY_SECOND, INTERVAL_HOUR, INTERVAL_HOUR_MINUTE,
+          INTERVAL_HOUR_SECOND, INTERVAL_MINUTE, INTERVAL_MINUTE_SECOND,
+          INTERVAL_SECOND,
           FLOAT, MULTISET, DISTINCT, STRUCTURED, ROW, CURSOR, COLUMN_LIST);
 
   public static final List<SqlTypeName> BOOLEAN_TYPES =
@@ -147,8 +177,26 @@ public enum SqlTypeName {
   public static final List<SqlTypeName> DATETIME_TYPES =
       ImmutableList.of(DATE, TIME, TIMESTAMP);
 
-  public static final List<SqlTypeName> INTERVAL_TYPES =
-      ImmutableList.of(INTERVAL_DAY_TIME, INTERVAL_YEAR_MONTH);
+  public static final Set<SqlTypeName> YEAR_INTERVAL_TYPES =
+      Sets.immutableEnumSet(SqlTypeName.INTERVAL_YEAR,
+          SqlTypeName.INTERVAL_YEAR_MONTH,
+          SqlTypeName.INTERVAL_MONTH);
+
+  public static final Set<SqlTypeName> DAY_INTERVAL_TYPES =
+      Sets.immutableEnumSet(SqlTypeName.INTERVAL_DAY,
+          SqlTypeName.INTERVAL_DAY_HOUR,
+          SqlTypeName.INTERVAL_DAY_MINUTE,
+          SqlTypeName.INTERVAL_DAY_SECOND,
+          SqlTypeName.INTERVAL_HOUR,
+          SqlTypeName.INTERVAL_HOUR_MINUTE,
+          SqlTypeName.INTERVAL_HOUR_SECOND,
+          SqlTypeName.INTERVAL_MINUTE,
+          SqlTypeName.INTERVAL_MINUTE_SECOND,
+          SqlTypeName.INTERVAL_SECOND);
+
+  public static final Set<SqlTypeName> INTERVAL_TYPES =
+      Sets.immutableEnumSet(
+          Iterables.concat(YEAR_INTERVAL_TYPES, DAY_INTERVAL_TYPES));
 
   private static final Map<Integer, SqlTypeName> JDBC_TYPE_TO_NAME =
       ImmutableMap.<Integer, SqlTypeName>builder()
@@ -206,7 +254,7 @@ public enum SqlTypeName {
   private final int jdbcOrdinal;
   private final SqlTypeFamily family;
 
-  private SqlTypeName(int signatures, boolean special, int jdbcType,
+  SqlTypeName(int signatures, boolean special, int jdbcType,
       SqlTypeFamily family) {
     this.signatures = signatures;
     this.special = special;
@@ -307,8 +355,19 @@ public enum SqlTypeName {
     switch (this) {
     case DECIMAL:
       return 0;
-    case INTERVAL_DAY_TIME:
+    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:
       return DEFAULT_INTERVAL_FRACTIONAL_SECOND_PRECISION;
     default:
       return -1;
@@ -680,8 +739,19 @@ public enum SqlTypeName {
     case TIME:
     case TIMESTAMP:
       return 1;
-    case INTERVAL_DAY_TIME:
+    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:
       return MIN_INTERVAL_START_PRECISION;
     default:
       return -1;
@@ -698,14 +768,92 @@ public enum SqlTypeName {
   public int getMinScale() {
     switch (this) {
     // TODO: Minimum numeric scale for decimal
-    case INTERVAL_DAY_TIME:
+    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:
       return MIN_INTERVAL_FRACTIONAL_SECOND_PRECISION;
     default:
       return -1;
     }
   }
 
+  /** Returns {@code HOUR} for {@code HOUR TO SECOND} and
+   * {@code HOUR}, {@code SECOND} for {@code SECOND}. */
+  public TimeUnit getStartUnit() {
+    switch (this) {
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+      return TimeUnit.YEAR;
+    case INTERVAL_MONTH:
+      return TimeUnit.MONTH;
+    case INTERVAL_DAY:
+    case INTERVAL_DAY_HOUR:
+    case INTERVAL_DAY_MINUTE:
+    case INTERVAL_DAY_SECOND:
+      return TimeUnit.DAY;
+    case INTERVAL_HOUR:
+    case INTERVAL_HOUR_MINUTE:
+    case INTERVAL_HOUR_SECOND:
+      return TimeUnit.HOUR;
+    case INTERVAL_MINUTE:
+    case INTERVAL_MINUTE_SECOND:
+      return TimeUnit.MINUTE;
+    case INTERVAL_SECOND:
+      return TimeUnit.SECOND;
+    default:
+      throw new AssertionError(this);
+    }
+  }
+
+  /** Returns {@code SECOND} for both {@code HOUR TO SECOND} and
+   * {@code SECOND}. */
+  public TimeUnit getEndUnit() {
+    switch (this) {
+    case INTERVAL_YEAR:
+      return TimeUnit.YEAR;
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
+      return TimeUnit.MONTH;
+    case INTERVAL_DAY:
+      return TimeUnit.DAY;
+    case INTERVAL_DAY_HOUR:
+    case INTERVAL_HOUR:
+      return TimeUnit.HOUR;
+    case INTERVAL_DAY_MINUTE:
+    case INTERVAL_HOUR_MINUTE:
+    case INTERVAL_MINUTE:
+      return TimeUnit.MINUTE;
+    case INTERVAL_DAY_SECOND:
+    case INTERVAL_HOUR_SECOND:
+    case INTERVAL_MINUTE_SECOND:
+    case INTERVAL_SECOND:
+      return TimeUnit.SECOND;
+    default:
+      throw new AssertionError(this);
+    }
+  }
+
+  public boolean isYearMonth() {
+    switch (this) {
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
+      return true;
+    default:
+      return false;
+    }
+  }
+
   /** Limit. */
   public enum Limit {
     ZERO, UNDERFLOW, OVERFLOW

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
index 203392a..ee7b41a 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
@@ -42,6 +42,7 @@ import com.google.common.collect.Lists;
 import java.nio.charset.Charset;
 import java.util.AbstractList;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -267,7 +268,7 @@ public abstract class SqlTypeUtil {
    * @see #isOfSameTypeName(SqlTypeName, RelDataType)
    */
   public static boolean isOfSameTypeName(
-      List<SqlTypeName> typeNames,
+      Collection<SqlTypeName> typeNames,
       RelDataType type) {
     for (SqlTypeName typeName : typeNames) {
       if (isOfSameTypeName(typeName, type)) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index 3aacce7..ae4f8e5 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -2665,8 +2665,19 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
       }
       break;
 
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
+    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:
       if (literal instanceof SqlIntervalLiteral) {
         SqlIntervalLiteral.IntervalValue interval =
             (SqlIntervalLiteral.IntervalValue)

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
index bf7fdd0..a22963f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
@@ -138,8 +138,19 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
     case DATE:
       return rexBuilder.makeDateLiteral((Calendar) value);
 
+    case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
-    case INTERVAL_DAY_TIME:
+    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:
       SqlIntervalQualifier sqlIntervalQualifier =
           ((SqlIntervalLiteral.IntervalValue) value).getIntervalQualifier();
       l = (long) SqlLiteral.value(literal);

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 c9db0f3..21aaf30 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -16,6 +16,7 @@
  */
 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;
@@ -620,8 +621,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     case MONTH:
     case DAY:
       switch (sqlTypeName) {
+      case INTERVAL_YEAR:
       case INTERVAL_YEAR_MONTH:
-      case INTERVAL_DAY_TIME:
+      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:
         res = divide(rexBuilder, res, TimeUnit.DAY.multiplier);
@@ -671,8 +683,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       case TIMESTAMP:
         // convert to seconds
         return divide(rexBuilder, res, TimeUnit.SECOND.multiplier);
-      case INTERVAL_DAY_TIME:
+      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);
       }
@@ -681,8 +704,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     case DOY:
     case WEEK:
       switch (sqlTypeName) {
-      case INTERVAL_DAY_TIME: // fall through
+      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:
         // TODO: is this check better to do in validation phase?
         // Currently there is parameter on TimeUnit to identify these type of units.
         throw new IllegalArgumentException("Extract " + unit + " from "
@@ -1032,8 +1066,19 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       if (operands.size() == 2) {
         final SqlTypeName sqlTypeName = operands.get(0).getType().getSqlTypeName();
         switch (sqlTypeName) {
-        case INTERVAL_DAY_TIME:
+        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:
           operands = ImmutableList.of(operands.get(1), operands.get(0));
         }
       }
@@ -1469,17 +1514,33 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
       //    => (t2 - t1) UNIT
       final RexBuilder rexBuilder = cx.getRexBuilder();
       final SqlLiteral unitLiteral = call.operand(0);
-      final TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class);
+      TimeUnit unit = unitLiteral.symbolValue(TimeUnit.class);
+      BigDecimal multiplier = BigDecimal.ONE;
+      BigDecimal divider = BigDecimal.ONE;
+      switch (unit) {
+      case MICROSECOND:
+      case MILLISECOND:
+      case WEEK:
+        multiplier = BigDecimal.valueOf(DateTimeUtils.MILLIS_PER_SECOND);
+        divider = unit.multiplier;
+        unit = TimeUnit.SECOND;
+        break;
+      case QUARTER:
+        divider = unit.multiplier;
+        unit = TimeUnit.MONTH;
+        break;
+      }
       final RelDataType intType =
           cx.getTypeFactory().createSqlType(SqlTypeName.INTEGER);
       final SqlIntervalQualifier qualifier =
           new SqlIntervalQualifier(unit, null, SqlParserPos.ZERO);
       final RelDataType intervalType =
           cx.getTypeFactory().createSqlIntervalType(qualifier);
-      return rexBuilder.makeCast(intType,
+      RexNode e = rexBuilder.makeCast(intType,
           rexBuilder.makeCall(intervalType, SqlStdOperatorTable.MINUS_DATE,
               ImmutableList.of(cx.convertExpression(call.operand(2)),
                   cx.convertExpression(call.operand(1)))));
+      return rexBuilder.multiplyDivide(e, multiplier, divider);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java
index f972db8..0eee37b 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -1877,8 +1877,7 @@ public class Util {
       Class<T> clazz) {
     final T[] ts = clazz.getEnumConstants();
     if (ts == null) {
-      // not an enum type
-      return null;
+      throw new AssertionError("not an enum type");
     }
     ImmutableMap.Builder<String, T> builder = ImmutableMap.builder();
     for (T t : ts) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
index 18ab7bd..4578822 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -272,7 +272,7 @@ public class CalciteRemoteDriverTest {
   @Test public void testRemoteTypeInfo() throws Exception {
     CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
         .metaData(GET_TYPEINFO)
-        .returns(CalciteAssert.checkResultCount(31));
+        .returns(CalciteAssert.checkResultCount(is(42)));
   }
 
   @Test public void testRemoteTableTypes() throws Exception {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 e81ed4c..fe51c64 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
@@ -5068,10 +5068,34 @@ public abstract class SqlOperatorBaseTest {
         + "timestamp '2016-02-24 12:42:25', "
         + "timestamp '2016-02-24 12:42:20')",
         "-5000000", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(SQL_TSI_FRAC_SECOND, "
+        + "timestamp '2016-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:20')",
+        "-5000000", "INTEGER NOT NULL");
     tester.checkScalar("timestampdiff(YEAR, "
         + "timestamp '2014-02-24 12:42:25', "
         + "timestamp '2016-02-24 12:42:25')",
         "2", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(WEEK, "
+        + "timestamp '2014-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:25')",
+        "104", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(WEEK, "
+        + "timestamp '2014-02-19 12:42:25', "
+        + "timestamp '2016-02-24 12:42:25')",
+        "105", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(MONTH, "
+        + "timestamp '2014-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:25')",
+        "24", "INTEGER NOT NULL");
+    tester.checkScalar("timestampdiff(QUARTER, "
+        + "timestamp '2014-02-24 12:42:25', "
+        + "timestamp '2016-02-24 12:42:25')",
+        "8", "INTEGER NOT NULL");
+    tester.checkFails("timestampdiff(CENTURY, "
+        + "timestamp '2014-02-24 12:42:25', "
+        + "timestamp '2614-02-24 12:42:25')",
+        "(?s)Encountered \"CENTURY\" at .*", false);
   }
 
   @Test public void testDenseRankFunc() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 1ba65de..e4f6976 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -53,7 +53,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
 import net.hydromatic.foodmart.data.hsqldb.FoodmartHsqldb;
 import net.hydromatic.scott.data.hsqldb.ScottHsqldb;
 
-import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matcher;
 
 import java.io.File;
 import java.io.PrintWriter;
@@ -86,6 +86,7 @@ import javax.sql.DataSource;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
@@ -287,12 +288,13 @@ public class CalciteAssert {
     };
   }
 
-  public static Function<ResultSet, Void> checkResultCount(final int expected) {
+  public static Function<ResultSet, Void>
+  checkResultCount(final Matcher<Integer> expected) {
     return new Function<ResultSet, Void>() {
       public Void apply(ResultSet resultSet) {
         try {
           final int count = CalciteAssert.countRows(resultSet);
-          assertEquals(expected, count);
+          assertThat(count, expected);
           return null;
         } catch (SQLException e) {
           throw new RuntimeException(e);
@@ -304,7 +306,7 @@ public class CalciteAssert {
   public static Function<Integer, Void> checkUpdateCount(final int expected) {
     return new Function<Integer, Void>() {
       public Void apply(Integer updateCount) {
-        assertThat(updateCount, CoreMatchers.is(expected));
+        assertThat(updateCount, is(expected));
         return null;
       }
     };
@@ -1194,7 +1196,7 @@ public class CalciteAssert {
     }
 
     public AssertQuery returnsCount(int expectedCount) {
-      return returns(checkResultCount(expectedCount));
+      return returns(checkResultCount(is(expectedCount)));
     }
 
     public final AssertQuery returns(Function<ResultSet, Void> checker) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/ac9c8c7a/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 f95c971..1c44a0b 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -50,6 +50,7 @@ import java.util.List;
 import java.util.Locale;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -3456,29 +3457,15 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     // accurately test bounds)
     final RelDataTypeSystem typeSystem =
         getTester().getValidator().getTypeFactory().getTypeSystem();
-    assertTrue(
-        SqlTypeName.INTERVAL_YEAR_MONTH.getMinPrecision() == 1);
-    assertTrue(
-        SqlTypeName.INTERVAL_DAY_TIME.getMinPrecision() == 1);
     final RelDataTypeSystem defTypeSystem = RelDataTypeSystem.DEFAULT;
-    assertEquals(10,
-        defTypeSystem.getMaxPrecision(SqlTypeName.INTERVAL_YEAR_MONTH));
-    assertEquals(10,
-        defTypeSystem.getMaxPrecision(SqlTypeName.INTERVAL_DAY_TIME));
-    assertEquals(2,
-        typeSystem.getDefaultPrecision(SqlTypeName.INTERVAL_YEAR_MONTH));
-    assertEquals(2,
-        typeSystem.getDefaultPrecision(SqlTypeName.INTERVAL_DAY_TIME));
-    assertTrue(
-        SqlTypeName.INTERVAL_YEAR_MONTH.getMinScale() == 1);
-    assertTrue(
-        SqlTypeName.INTERVAL_DAY_TIME.getMinScale() == 1);
-    assertEquals(9, typeSystem.getMaxScale(SqlTypeName.INTERVAL_YEAR_MONTH));
-    assertEquals(9, typeSystem.getMaxScale(SqlTypeName.INTERVAL_DAY_TIME));
-    assertTrue(
-        SqlTypeName.INTERVAL_YEAR_MONTH.getDefaultScale() == 6);
-    assertTrue(
-        SqlTypeName.INTERVAL_DAY_TIME.getDefaultScale() == 6);
+    for (SqlTypeName typeName : SqlTypeName.INTERVAL_TYPES) {
+      assertThat(typeName.getMinPrecision(), is(1));
+      assertThat(typeSystem.getMaxPrecision(typeName), is(10));
+      assertThat(typeSystem.getDefaultPrecision(typeName), is(2));
+      assertThat(typeName.getMinScale(), is(1));
+      assertThat(typeSystem.getMaxScale(typeName), is(9));
+      assertThat(typeName.getDefaultScale(), is(6));
+    }
 
     // Tests that should pass both parser and validator
     subTestIntervalYearPositive();