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 2014/09/19 03:03:03 UTC

[2/2] git commit: [OPTIQ-413] Add RelDataTypeSystem plugin, allowing different max precision of a DECIMAL

[OPTIQ-413] Add RelDataTypeSystem plugin, allowing different max precision of a DECIMAL


Project: http://git-wip-us.apache.org/repos/asf/incubator-optiq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-optiq/commit/0fd4e3d9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-optiq/tree/0fd4e3d9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-optiq/diff/0fd4e3d9

Branch: refs/heads/master
Commit: 0fd4e3d9ea63fa67a97ea8ba73e46a12e31af2b1
Parents: a2cc356
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Sep 18 12:05:22 2014 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Sep 18 17:33:14 2014 -0700

----------------------------------------------------------------------
 .../avatica/ConnectionConfigImpl.java           |  59 +++++
 .../hydromatic/avatica/ConnectionProperty.java  |   4 +-
 .../main/codegen/templates/CombinedParser.jj    |   5 +-
 .../optiq/config/OptiqConnectionConfig.java     |   2 +
 .../optiq/config/OptiqConnectionConfigImpl.java |   5 +
 .../optiq/config/OptiqConnectionProperty.java   |   7 +-
 .../hydromatic/optiq/impl/jdbc/JdbcSchema.java  |   3 +-
 .../optiq/jdbc/JavaTypeFactoryImpl.java         |  10 +-
 .../optiq/jdbc/OptiqConnectionImpl.java         |  12 +-
 .../optiq/rules/java/RexToLixTranslator.java    |   4 +-
 .../hydromatic/optiq/tools/FrameworkConfig.java |   8 +
 .../net/hydromatic/optiq/tools/Frameworks.java  |  28 +-
 .../eigenbase/rel/rules/ReduceDecimalsRule.java |  44 +++-
 .../eigenbase/reltype/RelDataTypeFactory.java   |   5 +
 .../reltype/RelDataTypeFactoryImpl.java         |  30 ++-
 .../eigenbase/reltype/RelDataTypeSystem.java    |  60 +++++
 .../reltype/RelDataTypeSystemImpl.java          |  98 +++++++
 .../main/java/org/eigenbase/rex/RexBuilder.java |   9 +-
 .../java/org/eigenbase/rex/RexExecutorImpl.java |   3 +-
 .../org/eigenbase/sql/SqlIntervalQualifier.java | 258 ++++++++++---------
 .../eigenbase/sql/SqlUnresolvedFunction.java    |   6 +-
 .../org/eigenbase/sql/parser/SqlParserUtil.java |   5 +-
 .../org/eigenbase/sql/type/BasicSqlType.java    |  41 +--
 .../org/eigenbase/sql/type/IntervalSqlType.java |  45 ++--
 .../org/eigenbase/sql/type/ReturnTypes.java     |  18 +-
 .../eigenbase/sql/type/SqlTypeFactoryImpl.java  |  32 ++-
 .../org/eigenbase/sql/type/SqlTypeName.java     |  72 ++----
 .../sql/validate/SqlValidatorImpl.java          |  48 ++--
 .../eigenbase/sql2rel/SqlToRelConverter.java    |  11 +-
 .../optiq/impl/clone/ArrayTableTest.java        |   7 +-
 .../optiq/test/MaterializationTest.java         |   4 +-
 .../hydromatic/optiq/tools/FrameworksTest.java  |  68 +++++
 .../org/eigenbase/relopt/RelOptUtilTest.java    |   3 +-
 .../relopt/volcano/VolcanoPlannerTest.java      |   3 +-
 .../sql/test/DefaultSqlTestFactory.java         |   4 +-
 .../org/eigenbase/sql/test/SqlAdvisorTest.java  |   6 +-
 .../eigenbase/sql/test/SqlOperatorBaseTest.java |  13 +-
 .../java/org/eigenbase/test/RexProgramTest.java |   2 +-
 .../org/eigenbase/test/RexTransformerTest.java  |   2 +-
 .../test/java/org/eigenbase/test/SargTest.java  |   3 +-
 .../java/org/eigenbase/test/SqlLimitsTest.java  |  72 +++---
 .../org/eigenbase/test/SqlToRelTestBase.java    |   2 +-
 .../eigenbase/test/SqlValidatorFeatureTest.java |   3 +-
 .../org/eigenbase/test/SqlValidatorTest.java    |  17 +-
 .../org/eigenbase/test/SqlLimitsTest.xml        |  14 +-
 45 files changed, 775 insertions(+), 380 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/avatica/src/main/java/net/hydromatic/avatica/ConnectionConfigImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/net/hydromatic/avatica/ConnectionConfigImpl.java b/avatica/src/main/java/net/hydromatic/avatica/ConnectionConfigImpl.java
index 89066eb..f406da2 100644
--- a/avatica/src/main/java/net/hydromatic/avatica/ConnectionConfigImpl.java
+++ b/avatica/src/main/java/net/hydromatic/avatica/ConnectionConfigImpl.java
@@ -16,6 +16,7 @@
  */
 package net.hydromatic.avatica;
 
+import java.lang.reflect.Field;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Properties;
@@ -123,6 +124,31 @@ public class ConnectionConfigImpl implements ConnectionConfig {
       //noinspection unchecked
       return get_(enumConverter(enumClass), defaultValue.name());
     }
+
+    /** Returns an instance of a plugin.
+     *
+     * <p>Throws if not set and no default.
+     * Also throws if the class does not implement the required interface,
+     * or if it does not have a public default constructor or an public static
+     * field called {@code #INSTANCE}. */
+    public <T> T getPlugin(Class<T> pluginClass, T defaultInstance) {
+      return getPlugin(pluginClass, (String) property.defaultValue(),
+          defaultInstance);
+    }
+
+    /** Returns an instance of a plugin, using a given class name if none is
+     * set.
+     *
+     * <p>Throws if not set and no default.
+     * Also throws if the class does not implement the required interface,
+     * or if it does not have a public default constructor or an public static
+     * field called {@code #INSTANCE}. */
+    public <T> T getPlugin(Class<T> pluginClass, String defaultClassName,
+        T defaultInstance) {
+      assert property.type() == ConnectionProperty.Type.PLUGIN;
+      return get_(pluginConverter(pluginClass, defaultInstance),
+          defaultClassName);
+    }
   }
 
   /** Callback to parse a property from string to its native type. */
@@ -165,6 +191,39 @@ public class ConnectionConfigImpl implements ConnectionConfig {
       }
     };
   }
+
+  public static <T> Converter<T> pluginConverter(final Class<T> pluginClass,
+      final T defaultInstance) {
+    return new Converter<T>() {
+      public T apply(ConnectionProperty connectionProperty, String s) {
+        if (s == null) {
+          if (defaultInstance != null) {
+            return defaultInstance;
+          }
+          throw new RuntimeException("Required property '"
+              + connectionProperty.camelName() + "' not specified");
+        }
+        // First look for a C.INSTANCE field, then do new C().
+        try {
+          //noinspection unchecked
+          final Class<T> clazz = (Class) Class.forName(s);
+          assert pluginClass.isAssignableFrom(clazz);
+          try {
+            // We assume that if there is an INSTANCE field it is static and
+            // has the right type.
+            final Field field = clazz.getField("INSTANCE");
+            return pluginClass.cast(field.get(null));
+          } catch (NoSuchFieldException e) {
+            // ignore
+          }
+          return clazz.newInstance();
+        } catch (Exception e) {
+          throw new RuntimeException("Property '" + s
+              + "' not valid for plugin type " + pluginClass.getName(), e);
+        }
+      }
+    };
+  }
 }
 
 // End ConnectionConfigImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/avatica/src/main/java/net/hydromatic/avatica/ConnectionProperty.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/net/hydromatic/avatica/ConnectionProperty.java b/avatica/src/main/java/net/hydromatic/avatica/ConnectionProperty.java
index 2dda49a..5fcdc50 100644
--- a/avatica/src/main/java/net/hydromatic/avatica/ConnectionProperty.java
+++ b/avatica/src/main/java/net/hydromatic/avatica/ConnectionProperty.java
@@ -46,13 +46,15 @@ public interface ConnectionProperty {
   enum Type {
     BOOLEAN,
     STRING,
-    ENUM;
+    ENUM,
+    PLUGIN;
 
     public boolean valid(Object defaultValue) {
       switch (this) {
       case BOOLEAN:
         return defaultValue instanceof Boolean;
       case STRING:
+      case PLUGIN:
         return defaultValue instanceof String;
       default:
         return defaultValue instanceof Enum;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/codegen/templates/CombinedParser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/CombinedParser.jj b/core/src/main/codegen/templates/CombinedParser.jj
index 6e3101b..2ccad91 100644
--- a/core/src/main/codegen/templates/CombinedParser.jj
+++ b/core/src/main/codegen/templates/CombinedParser.jj
@@ -33,6 +33,7 @@ package ${parser.package};
 import ${importStr};
 </#list>
 
+import org.eigenbase.reltype.RelDataType;
 import org.eigenbase.sql.*;
 import org.eigenbase.sql.parser.*;
 import org.eigenbase.sql.fun.*;
@@ -3118,8 +3119,8 @@ SqlIntervalQualifier IntervalQualifier() :
 {
     SqlIntervalQualifier.TimeUnit start;
     SqlIntervalQualifier.TimeUnit end = null;
-    int startPrec = SqlIntervalQualifier.getDefaultPrecisionId();
-    int secondFracPrec = SqlIntervalQualifier.getDefaultPrecisionId();
+    int startPrec = RelDataType.PRECISION_NOT_SPECIFIED;
+    int secondFracPrec = RelDataType.PRECISION_NOT_SPECIFIED;
 }
 {
     (

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfig.java b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfig.java
index a8a49ab..304a3cb 100644
--- a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfig.java
+++ b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfig.java
@@ -44,6 +44,8 @@ public interface OptiqConnectionConfig extends ConnectionConfig {
   boolean caseSensitive();
   /** @see net.hydromatic.optiq.config.OptiqConnectionProperty#SPARK */
   boolean spark();
+  /** @see net.hydromatic.optiq.config.OptiqConnectionProperty#TYPE_SYSTEM */
+  <T> T typeSystem(Class<T> typeSystemClass, T defaultTypeSystem);
 }
 
 // End OptiqConnectionConfig.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfigImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfigImpl.java b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfigImpl.java
index 719f33b..f08cc7c 100644
--- a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfigImpl.java
+++ b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionConfigImpl.java
@@ -82,6 +82,11 @@ public class OptiqConnectionConfigImpl extends ConnectionConfigImpl
   public boolean spark() {
     return OptiqConnectionProperty.SPARK.wrap(properties).getBoolean();
   }
+
+  public <T> T typeSystem(Class<T> typeSystemClass, T defaultTypeSystem) {
+    return OptiqConnectionProperty.TYPE_SYSTEM.wrap(properties)
+        .getPlugin(typeSystemClass, defaultTypeSystem);
+  }
 }
 
 // End OptiqConnectionConfigImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionProperty.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionProperty.java b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionProperty.java
index ba3089c..5f2d85c 100644
--- a/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionProperty.java
+++ b/core/src/main/java/net/hydromatic/optiq/config/OptiqConnectionProperty.java
@@ -68,7 +68,12 @@ public enum OptiqConnectionProperty implements ConnectionProperty {
   SPARK("spark", Type.BOOLEAN, false),
 
   /** Timezone, for example 'gmt-3'. Default is the JVM's time zone. */
-  TIMEZONE("timezone", Type.STRING, null);
+  TIMEZONE("timezone", Type.STRING, null),
+
+  /** Type system. The name of a class that implements
+   * {@code org.eigenbase.reltype.RelDataTypeSystem} and has a public default
+   * constructor or an {@code INSTANCE} constant. */
+  TYPE_SYSTEM("typeSystem", Type.PLUGIN, null);
 
   private final String camelName;
   private final Type type;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcSchema.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcSchema.java b/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcSchema.java
index b1940df..0301489 100644
--- a/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcSchema.java
+++ b/core/src/main/java/net/hydromatic/optiq/impl/jdbc/JdbcSchema.java
@@ -240,7 +240,8 @@ public class JdbcSchema implements Schema {
     // Temporary type factory, just for the duration of this method. Allowable
     // because we're creating a proto-type, not a type; before being used, the
     // proto-type will be copied into a real type factory.
-    final RelDataTypeFactory typeFactory = new SqlTypeFactoryImpl();
+    final RelDataTypeFactory typeFactory =
+        new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
     final RelDataTypeFactory.FieldInfoBuilder fieldInfo = typeFactory.builder();
     while (resultSet.next()) {
       final String columnName = resultSet.getString(4);

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/jdbc/JavaTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/net/hydromatic/optiq/jdbc/JavaTypeFactoryImpl.java
index 3202221..67fb093 100644
--- a/core/src/main/java/net/hydromatic/optiq/jdbc/JavaTypeFactoryImpl.java
+++ b/core/src/main/java/net/hydromatic/optiq/jdbc/JavaTypeFactoryImpl.java
@@ -53,6 +53,14 @@ public class JavaTypeFactoryImpl
   syntheticTypes =
       new HashMap<List<Pair<Type, Boolean>>, SyntheticRecordType>();
 
+  public JavaTypeFactoryImpl() {
+    this(RelDataTypeSystem.DEFAULT);
+  }
+
+  public JavaTypeFactoryImpl(RelDataTypeSystem typeSystem) {
+    super(typeSystem);
+  }
+
   public RelDataType createStructType(Class type) {
     List<RelDataTypeField> list = new ArrayList<RelDataTypeField>();
     for (Field field : type.getFields()) {
@@ -178,7 +186,7 @@ public class JavaTypeFactoryImpl
     }
     if (type instanceof JavaType) {
       return createTypeWithNullability(
-          new BasicSqlType(type.getSqlTypeName()),
+          createSqlType(type.getSqlTypeName()),
           type.isNullable());
     }
     return type;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqConnectionImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqConnectionImpl.java b/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqConnectionImpl.java
index d5c8592..80d77d3 100644
--- a/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqConnectionImpl.java
+++ b/core/src/main/java/net/hydromatic/optiq/jdbc/OptiqConnectionImpl.java
@@ -35,6 +35,7 @@ import net.hydromatic.optiq.runtime.Hook;
 import net.hydromatic.optiq.server.OptiqServer;
 import net.hydromatic.optiq.server.OptiqServerStatement;
 
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.advise.SqlAdvisor;
 import org.eigenbase.sql.advise.SqlAdvisorValidator;
 import org.eigenbase.sql.fun.SqlStdOperatorTable;
@@ -83,13 +84,18 @@ abstract class OptiqConnectionImpl
       String url, Properties info, OptiqRootSchema rootSchema,
       JavaTypeFactory typeFactory) {
     super(driver, factory, url, info);
+    OptiqConnectionConfig cfg = new OptiqConnectionConfigImpl(info);
     this.prepareFactory = driver.prepareFactory;
-    this.typeFactory =
-        typeFactory != null ? typeFactory : new JavaTypeFactoryImpl();
+    if (typeFactory != null) {
+      this.typeFactory = typeFactory;
+    } else {
+      final RelDataTypeSystem typeSystem =
+          cfg.typeSystem(RelDataTypeSystem.class, RelDataTypeSystem.DEFAULT);
+      this.typeFactory = new JavaTypeFactoryImpl(typeSystem);
+    }
     this.rootSchema =
         rootSchema != null ? rootSchema : OptiqSchema.createRootSchema(true);
 
-    OptiqConnectionConfig cfg = new OptiqConnectionConfigImpl(info);
     this.properties.put(InternalProperty.CASE_SENSITIVE, cfg.caseSensitive());
     this.properties.put(InternalProperty.UNQUOTED_CASING, cfg.unquotedCasing());
     this.properties.put(InternalProperty.QUOTED_CASING, cfg.quotedCasing());

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java b/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
index 369f9b1..4c13cfd 100644
--- a/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
+++ b/core/src/main/java/net/hydromatic/optiq/rules/java/RexToLixTranslator.java
@@ -251,7 +251,9 @@ public class RexToLixTranslator {
                 BuiltinMethod.INTERVAL_DAY_TIME_TO_STRING.method,
                 operand,
                 Expressions.constant(interval.foo()),
-                Expressions.constant(interval.getFractionalSecondPrecision())));
+                Expressions.constant(
+                    interval.getFractionalSecondPrecision(
+                        typeFactory.getTypeSystem()))));
         break;
       case BOOLEAN:
         convert = RexImpTable.optimize2(

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/tools/FrameworkConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/tools/FrameworkConfig.java b/core/src/main/java/net/hydromatic/optiq/tools/FrameworkConfig.java
index 4e9cd84..98d0739 100644
--- a/core/src/main/java/net/hydromatic/optiq/tools/FrameworkConfig.java
+++ b/core/src/main/java/net/hydromatic/optiq/tools/FrameworkConfig.java
@@ -22,6 +22,7 @@ import net.hydromatic.optiq.config.Lex;
 import org.eigenbase.relopt.Context;
 import org.eigenbase.relopt.RelOptCostFactory;
 import org.eigenbase.relopt.RelTraitDef;
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.SqlOperatorTable;
 import org.eigenbase.sql.parser.SqlParserImplFactory;
 import org.eigenbase.sql2rel.SqlRexConvertletTable;
@@ -31,6 +32,8 @@ import com.google.common.collect.ImmutableList;
 /**
  * Interface that describes how to configure planning sessions generated
  * using the Frameworks tools.
+ *
+ * @see Frameworks#newConfigBuilder()
  */
 public interface FrameworkConfig {
   /**
@@ -107,6 +110,11 @@ public interface FrameworkConfig {
    * calling {@link org.eigenbase.relopt.RelOptPlanner#getContext()}.
    */
   Context getContext();
+
+  /**
+   * Returns the type system.
+   */
+  RelDataTypeSystem getTypeSystem();
 }
 
 // End FrameworkConfig.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/net/hydromatic/optiq/tools/Frameworks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/net/hydromatic/optiq/tools/Frameworks.java b/core/src/main/java/net/hydromatic/optiq/tools/Frameworks.java
index d08c29c..62b6f3f 100644
--- a/core/src/main/java/net/hydromatic/optiq/tools/Frameworks.java
+++ b/core/src/main/java/net/hydromatic/optiq/tools/Frameworks.java
@@ -18,6 +18,7 @@ package net.hydromatic.optiq.tools;
 
 import net.hydromatic.optiq.SchemaPlus;
 import net.hydromatic.optiq.config.Lex;
+import net.hydromatic.optiq.config.OptiqConnectionProperty;
 import net.hydromatic.optiq.jdbc.OptiqConnection;
 import net.hydromatic.optiq.jdbc.OptiqSchema;
 import net.hydromatic.optiq.prepare.OptiqPrepareImpl;
@@ -29,6 +30,7 @@ import org.eigenbase.relopt.RelOptCluster;
 import org.eigenbase.relopt.RelOptCostFactory;
 import org.eigenbase.relopt.RelOptSchema;
 import org.eigenbase.relopt.RelTraitDef;
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.SqlOperatorTable;
 import org.eigenbase.sql.fun.SqlStdOperatorTable;
 import org.eigenbase.sql.parser.SqlParserImplFactory;
@@ -42,6 +44,7 @@ import com.google.common.collect.ImmutableList;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.util.List;
+import java.util.Properties;
 
 /**
  * Tools for invoking Optiq functionality without initializing a container /
@@ -134,8 +137,13 @@ public class Frameworks {
   public static <R> R withPrepare(PrepareAction<R> action) {
     try {
       Class.forName("net.hydromatic.optiq.jdbc.Driver");
+      final Properties info = new Properties();
+      if (action.config.getTypeSystem() != RelDataTypeSystem.DEFAULT) {
+        info.setProperty(OptiqConnectionProperty.TYPE_SYSTEM.camelName(),
+            action.config.getTypeSystem().getClass().getName());
+      }
       Connection connection =
-          DriverManager.getConnection("jdbc:optiq:");
+          DriverManager.getConnection("jdbc:optiq:", info);
       OptiqConnection optiqConnection =
           connection.unwrap(OptiqConnection.class);
       final OptiqServerStatement statement =
@@ -175,12 +183,14 @@ public class Frameworks {
     private SchemaPlus defaultSchema;
     private RelOptCostFactory costFactory;
     private SqlParserImplFactory parserFactory = SqlParserImpl.FACTORY;
+    private RelDataTypeSystem typeSystem = RelDataTypeSystem.DEFAULT;
 
     private ConfigBuilder() {}
 
     public FrameworkConfig build() {
       return new StdFrameworkConfig(context, convertletTable, operatorTable,
-          programs, traitDefs, lex, defaultSchema, costFactory, parserFactory);
+          programs, traitDefs, lex, defaultSchema, costFactory, parserFactory,
+          typeSystem);
     }
 
     public ConfigBuilder context(Context c) {
@@ -250,6 +260,11 @@ public class Frameworks {
       this.parserFactory = Preconditions.checkNotNull(parserFactory);
       return this;
     }
+
+    public ConfigBuilder typeSystem(RelDataTypeSystem typeSystem) {
+      this.typeSystem = Preconditions.checkNotNull(typeSystem);
+      return this;
+    }
   }
 
   /**
@@ -266,6 +281,7 @@ public class Frameworks {
     private final SchemaPlus defaultSchema;
     private final RelOptCostFactory costFactory;
     private final SqlParserImplFactory parserFactory;
+    private final RelDataTypeSystem typeSystem;
 
     public StdFrameworkConfig(Context context,
         SqlRexConvertletTable convertletTable,
@@ -275,7 +291,8 @@ public class Frameworks {
         Lex lex,
         SchemaPlus defaultSchema,
         RelOptCostFactory costFactory,
-        SqlParserImplFactory parserFactory) {
+        SqlParserImplFactory parserFactory,
+        RelDataTypeSystem typeSystem) {
       this.context = context;
       this.convertletTable = convertletTable;
       this.operatorTable = operatorTable;
@@ -285,6 +302,7 @@ public class Frameworks {
       this.defaultSchema = defaultSchema;
       this.costFactory = costFactory;
       this.parserFactory = parserFactory;
+      this.typeSystem = typeSystem;
     }
 
     public Lex getLex() {
@@ -322,6 +340,10 @@ public class Frameworks {
     public SqlOperatorTable getOperatorTable() {
       return operatorTable;
     }
+
+    public RelDataTypeSystem getTypeSystem() {
+      return typeSystem;
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/rel/rules/ReduceDecimalsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rel/rules/ReduceDecimalsRule.java b/core/src/main/java/org/eigenbase/rel/rules/ReduceDecimalsRule.java
index 1a9325d..d89561d 100644
--- a/core/src/main/java/org/eigenbase/rel/rules/ReduceDecimalsRule.java
+++ b/core/src/main/java/org/eigenbase/rel/rules/ReduceDecimalsRule.java
@@ -336,7 +336,9 @@ public class ReduceDecimalsRule extends RelOptRule {
      * @return 10^scale as an exact numeric value
      */
     protected RexNode makeScaleFactor(int scale) {
-      assert (scale > 0) && (scale < SqlTypeName.MAX_NUMERIC_PRECISION);
+      assert scale > 0;
+      assert scale
+          < builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
       return makeExactLiteral(powerOfTen(scale));
     }
 
@@ -364,7 +366,9 @@ public class ReduceDecimalsRule extends RelOptRule {
      * @return 10^scale / 2 as an exact numeric value
      */
     protected RexNode makeRoundFactor(int scale) {
-      assert (scale > 0) && (scale < SqlTypeName.MAX_NUMERIC_PRECISION);
+      assert scale > 0;
+      assert scale
+          < builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
       return makeExactLiteral(powerOfTen(scale) / 2);
     }
 
@@ -372,7 +376,9 @@ public class ReduceDecimalsRule extends RelOptRule {
      * Calculates a power of ten, as a long value
      */
     protected long powerOfTen(int scale) {
-      assert (scale >= 0) && (scale < SqlTypeName.MAX_NUMERIC_PRECISION);
+      assert scale >= 0;
+      assert scale
+          < builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
       return BigInteger.TEN.pow(scale).longValue();
     }
 
@@ -400,7 +406,9 @@ public class ReduceDecimalsRule extends RelOptRule {
      * @return value * 10^scale as an exact numeric value
      */
     protected RexNode scaleUp(RexNode value, int scale) {
-      assert (scale >= 0) && (scale < SqlTypeName.MAX_NUMERIC_PRECISION);
+      assert scale >= 0;
+      assert scale
+          < builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
       if (scale == 0) {
         return value;
       }
@@ -422,8 +430,9 @@ public class ReduceDecimalsRule extends RelOptRule {
      * exact numeric value
      */
     protected RexNode scaleDown(RexNode value, int scale) {
-      int maxPrecision = SqlTypeName.MAX_NUMERIC_PRECISION;
-      assert (scale >= 0) && (scale <= maxPrecision);
+      final int maxPrecision =
+          builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
+      assert scale >= 0 && scale <= maxPrecision;
       if (scale == 0) {
         return value;
       }
@@ -462,12 +471,13 @@ public class ReduceDecimalsRule extends RelOptRule {
      * double precision arithmetic.
      *
      * @param value the integer representation of a decimal
-     * @param scale a value from zero to {@link
-     *              SqlTypeName#MAX_NUMERIC_PRECISION MAX_NUMERIC_PRECISION}
+     * @param scale a value from zero to max precision
      * @return value/10^scale as a double precision value
      */
     protected RexNode scaleDownDouble(RexNode value, int scale) {
-      assert (scale >= 0) && (scale <= SqlTypeName.MAX_NUMERIC_PRECISION);
+      assert scale >= 0;
+      assert scale
+          <= builder.getTypeFactory().getTypeSystem().getMaxNumericPrecision();
       RexNode cast = ensureType(real8, value);
       if (scale == 0) {
         return cast;
@@ -495,8 +505,10 @@ public class ReduceDecimalsRule extends RelOptRule {
      * corresponding to the input value
      */
     protected RexNode ensureScale(RexNode value, int scale, int required) {
-      int maxPrecision = SqlTypeName.MAX_NUMERIC_PRECISION;
-      assert (scale <= maxPrecision) && (required <= maxPrecision);
+      final RelDataTypeSystem typeSystem =
+          builder.getTypeFactory().getTypeSystem();
+      final int maxPrecision = typeSystem.getMaxNumericPrecision();
+      assert scale <= maxPrecision && required <= maxPrecision;
       assert required >= scale;
       if (scale == required) {
         return value;
@@ -509,7 +521,7 @@ public class ReduceDecimalsRule extends RelOptRule {
       }
 
       // TODO: make a validator exception for this
-      if (scaleDiff >= SqlTypeName.MAX_NUMERIC_PRECISION) {
+      if (scaleDiff >= maxPrecision) {
         throw Util.needToImplement(
             "Source type with scale " + scale
             + " cannot be converted to target type with scale "
@@ -1002,11 +1014,13 @@ public class ReduceDecimalsRule extends RelOptRule {
       RexNode decValue = call.operands.get(0);
       int scale = decValue.getType().getScale();
       RexNode value = decodeValue(decValue);
+      final RelDataTypeSystem typeSystem =
+          builder.getTypeFactory().getTypeSystem();
 
       RexNode rewrite;
       if (scale == 0) {
         rewrite = decValue;
-      } else if (scale == SqlTypeName.MAX_NUMERIC_PRECISION) {
+      } else if (scale == typeSystem.getMaxNumericPrecision()) {
         rewrite =
             makeCase(
                 makeIsNegative(value),
@@ -1049,11 +1063,13 @@ public class ReduceDecimalsRule extends RelOptRule {
       RexNode decValue = call.operands.get(0);
       int scale = decValue.getType().getScale();
       RexNode value = decodeValue(decValue);
+      final RelDataTypeSystem typeSystem =
+          builder.getTypeFactory().getTypeSystem();
 
       RexNode rewrite;
       if (scale == 0) {
         rewrite = decValue;
-      } else if (scale == SqlTypeName.MAX_NUMERIC_PRECISION) {
+      } else if (scale == typeSystem.getMaxNumericPrecision()) {
         rewrite =
             makeCase(
                 makeIsPositive(value),

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactory.java b/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactory.java
index ab26365..0d9fd06 100644
--- a/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactory.java
+++ b/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactory.java
@@ -40,6 +40,11 @@ public interface RelDataTypeFactory {
   //~ Methods ----------------------------------------------------------------
 
   /**
+   * Returns the type system.
+   */
+  RelDataTypeSystem getTypeSystem();
+
+  /**
    * Creates a type which corresponds to a Java class.
    *
    * @param clazz the Java class used to define the type

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactoryImpl.java b/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactoryImpl.java
index db9ceda..80d066c 100644
--- a/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactoryImpl.java
+++ b/core/src/main/java/org/eigenbase/reltype/RelDataTypeFactoryImpl.java
@@ -88,13 +88,30 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
           .put(Timestamp.class, SqlTypeFamily.TIMESTAMP)
           .build();
 
+  protected final RelDataTypeSystem typeSystem;
+
   //~ Constructors -----------------------------------------------------------
 
+  /** Creates a type factory with default type system.
+   *
+   * @deprecated Will be removed after optiq-0.9.1.
+   */
   protected RelDataTypeFactoryImpl() {
+    this(RelDataTypeSystem.DEFAULT);
+    Bug.upgrade("optiq-0.9.1");
+  }
+
+  /** Creates a type factory. */
+  protected RelDataTypeFactoryImpl(RelDataTypeSystem typeSystem) {
+    this.typeSystem = Preconditions.checkNotNull(typeSystem);
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  public RelDataTypeSystem getTypeSystem() {
+    return typeSystem;
+  }
+
   // implement RelDataTypeFactory
   public RelDataType createJavaType(Class clazz) {
     final JavaType javaType =
@@ -450,12 +467,12 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
         int s2 = type2.getScale();
 
         int scale = s1 + s2;
-        scale = Math.min(scale, SqlTypeName.MAX_NUMERIC_SCALE);
+        scale = Math.min(scale, typeSystem.getMaxNumericScale());
         int precision = p1 + p2;
         precision =
             Math.min(
                 precision,
-                SqlTypeName.MAX_NUMERIC_PRECISION);
+                typeSystem.getMaxNumericPrecision());
 
         RelDataType ret;
         ret =
@@ -511,20 +528,21 @@ public abstract class RelDataTypeFactoryImpl implements RelDataTypeFactory {
         int s1 = type1.getScale();
         int s2 = type2.getScale();
 
+        final int maxNumericPrecision = typeSystem.getMaxNumericPrecision();
         int dout =
             Math.min(
                 p1 - s1 + s2,
-                SqlTypeName.MAX_NUMERIC_PRECISION);
+                maxNumericPrecision);
 
         int scale = Math.max(6, s1 + p2 + 1);
         scale =
             Math.min(
                 scale,
-                SqlTypeName.MAX_NUMERIC_PRECISION - dout);
-        scale = Math.min(scale, SqlTypeName.MAX_NUMERIC_SCALE);
+                maxNumericPrecision - dout);
+        scale = Math.min(scale, getTypeSystem().getMaxNumericScale());
 
         int precision = dout + scale;
-        assert precision <= SqlTypeName.MAX_NUMERIC_PRECISION;
+        assert precision <= maxNumericPrecision;
         assert precision > 0;
 
         RelDataType ret;

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystem.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystem.java b/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystem.java
new file mode 100644
index 0000000..e72722f
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystem.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eigenbase.reltype;
+
+import org.eigenbase.sql.type.SqlTypeName;
+
+/**
+ * Type system.
+ *
+ * <p>Provides behaviors concerning type limits and behaviors. For example,
+ * in the default system, a DECIMAL can have maximum precision 19, but Hive
+ * overrides to 38.
+ *
+ * <p>The default implementation is {@link #DEFAULT}.
+ */
+public interface RelDataTypeSystem {
+  /** Default type system. */
+  RelDataTypeSystem DEFAULT = new RelDataTypeSystemImpl() { };
+
+  /** Returns the maximum scale of a given type. */
+  int getMaxScale(SqlTypeName typeName);
+
+  /**
+   * Returns default precision for this type if supported, otherwise -1 if
+   * precision is either unsupported or must be specified explicitly.
+   *
+   * @return Default precision
+   */
+  int getDefaultPrecision(SqlTypeName typeName);
+
+  /**
+   * Returns the maximum precision (or length) allowed for this type, or -1 if
+   * precision/length are not applicable for this type.
+   *
+   * @return Maximum allowed precision
+   */
+  int getMaxPrecision(SqlTypeName typeName);
+
+  /** Returns the maximum scale of a NUMERIC or DECIMAL type. */
+  int getMaxNumericScale();
+
+  /** Returns the maximum precision of a NUMERIC or DECIMAL type. */
+  int getMaxNumericPrecision();
+}
+
+// End RelDataTypeFactory.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystemImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystemImpl.java b/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystemImpl.java
new file mode 100644
index 0000000..b158974
--- /dev/null
+++ b/core/src/main/java/org/eigenbase/reltype/RelDataTypeSystemImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eigenbase.reltype;
+
+import org.eigenbase.sql.type.SqlTypeName;
+
+/** Default implementation of {@link org.eigenbase.reltype.RelDataTypeSystem},
+ * providing parameters from the SQL standard.
+ *
+ * <p>To implement other type systems, create a derived class and override
+ * values as needed.
+ *
+ * <table border='1'>
+ *   <tr><td>Parameter</td>        <td>Value</td></tr>
+ *   <tr><td>MAX_NUMERIC_SCALE</td><td>19</td></tr>
+ * </table>
+ */
+public abstract class RelDataTypeSystemImpl implements RelDataTypeSystem {
+  public int getMaxScale(SqlTypeName typeName) {
+    switch (typeName) {
+    case DECIMAL:
+      return getMaxNumericScale();
+    case INTERVAL_DAY_TIME:
+    case INTERVAL_YEAR_MONTH:
+      return SqlTypeName.MAX_INTERVAL_FRACTIONAL_SECOND_PRECISION;
+    default:
+      return -1;
+    }
+  }
+
+  public int getDefaultPrecision(SqlTypeName typeName) {
+    switch (typeName) {
+    case CHAR:
+    case BINARY:
+    case VARCHAR:
+    case VARBINARY:
+      return 1;
+    case TIME:
+      return 0;
+    case TIMESTAMP:
+      // TODO jvs 26-July-2004:  should be 6 for microseconds,
+      // but we can't support that yet
+      return 0;
+    case DECIMAL:
+      return getMaxNumericPrecision();
+    case INTERVAL_DAY_TIME:
+    case INTERVAL_YEAR_MONTH:
+      return SqlTypeName.DEFAULT_INTERVAL_START_PRECISION;
+    default:
+      return -1;
+    }
+  }
+
+  public int getMaxPrecision(SqlTypeName typeName) {
+    switch (typeName) {
+    case DECIMAL:
+      return getMaxNumericPrecision();
+    case VARCHAR:
+    case CHAR:
+      return 65536;
+    case VARBINARY:
+    case BINARY:
+      return 65536;
+    case TIME:
+    case TIMESTAMP:
+      return SqlTypeName.MAX_DATETIME_PRECISION;
+    case INTERVAL_DAY_TIME:
+    case INTERVAL_YEAR_MONTH:
+      return SqlTypeName.MAX_INTERVAL_START_PRECISION;
+    default:
+      return -1;
+    }
+  }
+
+  public int getMaxNumericScale() {
+    return 19;
+  }
+
+  public int getMaxNumericPrecision() {
+    return 19;
+  }
+}
+
+// End RelDataTypeSystemImpl.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rex/RexBuilder.java b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
index d393a16..251af45 100644
--- a/core/src/main/java/org/eigenbase/rex/RexBuilder.java
+++ b/core/src/main/java/org/eigenbase/rex/RexBuilder.java
@@ -529,7 +529,8 @@ public class RexBuilder {
     if (endUnit == TimeUnit.SECOND) {
       scale = Math.min(
           intervalType.getIntervalQualifier()
-              .getFractionalSecondPrecision(), 3);
+              .getFractionalSecondPrecision(typeFactory.getTypeSystem()),
+          3);
     }
     BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier)
         .divide(BigDecimal.TEN.pow(scale));
@@ -560,7 +561,8 @@ public class RexBuilder {
     if (endUnit == TimeUnit.SECOND) {
       scale = Math.min(
           intervalType.getIntervalQualifier()
-              .getFractionalSecondPrecision(), 3);
+              .getFractionalSecondPrecision(typeFactory.getTypeSystem()),
+          3);
     }
     BigDecimal multiplier = BigDecimal.valueOf(endUnit.multiplier)
         .divide(BigDecimal.TEN.pow(scale));
@@ -798,7 +800,8 @@ public class RexBuilder {
     RelDataType relType;
     int scale = bd.scale();
     long l = bd.unscaledValue().longValue();
-    assert (scale >= 0) && (scale <= SqlTypeName.MAX_NUMERIC_SCALE);
+    assert scale >= 0;
+    assert scale <= typeFactory.getTypeSystem().getMaxNumericScale() : scale;
     assert BigDecimal.valueOf(l, scale).equals(bd);
     if (scale == 0) {
       if ((l >= Integer.MIN_VALUE) && (l <= Integer.MAX_VALUE)) {

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/rex/RexExecutorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/rex/RexExecutorImpl.java b/core/src/main/java/org/eigenbase/rex/RexExecutorImpl.java
index b187344..da34a55 100644
--- a/core/src/main/java/org/eigenbase/rex/RexExecutorImpl.java
+++ b/core/src/main/java/org/eigenbase/rex/RexExecutorImpl.java
@@ -61,7 +61,8 @@ public class RexExecutorImpl implements RelOptPlanner.Executor {
       programBuilder.addProject(
           node, "c" + programBuilder.getProjectList().size());
     }
-    final JavaTypeFactoryImpl javaTypeFactory = new JavaTypeFactoryImpl();
+    final JavaTypeFactoryImpl javaTypeFactory =
+        new JavaTypeFactoryImpl(rexBuilder.getTypeFactory().getTypeSystem());
     final BlockBuilder blockBuilder = new BlockBuilder();
     final ParameterExpression root0_ =
         Expressions.parameter(Object.class, "root0");

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/SqlIntervalQualifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/SqlIntervalQualifier.java b/core/src/main/java/org/eigenbase/sql/SqlIntervalQualifier.java
index 2d3eb7c..406ed57 100644
--- a/core/src/main/java/org/eigenbase/sql/SqlIntervalQualifier.java
+++ b/core/src/main/java/org/eigenbase/sql/SqlIntervalQualifier.java
@@ -20,6 +20,8 @@ import java.math.BigDecimal;
 import java.util.*;
 import java.util.regex.*;
 
+import org.eigenbase.reltype.RelDataType;
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.parser.*;
 import org.eigenbase.sql.type.*;
 import org.eigenbase.sql.util.*;
@@ -29,6 +31,7 @@ import org.eigenbase.util14.DateTimeUtil;
 
 import net.hydromatic.optiq.runtime.SqlFunctions;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 
 import static org.eigenbase.util.Static.RESOURCE;
@@ -83,7 +86,6 @@ import static org.eigenbase.util.Static.RESOURCE;
 public class SqlIntervalQualifier extends SqlNode {
   //~ Static fields/initializers ---------------------------------------------
 
-  private static final int USE_DEFAULT_PRECISION = -1;
   private static final BigDecimal ZERO = BigDecimal.ZERO;
   private static final BigDecimal THOUSAND = BigDecimal.valueOf(1000);
   private static final BigDecimal INT_MAX_VALUE_PLUS_ONE =
@@ -204,9 +206,6 @@ public class SqlIntervalQualifier extends SqlNode {
   private final TimeUnitRange timeUnitRange;
   private final int fractionalSecondPrecision;
 
-  private final boolean useDefaultStartPrecision;
-  private final boolean useDefaultFractionalSecondPrecision;
-
   //~ Constructors -----------------------------------------------------------
 
   public SqlIntervalQualifier(
@@ -216,39 +215,10 @@ public class SqlIntervalQualifier extends SqlNode {
       int fractionalSecondPrecision,
       SqlParserPos pos) {
     super(pos);
-    assert null != startUnit;
-
-    this.timeUnitRange = TimeUnitRange.of(startUnit, endUnit);
-
-    // if unspecified, start precision = 2
-    if (startPrecision == USE_DEFAULT_PRECISION) {
-      useDefaultStartPrecision = true;
-      if (this.isYearMonth()) {
-        this.startPrecision =
-            SqlTypeName.INTERVAL_YEAR_MONTH.getDefaultPrecision();
-      } else {
-        this.startPrecision =
-            SqlTypeName.INTERVAL_DAY_TIME.getDefaultPrecision();
-      }
-    } else {
-      useDefaultStartPrecision = false;
-      this.startPrecision = startPrecision;
-    }
-
-    // unspecified fractional second precision = 6
-    if (fractionalSecondPrecision == USE_DEFAULT_PRECISION) {
-      useDefaultFractionalSecondPrecision = true;
-      if (this.isYearMonth()) {
-        this.fractionalSecondPrecision =
-            SqlTypeName.INTERVAL_YEAR_MONTH.getDefaultScale();
-      } else {
-        this.fractionalSecondPrecision =
-            SqlTypeName.INTERVAL_DAY_TIME.getDefaultScale();
-      }
-    } else {
-      useDefaultFractionalSecondPrecision = false;
-      this.fractionalSecondPrecision = fractionalSecondPrecision;
-    }
+    this.timeUnitRange =
+        TimeUnitRange.of(Preconditions.checkNotNull(startUnit), endUnit);
+    this.startPrecision = startPrecision;
+    this.fractionalSecondPrecision = fractionalSecondPrecision;
   }
 
   public SqlIntervalQualifier(
@@ -257,14 +227,20 @@ public class SqlIntervalQualifier extends SqlNode {
       SqlParserPos pos) {
     this(
         startUnit,
-        USE_DEFAULT_PRECISION,
+        RelDataType.PRECISION_NOT_SPECIFIED,
         endUnit,
-        USE_DEFAULT_PRECISION,
+        RelDataType.PRECISION_NOT_SPECIFIED,
         pos);
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  public SqlTypeName typeName() {
+    return isYearMonth()
+        ? SqlTypeName.INTERVAL_YEAR_MONTH
+        : SqlTypeName.INTERVAL_DAY_TIME;
+  }
+
   public SqlFunctions.TimeUnitRange foo() {
     return SqlFunctions.TimeUnitRange.valueOf(timeUnitRange.name());
   }
@@ -289,33 +265,34 @@ public class SqlIntervalQualifier extends SqlNode {
     return true;
   }
 
-  public static int getDefaultPrecisionId() {
-    return USE_DEFAULT_PRECISION;
+  public int getStartPrecision(RelDataTypeSystem typeSystem) {
+    if (startPrecision == RelDataType.PRECISION_NOT_SPECIFIED) {
+      return typeSystem.getDefaultPrecision(typeName());
+    } else {
+      return startPrecision;
+    }
   }
 
-  public int getStartPrecision() {
+  public int getStartPrecisionPreservingDefault() {
     return startPrecision;
   }
 
-  public int getStartPrecisionPreservingDefault() {
-    if (useDefaultStartPrecision) {
-      return USE_DEFAULT_PRECISION;
-    } else {
-      return startPrecision;
-    }
+  private boolean useDefaultStartPrecision() {
+    return startPrecision == RelDataType.PRECISION_NOT_SPECIFIED;
   }
 
   public static int combineStartPrecisionPreservingDefault(
+      RelDataTypeSystem typeSystem,
       SqlIntervalQualifier qual1,
       SqlIntervalQualifier qual2) {
-    if (qual1.getStartPrecision()
-        > qual2.getStartPrecision()) {
+    final int start1 = qual1.getStartPrecision(typeSystem);
+    final int start2 = qual2.getStartPrecision(typeSystem);
+    if (start1 > start2) {
       // qual1 is more precise, but if it has the default indicator
       // set, we need to return that indicator so result will also
       // use default
       return qual1.getStartPrecisionPreservingDefault();
-    } else if (qual1.getStartPrecision()
-        < qual2.getStartPrecision()) {
+    } else if (start1 < start2) {
       // qual2 is more precise, but if it has the default indicator
       // set, we need to return that indicator so result will also
       // use default
@@ -323,39 +300,47 @@ public class SqlIntervalQualifier extends SqlNode {
     } else {
       // they are equal.  return default if both are default,
       // otherwise return exact precision
-      if (qual1.useDefaultStartPrecision
-          && qual2.useDefaultStartPrecision) {
+      if (qual1.useDefaultStartPrecision()
+          && qual2.useDefaultStartPrecision()) {
         return qual1.getStartPrecisionPreservingDefault();
       } else {
-        return qual1.getStartPrecision();
+        return start1;
       }
     }
   }
 
-  public int getFractionalSecondPrecision() {
-    return fractionalSecondPrecision;
+  public int getFractionalSecondPrecision(RelDataTypeSystem typeSystem) {
+    if (fractionalSecondPrecision == RelDataType.PRECISION_NOT_SPECIFIED) {
+      return typeName().getDefaultScale();
+    } else {
+      return fractionalSecondPrecision;
+    }
   }
 
   public int getFractionalSecondPrecisionPreservingDefault() {
-    if (useDefaultFractionalSecondPrecision) {
-      return USE_DEFAULT_PRECISION;
+    if (useDefaultFractionalSecondPrecision()) {
+      return RelDataType.PRECISION_NOT_SPECIFIED;
     } else {
       return startPrecision;
     }
   }
 
+  private boolean useDefaultFractionalSecondPrecision() {
+    return fractionalSecondPrecision == RelDataType.PRECISION_NOT_SPECIFIED;
+  }
+
   public static int combineFractionalSecondPrecisionPreservingDefault(
+      RelDataTypeSystem typeSystem,
       SqlIntervalQualifier qual1,
       SqlIntervalQualifier qual2) {
-    if (qual1.getFractionalSecondPrecision()
-        > qual2.getFractionalSecondPrecision()) {
+    final int p1 = qual1.getFractionalSecondPrecision(typeSystem);
+    final int p2 = qual2.getFractionalSecondPrecision(typeSystem);
+    if (p1 > p2) {
       // qual1 is more precise, but if it has the default indicator
       // set, we need to return that indicator so result will also
       // use default
       return qual1.getFractionalSecondPrecisionPreservingDefault();
-    } else if (
-        qual1.getFractionalSecondPrecision()
-            < qual2.getFractionalSecondPrecision()) {
+    } else if (p1 < p2) {
       // qual2 is more precise, but if it has the default indicator
       // set, we need to return that indicator so result will also
       // use default
@@ -363,11 +348,11 @@ public class SqlIntervalQualifier extends SqlNode {
     } else {
       // they are equal.  return default if both are default,
       // otherwise return exact precision
-      if (qual1.useDefaultFractionalSecondPrecision
-          && qual2.useDefaultFractionalSecondPrecision) {
+      if (qual1.useDefaultFractionalSecondPrecision()
+          && qual2.useDefaultFractionalSecondPrecision()) {
         return qual1.getFractionalSecondPrecisionPreservingDefault();
       } else {
-        return qual1.getFractionalSecondPrecision();
+        return p1;
       }
     }
   }
@@ -381,29 +366,30 @@ public class SqlIntervalQualifier extends SqlNode {
   }
 
   public SqlNode clone(SqlParserPos pos) {
-    return new SqlIntervalQualifier(
-        timeUnitRange.startUnit,
-        useDefaultStartPrecision ? USE_DEFAULT_PRECISION
-            : startPrecision,
-        timeUnitRange.endUnit,
-        useDefaultFractionalSecondPrecision ? USE_DEFAULT_PRECISION
-            : fractionalSecondPrecision,
-        pos);
+    return new SqlIntervalQualifier(timeUnitRange.startUnit, startPrecision,
+        timeUnitRange.endUnit, fractionalSecondPrecision, pos);
   }
 
   public void unparse(
       SqlWriter writer,
       int leftPrec,
       int rightPrec) {
+    unparse(RelDataTypeSystem.DEFAULT, writer);
+  }
+
+  public void unparse(RelDataTypeSystem typeSystem, SqlWriter writer) {
     final String start = timeUnitRange.startUnit.name();
+    final int fractionalSecondPrecision =
+        getFractionalSecondPrecision(typeSystem);
+    final int startPrecision = getStartPrecision(typeSystem);
     if (timeUnitRange.startUnit == TimeUnit.SECOND) {
-      if (!useDefaultFractionalSecondPrecision) {
+      if (!useDefaultFractionalSecondPrecision()) {
         final SqlWriter.Frame frame = writer.startFunCall(start);
         writer.print(startPrecision);
         writer.sep(",", true);
-        writer.print(fractionalSecondPrecision);
+        writer.print(getFractionalSecondPrecision(typeSystem));
         writer.endList(frame);
-      } else if (!useDefaultStartPrecision) {
+      } else if (!useDefaultStartPrecision()) {
         final SqlWriter.Frame frame = writer.startFunCall(start);
         writer.print(startPrecision);
         writer.endList(frame);
@@ -411,7 +397,7 @@ public class SqlIntervalQualifier extends SqlNode {
         writer.keyword(start);
       }
     } else {
-      if (!useDefaultStartPrecision) {
+      if (!useDefaultStartPrecision()) {
         final SqlWriter.Frame frame = writer.startFunCall(start);
         writer.print(startPrecision);
         writer.endList(frame);
@@ -423,7 +409,7 @@ public class SqlIntervalQualifier extends SqlNode {
         writer.keyword("TO");
         final String end = timeUnitRange.endUnit.name();
         if ((TimeUnit.SECOND == timeUnitRange.endUnit)
-            && (!useDefaultFractionalSecondPrecision)) {
+            && (!useDefaultFractionalSecondPrecision())) {
           final SqlWriter.Frame frame = writer.startFunCall(end);
           writer.print(fractionalSecondPrecision);
           writer.endList(frame);
@@ -474,21 +460,23 @@ public class SqlIntervalQualifier extends SqlNode {
     return unsignedValue;
   }
 
-  private boolean isLeadFieldInRange(BigDecimal value, TimeUnit unit) {
+  private boolean isLeadFieldInRange(RelDataTypeSystem typeSystem,
+      BigDecimal value, TimeUnit unit) {
     // we should never get handed a negative field value
     assert value.compareTo(ZERO) >= 0;
 
     // Leading fields are only restricted by startPrecision.
+    final int startPrecision = getStartPrecision(typeSystem);
     return startPrecision < POWERS10.length
         ? value.compareTo(POWERS10[startPrecision]) < 0
         : value.compareTo(INT_MAX_VALUE_PLUS_ONE) < 0;
   }
 
-  private void checkLeadFieldInRange(
-      int sign, BigDecimal value, TimeUnit unit, SqlParserPos pos) {
-    if (!isLeadFieldInRange(value, unit)) {
+  private void checkLeadFieldInRange(RelDataTypeSystem typeSystem, int sign,
+      BigDecimal value, TimeUnit unit, SqlParserPos pos) {
+    if (!isLeadFieldInRange(typeSystem, value, unit)) {
       throw fieldExceedsPrecisionException(
-          pos, sign, value, unit, startPrecision);
+          pos, sign, value, unit, getStartPrecision(typeSystem));
     }
   }
 
@@ -581,7 +569,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsYear(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -600,7 +588,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, year, TimeUnit.YEAR, pos);
+      checkLeadFieldInRange(typeSystem, sign, year, TimeUnit.YEAR, pos);
 
       // package values up for return
       return fillIntervalValueArray(sign, year, ZERO);
@@ -615,7 +603,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsYearToMonth(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -636,7 +624,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, year, TimeUnit.YEAR, pos);
+      checkLeadFieldInRange(typeSystem, sign, year, TimeUnit.YEAR, pos);
       if (!(isSecondaryFieldInRange(month, TimeUnit.MONTH))) {
         throw invalidValueException(pos, originalValue);
       }
@@ -654,7 +642,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsMonth(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -673,7 +661,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, month, TimeUnit.MONTH, pos);
+      checkLeadFieldInRange(typeSystem, sign, month, TimeUnit.MONTH, pos);
 
       // package values up for return
       return fillIntervalValueArray(sign, ZERO, month);
@@ -688,7 +676,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsDay(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -707,7 +695,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, day, TimeUnit.DAY, pos);
+      checkLeadFieldInRange(typeSystem, sign, day, TimeUnit.DAY, pos);
 
       // package values up for return
       return fillIntervalValueArray(sign, day, ZERO, ZERO, ZERO, ZERO);
@@ -722,7 +710,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsDayToHour(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -743,7 +731,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, day, TimeUnit.DAY, pos);
+      checkLeadFieldInRange(typeSystem, sign, day, TimeUnit.DAY, pos);
       if (!(isSecondaryFieldInRange(hour, TimeUnit.HOUR))) {
         throw invalidValueException(pos, originalValue);
       }
@@ -761,7 +749,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsDayToMinute(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -784,7 +772,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, day, TimeUnit.DAY, pos);
+      checkLeadFieldInRange(typeSystem, sign, day, TimeUnit.DAY, pos);
       if (!(isSecondaryFieldInRange(hour, TimeUnit.HOUR))
           || !(isSecondaryFieldInRange(minute, TimeUnit.MINUTE))) {
         throw invalidValueException(pos, originalValue);
@@ -803,7 +791,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsDayToSecond(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -817,6 +805,8 @@ public class SqlIntervalQualifier extends SqlNode {
     // validate as DAY(startPrecision) TO MINUTE,
     // e.g. 'DD HH:MM:SS' or 'DD HH:MM:SS.SSS'
     // Note: must check two patterns, since fractional second is optional
+    final int fractionalSecondPrecision =
+        getFractionalSecondPrecision(typeSystem);
     String intervalPatternWithFracSec =
         "(\\d+) (\\d{1,2}):(\\d{1,2}):(\\d{1,2})\\.(\\d{1,"
         + fractionalSecondPrecision + "})";
@@ -849,7 +839,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, day, TimeUnit.DAY, pos);
+      checkLeadFieldInRange(typeSystem, sign, day, TimeUnit.DAY, pos);
       if (!(isSecondaryFieldInRange(hour, TimeUnit.HOUR))
           || !(isSecondaryFieldInRange(minute, TimeUnit.MINUTE))
           || !(isSecondaryFieldInRange(second, TimeUnit.SECOND))
@@ -876,7 +866,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsHour(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -895,7 +885,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, hour, TimeUnit.HOUR, pos);
+      checkLeadFieldInRange(typeSystem, sign, hour, TimeUnit.HOUR, pos);
 
       // package values up for return
       return fillIntervalValueArray(sign, ZERO, hour, ZERO, ZERO, ZERO);
@@ -911,7 +901,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsHourToMinute(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -932,7 +922,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, hour, TimeUnit.HOUR, pos);
+      checkLeadFieldInRange(typeSystem, sign, hour, TimeUnit.HOUR, pos);
       if (!(isSecondaryFieldInRange(minute, TimeUnit.MINUTE))) {
         throw invalidValueException(pos, originalValue);
       }
@@ -951,7 +941,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsHourToSecond(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -964,6 +954,8 @@ public class SqlIntervalQualifier extends SqlNode {
     // validate as HOUR(startPrecision) TO SECOND,
     // e.g. 'HH:MM:SS' or 'HH:MM:SS.SSS'
     // Note: must check two patterns, since fractional second is optional
+    final int fractionalSecondPrecision =
+        getFractionalSecondPrecision(typeSystem);
     String intervalPatternWithFracSec =
         "(\\d+):(\\d{1,2}):(\\d{1,2})\\.(\\d{1,"
         + fractionalSecondPrecision + "})";
@@ -995,7 +987,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, hour, TimeUnit.HOUR, pos);
+      checkLeadFieldInRange(typeSystem, sign, hour, TimeUnit.HOUR, pos);
       if (!(isSecondaryFieldInRange(minute, TimeUnit.MINUTE))
           || !(isSecondaryFieldInRange(second, TimeUnit.SECOND))
           || !(isFractionalSecondFieldInRange(secondFrac))) {
@@ -1021,7 +1013,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsMinute(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -1040,7 +1032,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, minute, TimeUnit.MINUTE, pos);
+      checkLeadFieldInRange(typeSystem, sign, minute, TimeUnit.MINUTE, pos);
 
       // package values up for return
       return fillIntervalValueArray(sign, ZERO, ZERO, minute, ZERO, ZERO);
@@ -1056,7 +1048,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsMinuteToSecond(
-      int sign,
+      RelDataTypeSystem typeSystem, int sign,
       String value,
       String originalValue,
       SqlParserPos pos) {
@@ -1068,6 +1060,8 @@ public class SqlIntervalQualifier extends SqlNode {
     // validate as MINUTE(startPrecision) TO SECOND,
     // e.g. 'MM:SS' or 'MM:SS.SSS'
     // Note: must check two patterns, since fractional second is optional
+    final int fractionalSecondPrecision =
+        getFractionalSecondPrecision(typeSystem);
     String intervalPatternWithFracSec =
         "(\\d+):(\\d{1,2})\\.(\\d{1," + fractionalSecondPrecision + "})";
     String intervalPatternWithoutFracSec =
@@ -1097,7 +1091,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, minute, TimeUnit.MINUTE, pos);
+      checkLeadFieldInRange(typeSystem, sign, minute, TimeUnit.MINUTE, pos);
       if (!(isSecondaryFieldInRange(second, TimeUnit.SECOND))
           || !(isFractionalSecondFieldInRange(secondFrac))) {
         throw invalidValueException(pos, originalValue);
@@ -1122,6 +1116,7 @@ public class SqlIntervalQualifier extends SqlNode {
    * @throws EigenbaseContextException if the interval value is illegal.
    */
   private int[] evaluateIntervalLiteralAsSecond(
+      RelDataTypeSystem typeSystem,
       int sign,
       String value,
       String originalValue,
@@ -1133,6 +1128,8 @@ public class SqlIntervalQualifier extends SqlNode {
     // validate as SECOND(startPrecision, fractionalSecondPrecision)
     // e.g. 'SS' or 'SS.SSS'
     // Note: must check two patterns, since fractional second is optional
+    final int fractionalSecondPrecision =
+        getFractionalSecondPrecision(typeSystem);
     String intervalPatternWithFracSec =
         "(\\d+)\\.(\\d{1," + fractionalSecondPrecision + "})";
     String intervalPatternWithoutFracSec =
@@ -1161,7 +1158,7 @@ public class SqlIntervalQualifier extends SqlNode {
       }
 
       // Validate individual fields
-      checkLeadFieldInRange(sign, second, TimeUnit.SECOND, pos);
+      checkLeadFieldInRange(typeSystem, sign, second, TimeUnit.SECOND, pos);
       if (!(isFractionalSecondFieldInRange(secondFrac))) {
         throw invalidValueException(pos, originalValue);
       }
@@ -1183,7 +1180,8 @@ public class SqlIntervalQualifier extends SqlNode {
    * @return field values, never null
    * @throws EigenbaseContextException if the interval value is illegal
    */
-  public int[] evaluateIntervalLiteral(String value, SqlParserPos pos) {
+  public int[] evaluateIntervalLiteral(String value, SqlParserPos pos,
+      RelDataTypeSystem typeSystem) {
     // save original value for if we have to throw
     final String value0 = value;
 
@@ -1207,31 +1205,43 @@ public class SqlIntervalQualifier extends SqlNode {
     // well as explicit or implicit precision and range.
     switch (timeUnitRange) {
     case YEAR:
-      return evaluateIntervalLiteralAsYear(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsYear(typeSystem, sign, value, value0,
+          pos);
     case YEAR_TO_MONTH:
-      return evaluateIntervalLiteralAsYearToMonth(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsYearToMonth(typeSystem, sign, value,
+          value0, pos);
     case MONTH:
-      return evaluateIntervalLiteralAsMonth(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsMonth(typeSystem, sign, value, value0,
+          pos);
     case DAY:
-      return evaluateIntervalLiteralAsDay(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsDay(typeSystem, sign, value, value0, pos);
     case DAY_TO_HOUR:
-      return evaluateIntervalLiteralAsDayToHour(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsDayToHour(typeSystem, sign, value, value0,
+          pos);
     case DAY_TO_MINUTE:
-      return evaluateIntervalLiteralAsDayToMinute(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsDayToMinute(typeSystem, sign, value,
+          value0, pos);
     case DAY_TO_SECOND:
-      return evaluateIntervalLiteralAsDayToSecond(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsDayToSecond(typeSystem, sign, value,
+          value0, pos);
     case HOUR:
-      return evaluateIntervalLiteralAsHour(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsHour(typeSystem, sign, value, value0,
+          pos);
     case HOUR_TO_MINUTE:
-      return evaluateIntervalLiteralAsHourToMinute(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsHourToMinute(typeSystem, sign, value,
+          value0, pos);
     case HOUR_TO_SECOND:
-      return evaluateIntervalLiteralAsHourToSecond(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsHourToSecond(typeSystem, sign, value,
+          value0, pos);
     case MINUTE:
-      return evaluateIntervalLiteralAsMinute(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsMinute(typeSystem, sign, value, value0,
+          pos);
     case MINUTE_TO_SECOND:
-      return evaluateIntervalLiteralAsMinuteToSecond(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsMinuteToSecond(typeSystem, sign, value,
+          value0, pos);
     case SECOND:
-      return evaluateIntervalLiteralAsSecond(sign, value, value0, pos);
+      return evaluateIntervalLiteralAsSecond(typeSystem, sign, value, value0,
+          pos);
     default:
       throw invalidValueException(pos, value0);
     }

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/SqlUnresolvedFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/SqlUnresolvedFunction.java b/core/src/main/java/org/eigenbase/sql/SqlUnresolvedFunction.java
index a8a5ac6..a607022 100644
--- a/core/src/main/java/org/eigenbase/sql/SqlUnresolvedFunction.java
+++ b/core/src/main/java/org/eigenbase/sql/SqlUnresolvedFunction.java
@@ -19,7 +19,6 @@ package org.eigenbase.sql;
 import java.util.List;
 
 import org.eigenbase.reltype.RelDataType;
-import org.eigenbase.sql.type.BasicSqlType;
 import org.eigenbase.sql.type.SqlOperandTypeChecker;
 import org.eigenbase.sql.type.SqlOperandTypeInference;
 import org.eigenbase.sql.type.SqlReturnTypeInference;
@@ -64,9 +63,8 @@ public class SqlUnresolvedFunction extends SqlFunction {
    * fail.
    */
   @Override
-  public RelDataType inferReturnType(
-      SqlOperatorBinding opBinding) {
-    return new BasicSqlType(SqlTypeName.ANY);
+  public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
+    return opBinding.getTypeFactory().createSqlType(SqlTypeName.ANY);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/parser/SqlParserUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/parser/SqlParserUtil.java b/core/src/main/java/org/eigenbase/sql/parser/SqlParserUtil.java
index 30fe3d4..1297f35 100644
--- a/core/src/main/java/org/eigenbase/sql/parser/SqlParserUtil.java
+++ b/core/src/main/java/org/eigenbase/sql/parser/SqlParserUtil.java
@@ -22,6 +22,7 @@ import java.text.*;
 import java.util.*;
 import java.util.logging.*;
 
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.*;
 import org.eigenbase.trace.*;
 import org.eigenbase.util.*;
@@ -135,7 +136,7 @@ public final class SqlParserUtil {
     int[] ret;
     try {
       ret = intervalQualifier.evaluateIntervalLiteral(literal,
-          intervalQualifier.getParserPosition());
+          intervalQualifier.getParserPosition(), RelDataTypeSystem.DEFAULT);
       assert ret != null;
     } catch (EigenbaseContextException e) {
       throw Util.newInternal(
@@ -177,7 +178,7 @@ public final class SqlParserUtil {
     int[] ret;
     try {
       ret = intervalQualifier.evaluateIntervalLiteral(literal,
-          intervalQualifier.getParserPosition());
+          intervalQualifier.getParserPosition(), RelDataTypeSystem.DEFAULT);
       assert ret != null;
     } catch (EigenbaseContextException e) {
       throw Util.newInternal(

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/type/BasicSqlType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/BasicSqlType.java b/core/src/main/java/org/eigenbase/sql/type/BasicSqlType.java
index ab79e8f..796f45b 100644
--- a/core/src/main/java/org/eigenbase/sql/type/BasicSqlType.java
+++ b/core/src/main/java/org/eigenbase/sql/type/BasicSqlType.java
@@ -18,6 +18,7 @@ package org.eigenbase.sql.type;
 
 import java.nio.charset.*;
 
+import org.eigenbase.reltype.RelDataTypeSystem;
 import org.eigenbase.sql.*;
 import org.eigenbase.util.*;
 
@@ -30,8 +31,9 @@ public class BasicSqlType extends AbstractSqlType {
 
   //~ Instance fields --------------------------------------------------------
 
-  private int precision;
-  private int scale;
+  private final int precision;
+  private final int scale;
+  private final RelDataTypeSystem typeSystem;
   private SqlCollation collation;
   private SerializableCharset wrappedCharset;
 
@@ -43,12 +45,11 @@ public class BasicSqlType extends AbstractSqlType {
    *
    * @param typeName Type name
    */
-  public BasicSqlType(SqlTypeName typeName) {
-    super(typeName, false, null);
+  public BasicSqlType(RelDataTypeSystem typeSystem, SqlTypeName typeName) {
+    this(typeSystem, typeName, false, PRECISION_NOT_SPECIFIED,
+        SCALE_NOT_SPECIFIED);
     assert typeName.allowsPrecScale(false, false)
         : "typeName.allowsPrecScale(false,false), typeName=" + typeName.name();
-    this.precision = PRECISION_NOT_SPECIFIED;
-    this.scale = SCALE_NOT_SPECIFIED;
     computeDigest();
   }
 
@@ -57,14 +58,11 @@ public class BasicSqlType extends AbstractSqlType {
    *
    * @param typeName Type name
    */
-  public BasicSqlType(
-      SqlTypeName typeName,
+  public BasicSqlType(RelDataTypeSystem typeSystem, SqlTypeName typeName,
       int precision) {
-    super(typeName, false, null);
+    this(typeSystem, typeName, false, precision, SCALE_NOT_SPECIFIED);
     assert typeName.allowsPrecScale(true, false)
         : "typeName.allowsPrecScale(true, false)";
-    this.precision = precision;
-    this.scale = SCALE_NOT_SPECIFIED;
     computeDigest();
   }
 
@@ -73,15 +71,24 @@ public class BasicSqlType extends AbstractSqlType {
    *
    * @param typeName Type name
    */
-  public BasicSqlType(
+  public BasicSqlType(RelDataTypeSystem typeSystem, SqlTypeName typeName,
+      int precision, int scale) {
+    this(typeSystem, typeName, false, precision, scale);
+    assert typeName.allowsPrecScale(true, true);
+    computeDigest();
+  }
+
+  /** Internal constructor. */
+  private BasicSqlType(
+      RelDataTypeSystem typeSystem,
       SqlTypeName typeName,
+      boolean nullable,
       int precision,
       int scale) {
-    super(typeName, false, null);
-    assert typeName.allowsPrecScale(true, true);
+    super(typeName, nullable, null);
+    this.typeSystem = typeSystem;
     this.precision = precision;
     this.scale = scale;
-    computeDigest();
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -137,7 +144,7 @@ public class BasicSqlType extends AbstractSqlType {
       case BIGINT:
         return 19;
       case DECIMAL:
-        return SqlTypeName.MAX_NUMERIC_PRECISION;
+        return RelDataTypeSystem.DEFAULT.getMaxNumericPrecision(); // FIXME
       case REAL:
         return 7;
       case FLOAT:
@@ -205,7 +212,7 @@ public class BasicSqlType extends AbstractSqlType {
     // since (for instance) TIME is equivalent to TIME(0).
     if (withDetail) {
       // -1 means there is no default value for precision
-      if (typeName.getDefaultPrecision() > -1) {
+      if (typeSystem.getDefaultPrecision(typeName) > -1) {
         printPrecision = true;
       }
       if (typeName.getDefaultScale() > -1) {

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/type/IntervalSqlType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/IntervalSqlType.java b/core/src/main/java/org/eigenbase/sql/type/IntervalSqlType.java
index c3141f7..c82671c 100644
--- a/core/src/main/java/org/eigenbase/sql/type/IntervalSqlType.java
+++ b/core/src/main/java/org/eigenbase/sql/type/IntervalSqlType.java
@@ -19,6 +19,8 @@ package org.eigenbase.sql.type;
 import org.eigenbase.reltype.*;
 import org.eigenbase.sql.*;
 import org.eigenbase.sql.parser.*;
+import org.eigenbase.sql.pretty.SqlPrettyWriter;
+import org.eigenbase.sql.util.SqlString;
 
 /**
  * IntervalSqlType represents a standard SQL datetime interval type.
@@ -26,6 +28,7 @@ import org.eigenbase.sql.parser.*;
 public class IntervalSqlType extends AbstractSqlType {
   //~ Instance fields --------------------------------------------------------
 
+  private final RelDataTypeSystem typeSystem;
   private SqlIntervalQualifier intervalQualifier;
 
   //~ Constructors -----------------------------------------------------------
@@ -34,14 +37,15 @@ public class IntervalSqlType extends AbstractSqlType {
    * Constructs an IntervalSqlType. This should only be called from a factory
    * method.
    */
-  public IntervalSqlType(
+  public IntervalSqlType(RelDataTypeSystem typeSystem,
       SqlIntervalQualifier intervalQualifier,
       boolean isNullable) {
-    super(
-        intervalQualifier.isYearMonth() ? SqlTypeName.INTERVAL_YEAR_MONTH
+    super(intervalQualifier.isYearMonth()
+            ? SqlTypeName.INTERVAL_YEAR_MONTH
             : SqlTypeName.INTERVAL_DAY_TIME,
         isNullable,
         null);
+    this.typeSystem = typeSystem;
     this.intervalQualifier = intervalQualifier;
     computeDigest();
   }
@@ -51,7 +55,15 @@ public class IntervalSqlType extends AbstractSqlType {
   // implement RelDataTypeImpl
   protected void generateTypeString(StringBuilder sb, boolean withDetail) {
     sb.append("INTERVAL ");
-    sb.append(intervalQualifier.toString());
+    SqlDialect dialect = null;
+    dialect = SqlDialect.DUMMY;
+    SqlPrettyWriter writer = new SqlPrettyWriter(dialect);
+    writer.setAlwaysUseParentheses(false);
+    writer.setSelectListItemsOnSeparateLines(false);
+    writer.setIndentation(0);
+    intervalQualifier.unparse(writer, 0, 0);
+    final String sql = writer.toString();
+    sb.append(new SqlString(dialect, sql).getSql());
   }
 
   // implement RelDataType
@@ -88,10 +100,10 @@ public class IntervalSqlType extends AbstractSqlType {
     int secondPrec =
         this.intervalQualifier.getStartPrecisionPreservingDefault();
     int fracPrec =
-        SqlIntervalQualifier
-            .combineFractionalSecondPrecisionPreservingDefault(
-                this.intervalQualifier,
-                that.intervalQualifier);
+        SqlIntervalQualifier.combineFractionalSecondPrecisionPreservingDefault(
+            typeSystem,
+            this.intervalQualifier,
+            that.intervalQualifier);
 
     if (thisStart.ordinal() > thatStart.ordinal()) {
       thisEnd = thisStart;
@@ -101,17 +113,15 @@ public class IntervalSqlType extends AbstractSqlType {
     } else if (thisStart.ordinal() == thatStart.ordinal()) {
       secondPrec =
           SqlIntervalQualifier.combineStartPrecisionPreservingDefault(
+              typeFactory.getTypeSystem(),
               this.intervalQualifier,
               that.intervalQualifier);
-    } else if (
-        (null == thisEnd)
-            || (thisEnd.ordinal() < thatStart.ordinal())) {
+    } else if (null == thisEnd || thisEnd.ordinal() < thatStart.ordinal()) {
       thisEnd = thatStart;
     }
 
     if (null != thatEnd) {
-      if ((null == thisEnd)
-          || (thisEnd.ordinal() < thatEnd.ordinal())) {
+      if (null == thisEnd || thisEnd.ordinal() < thatEnd.ordinal()) {
         thisEnd = thatEnd;
       }
     }
@@ -131,17 +141,14 @@ public class IntervalSqlType extends AbstractSqlType {
     return (IntervalSqlType) intervalType;
   }
 
-  // implement RelDataType
-  public int getPrecision() {
-    return intervalQualifier.getStartPrecision();
+  @Override public int getPrecision() {
+    return intervalQualifier.getStartPrecision(typeSystem);
   }
 
   @Override
   public int getScale() {
-    // TODO Auto-generated method stub
-    return intervalQualifier.getFractionalSecondPrecision();
+    return intervalQualifier.getFractionalSecondPrecision(typeSystem);
   }
-
 }
 
 // End IntervalSqlType.java

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/type/ReturnTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/ReturnTypes.java b/core/src/main/java/org/eigenbase/sql/type/ReturnTypes.java
index 573c36c..55c2893 100644
--- a/core/src/main/java/org/eigenbase/sql/type/ReturnTypes.java
+++ b/core/src/main/java/org/eigenbase/sql/type/ReturnTypes.java
@@ -468,23 +468,21 @@ public abstract class ReturnTypes {
               int s1 = type1.getScale();
               int s2 = type2.getScale();
 
+              final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
               int scale = Math.max(s1, s2);
-              assert scale <= SqlTypeName.MAX_NUMERIC_SCALE;
+              final RelDataTypeSystem typeSystem = typeFactory.getTypeSystem();
+              assert scale <= typeSystem.getMaxNumericScale();
               int precision = Math.max(p1 - s1, p2 - s2) + scale + 1;
               precision =
                   Math.min(
                       precision,
-                      SqlTypeName.MAX_NUMERIC_PRECISION);
+                      typeSystem.getMaxNumericPrecision());
               assert precision > 0;
 
-              RelDataType ret;
-              ret =
-                  opBinding.getTypeFactory().createSqlType(
-                      SqlTypeName.DECIMAL,
-                      precision,
-                      scale);
-
-              return ret;
+              return typeFactory.createSqlType(
+                  SqlTypeName.DECIMAL,
+                  precision,
+                  scale);
             }
           }
 

http://git-wip-us.apache.org/repos/asf/incubator-optiq/blob/0fd4e3d9/core/src/main/java/org/eigenbase/sql/type/SqlTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/eigenbase/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/eigenbase/sql/type/SqlTypeFactoryImpl.java
index 71ccbf9..04110b8 100644
--- a/core/src/main/java/org/eigenbase/sql/type/SqlTypeFactoryImpl.java
+++ b/core/src/main/java/org/eigenbase/sql/type/SqlTypeFactoryImpl.java
@@ -24,13 +24,14 @@ import org.eigenbase.sql.*;
 import org.eigenbase.util.*;
 
 /**
- * SqlTypeFactoryImpl provides a default implementation of {@link
- * RelDataTypeFactory} which supports SQL types.
+ * SqlTypeFactoryImpl provides a default implementation of
+ * {@link RelDataTypeFactory} which supports SQL types.
  */
 public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
   //~ Constructors -----------------------------------------------------------
 
-  public SqlTypeFactoryImpl() {
+  public SqlTypeFactoryImpl(RelDataTypeSystem typeSystem) {
+    super(typeSystem);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -38,10 +39,10 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
   // implement RelDataTypeFactory
   public RelDataType createSqlType(SqlTypeName typeName) {
     if (typeName.allowsPrec()) {
-      return createSqlType(typeName, typeName.getDefaultPrecision());
+      return createSqlType(typeName, typeSystem.getDefaultPrecision(typeName));
     }
     assertBasic(typeName);
-    RelDataType newType = new BasicSqlType(typeName);
+    RelDataType newType = new BasicSqlType(typeSystem, typeName);
     return canonize(newType);
   }
 
@@ -55,7 +56,7 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
     assertBasic(typeName);
     assert (precision >= 0)
         || (precision == RelDataType.PRECISION_NOT_SPECIFIED);
-    RelDataType newType = new BasicSqlType(typeName, precision);
+    RelDataType newType = new BasicSqlType(typeSystem, typeName, precision);
     newType = SqlTypeUtil.addCharsetAndCollation(newType, this);
     return canonize(newType);
   }
@@ -68,7 +69,8 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
     assertBasic(typeName);
     assert (precision >= 0)
         || (precision == RelDataType.PRECISION_NOT_SPECIFIED);
-    RelDataType newType = new BasicSqlType(typeName, precision, scale);
+    RelDataType newType =
+        new BasicSqlType(typeSystem, typeName, precision, scale);
     newType = SqlTypeUtil.addCharsetAndCollation(newType, this);
     return canonize(newType);
   }
@@ -100,7 +102,8 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
   // implement RelDataTypeFactory
   public RelDataType createSqlIntervalType(
       SqlIntervalQualifier intervalQualifier) {
-    RelDataType newType = new IntervalSqlType(intervalQualifier, false);
+    RelDataType newType =
+        new IntervalSqlType(typeSystem, intervalQualifier, false);
     return canonize(newType);
   }
 
@@ -339,23 +342,24 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
               int p2 = type.getPrecision();
               int s1 = resultType.getScale();
               int s2 = type.getScale();
+              final int maxPrecision = typeSystem.getMaxNumericPrecision();
+              final int maxScale = typeSystem.getMaxNumericScale();
 
               int dout = Math.max(p1 - s1, p2 - s2);
               dout =
                   Math.min(
                       dout,
-                      SqlTypeName.MAX_NUMERIC_PRECISION);
+                      maxPrecision);
 
               int scale = Math.max(s1, s2);
               scale =
                   Math.min(
                       scale,
-                      SqlTypeName.MAX_NUMERIC_PRECISION - dout);
-              scale =
-                  Math.min(scale, SqlTypeName.MAX_NUMERIC_SCALE);
+                      maxPrecision - dout);
+              scale = Math.min(scale, maxScale);
 
               int precision = dout + scale;
-              assert precision <= SqlTypeName.MAX_NUMERIC_PRECISION;
+              assert precision <= maxPrecision;
               assert precision > 0;
 
               resultType =
@@ -461,7 +465,7 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
   }
 
   private RelDataType copyIntervalType(RelDataType type, boolean nullable) {
-    return new IntervalSqlType(
+    return new IntervalSqlType(typeSystem,
         type.getIntervalQualifier(),
         nullable);
   }