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 2015/04/26 04:32:54 UTC

[2/2] incubator-calcite git commit: [CALCITE-522] In remote JDBC driver, transmit static database properties as a map

[CALCITE-522] In remote JDBC driver, transmit static database properties as a map


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

Branch: refs/heads/master
Commit: e218cb1534ea6e0c5d9a2f41a6005fa28a6164d2
Parents: 93c2ff5
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Apr 20 18:36:57 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Sat Apr 25 17:47:57 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   |  33 ++---
 .../calcite/avatica/RemoteDriverTest.java       | 124 ++++++++++++-------
 .../avatica/AvaticaDatabaseMetaData.java        |  18 ++-
 .../apache/calcite/avatica/AvaticaUtils.java    |  25 ++++
 .../java/org/apache/calcite/avatica/Meta.java   |  95 +++++++++-----
 .../org/apache/calcite/avatica/MetaImpl.java    |   4 +-
 .../org/apache/calcite/avatica/SqlType.java     |  22 +---
 .../calcite/avatica/remote/LocalService.java    |   5 +-
 .../calcite/avatica/remote/RemoteMeta.java      |  20 ++-
 .../apache/calcite/avatica/remote/Service.java  |  14 +--
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  31 ++++-
 .../apache/calcite/jdbc/DatabaseProperties.java |  78 ------------
 .../calcite/jdbc/CalciteRemoteDriverTest.java   |  25 ++--
 13 files changed, 261 insertions(+), 233 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index e790e9f..e574fe6 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -31,7 +31,9 @@ import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.RemovalListener;
 import com.google.common.cache.RemovalNotification;
 
+import java.lang.reflect.InvocationTargetException;
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
@@ -42,7 +44,9 @@ import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
 import java.util.UUID;
@@ -348,27 +352,28 @@ public class JdbcMeta implements Meta {
     }
   }
 
-  public String getDatabaseProperties(Meta.DatabaseProperties propertyName) {
+  public Map<DatabaseProperty, Object> getDatabaseProperties() {
     try {
-      switch(propertyName) {
-      case NUMERIC_FUNCTIONS:
-        return connection.getMetaData().getNumericFunctions();
-      case SYSTEM_FUNCTIONS:
-        return connection.getMetaData().getSystemFunctions();
-      case TIME_DATE_FUNCTIONS:
-        return connection.getMetaData().getTimeDateFunctions();
-      case STRING_FUNCTIONS:
-        return connection.getMetaData().getStringFunctions();
-      case SQL_KEYWORDS:
-        return connection.getMetaData().getSQLKeywords();
-      default:
-        return "";
+      final Map<DatabaseProperty, Object> map = new HashMap<>();
+      final DatabaseMetaData metaData = connection.getMetaData();
+      for (DatabaseProperty p : DatabaseProperty.values()) {
+        addProperty(map, metaData, p);
       }
+      return map;
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
   }
 
+  private static Object addProperty(Map<DatabaseProperty, Object> map,
+      DatabaseMetaData metaData, DatabaseProperty p) throws SQLException {
+    try {
+      return map.put(p, p.method.invoke(metaData));
+    } catch (IllegalAccessException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   public MetaResultSet getTables(String catalog, Pat schemaPattern,
       Pat tableNamePattern, List<String> typeList) {
     try {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
index 7ec10d8..21989ed 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/RemoteDriverTest.java
@@ -32,6 +32,7 @@ import org.junit.Test;
 
 import java.lang.reflect.Field;
 import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.Date;
 import java.sql.DriverManager;
 import java.sql.ParameterMetaData;
@@ -83,6 +84,21 @@ public class RemoteDriverTest {
     return DriverManager.getConnection("jdbc:avatica:remote:factory=" + QRJS);
   }
 
+  private Connection canon() throws SQLException {
+    return DriverManager.getConnection(CONNECTION_SPEC.url,
+        CONNECTION_SPEC.username, CONNECTION_SPEC.password);
+  }
+
+  /** Executes a lambda for the canonical connection and the local
+   * connection. */
+  public void eachConnection(ConnectionFunction f) throws Exception {
+    for (int i = 0; i < 2; i++) {
+      try (Connection connection = i == 0 ? canon() : ljs()) {
+        f.apply(connection);
+      }
+    }
+  }
+
   @Before
   public void before() throws Exception {
     QuasiRemoteJdbcServiceFactory.initService();
@@ -111,40 +127,35 @@ public class RemoteDriverTest {
 
   @Test public void testDatabaseProperties() throws Exception {
     final Connection connection = ljs();
-    for (Meta.DatabaseProperties p : Meta.DatabaseProperties.values()) {
-      switch(p) {
-      case NUMERIC_FUNCTIONS:
-        assertEquals("Fail to get NUMERIC_FUNCTIONS",
-          "ABS,ACOS,ASIN,ATAN,ATAN2,BITAND,BITOR,BITXOR,"
-          + "CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MOD,"
-          + "PI,POWER,RADIANS,RAND,ROUND,ROUNDMAGIC,SIGN,SIN,"
-          + "SQRT,TAN,TRUNCATE",
-          connection.getMetaData().getNumericFunctions());
+    for (Meta.DatabaseProperty p : Meta.DatabaseProperty.values()) {
+      switch (p) {
+      case GET_NUMERIC_FUNCTIONS:
+        assertThat(connection.getMetaData().getNumericFunctions(),
+            equalTo("ABS,ACOS,ASIN,ATAN,ATAN2,BITAND,BITOR,BITXOR,"
+                + "CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MOD,"
+                + "PI,POWER,RADIANS,RAND,ROUND,ROUNDMAGIC,SIGN,SIN,"
+                + "SQRT,TAN,TRUNCATE"));
         break;
-      case SYSTEM_FUNCTIONS:
-        assertEquals("Fail to get SYSTEM_FUNCTIONS",
-          "DATABASE,IFNULL,USER",
-          connection.getMetaData().getSystemFunctions());
+      case GET_SYSTEM_FUNCTIONS:
+        assertThat(connection.getMetaData().getSystemFunctions(),
+            equalTo("DATABASE,IFNULL,USER"));
         break;
-      case TIME_DATE_FUNCTIONS:
-        assertEquals("Fail to get TIME_DATE_FUNCTIONS",
-          "CURDATE,CURTIME,DATEDIFF,DAYNAME,DAYOFMONTH,DAYOFWEEK,"
-          + "DAYOFYEAR,HOUR,MINUTE,MONTH,MONTHNAME,NOW,QUARTER,SECOND,"
-          + "SECONDS_SINCE_MIDNIGHT,TIMESTAMPADD,TIMESTAMPDIFF,"
-          + "TO_CHAR,WEEK,YEAR",
-          connection.getMetaData().getTimeDateFunctions());
+      case GET_TIME_DATE_FUNCTIONS:
+        assertThat(connection.getMetaData().getTimeDateFunctions(),
+            equalTo("CURDATE,CURTIME,DATEDIFF,DAYNAME,DAYOFMONTH,DAYOFWEEK,"
+                + "DAYOFYEAR,HOUR,MINUTE,MONTH,MONTHNAME,NOW,QUARTER,SECOND,"
+                + "SECONDS_SINCE_MIDNIGHT,TIMESTAMPADD,TIMESTAMPDIFF,"
+                + "TO_CHAR,WEEK,YEAR"));
         break;
-      case SQL_KEYWORDS:
-        assertEquals("Fail to get SQL_KEYWORDS",
-          "", //No SQL keywords return for HSQLDB
-          connection.getMetaData().getSQLKeywords());
+      case GET_S_Q_L_KEYWORDS:
+        assertThat(connection.getMetaData().getSQLKeywords(),
+            equalTo("")); // No SQL keywords return for HSQLDB
         break;
-      case STRING_FUNCTIONS:
-        assertEquals("Fail to get STRING_FUNCTIONS",
-          "ASCII,CHAR,CONCAT,DIFFERENCE,HEXTORAW,INSERT,LCASE,"
-          + "LEFT,LENGTH,LOCATE,LTRIM,RAWTOHEX,REPEAT,REPLACE,"
-          + "RIGHT,RTRIM,SOUNDEX,SPACE,SUBSTR,UCASE",
-          connection.getMetaData().getStringFunctions());
+      case GET_STRING_FUNCTIONS:
+        assertThat(connection.getMetaData().getStringFunctions(),
+            equalTo("ASCII,CHAR,CONCAT,DIFFERENCE,HEXTORAW,INSERT,LCASE,"
+                + "LEFT,LENGTH,LOCATE,LTRIM,RAWTOHEX,REPEAT,REPLACE,"
+                + "RIGHT,RTRIM,SOUNDEX,SPACE,SUBSTR,UCASE"));
         break;
       default:
       }
@@ -395,9 +406,7 @@ public class RemoteDriverTest {
 
   @Test public void testTypeHandling() throws Exception {
     final String query = "select * from EMP";
-    try (Connection cannon =
-             DriverManager.getConnection(CONNECTION_SPEC.url,
-                 CONNECTION_SPEC.username, CONNECTION_SPEC.password);
+    try (Connection cannon = canon();
         Connection underTest = ljs();
         Statement s1 = cannon.createStatement();
         Statement s2 = underTest.createStatement()) {
@@ -472,6 +481,11 @@ public class RemoteDriverTest {
         throws SQLException;
   }
 
+  /** Callback to execute some code against a connection. */
+  interface ConnectionFunction {
+    void apply(Connection c1) throws Exception;
+  }
+
   @Test public void testSetParameter() throws Exception {
     checkSetParameter("select ? from (values 1)",
         new PreparedStatementFunction() {
@@ -495,9 +509,7 @@ public class RemoteDriverTest {
 
   void checkSetParameter(String query, PreparedStatementFunction fn)
       throws SQLException {
-    try (Connection cannon =
-             DriverManager.getConnection(CONNECTION_SPEC.url,
-                 CONNECTION_SPEC.username, CONNECTION_SPEC.password);
+    try (Connection cannon = canon();
          Connection underTest = ljs();
          PreparedStatement s1 = cannon.prepareStatement(query);
          PreparedStatement s2 = underTest.prepareStatement(query)) {
@@ -619,26 +631,23 @@ public class RemoteDriverTest {
     final ParameterMetaData parameterMetaData = ps.getParameterMetaData();
     assertThat(parameterMetaData.getParameterCount(), equalTo(1));
 
-    ps.setBytes(1, new byte[] {65, 0, 66});
+    ps.setBytes(1, new byte[]{65, 0, 66});
     final ResultSet resultSet = ps.executeQuery();
     assertTrue(resultSet.next());
     assertThat(resultSet.getBytes(1),
-        equalTo(new byte[] {(byte) 0xDE, 65, 0, 66}));
+        equalTo(new byte[]{(byte) 0xDE, 65, 0, 66}));
     resultSet.close();
     ps.close();
     connection.close();
   }
 
   @Test public void testPrepareBindExecuteFetchDate() throws Exception {
-    checkPrepareBindExecuteFetchDate(ljs());
-  }
-
-  @Test public void testPrepareBindExecuteFetchDate2() throws Exception {
-    try (Connection cannon =
-             DriverManager.getConnection(CONNECTION_SPEC.url,
-                 CONNECTION_SPEC.username, CONNECTION_SPEC.password)) {
-      checkPrepareBindExecuteFetchDate(cannon);
-    }
+    eachConnection(
+        new ConnectionFunction() {
+          public void apply(Connection c1) throws Exception {
+            checkPrepareBindExecuteFetchDate(c1);
+          }
+        });
   }
 
   private void checkPrepareBindExecuteFetchDate(Connection connection) throws Exception {
@@ -706,6 +715,27 @@ public class RemoteDriverTest {
     connection.close();
   }
 
+  @Test public void testDatabaseProperty() throws Exception {
+    eachConnection(
+        new ConnectionFunction() {
+          public void apply(Connection c1) throws Exception {
+            checkDatabaseProperty(c1);
+          }
+        });
+  }
+
+  private void checkDatabaseProperty(Connection connection)
+      throws SQLException {
+    final DatabaseMetaData metaData = connection.getMetaData();
+    assertThat(metaData.getSQLKeywords(), equalTo(""));
+    assertThat(metaData.getStringFunctions(),
+        equalTo("ASCII,CHAR,CONCAT,DIFFERENCE,HEXTORAW,INSERT,LCASE,LEFT,"
+            + "LENGTH,LOCATE,LTRIM,RAWTOHEX,REPEAT,REPLACE,RIGHT,RTRIM,SOUNDEX,"
+            + "SPACE,SUBSTR,UCASE"));
+    assertThat(metaData.getDefaultTransactionIsolation(),
+        equalTo(Connection.TRANSACTION_READ_COMMITTED));
+  }
+
   /**
    * Factory that creates a service based on a local JDBC connection.
    */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/AvaticaDatabaseMetaData.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaDatabaseMetaData.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaDatabaseMetaData.java
index 32f7e37..2c5e6e6 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaDatabaseMetaData.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaDatabaseMetaData.java
@@ -182,23 +182,28 @@ public class AvaticaDatabaseMetaData implements DatabaseMetaData {
   }
 
   public String getSQLKeywords() throws SQLException {
-    return connection.meta.getDatabaseProperties(Meta.DatabaseProperties.SQL_KEYWORDS);
+    return Meta.DatabaseProperty.GET_S_Q_L_KEYWORDS
+        .getProp(connection.meta, String.class);
   }
 
   public String getNumericFunctions() throws SQLException {
-    return connection.meta.getDatabaseProperties(Meta.DatabaseProperties.NUMERIC_FUNCTIONS);
+    return Meta.DatabaseProperty.GET_NUMERIC_FUNCTIONS
+        .getProp(connection.meta, String.class);
   }
 
   public String getStringFunctions() throws SQLException {
-    return connection.meta.getDatabaseProperties(Meta.DatabaseProperties.STRING_FUNCTIONS);
+    return Meta.DatabaseProperty.GET_STRING_FUNCTIONS
+        .getProp(connection.meta, String.class);
   }
 
   public String getSystemFunctions() throws SQLException {
-    return connection.meta.getDatabaseProperties(Meta.DatabaseProperties.SYSTEM_FUNCTIONS);
+    return Meta.DatabaseProperty.GET_SYSTEM_FUNCTIONS
+        .getProp(connection.meta, String.class);
   }
 
   public String getTimeDateFunctions() throws SQLException {
-    return connection.meta.getDatabaseProperties(Meta.DatabaseProperties.TIME_DATE_FUNCTIONS);
+    return Meta.DatabaseProperty.GET_TIME_DATE_FUNCTIONS
+        .getProp(connection.meta, String.class);
   }
 
   public String getSearchStringEscape() throws SQLException {
@@ -523,7 +528,8 @@ public class AvaticaDatabaseMetaData implements DatabaseMetaData {
   }
 
   public int getDefaultTransactionIsolation() throws SQLException {
-    return Connection.TRANSACTION_NONE;
+    return Meta.DatabaseProperty.GET_DEFAULT_TRANSACTION_ISOLATION
+        .getProp(connection.meta, Integer.class);
   }
 
   public boolean supportsTransactions() throws SQLException {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
index b03cc19..77fafc4 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaUtils.java
@@ -17,12 +17,28 @@
 package org.apache.calcite.avatica;
 
 import java.util.AbstractList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /** Avatica utilities. */
 public class AvaticaUtils {
+  private static final Map<Class, Class> BOX;
+
   private AvaticaUtils() {}
 
+  static {
+    BOX = new HashMap<>();
+    BOX.put(boolean.class, Boolean.class);
+    BOX.put(byte.class, Byte.class);
+    BOX.put(char.class, Character.class);
+    BOX.put(short.class, Short.class);
+    BOX.put(int.class, Integer.class);
+    BOX.put(long.class, Long.class);
+    BOX.put(float.class, Float.class);
+    BOX.put(double.class, Double.class);
+  }
+
   /**
    * Does nothing with its argument. Call this method when you have a value
    * you are not interested in, but you don't want the compiler to warn that
@@ -92,6 +108,15 @@ public class AvaticaUtils {
     }
     return buf.toString();
   }
+
+  /** Returns the boxed class. For example, {@code box(int.class)}
+   * returns {@code java.lang.Integer}. */
+  public static Class box(Class clazz) {
+    if (clazz.isPrimitive()) {
+      return BOX.get(clazz);
+    }
+    return clazz;
+  }
 }
 
 // End AvaticaUtils.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index 0c9e8ad..e98c7f1 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -25,6 +25,9 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -42,13 +45,12 @@ import java.util.Objects;
 public interface Meta {
 
   /**
-   * Return database static properties, deprecating single function call getNumericFunctions,
-   * getStringFunctions, getSystemFunctions, getSqlKeywords and getTimeDateFunctions
+   * Returns a map of static database properties.
    *
-   * @param DatabaseProperty to get
-   * @return CSV String of the supported function/keyword
+   * <p>The provider can omit properties whose value is the same as the
+   * default.
    */
-  String getDatabaseProperties(DatabaseProperties databaseProperty);
+  Map<DatabaseProperty, Object> getDatabaseProperties();
 
   MetaResultSet getTables(String catalog,
       Pat schemaPattern,
@@ -238,33 +240,70 @@ public interface Meta {
     }
   }
 
-  /** Database Properties Enum for Meta#{@link Meta#getDatabaseProperties(DatabaseProperties)}}
-   */
-  enum DatabaseProperties {
-    NUMERIC_FUNCTIONS,
-    STRING_FUNCTIONS,
-    SYSTEM_FUNCTIONS,
-    TIME_DATE_FUNCTIONS,
-    SQL_KEYWORDS;
-  }
-
-  /** POJO for Meta#{@link Meta#getDatabaseProperties(PropertyName)}}
+  /** Database property.
    *
-   * <p>Payload for {@link Service.DatabasePropertyRequest} and
-   * {@link Service.DatabasePropertyResponse}
+   * <p>Values exist for methods, such as
+   * {@link DatabaseMetaData#getSQLKeywords()}, which always return the same
+   * value at all times and across connections.
    *
-   * For {@link Service.Request}, the value is set to null
+   * @see #getDatabaseProperties()
    */
-  class DatabaseProperty {
-    public final DatabaseProperties databaseProperty;
-    public final String value;
+  enum DatabaseProperty {
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getNumericFunctions()}. */
+    GET_NUMERIC_FUNCTIONS(""),
+
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getStringFunctions()}. */
+    GET_STRING_FUNCTIONS(""),
+
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getSystemFunctions()}. */
+    GET_SYSTEM_FUNCTIONS(""),
+
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getTimeDateFunctions()}. */
+    GET_TIME_DATE_FUNCTIONS(""),
+
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getSQLKeywords()}. */
+    GET_S_Q_L_KEYWORDS(""),
+
+    /** Database property containing the value of
+     * {@link DatabaseMetaData#getDefaultTransactionIsolation()}. */
+    GET_DEFAULT_TRANSACTION_ISOLATION(Connection.TRANSACTION_NONE);
+
+    public final Class<?> type;
+    public final Object defaultValue;
+    public final Method method;
+
+    <T> DatabaseProperty(T defaultValue) {
+      this.defaultValue = defaultValue;
+      final String methodName = AvaticaUtils.toCamelCase(name());
+      try {
+        this.method = DatabaseMetaData.class.getMethod(methodName);
+      } catch (NoSuchMethodException e) {
+        throw new RuntimeException(e);
+      }
+      this.type = AvaticaUtils.box(method.getReturnType());
+      assert defaultValue == null || defaultValue.getClass() == type;
+    }
 
-    @JsonCreator
-    public DatabaseProperty(
-      @JsonProperty("propertyName") DatabaseProperties dbProp,
-      @JsonProperty("value") String value) {
-      this.databaseProperty = dbProp;
-      this.value = value;
+    /** Returns a value of this property, using the default value if the map
+     * does not contain an explicit value. */
+    public <T> T getProp(Meta meta, Class<T> aClass) {
+      return getProp(meta.getDatabaseProperties(), aClass);
+    }
+
+    /** Returns a value of this property, using the default value if the map
+     * does not contain an explicit value. */
+    public <T> T getProp(Map<DatabaseProperty, Object> map, Class<T> aClass) {
+      assert aClass == type;
+      Object v = map.get(this);
+      if (v == null) {
+        v = defaultValue;
+      }
+      return aClass.cast(v);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
index c310a9f..fe1687c 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
@@ -510,8 +510,8 @@ public abstract class MetaImpl implements Meta {
   public static class MetaSuperTable {
   }
 
-  public String getDatabaseProperties(Meta.DatabaseProperties propName) {
-    return "";
+  public Map<DatabaseProperty, Object> getDatabaseProperties() {
+    return Collections.emptyMap();
   }
 
   public MetaResultSet getTables(String catalog,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java b/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java
index b224469..9e4b2ba 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java
@@ -385,16 +385,7 @@ public enum SqlType {
 
   /** Returns the boxed type. */
   public Class boxedClass() {
-    return box(clazz);
-  }
-
-  /** Returns the boxed class. For example, {@code box(int.class)}
-   * returns {@code java.lang.Integer}. */
-  private static Class box(Class clazz) {
-    if (clazz.isPrimitive()) {
-      return BOX.get(clazz);
-    }
-    return clazz;
+    return AvaticaUtils.box(clazz);
   }
 
   /** Returns the entries in JDBC table B-5. */
@@ -410,12 +401,10 @@ public enum SqlType {
 
   public static final Map<Class, EnumSet<SqlType>> SET_LIST;
   public static final Map<Method, EnumSet<SqlType>> GET_LIST;
-  private static final Map<Class, Class> BOX;
 
   static {
     SET_LIST = new HashMap<>();
     GET_LIST = new HashMap<>();
-    BOX = new HashMap<>();
 
     EnumSet<SqlType> numericTypes = EnumSet.of(TINYINT, SMALLINT, INTEGER,
         BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, BOOLEAN);
@@ -497,15 +486,6 @@ public enum SqlType {
     GET_LIST.put(Method.GET_OBJECT, EnumSet.allOf(SqlType.class));
     GET_LIST.put(Method.GET_ROW_ID, EnumSet.of(ROWID));
     GET_LIST.put(Method.GET_SQLXML, EnumSet.of(SQLXML));
-
-    BOX.put(boolean.class, Boolean.class);
-    BOX.put(byte.class, Byte.class);
-    BOX.put(char.class, Character.class);
-    BOX.put(short.class, Short.class);
-    BOX.put(int.class, Integer.class);
-    BOX.put(long.class, Long.class);
-    BOX.put(float.class, Float.class);
-    BOX.put(double.class, Double.class);
   }
 
   @SafeVarargs

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
index c43fbc5..88a6d59 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/LocalService.java
@@ -193,10 +193,7 @@ public class LocalService implements Service {
   }
 
   public DatabasePropertyResponse apply(DatabasePropertyRequest request) {
-    final Meta.DatabaseProperty dbProperty = new Meta.DatabaseProperty(
-        request.dbProps.databaseProperty,
-        meta.getDatabaseProperties(request.dbProps.databaseProperty));
-    return new DatabasePropertyResponse(dbProperty);
+    return new DatabasePropertyResponse(meta.getDatabaseProperties());
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
index fc6e912..a585c2f 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/RemoteMeta.java
@@ -36,7 +36,7 @@ import java.util.Map;
 class RemoteMeta extends MetaImpl {
   final Service service;
   final Map<String, ConnectionPropertiesImpl> propsMap = new HashMap<>();
-  private final Map<Meta.DatabaseProperties, String> dbPropMap = new HashMap<>();
+  private Map<DatabaseProperty, Object> databaseProperties;
 
   public RemoteMeta(AvaticaConnection connection, Service service) {
     super(connection);
@@ -62,17 +62,15 @@ class RemoteMeta extends MetaImpl {
         response.ownStatement, signature0, response.firstFrame);
   }
 
-  @Override public String getDatabaseProperties(Meta.DatabaseProperties databaseProperty) {
-    String dbProp = dbPropMap.get(databaseProperty);
-    if (dbProp == null) {
-      final Meta.DatabaseProperty dbProps =
-          new Meta.DatabaseProperty(databaseProperty, null);
-      final Service.DatabasePropertyResponse response =
-        service.apply(new Service.DatabasePropertyRequest(dbProps));
-      dbPropMap.put(databaseProperty, response.dbProps.value);
-      dbProp = response.dbProps.value;
+  @Override public Map<DatabaseProperty, Object> getDatabaseProperties() {
+    synchronized (this) {
+      // Compute map on first use, and cache
+      if (databaseProperties == null) {
+        databaseProperties =
+            service.apply(new Service.DatabasePropertyRequest()).map;
+      }
+      return databaseProperties;
     }
-    return dbProp;
   }
 
   @Override public StatementHandle createStatement(ConnectionHandle ch) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
index 1014dfd..8fe888e 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/Service.java
@@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * API for request-response calls to an Avatica server.
@@ -108,11 +109,8 @@ public interface Service {
   /** Request for
    * {@link org.apache.calcite.avatica.Meta#getDatabaseProperties()}. */
   class DatabasePropertyRequest extends Request {
-    public final Meta.DatabaseProperty dbProps;
-
     @JsonCreator
-    public DatabasePropertyRequest(@JsonProperty("dbProps") Meta.DatabaseProperty dbProps) {
-      this.dbProps = dbProps;
+    public DatabasePropertyRequest() {
     }
 
     DatabasePropertyResponse accept(Service service) {
@@ -454,13 +452,13 @@ public interface Service {
   }
 
   /** Response for
-   * {@link Meta#getDatabaseProperties(Meta.DatabaseProperty)}. */
+   * {@link Meta#getDatabaseProperties()}. */
   class DatabasePropertyResponse extends Response {
-    public final Meta.DatabaseProperty dbProps;
+    public final Map<Meta.DatabaseProperty, Object> map;
 
     @JsonCreator
-    public DatabasePropertyResponse(@JsonProperty("dbProps") Meta.DatabaseProperty dbProps) {
-      this.dbProps = dbProps;
+    public DatabasePropertyResponse(@JsonProperty("map") Map<Meta.DatabaseProperty, Object> map) {
+      this.map = map;
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
index 18dd609..c2ea970 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -44,6 +44,8 @@ import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.AbstractTableQueryable;
 import org.apache.calcite.server.CalciteServerStatement;
+import org.apache.calcite.sql.SqlJdbcFunctionCall;
+import org.apache.calcite.sql.parser.SqlParser;
 import org.apache.calcite.util.Util;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -209,8 +211,33 @@ public class CalciteMetaImpl extends MetaImpl {
     return (CalciteConnectionImpl) connection;
   }
 
-  @Override public String getDatabaseProperties(Meta.DatabaseProperties dbProp) {
-    return org.apache.calcite.jdbc.DatabaseProperties.getProperty(dbProp);
+  @Override public Map<DatabaseProperty, Object> getDatabaseProperties() {
+    final ImmutableMap.Builder<DatabaseProperty, Object> builder =
+        ImmutableMap.builder();
+    for (DatabaseProperty p : DatabaseProperty.values()) {
+      addProperty(builder, p);
+    }
+    return builder.build();
+  }
+
+  private ImmutableMap.Builder<DatabaseProperty, Object> addProperty(
+      ImmutableMap.Builder<DatabaseProperty, Object> builder,
+      DatabaseProperty p) {
+    switch (p) {
+    case GET_S_Q_L_KEYWORDS:
+      return builder.put(p,
+          SqlParser.create("").getMetadata().getJdbcKeywords());
+    case GET_NUMERIC_FUNCTIONS:
+      return builder.put(p, SqlJdbcFunctionCall.getNumericFunctions());
+    case GET_STRING_FUNCTIONS:
+      return builder.put(p, SqlJdbcFunctionCall.getStringFunctions());
+    case GET_SYSTEM_FUNCTIONS:
+      return builder.put(p, SqlJdbcFunctionCall.getSystemFunctions());
+    case GET_TIME_DATE_FUNCTIONS:
+      return builder.put(p, SqlJdbcFunctionCall.getTimeDateFunctions());
+    default:
+      return builder;
+    }
   }
 
   public MetaResultSet getTables(String catalog,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/core/src/main/java/org/apache/calcite/jdbc/DatabaseProperties.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/DatabaseProperties.java b/core/src/main/java/org/apache/calcite/jdbc/DatabaseProperties.java
deleted file mode 100644
index 59c231b..0000000
--- a/core/src/main/java/org/apache/calcite/jdbc/DatabaseProperties.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.apache.calcite.jdbc;
-
-import org.apache.calcite.avatica.AvaticaDatabaseMetaData;
-import org.apache.calcite.avatica.Meta;
-import org.apache.calcite.sql.SqlJdbcFunctionCall;
-import org.apache.calcite.sql.parser.SqlParser;
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Definition of a database static properties.
- * {@link Meta.PropertyName} enumerates current database properties,
- * supporting some of the static String properties return via
- * {@link AvaticaDatabaseMetaData}
- */
-public enum DatabaseProperties {
-  NUMERIC_FUNCTIONS(Meta.DatabaseProperties.NUMERIC_FUNCTIONS,
-    SqlJdbcFunctionCall.getNumericFunctions()),
-  STRING_FUNCTIONS(Meta.DatabaseProperties.STRING_FUNCTIONS,
-    SqlJdbcFunctionCall.getStringFunctions()),
-  SYSTEM_FUNCTIONS(Meta.DatabaseProperties.SYSTEM_FUNCTIONS,
-    SqlJdbcFunctionCall.getSystemFunctions()),
-  TIME_DATE_FUNCTIONS(Meta.DatabaseProperties.TIME_DATE_FUNCTIONS,
-    SqlJdbcFunctionCall.getTimeDateFunctions()),
-  SQL_KEYWORDS(Meta.DatabaseProperties.SQL_KEYWORDS,
-    SqlParser.create("").getMetadata().getJdbcKeywords());
-
-  private Meta.DatabaseProperties databaseProperty;
-  private String defaultValue;
-  private static final Map<Meta.DatabaseProperties, DatabaseProperties> NAME_TO_PROPS;
-
-  static {
-    NAME_TO_PROPS = new HashMap<Meta.DatabaseProperties, DatabaseProperties>();
-    for (DatabaseProperties p : DatabaseProperties.values()) {
-      NAME_TO_PROPS.put(p.databaseProperty, p);
-    }
-  }
-
-  DatabaseProperties(Meta.DatabaseProperties dbProp, String defaultValue) {
-    this.databaseProperty = dbProp;
-    this.defaultValue = defaultValue;
-  }
-
-  public Meta.DatabaseProperties databaseProperty() {
-    return this.databaseProperty;
-  }
-
-  public String defaultValue() {
-    return this.defaultValue;
-  }
-
-  public static String getProperty(Meta.DatabaseProperties dbProps) {
-    final DatabaseProperties dbProp = NAME_TO_PROPS.get(dbProps);
-    if (dbProp != null) {
-      return dbProp.defaultValue;
-    } else {
-      return "";
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/e218cb15/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 db71914..b9e09a2 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -68,6 +68,7 @@ import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -198,27 +199,27 @@ public class CalciteRemoteDriverTest {
     final Connection connection =
         CalciteAssert.hr().connect();
     assertThat(connection.isClosed(), is(false));
-    for (DatabaseProperties p : DatabaseProperties.values()) {
-      switch(p.databaseProperty()) {
-      case NUMERIC_FUNCTIONS:
+    for (Meta.DatabaseProperty p : Meta.DatabaseProperty.values()) {
+      switch (p) {
+      case GET_NUMERIC_FUNCTIONS:
         assertThat(connection.getMetaData().getNumericFunctions(),
-          is(p.defaultValue()));
+            not(equalTo("")));
         break;
-      case SYSTEM_FUNCTIONS:
+      case GET_SYSTEM_FUNCTIONS:
         assertThat(connection.getMetaData().getSystemFunctions(),
-          is(p.defaultValue()));
+            CoreMatchers.notNullValue());
         break;
-      case TIME_DATE_FUNCTIONS:
+      case GET_TIME_DATE_FUNCTIONS:
         assertThat(connection.getMetaData().getTimeDateFunctions(),
-          is(p.defaultValue()));
+            not(equalTo("")));
         break;
-      case SQL_KEYWORDS:
+      case GET_S_Q_L_KEYWORDS:
         assertThat(connection.getMetaData().getSQLKeywords(),
-          is(p.defaultValue()));
+            not(equalTo("")));
         break;
-      case STRING_FUNCTIONS:
+      case GET_STRING_FUNCTIONS:
         assertThat(connection.getMetaData().getStringFunctions(),
-          is(p.defaultValue()));
+            not(equalTo("")));
         break;
       default:
       }