http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java
----------------------------------------------------------------------
diff --git 
a/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java 
b/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java
new file mode 100644
index 0000000..4ca9ce1
--- /dev/null
+++ b/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java
@@ -0,0 +1,466 @@
+/*
+ * 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.avatica;
+
+import org.apache.calcite.avatica.proto.Common;
+import org.apache.calcite.avatica.proto.Common.MetaDataOperationArgument;
+import 
org.apache.calcite.avatica.proto.Common.MetaDataOperationArgument.ArgumentType;
+import org.apache.calcite.avatica.remote.MetaDataOperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A struct used to encapsulate the necessary information to reconstitute a 
ResultSet in the
+ * Avatica server.
+ */
+public class QueryState {
+
+  /**
+   * An enumeration that represents how a ResultSet was created.
+   */
+  public enum StateType {
+    SQL,
+    METADATA;
+
+    public Common.StateType toProto() {
+      switch (this) {
+      case SQL:
+        return Common.StateType.SQL;
+      case METADATA:
+        return Common.StateType.METADATA;
+      default:
+        return Common.StateType.UNRECOGNIZED;
+      }
+    }
+
+    public static StateType fromProto(Common.StateType protoType) {
+      switch (protoType) {
+      case SQL:
+        return StateType.SQL;
+      case METADATA:
+        return StateType.METADATA;
+      default:
+        throw new IllegalArgumentException("Unhandled StateType " + protoType);
+      }
+    }
+  }
+
+  @JsonProperty("type")
+  public final StateType type;
+
+  @JsonProperty("sql")
+  public final String sql;
+
+  @JsonProperty("metaDataOperation")
+  public final MetaDataOperation metaDataOperation;
+  @JsonProperty("operationArgs")
+  public final Object[] operationArgs;
+
+  /**
+   * Constructor encapsulating a SQL query used to create a result set.
+   *
+   * @param sql The SQL query.
+   */
+  public QueryState(String sql) {
+    // This doesn't to be non-null
+    this.sql = sql;
+    this.type = StateType.SQL;
+
+    // Null out the members we don't use.
+    this.metaDataOperation = null;
+    this.operationArgs = null;
+  }
+
+  /**
+   * Constructor encapsulating a metadata operation's result set.
+   *
+   * @param op A pointer to the {@link DatabaseMetaData} operation being 
invoked.
+   * @param args The arguments to the method being invoked.
+   */
+  public QueryState(MetaDataOperation op, Object... args) {
+    this.metaDataOperation = Objects.requireNonNull(op);
+    this.operationArgs = Arrays.copyOf(Objects.requireNonNull(args), 
args.length);
+    this.type = StateType.METADATA;
+
+    // Null out the members we won't use
+    this.sql = null;
+  }
+
+  /**
+   * Not intended for external use. For Jackson-databind only.
+   */
+  public QueryState(StateType type, String sql, MetaDataOperation op, 
Object... args) {
+    this.type = Objects.requireNonNull(type);
+    switch (type) {
+    case SQL:
+      this.sql = Objects.requireNonNull(sql);
+      if (null != op) {
+        throw new IllegalArgumentException("Expected null MetaDataOperation, 
but got " + op);
+      }
+      this.metaDataOperation = null;
+      if (null != args) {
+        throw new IllegalArgumentException("Expected null arguments, but got "
+            + Arrays.toString(args));
+      }
+      this.operationArgs = null;
+      break;
+    case METADATA:
+      this.metaDataOperation = Objects.requireNonNull(op);
+      this.operationArgs = Objects.requireNonNull(args);
+      if (null != sql) {
+        throw new IllegalArgumentException("Expected null SQl but got " + sql);
+      }
+      this.sql = null;
+      break;
+    default:
+      throw new IllegalArgumentException("Unable to handle StateType " + type);
+    }
+  }
+
+  /**
+   * Not intended for external use. For Jackson-databind only.
+   */
+  public QueryState() {
+    this.sql = null;
+    this.metaDataOperation = null;
+    this.type = null;
+    this.operationArgs = null;
+  }
+
+  /**
+   * @return The {@link StateType} for this encapsulated state.
+   */
+  public StateType getType() {
+    return type;
+  }
+
+  /**
+   * @return The SQL expression to invoke.
+   */
+  public String getSql() {
+    assert type == StateType.SQL;
+    return sql;
+  }
+
+  /**
+   * @return The metadata operation to invoke.
+   */
+  public MetaDataOperation getMetaDataOperation() {
+    assert type == StateType.METADATA;
+    return metaDataOperation;
+  }
+
+  /**
+   * @return The Arguments for the given metadata operation.
+   */
+  public Object[] getOperationArgs() {
+    assert type == StateType.METADATA;
+    return operationArgs;
+  }
+
+  public ResultSet invoke(Connection conn, Statement statement) throws 
SQLException {
+    switch (type) {
+    case SQL:
+      boolean ret = Objects.requireNonNull(statement).execute(sql);
+      ResultSet results = statement.getResultSet();
+
+      // Either execute(sql) returned true or the resultSet was null
+      assert ret || null == results;
+
+      return results;
+    case METADATA:
+      DatabaseMetaData metadata = Objects.requireNonNull(conn).getMetaData();
+      switch (metaDataOperation) {
+      case GET_ATTRIBUTES:
+        verifyOpArgs(4);
+        return metadata.getAttributes((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_BEST_ROW_IDENTIFIER:
+        verifyOpArgs(5);
+        return metadata.getBestRowIdentifier((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (int) operationArgs[3],
+            (boolean) operationArgs[4]);
+      case GET_CATALOGS:
+        verifyOpArgs(0);
+        return metadata.getCatalogs();
+      case GET_COLUMNS:
+        verifyOpArgs(4);
+        return metadata.getColumns((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_COLUMN_PRIVILEGES:
+        verifyOpArgs(4);
+        return metadata.getColumnPrivileges((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_CROSS_REFERENCE:
+        verifyOpArgs(6);
+        return metadata.getCrossReference((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3],
+            (String) operationArgs[4],
+            (String) operationArgs[5]);
+      case GET_EXPORTED_KEYS:
+        verifyOpArgs(3);
+        return metadata.getExportedKeys((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_FUNCTIONS:
+        verifyOpArgs(3);
+        return metadata.getFunctions((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_FUNCTION_COLUMNS:
+        verifyOpArgs(4);
+        return metadata.getFunctionColumns((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_IMPORTED_KEYS:
+        verifyOpArgs(3);
+        return metadata.getImportedKeys((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_INDEX_INFO:
+        verifyOpArgs(5);
+        return metadata.getIndexInfo((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (boolean) operationArgs[3],
+            (boolean) operationArgs[4]);
+      case GET_PRIMARY_KEYS:
+        verifyOpArgs(3);
+        return metadata.getPrimaryKeys((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_PROCEDURES:
+        verifyOpArgs(3);
+        return metadata.getProcedures((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_PROCEDURE_COLUMNS:
+        verifyOpArgs(4);
+        return metadata.getProcedureColumns((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_PSEUDO_COLUMNS:
+        verifyOpArgs(4);
+        return metadata.getPseudoColumns((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String) operationArgs[3]);
+      case GET_SCHEMAS:
+        verifyOpArgs(0);
+        return metadata.getSchemas();
+      case GET_SCHEMAS_WITH_ARGS:
+        verifyOpArgs(2);
+        return metadata.getSchemas((String) operationArgs[0],
+            (String) operationArgs[1]);
+      case GET_SUPER_TABLES:
+        verifyOpArgs(3);
+        return metadata.getSuperTables((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_SUPER_TYPES:
+        verifyOpArgs(3);
+        return metadata.getSuperTypes((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_TABLES:
+        verifyOpArgs(4);
+        return metadata.getTables((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (String[]) operationArgs[3]);
+      case GET_TABLE_PRIVILEGES:
+        verifyOpArgs(3);
+        return metadata.getTablePrivileges((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      case GET_TABLE_TYPES:
+        verifyOpArgs(0);
+        return metadata.getTableTypes();
+      case GET_TYPE_INFO:
+        verifyOpArgs(0);
+        return metadata.getTypeInfo();
+      case GET_UDTS:
+        verifyOpArgs(4);
+        return metadata.getUDTs((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2],
+            (int[]) operationArgs[3]);
+      case GET_VERSION_COLUMNS:
+        verifyOpArgs(3);
+        return metadata.getVersionColumns((String) operationArgs[0],
+            (String) operationArgs[1],
+            (String) operationArgs[2]);
+      default:
+        throw new IllegalArgumentException("Unhandled Metadata operation: " + 
metaDataOperation);
+      }
+    default:
+      throw new IllegalArgumentException("Unable to process QueryState of type 
" + type);
+    }
+  }
+
+  private void verifyOpArgs(int expectedArgs) {
+    if (expectedArgs != operationArgs.length) {
+      throw new RuntimeException("Expected " + expectedArgs + " arguments, but 
got "
+          + Arrays.toString(operationArgs));
+    }
+  }
+
+  public Common.QueryState toProto() {
+    Common.QueryState.Builder builder = Common.QueryState.newBuilder();
+
+    // Required
+    switch (type) {
+    case SQL:
+      builder.setType(Common.StateType.SQL);
+      break;
+    case METADATA:
+      builder.setType(Common.StateType.METADATA);
+      break;
+    default:
+      throw new IllegalStateException("Unhandled type: " + type);
+    }
+
+    // Optional SQL
+    if (null != sql) {
+      builder.setSql(sql).setHasSql(true);
+    }
+
+    // Optional metaDataOperation
+    if (null != metaDataOperation) {
+      builder.setOp(metaDataOperation.toProto()).setHasOp(true);
+    }
+
+    // Optional operationArgs
+    if (null != operationArgs) {
+      builder.setHasArgs(true);
+      for (Object arg : operationArgs) {
+        MetaDataOperationArgument.Builder argBuilder = 
MetaDataOperationArgument.newBuilder();
+
+        if (null == arg) {
+          builder.addArgs(argBuilder.setType(ArgumentType.NULL).build());
+        } else if (arg instanceof String) {
+          builder.addArgs(argBuilder.setType(ArgumentType.STRING)
+              .setStringValue((String) arg).build());
+        } else if (arg instanceof Integer) {
+          
builder.addArgs(argBuilder.setType(ArgumentType.INT).setIntValue((int) 
arg).build());
+        } else if (arg instanceof Boolean) {
+          builder.addArgs(
+              argBuilder.setType(ArgumentType.BOOL).setBoolValue((boolean) 
arg).build());
+        } else if (arg instanceof String[]) {
+          argBuilder.setType(ArgumentType.REPEATED_STRING);
+          for (String strArg : (String[]) arg) {
+            argBuilder.addStringArrayValues(strArg);
+          }
+          builder.addArgs(argBuilder.build());
+        } else if (arg instanceof int[]) {
+          argBuilder.setType(ArgumentType.REPEATED_INT);
+          for (int intArg : (int[]) arg) {
+            argBuilder.addIntArrayValues(intArg);
+          }
+          builder.addArgs(argBuilder.build());
+        } else {
+          throw new RuntimeException("Unexpected operation argument: " + 
arg.getClass());
+        }
+      }
+    } else {
+      builder.setHasArgs(false);
+    }
+
+    return builder.build();
+  }
+
+  public static QueryState fromProto(Common.QueryState protoState) {
+    StateType type = StateType.fromProto(protoState.getType());
+    String sql = protoState.getHasSql() ? protoState.getSql() : null;
+    MetaDataOperation op = protoState.getHasOp()
+        ? MetaDataOperation.fromProto(protoState.getOp()) : null;
+    Object[] opArgs = null;
+    if (protoState.getHasArgs()) {
+      opArgs = new Object[protoState.getArgsCount()];
+      int i = 0;
+      for (Common.MetaDataOperationArgument arg : protoState.getArgsList()) {
+        switch (arg.getType()) {
+        case STRING:
+          opArgs[i] = arg.getStringValue();
+          break;
+        case BOOL:
+          opArgs[i] = arg.getBoolValue();
+          break;
+        case INT:
+          opArgs[i] = arg.getIntValue();
+          break;
+        case REPEATED_STRING:
+          opArgs[i] = arg.getStringArrayValuesList().toArray(
+              new String[arg.getStringArrayValuesCount()]);
+          break;
+        case REPEATED_INT:
+          int[] arr = new int[arg.getIntArrayValuesCount()];
+          int offset = 0;
+          for (Integer val : arg.getIntArrayValuesList()) {
+            arr[offset] = val;
+            offset++;
+          }
+          opArgs[i] = arr;
+          break;
+        case NULL:
+          opArgs[i] = null;
+          break;
+        default:
+          throw new RuntimeException("Could not interpret " + arg.getType());
+        }
+
+        i++;
+      }
+    }
+
+    return new QueryState(type, sql, op, opArgs);
+  }
+
+  @Override public int hashCode() {
+    return Objects.hash(metaDataOperation, Arrays.hashCode(operationArgs), 
sql);
+  }
+
+  @Override public boolean equals(Object o) {
+    return o == this
+        || o instanceof QueryState
+        && metaDataOperation == ((QueryState) o).metaDataOperation
+        && Arrays.deepEquals(operationArgs, ((QueryState) o).operationArgs)
+        && Objects.equals(sql, ((QueryState) o).sql);
+  }
+}
+
+// End QueryState.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java
----------------------------------------------------------------------
diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java 
b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java
new file mode 100644
index 0000000..e34bee6
--- /dev/null
+++ b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java
@@ -0,0 +1,559 @@
+/*
+ * 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.avatica;
+
+import org.apache.calcite.avatica.util.ByteString;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.Ref;
+import java.sql.RowId;
+import java.sql.Struct;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Extends the information in {@link java.sql.Types}.
+ *
+ * <p>The information in the following conversions tables
+ * (from the JDBC 4.1 specification) is held in members of this class.
+ *
+ * <p>Table B-1: JDBC Types Mapped to Java Types
+ *
+ * <pre>
+ * JDBC Type     Java Type
+ * ============= =========================
+ * CHAR          String
+ * VARCHAR       String
+ * LONGVARCHAR   String
+ * NUMERIC       java.math.BigDecimal
+ * DECIMAL       java.math.BigDecimal
+ * BIT           boolean
+ * BOOLEAN       boolean
+ * TINYINT       byte
+ * SMALLINT      short
+ * INTEGER       int
+ * BIGINT        long
+ * REAL          float
+ * FLOAT         double
+ * DOUBLE        double
+ * BINARY        byte[]
+ * VARBINARY     byte[]
+ * LONGVARBINARY byte[]
+ * DATE          java.sql.Date
+ * TIME          java.sql.Time
+ * TIMESTAMP     java.sql.Timestamp
+ * CLOB          java.sql.Clob
+ * BLOB          java.sql.Blob
+ * ARRAY         java.sql.Array
+ * DISTINCT      mapping of underlying type
+ * STRUCT        java.sql.Struct
+ * REF           java.sql.Ref
+ * DATALINK      java.net.URL
+ * JAVA_OBJECT   underlying Java class
+ * ROWID         java.sql.RowId
+ * NCHAR         String
+ * NVARCHAR      String
+ * LONGNVARCHAR  String
+ * NCLOB         java.sql.NClob
+ * SQLXML        java.sql.SQLXML
+ * </pre>
+ *
+ * <p>Table B-2: Standard Mapping from Java Types to JDBC Types
+ *
+ * <pre>
+ * Java Type            JDBC Type
+ * ==================== ==============================================
+ * String               CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR or
+ *                      LONGNVARCHAR
+ * java.math.BigDecimal NUMERIC
+ * boolean              BIT or BOOLEAN
+ * byte                 TINYINT
+ * short                SMALLINT
+ * int                  INTEGER
+ * long                 BIGINT
+ * float                REAL
+ * double               DOUBLE
+ * byte[]               BINARY, VARBINARY, or LONGVARBINARY
+ * java.sql.Date        DATE
+ * java.sql.Time        TIME
+ * java.sql.Timestamp   TIMESTAMP
+ * java.sql.Clob        CLOB
+ * java.sql.Blob        BLOB
+ * java.sql.Array       ARRAY
+ * java.sql.Struct      STRUCT
+ * java.sql.Ref         REF
+ * java.net.URL         DATALINK
+ * Java class           JAVA_OBJECT
+ * java.sql.RowId       ROWID
+ * java.sql.NClob       NCLOB
+ * java.sql.SQLXML      SQLXML
+ * </pre>
+ *
+ * <p>TABLE B-3: Mapping from JDBC Types to Java Object Types
+ *
+ * <pre>
+ * JDBC Type     Java Object Type
+ * ============= ======================
+ * CHAR          String
+ * VARCHAR       String
+ * LONGVARCHAR   String
+ * NUMERIC       java.math.BigDecimal
+ * DECIMAL       java.math.BigDecimal
+ * BIT           Boolean
+ * BOOLEAN       Boolean
+ * TINYINT       Integer
+ * SMALLINT      Integer
+ * INTEGER       Integer
+ * BIGINT        Long
+ * REAL          Float
+ * FLOAT         Double
+ * DOUBLE        Double
+ * BINARY        byte[]
+ * VARBINARY     byte[]
+ * LONGVARBINARY byte[]
+ * DATE          java.sql.Date
+ * TIME          java.sql.Time
+ * TIMESTAMP     java.sql.Timestamp
+ * DISTINCT      Object type of underlying type
+ * CLOB          java.sql.Clob
+ * BLOB          java.sql.Blob
+ * ARRAY         java.sql.Array
+ * STRUCT        java.sql.Struct or java.sql.SQLData
+ * REF           java.sql.Ref
+ * DATALINK      java.net.URL
+ * JAVA_OBJECT   underlying Java class
+ * ROWID         java.sql.RowId
+ * NCHAR         String
+ * NVARCHAR      String
+ * LONGNVARCHAR  String
+ * NCLOB         java.sql.NClob
+ * SQLXML        java.sql.SQLXML
+ * </pre>
+ *
+ * <p>TABLE B-4: Mapping from Java Object Types to JDBC Types
+ *
+ * <pre>
+ * Java Object Type     JDBC Type
+ * ==================== ===========================================
+ * String               CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR
+ *                      or LONGNVARCHAR
+ * java.math.BigDecimal NUMERIC
+ * Boolean              BIT or BOOLEAN
+ * Byte                 TINYINT
+ * Short                SMALLINT
+ * Integer              INTEGER
+ * Long                 BIGINT
+ * Float                REAL
+ * Double               DOUBLE
+ * byte[]               BINARY, VARBINARY, or LONGVARBINARY
+ * java.math.BigInteger BIGINT
+ * java.sql.Date        DATE
+ * java.sql.Time        TIME
+ * java.sql.Timestamp   TIMESTAMP
+ * java.sql.Clob        CLOB
+ * java.sql.Blob        BLOB
+ * java.sql.Array       ARRAY
+ * java.sql.Struct      STRUCT
+ * java.sql.Ref         REF
+ * java.net.URL         DATALINK
+ * Java class           JAVA_OBJECT
+ * java.sql.RowId       ROWID
+ * java.sql.NClob       NCLOB
+ * java.sql.SQLXML      SQLXML
+ * java.util.Calendar   TIMESTAMP
+ * java.util.Date       TIMESTAMP
+ * </pre>
+ *
+ * <p><a name="B5">TABLE B-5</a>: Conversions performed by {@code setObject} 
and
+ * {@code setNull} between Java object types and target JDBC types
+ *
+ * <!--
+ * CHECKSTYLE: OFF
+ * -->
+ * <pre>
+ *                      T S I B R F D D N B B C V L B V L D T T A B C S R D J 
R N N L N S
+ *                      I M N I E L O E U I O H A O I A O A I I R L L T E A A 
O C V O C Q
+ *                      N A T G A O U C M T O A R N N R N T M M R O O R F T V 
W H A N L L
+ *                      Y L E I L A B I E   L R C G A B G E E E A B B U   A A 
I A R G O X
+ *                      I L G N   T L M R   E   H V R I V E   S Y     C   L _ 
D R C N B M
+ *                      N I E T     E A I   A   A A Y N A     T       T   I O  
   H V   L
+ *                      T N R         L C   N   R R   A R     A           N B  
   A A
+ *                        T                       C   R B     M           K J  
   R R
+ *                                                H   Y I     P                
     C
+ * Java type                                  
+ * ==================== = = = = = = = = = = = = = = = = = = = = = = = = = = = 
= = = = = =
+ * String               x x x x x x x x x x x x x x x x x x x x . . . . . . . 
. x x x . .
+ * java.math.BigDecimal x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Boolean              x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Byte                 x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Short                x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Integer              x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Long                 x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Float                x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * Double               x x x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * byte[]               . . . . . . . . . . . . . . x x x . . . . . . . . . . 
. . . . . .
+ * java.math.BigInteger . . . x . . . . . . . x x x . . . . . . . . . . . . . 
. . . . . .
+ * java.sql.Date        . . . . . . . . . . . x x x . . . x . x . . . . . . . 
. . . . . .
+ * java.sql.Time        . . . . . . . . . . . x x x . . . . x x . . . . . . . 
. . . . . .
+ * java.sql.Timestamp   . . . . . . . . . . . x x x . . . x x x . . . . . . . 
. . . . . .
+ * java.sql.Array       . . . . . . . . . . . . . . . . . . . . x . . . . . . 
. . . . . .
+ * java.sql.Blob        . . . . . . . . . . . . . . . . . . . . . x . . . . . 
. . . . . .
+ * java.sql.Clob        . . . . . . . . . . . . . . . . . . . . . . x . . . . 
. . . . . .
+ * java.sql.Struct      . . . . . . . . . . . . . . . . . . . . . . . x . . . 
. . . . . .
+ * java.sql.Ref         . . . . . . . . . . . . . . . . . . . . . . . . x . . 
. . . . . .
+ * java.net.URL         . . . . . . . . . . . . . . . . . . . . . . . . . x . 
. . . . . .
+ * Java class           . . . . . . . . . . . . . . . . . . . . . . . . . . x 
. . . . . .
+ * java.sql.Rowid       . . . . . . . . . . . . . . . . . . . . . . . . . . . 
x . . . . .
+ * java.sql.NClob       . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . x .
+ * java.sql.SQLXML      . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . x
+ * java.util.Calendar   . . . . . . . . . . . x x x . . . x x x . . . . . . . 
. . . . . .
+ * java.util.Date       . . . . . . . . . . . x x x . . . x x x . . . . . . . 
. . . . . .
+ * </pre>
+ * <!--
+ * CHECKSTYLE: ON
+ * -->
+ *
+ * <p><a name="B6">TABLE B-6</a>: Use of {@code ResultSet} getter methods to
+ * retrieve JDBC data types
+ *
+ * <!--
+ * CHECKSTYLE: OFF
+ * -->
+ * <pre>
+ *                      T S I B R F D D N B B C V L B V L D T T C B A R D S J 
R N N L N S
+ *                      I M N I E L O E U I O H A O I A O A I I L L R E A T A 
O C V O C Q
+ *                      N A T G A O U C M T O A R N N R N T M M O O R F T R V 
W H A N L L
+ *                      Y L E I L A B I E   L R C G A B G E E E B B A   A U A 
I A R G O X
+ *                      I L G N   T L M R   E   H V R I V E   S     Y   L C _ 
D R C N B M
+ *                      N I E T     E A I   A   A A Y N A     T         I T O  
   H V   L
+ *                      T N R         L C   N   R R   A R     A         N   B  
   A A
+ *                        T                       C   R B     M         K   J  
   R R
+ *                                                H   Y I     P                
     C
+ * Java type                                                                
+ * ==================== = = = = = = = = = = = = = = = = = = = = = = = = = = = 
= = = = = =
+ * getByte              X x x x x x x x x x x x x . . . . . . . . . . . . . . 
x . . . . .
+ * getShort             x X x x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getInt               x x X x x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getLong              x x x X x x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getFloat             x x x x X x x x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getDouble            x x x x x X X x x x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getBigDecimal        x x x x x x x X X x x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getBoolean           x x x x x x x x x X x x x . . . . . . . . . . . . . . 
. . . . . .
+ * getString            x x x x x x x x x x x X X x x x x x x x . . . . x . . 
. x x x . .
+ * getNString           x x x x x x x x x x x x x x x x x x x x . . . . x . . 
. X X x . .
+ * getBytes             . . . . . . . . . . . . . . X X x . . . . . . . . . . 
. . . . . .
+ * getDate              . . . . . . . . . . . x x x . . . X . x . . . . . . . 
. . . . . .
+ * getTime              . . . . . . . . . . . x x x . . . . X x . . . . . . . 
. . . . . .
+ * getTimestamp         . . . . . . . . . . . x x x . . . x x X . . . . . . . 
. . . . x .
+ * getAsciiStream       . . . . . . . . . . . x x X x x x . . . x . . . . . . 
. . . . . x
+ * getBinaryStream      . . . . . . . . . . . . . . x x X . . . . x . . . . . 
. . . . x x
+ * getCharacterStream   . . . . . . . . . . . x x X x x x . . . x . . . . . . 
. x x x x x
+ * getNCharacterStream  . . . . . . . . . . . x x x x x x . . . x . . . . . . 
. x x X x x
+ * getClob              . . . . . . . . . . . . . . . . . . . . X . . . . . . 
. . . . x .
+ * getNClob             . . . . . . . . . . . . . . . . . . . . x . . . . . . 
. . . . X .
+ * getBlob              . . . . . . . . . . . . . . . . . . . . . X . . . . . 
. . . . . .
+ * getArray             . . . . . . . . . . . . . . . . . . . . . . X . . . . 
. . . . . .
+ * getRef               . . . . . . . . . . . . . . . . . . . . . . . X . . . 
. . . . . .
+ * getURL               . . . . . . . . . . . . . . . . . . . . . . . . X . . 
. . . . . .
+ * getObject            x x x x x x x x x x x x x x x x x x x x x x x x x X X 
x x x x x x
+ * getRowId             . . . . . . . . . . . . . . . . . . . . . . . . . . . 
X . . . . .
+ * getSQLXML            . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . X
+ * </pre>
+ * <!--
+ * CHECKSTYLE: ON
+ * -->
+ */
+public enum SqlType {
+  BIT(Types.BIT, boolean.class),
+  BOOLEAN(Types.BOOLEAN, boolean.class),
+  TINYINT(Types.TINYINT, byte.class),
+  SMALLINT(Types.SMALLINT, short.class),
+  INTEGER(Types.INTEGER, int.class),
+  BIGINT(Types.BIGINT, long.class),
+  NUMERIC(Types.NUMERIC, BigDecimal.class),
+  DECIMAL(Types.DECIMAL, BigDecimal.class),
+  FLOAT(Types.FLOAT, double.class),
+  REAL(Types.REAL, float.class),
+  DOUBLE(Types.DOUBLE, double.class),
+  DATE(Types.DATE, java.sql.Date.class, int.class),
+  TIME(Types.TIME, Time.class, int.class),
+  TIMESTAMP(Types.TIMESTAMP, Timestamp.class, long.class),
+  INTERVAL_YEAR_MONTH(Types.OTHER, Boolean.class),
+  INTERVAL_DAY_TIME(Types.OTHER, Boolean.class),
+  CHAR(Types.CHAR, String.class),
+  VARCHAR(Types.VARCHAR, String.class),
+  LONGVARCHAR(Types.LONGVARCHAR, String.class),
+  BINARY(Types.BINARY, byte[].class, ByteString.class, String.class),
+  VARBINARY(Types.VARBINARY, byte[].class, ByteString.class, String.class),
+  LONGVARBINARY(Types.LONGVARBINARY, byte[].class, ByteString.class,
+      String.class),
+  NULL(Types.NULL, Void.class),
+  ANY(Types.JAVA_OBJECT, Object.class),
+  SYMBOL(Types.OTHER, Object.class),
+  MULTISET(Types.ARRAY, List.class),
+  ARRAY(Types.ARRAY, Array.class),
+  BLOB(Types.BLOB, Blob.class),
+  CLOB(Types.CLOB, Clob.class),
+  SQLXML(Types.SQLXML, java.sql.SQLXML.class),
+  MAP(Types.OTHER, Map.class),
+  DISTINCT(Types.DISTINCT, Object.class),
+  STRUCT(Types.STRUCT, Struct.class),
+  REF(Types.REF, Ref.class),
+  DATALINK(Types.DATALINK, URL.class),
+  JAVA_OBJECT(Types.JAVA_OBJECT, Object.class),
+  ROWID(Types.ROWID, RowId.class),
+  NCHAR(Types.NCHAR, String.class),
+  NVARCHAR(Types.NVARCHAR, String.class),
+  LONGNVARCHAR(Types.LONGNVARCHAR, String.class),
+  NCLOB(Types.NCLOB, NClob.class),
+  ROW(Types.STRUCT, Object.class),
+  OTHER(Types.OTHER, Object.class),
+  CURSOR(2012, Object.class),
+  COLUMN_LIST(Types.OTHER + 2, Object.class);
+
+  /** Type id as appears in {@link java.sql.Types},
+   * e.g. {@link java.sql.Types#INTEGER}. */
+  public final int id;
+
+  /** Default Java type for this SQL type, as described in table B-1. */
+  public final Class clazz;
+
+  /** Class used internally in Calcite to represent instances of this type. */
+  public final Class internal;
+
+  /** Class used to serialize values of this type as JSON. */
+  public final Class serial;
+
+  private static final Map<Integer, SqlType> BY_ID = new HashMap<>();
+  static {
+    for (SqlType sqlType : values()) {
+      BY_ID.put(sqlType.id, sqlType);
+    }
+  }
+
+  SqlType(int id, Class clazz, Class internal, Class serial) {
+    this.id = id;
+    this.clazz = clazz;
+    this.internal = internal;
+    this.serial = serial;
+  }
+
+  SqlType(int id, Class clazz, Class internal) {
+    this(id, clazz, internal, internal);
+  }
+
+  SqlType(int id, Class clazz) {
+    this(id, clazz, clazz, clazz);
+  }
+
+  public static SqlType valueOf(int type) {
+    final SqlType sqlType = BY_ID.get(type);
+    if (sqlType == null) {
+      throw new IllegalArgumentException("Unknown SQL type " + type);
+    }
+    return sqlType;
+  }
+
+  /** Returns the boxed type. */
+  public Class boxedClass() {
+    return AvaticaUtils.box(clazz);
+  }
+
+  /** Returns the entries in JDBC table B-5. */
+  public static Iterable<Map.Entry<Class, SqlType>> getSetConversions() {
+    final ArrayList<Map.Entry<Class, SqlType>> list = new ArrayList<>();
+    for (Map.Entry<Class, EnumSet<SqlType>> entry : SET_LIST.entrySet()) {
+      for (SqlType sqlType : entry.getValue()) {
+        list.add(new AbstractMap.SimpleEntry<>(entry.getKey(), sqlType));
+      }
+    }
+    return list;
+  }
+
+  public static final Map<Class, EnumSet<SqlType>> SET_LIST;
+  public static final Map<Method, EnumSet<SqlType>> GET_LIST;
+
+  static {
+    SET_LIST = new HashMap<>();
+    GET_LIST = new HashMap<>();
+
+    EnumSet<SqlType> numericTypes = EnumSet.of(TINYINT, SMALLINT, INTEGER,
+        BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, BOOLEAN);
+    Class[] numericClasses = {
+      BigDecimal.class, Boolean.class, Byte.class, Short.class, Integer.class,
+      Long.class, Float.class, Double.class
+    };
+    EnumSet<SqlType> charTypes = EnumSet.of(CHAR, VARCHAR, LONGVARCHAR);
+    EnumSet<SqlType> ncharTypes = EnumSet.of(NCHAR, NVARCHAR, LONGNVARCHAR);
+    EnumSet<SqlType> binaryTypes = EnumSet.of(BINARY, VARBINARY, 
LONGVARBINARY);
+    EnumSet<SqlType> dateTimeTypes = EnumSet.of(DATE, TIME, TIMESTAMP);
+    final EnumSet<SqlType> numericCharTypes = concat(numericTypes, charTypes);
+    SET_LIST.put(String.class,
+        concat(numericCharTypes, binaryTypes, dateTimeTypes, ncharTypes));
+    for (Class clazz : numericClasses) {
+      SET_LIST.put(clazz, numericCharTypes);
+    }
+    SET_LIST.put(byte[].class, binaryTypes);
+    SET_LIST.put(BigInteger.class,
+        EnumSet.of(BIGINT, CHAR, VARCHAR, LONGVARCHAR));
+    SET_LIST.put(java.sql.Date.class,
+        concat(charTypes, EnumSet.of(DATE, TIMESTAMP)));
+    SET_LIST.put(Time.class,
+        concat(charTypes, EnumSet.of(TIME, TIMESTAMP)));
+    SET_LIST.put(Timestamp.class,
+        concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP)));
+    SET_LIST.put(Array.class, EnumSet.of(ARRAY));
+    SET_LIST.put(Blob.class, EnumSet.of(BLOB));
+    SET_LIST.put(Clob.class, EnumSet.of(CLOB));
+    SET_LIST.put(Struct.class, EnumSet.of(STRUCT));
+    SET_LIST.put(Ref.class, EnumSet.of(REF));
+    SET_LIST.put(URL.class, EnumSet.of(DATALINK));
+    SET_LIST.put(Class.class, EnumSet.of(JAVA_OBJECT));
+    SET_LIST.put(RowId.class, EnumSet.of(ROWID));
+    SET_LIST.put(NClob.class, EnumSet.of(NCLOB));
+    SET_LIST.put(java.sql.SQLXML.class, EnumSet.of(SQLXML));
+    SET_LIST.put(Calendar.class,
+        concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP)));
+    SET_LIST.put(java.util.Date.class,
+        concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP)));
+
+    EnumSet<Method> numericMethods =
+        EnumSet.of(Method.GET_BYTE, Method.GET_SHORT, Method.GET_INT,
+            Method.GET_LONG, Method.GET_FLOAT, Method.GET_DOUBLE,
+            Method.GET_BIG_DECIMAL, Method.GET_BOOLEAN);
+    for (Method method : numericMethods) {
+      GET_LIST.put(method, numericCharTypes);
+    }
+    GET_LIST.put(Method.GET_BYTE, EnumSet.of(ROWID));
+    for (Method method : EnumSet.of(Method.GET_STRING, Method.GET_N_STRING)) {
+      GET_LIST.put(method,
+          concat(numericCharTypes, binaryTypes, dateTimeTypes,
+              EnumSet.of(DATALINK), ncharTypes));
+    }
+    GET_LIST.put(Method.GET_BYTES, binaryTypes);
+    GET_LIST.put(Method.GET_DATE,
+        concat(charTypes, EnumSet.of(DATE, TIMESTAMP)));
+    GET_LIST.put(Method.GET_TIME,
+        concat(charTypes, EnumSet.of(TIME, TIMESTAMP)));
+    GET_LIST.put(Method.GET_TIMESTAMP,
+        concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP)));
+    GET_LIST.put(Method.GET_ASCII_STREAM,
+        concat(charTypes, binaryTypes, EnumSet.of(CLOB, NCLOB)));
+    GET_LIST.put(Method.GET_BINARY_STREAM,
+        concat(binaryTypes, EnumSet.of(BLOB, SQLXML)));
+    GET_LIST.put(Method.GET_CHARACTER_STREAM,
+        concat(charTypes, binaryTypes, ncharTypes,
+            EnumSet.of(CLOB, NCLOB, SQLXML)));
+    GET_LIST.put(Method.GET_N_CHARACTER_STREAM,
+        concat(
+            charTypes, binaryTypes, ncharTypes, EnumSet.of(CLOB, NCLOB, 
SQLXML)));
+    GET_LIST.put(Method.GET_CLOB, EnumSet.of(CLOB, NCLOB));
+    GET_LIST.put(Method.GET_N_CLOB, EnumSet.of(CLOB, NCLOB));
+    GET_LIST.put(Method.GET_BLOB, EnumSet.of(BLOB));
+    GET_LIST.put(Method.GET_ARRAY, EnumSet.of(ARRAY));
+    GET_LIST.put(Method.GET_REF, EnumSet.of(REF));
+    GET_LIST.put(Method.GET_BLOB, EnumSet.of(BLOB));
+    GET_LIST.put(Method.GET_URL, EnumSet.of(DATALINK));
+    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));
+  }
+
+  @SafeVarargs
+  private static <E extends Enum<E>> EnumSet<E> concat(Collection<E>... ess) {
+    final List<E> list = new ArrayList<>();
+    for (Collection<E> es : ess) {
+      list.addAll(es);
+    }
+    return EnumSet.copyOf(list);
+  }
+
+  /** Returns whether {@link java.sql.PreparedStatement#setObject} and
+   * {@link PreparedStatement#setNull} can assign a value of a particular class
+   * to a column of a particular SQL type.
+   *
+   * <p>The JDBC standard describes the mapping in table <a href="#B5">B-5</a>.
+   */
+  public static boolean canSet(Class aClass, SqlType sqlType) {
+    final EnumSet<SqlType> sqlTypes = SET_LIST.get(aClass);
+    return sqlTypes != null && sqlTypes.contains(sqlType);
+  }
+
+  /** Returns whether {@link java.sql.ResultSet#getInt(int)} and similar 
methods
+   * can convert a value to a particular SQL type.
+   *
+   * <p>The JDBC standard describes the mapping in table <a href="#B6">B-6</a>.
+   */
+  public static boolean canGet(Method method, SqlType sqlType) {
+    final EnumSet<SqlType> sqlTypes = GET_LIST.get(method);
+    return sqlTypes != null && sqlTypes.contains(sqlType);
+  }
+
+  /** Getter methods in {@link java.sql.ResultSet}. */
+  public enum Method {
+    GET_BYTE("getByte"),
+    GET_SHORT("getShort"),
+    GET_INT("getInt"),
+    GET_LONG("getLong"),
+    GET_FLOAT("getFloat"),
+    GET_DOUBLE("getDouble"),
+    GET_BIG_DECIMAL("getBigDecimal"),
+    GET_BOOLEAN("getBoolean"),
+    GET_STRING("getString"),
+    GET_N_STRING("getNString"),
+    GET_BYTES("getBytes"),
+    GET_DATE("getDate"),
+    GET_TIME("getTime"),
+    GET_TIMESTAMP("getTimestamp"),
+    GET_ASCII_STREAM("getAsciiStream"),
+    GET_BINARY_STREAM("getBinaryStream"),
+    GET_CHARACTER_STREAM("getCharacterStream"),
+    GET_N_CHARACTER_STREAM("getNCharacterStream"),
+    GET_CLOB("getClob"),
+    GET_N_CLOB("getNClob"),
+    GET_BLOB("getBlob"),
+    GET_ARRAY("getArray"),
+    GET_REF("getRef"),
+    GET_URL("getURL"),
+    GET_OBJECT("getObject"),
+    GET_ROW_ID("getRowId"),
+    GET_SQLXML("getSQLXML");
+
+    public final String methodName;
+
+    Method(String methodName) {
+      this.methodName = methodName;
+    }
+  }
+}
+
+// End SqlType.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
----------------------------------------------------------------------
diff --git 
a/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java 
b/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
new file mode 100644
index 0000000..b1fe787
--- /dev/null
+++ 
b/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
@@ -0,0 +1,255 @@
+/*
+ * 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.avatica;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.DriverPropertyInfo;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Implementation of JDBC driver that does not register itself.
+ *
+ * <p>You can easily create a "vanity driver" that recognizes its own
+ * URL prefix as a sub-class of this class. Per the JDBC specification it
+ * must register itself when the class is loaded.</p>
+ *
+ * <p>Derived classes must implement {@link #createDriverVersion()} and
+ * {@link #getConnectStringPrefix()}, and may override
+ * {@link #createFactory()}.</p>
+ *
+ * <p>The provider must implement:</p>
+ * <ul>
+ *   <li>{@link Meta#prepare(Meta.ConnectionHandle, String, long)}
+ *   <li>{@link 
Meta#createIterable(org.apache.calcite.avatica.Meta.StatementHandle, 
org.apache.calcite.avatica.QueryState, 
org.apache.calcite.avatica.Meta.Signature, java.util.List, Meta.Frame)}
+ * </ul>
+ */
+public abstract class UnregisteredDriver implements java.sql.Driver {
+  final DriverVersion version;
+  protected final AvaticaFactory factory;
+  public final Handler handler;
+
+  protected UnregisteredDriver() {
+    this.factory = createFactory();
+    this.version = createDriverVersion();
+    this.handler = createHandler();
+  }
+
+  /**
+   * Creates a factory for JDBC objects (connection, statement).
+   * Called from the driver constructor.
+   *
+   * <p>The default implementation calls {@link JdbcVersion#current},
+   * then {@link #getFactoryClassName} with that version,
+   * then passes that class name to {@link #instantiateFactory(String)}.
+   * This approach is recommended it does not include in the code references
+   * to classes that may not be instantiable in all JDK versions.
+   * But drivers are free to do it their own way.</p>
+   *
+   * @return JDBC object factory
+   */
+  protected AvaticaFactory createFactory() {
+    return instantiateFactory(getFactoryClassName(JdbcVersion.current()));
+  }
+
+  /** Creates a Handler. */
+  protected Handler createHandler() {
+    return new HandlerImpl();
+  }
+
+  /**
+   * Returns the name of a class to be factory for JDBC objects
+   * (connection, statement) appropriate for the current JDBC version.
+   */
+  protected String getFactoryClassName(JdbcVersion jdbcVersion) {
+    switch (jdbcVersion) {
+    case JDBC_30:
+    case JDBC_40:
+      throw new IllegalArgumentException("JDBC version not supported: "
+          + jdbcVersion);
+    case JDBC_41:
+    default:
+      return "org.apache.calcite.avatica.AvaticaJdbc41Factory";
+    }
+  }
+
+  /**
+   * Creates an object describing the name and version of this driver.
+   * Called from the driver constructor.
+   */
+  protected abstract DriverVersion createDriverVersion();
+
+  /**
+   * Returns the connection properties supported by this driver.
+   */
+  protected Collection<ConnectionProperty> getConnectionProperties() {
+    return Arrays.<ConnectionProperty>asList(
+        BuiltInConnectionProperty.values());
+  }
+
+  /** Helper method for creating factories. */
+  protected static AvaticaFactory instantiateFactory(String factoryClassName) {
+    try {
+      final Class<?> clazz = Class.forName(factoryClassName);
+      return (AvaticaFactory) clazz.newInstance();
+    } catch (ClassNotFoundException e) {
+      throw handle("Error loading factory " + factoryClassName, e);
+    } catch (IllegalAccessException e) {
+      throw handle("Error loading factory " + factoryClassName, e);
+    } catch (InstantiationException e) {
+      throw handle("Error loading factory " + factoryClassName, e);
+    } catch (Throwable e) {
+      // It is not usually good to catch Throwable. But class loading can fail
+      // with serious errors such as java.lang.NoClassDefFoundError
+      throw handle("Error loading factory " + factoryClassName, e);
+    }
+  }
+
+  private static RuntimeException handle(String msg, Throwable e) {
+    Logger.getLogger("").log(Level.SEVERE, msg, e);
+    throw new RuntimeException(msg, e);
+  }
+
+  public Connection connect(String url, Properties info) throws SQLException {
+    if (!acceptsURL(url)) {
+      return null;
+    }
+    final String prefix = getConnectStringPrefix();
+    assert url.startsWith(prefix);
+    final String urlSuffix = url.substring(prefix.length());
+    final Properties info2 = ConnectStringParser.parse(urlSuffix, info);
+    final AvaticaConnection connection =
+        factory.newConnection(this, factory, url, info2);
+    handler.onConnectionInit(connection);
+    return connection;
+  }
+
+  public boolean acceptsURL(String url) throws SQLException {
+    return url.startsWith(getConnectStringPrefix());
+  }
+
+  /** Returns the prefix of the connect string that this driver will recognize
+   * as its own. For example, "jdbc:calcite:". */
+  protected abstract String getConnectStringPrefix();
+
+  public DriverPropertyInfo[] getPropertyInfo(
+      String url, Properties info) throws SQLException {
+    List<DriverPropertyInfo> list = new ArrayList<DriverPropertyInfo>();
+
+    // First, add the contents of info
+    for (Map.Entry<Object, Object> entry : info.entrySet()) {
+      list.add(
+          new DriverPropertyInfo(
+              (String) entry.getKey(),
+              (String) entry.getValue()));
+    }
+    // Next, add property definitions not mentioned in info
+    for (ConnectionProperty p : getConnectionProperties()) {
+      if (info.containsKey(p.name())) {
+        continue;
+      }
+      list.add(new DriverPropertyInfo(p.name(), null));
+    }
+    return list.toArray(new DriverPropertyInfo[list.size()]);
+  }
+
+  // JDBC 4.1 support (JDK 1.7 and higher)
+  public Logger getParentLogger() {
+    return Logger.getLogger("");
+  }
+
+  /**
+   * Returns the driver version object. Not in the JDBC API.
+   *
+   * @return Driver version
+   */
+  public DriverVersion getDriverVersion() {
+    return version;
+  }
+
+  public final int getMajorVersion() {
+    return version.majorVersion;
+  }
+
+  public final int getMinorVersion() {
+    return version.minorVersion;
+  }
+
+  public boolean jdbcCompliant() {
+    return version.jdbcCompliant;
+  }
+
+  /**
+   * Registers this driver with the driver manager.
+   */
+  protected void register() {
+    try {
+      DriverManager.registerDriver(this);
+    } catch (SQLException e) {
+      System.out.println(
+          "Error occurred while registering JDBC driver "
+          + this + ": " + e.toString());
+    }
+  }
+
+  /** Creates a service handler that will give connections from this Driver
+   * their behavior. */
+  public abstract Meta createMeta(AvaticaConnection connection);
+
+  /** JDBC version. */
+  protected enum JdbcVersion {
+    /** Unknown JDBC version. */
+    JDBC_UNKNOWN,
+    /** JDBC version 3.0. Generally associated with JDK 1.5. */
+    JDBC_30,
+    /** JDBC version 4.0. Generally associated with JDK 1.6. */
+    JDBC_40,
+    /** JDBC version 4.1. Generally associated with JDK 1.7. */
+    JDBC_41;
+
+    /** Deduces the current JDBC version. */
+    public static JdbcVersion current() {
+      try {
+        // If java.sql.PseudoColumnUsage is present, we are running JDBC
+        // 4.1 or later.
+        Class.forName("java.sql.PseudoColumnUsage");
+        return JDBC_41;
+      } catch (ClassNotFoundException e) {
+        // java.sql.PseudoColumnUsage is not present. This means we are
+        // running JDBC 4.0 or earlier.
+        try {
+          Class.forName("java.sql.Wrapper");
+          return JDBC_40;
+        } catch (ClassNotFoundException e2) {
+          // java.sql.Wrapper is not present. This means we are
+          // running JDBC 3.0 or earlier (probably JDK 1.5).
+          return JDBC_30;
+        }
+      }
+    }
+  }
+}
+
+// End UnregisteredDriver.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java
----------------------------------------------------------------------
diff --git 
a/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java 
b/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java
new file mode 100644
index 0000000..89a9fbb
--- /dev/null
+++ b/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/**
+ * Avatica JDBC framework.
+ */
+@PackageMarker
+package org.apache.calcite.avatica;
+
+import org.apache.calcite.avatica.util.PackageMarker;
+
+// End package-info.java

Reply via email to