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/03/23 18:26:15 UTC

[1/9] incubator-calcite git commit: Update release HOWTO

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 60789a572 -> 574dc7cc8


Update release HOWTO


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

Branch: refs/heads/master
Commit: 3b10a6a5589c6af9e234bc3acfbaa3b0d002db12
Parents: 60789a5
Author: Julian Hyde <jh...@apache.org>
Authored: Fri Mar 13 14:39:22 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 01:13:57 2015 -0700

----------------------------------------------------------------------
 doc/HOWTO.md | 58 +++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/3b10a6a5/doc/HOWTO.md
----------------------------------------------------------------------
diff --git a/doc/HOWTO.md b/doc/HOWTO.md
index a62ae5f..9e18dc7 100644
--- a/doc/HOWTO.md
+++ b/doc/HOWTO.md
@@ -318,6 +318,20 @@ Before you start:
   a fix version assigned (most likely the version we are
   just about to release)
 
+Create a release branch named after the release, e.g. `branch-1.1`, and push it to Apache.
+
+```bash
+$ git checkout -b branch-X.Y
+$ git push -u origin branch-X.Y
+
+We will use the branch for the entire the release process. Meanwhile,
+we do not allow commits to the master branch. After the release is
+final, we can use `git merge --ff-only` to append the changes on the
+release branch onto the master branch. (Apache does not allow reverts
+to the master branch, which makes it difficult to clean up the kind of
+messy commits that inevitably happen while you are trying to finalize
+a release.)
+
 Now, set up your environment and do a dry run. The dry run will not
 commit any changes back to git and gives you the opportunity to verify
 that the release process will complete as expected.
@@ -353,9 +367,8 @@ Check the artifacts:
   no binary distro), check that all files belong to a directory called
   `apache-calcite-X.Y.Z-incubating-src`.
 * That directory must contain files `DISCLAIMER`, `NOTICE`, `LICENSE`,
-  `README`, `README.md`, `git.properties`
+  `README`, `README.md`
   * Check that the version in `README` is correct
-  * Check that `git.properties` is current
 * In each .jar (for example
   `core/target/calcite-core-X.Y.Z-incubating.jar` and
   `mongodb/target/calcite-mongodb-X.Y.Z-incubating-sources.jar`), check
@@ -385,17 +398,25 @@ Verify the staged artifacts in the Nexus repository:
   https://repository.apache.org/content/repositories/orgapachecalcite-1000
   (or a similar URL)
 
-Upload the artifacts to a staging area (in this case, your
-people.apache.org home directory):
+Upload the artifacts via subversion to a staging area,
+https://dist.apache.org/repos/dist/dev/incubator/calcite/apache-calcite-X.Y.Z-incubating-rcN:
 
 ```bash
+# Create a subversion workspace, if you haven't already
+mkdir -p ~/dist/dev
+pushd ~/dist/dev
+svn co https://dist.apache.org/repos/dist/dev/incubator/calcite
+popd
+
 # Move the files into a directory
 cd target
-mkdir apache-calcite-X.Y.Z-incubating-rcN
-mv apache-calcite-* calcite-X.Y.Z-incubating-rcN
+mkdir ~/dist/dev/calcite/apache-calcite-X.Y.Z-incubating-rcN
+mv apache-calcite-* ~/dist/dev/calcite/apache-calcite-X.Y.Z-incubating-rcN
 
-# Upload to staging area (your people.apache.org home directory)
-scp -rp apache-calcite-X.Y.Z-incubating-rcN people.apache.org:public_html
+# Check in
+cd ~/dist/dev/calcite
+svn add apache-calcite-X.Y.Z-incubating-rcN
+svn ci
 ```
 
 ## Cleaning up after a failed release attempt (for Calcite committers)
@@ -482,7 +503,7 @@ http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/NNNNNN
 Its hash is XXXX.
 
 The artifacts to be voted on are located here:
-http://people.apache.org/~jhyde/apache-calcite-X.Y.Z-incubating-rcN/
+https://dist.apache.org/repos/dist/dev/incubator/calcite/apache-calcite-X.Y.Z-incubating-rcN/
 
 The hashes of the artifacts are as follows:
 src.tar.gz.md5 XXXX
@@ -567,7 +588,7 @@ http://git-wip-us.apache.org/repos/asf/incubator-calcite/commit/NNNNNN
 Its hash is XXXX.
 
 The artifacts to be voted on are located here:
-http://people.apache.org/~jhyde/apache-calcite-X.Y.Z-incubating-rcN/
+https://dist.apache.org/repos/dist/dev/incubator/calcite/apache-calcite-X.Y.Z-incubating-rcN/
 
 The hashes of the artifacts are as follows:
 src.tar.gz.md5 XXXX
@@ -630,12 +651,19 @@ Promote the staged nexus artifacts.
 Check the artifacts into svn.
 
 ```bash
-ssh people.apache.org
-mkdir -p dist
-cd dist
-svn co https://dist.apache.org/repos/dist/release/incubator/calcite
+# Get the release candidate.
+mkdir -p ~/dist/dev
+cd ~/dist/dev
+svn co https://dist.apache.org/repos/dist/dev/incubator/calcite
+
 # Copy the artifacts. Note that the copy does not have '-rcN' suffix.
-cp -rp ../public_html/apache-calcite-X.Y.Z-incubating-rcN calcite/apache-calcite-X.Y.Z-incubating
+mkdir -p ~/dist/release
+cd ~/dist/release
+svn co https://dist.apache.org/repos/dist/release/incubator/calcite
+cd calcite
+cp -rp ../../dev/calcite/apache-calcite-X.Y.Z-incubating-rcN apache-calcite-X.Y.Z-incubating
+svn add apache-calcite-X.Y.Z-incubating
+
 # Check in.
 svn ci
 ```


[6/9] incubator-calcite git commit: [CALCITE-627] Add Avatica support for getTableTypes, getColumns (Xavier FH Leong)

Posted by jh...@apache.org.
[CALCITE-627] Add Avatica support for getTableTypes, getColumns (Xavier FH Leong)


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

Branch: refs/heads/master
Commit: fe13dd3bcbac3998defa37929da0ab428372d2a1
Parents: 4d2f647
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Mar 18 14:14:31 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 01:45:01 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/remote/JsonService.java     | 16 ++++++++
 .../calcite/avatica/remote/LocalService.java    | 14 +++++++
 .../calcite/avatica/remote/RemoteMeta.java      | 15 +++++++
 .../apache/calcite/avatica/remote/Service.java  | 41 ++++++++++++++++++++
 .../calcite/jdbc/CalciteRemoteDriverTest.java   | 33 ++++++++++++++++
 5 files changed, 119 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fe13dd3b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
index 7e110ff..cc0ca6e 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
@@ -82,6 +82,22 @@ public abstract class JsonService implements Service {
     }
   }
 
+  public ResultSetResponse apply(TableTypesRequest request) {
+    try {
+      return decode(apply(encode(request)), ResultSetResponse.class);
+    } catch (IOException e) {
+      throw handle(e);
+    }
+  }
+
+  public ResultSetResponse apply(ColumnsRequest request) {
+    try {
+      return decode(apply(encode(request)), ResultSetResponse.class);
+    } catch (IOException e) {
+      throw handle(e);
+    }
+  }
+
   public PrepareResponse apply(PrepareRequest request) {
     try {
       return decode(apply(encode(request)), PrepareResponse.class);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fe13dd3b/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 faf60b8..fa7611e 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
@@ -103,6 +103,20 @@ public class LocalService implements Service {
     return toResponse(resultSet);
   }
 
+  public ResultSetResponse apply(TableTypesRequest request) {
+    final Meta.MetaResultSet resultSet = meta.getTableTypes();
+    return toResponse(resultSet);
+  }
+
+  public ResultSetResponse apply(ColumnsRequest request) {
+    final Meta.MetaResultSet resultSet =
+        meta.getColumns(request.catalog,
+            Meta.Pat.of(request.schemaPattern),
+            Meta.Pat.of(request.tableNamePattern),
+            Meta.Pat.of(request.columnNamePattern));
+    return toResponse(resultSet);
+  }
+
   public PrepareResponse apply(PrepareRequest request) {
     final Meta.StatementHandle h =
         new Meta.StatementHandle(request.statementId);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fe13dd3b/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 83dd28c..10439ce 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
@@ -79,6 +79,21 @@ class RemoteMeta extends MetaImpl {
     return toResultSet(MetaTable.class, response);
   }
 
+  @Override public MetaResultSet getTableTypes() {
+    final Service.ResultSetResponse response =
+        service.apply(new Service.TableTypesRequest());
+    return toResultSet(MetaTableType.class, response);
+  }
+
+  @Override public MetaResultSet getColumns(String catalog, Pat schemaPattern,
+      Pat tableNamePattern, Pat columnNamePattern) {
+    final Service.ResultSetResponse response =
+        service.apply(
+            new Service.ColumnsRequest(catalog, schemaPattern.s,
+                tableNamePattern.s, columnNamePattern.s));
+    return toResultSet(MetaColumn.class, response);
+  }
+
   @Override public Signature prepare(StatementHandle h, String sql,
       int maxRowCount) {
     final Service.PrepareResponse response =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fe13dd3b/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 cf73b49..ed2c332 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
@@ -33,6 +33,8 @@ public interface Service {
   ResultSetResponse apply(CatalogsRequest request);
   ResultSetResponse apply(SchemasRequest request);
   ResultSetResponse apply(TablesRequest request);
+  ResultSetResponse apply(TableTypesRequest request);
+  ResultSetResponse apply(ColumnsRequest request);
   PrepareResponse apply(PrepareRequest request);
   ResultSetResponse apply(PrepareAndExecuteRequest request);
   FetchResponse apply(FetchRequest request);
@@ -52,6 +54,9 @@ public interface Service {
       @JsonSubTypes.Type(value = CatalogsRequest.class, name = "getCatalogs"),
       @JsonSubTypes.Type(value = SchemasRequest.class, name = "getSchemas"),
       @JsonSubTypes.Type(value = TablesRequest.class, name = "getTables"),
+      @JsonSubTypes.Type(value = TableTypesRequest.class,
+          name = "getTableTypes"),
+      @JsonSubTypes.Type(value = ColumnsRequest.class, name = "getColumns"),
       @JsonSubTypes.Type(value = PrepareRequest.class, name = "prepare"),
       @JsonSubTypes.Type(value = PrepareAndExecuteRequest.class,
           name = "prepareAndExecute"),
@@ -127,11 +132,47 @@ public interface Service {
     }
   }
 
+  /** Request for
+   * {@link Meta#getTableTypes()}. */
+  class TableTypesRequest extends Request {
+
+    ResultSetResponse accept(Service service) {
+      return service.apply(this);
+    }
+  }
+
+  /** Request for
+   * {@link Meta#getColumns(String, org.apache.calcite.avatica.Meta.Pat, org.apache.calcite.avatica.Meta.Pat, org.apache.calcite.avatica.Meta.Pat)}.
+   */
+  class ColumnsRequest extends Request {
+    public final String catalog;
+    public final String schemaPattern;
+    public final String tableNamePattern;
+    public final String columnNamePattern;
+
+    @JsonCreator
+    public ColumnsRequest(@JsonProperty("catalog") String catalog,
+        @JsonProperty("schemaPattern") String schemaPattern,
+        @JsonProperty("tableNamePattern") String tableNamePattern,
+        @JsonProperty("columnNamePattern") String columnNamePattern) {
+      this.catalog = catalog;
+      this.schemaPattern = schemaPattern;
+      this.tableNamePattern = tableNamePattern;
+      this.columnNamePattern = columnNamePattern;
+    }
+
+    ResultSetResponse accept(Service service) {
+      return service.apply(this);
+    }
+  }
+
   /** Response that contains a result set.
    *
    * <p>Several types of request, including
    * {@link org.apache.calcite.avatica.Meta#getCatalogs()} and
    * {@link org.apache.calcite.avatica.Meta#getSchemas(String, org.apache.calcite.avatica.Meta.Pat)}
+   * {@link Meta#getTables(String, org.apache.calcite.avatica.Meta.Pat, org.apache.calcite.avatica.Meta.Pat, List<String>)}
+   * {@link Meta#getTableTypes()}
    * return this response. */
   class ResultSetResponse extends Response {
     public final int statementId;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/fe13dd3b/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 0d5f91e..8d10a98 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -81,6 +81,26 @@ public class CalciteRemoteDriverTest {
           }
         }
       };
+  private static final Function<Connection, ResultSet> GET_COLUMNS =
+      new Function<Connection, ResultSet>() {
+        public ResultSet apply(Connection input) {
+          try {
+            return input.getMetaData().getColumns(null, null, null, null);
+          } catch (SQLException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
+  private static final Function<Connection, ResultSet> GET_TABLE_TYPES =
+      new Function<Connection, ResultSet>() {
+        public ResultSet apply(Connection input) {
+          try {
+            return input.getMetaData().getTableTypes();
+          } catch (SQLException e) {
+            throw new RuntimeException(e);
+          }
+        }
+      };
 
   private static Connection localConnection;
   private static Connection remoteConnection;
@@ -159,6 +179,19 @@ public class CalciteRemoteDriverTest {
             + "TABLE_SCHEM=metadata; TABLE_CATALOG=null\n");
   }
 
+  @Test public void testRemoteColumns() throws Exception {
+    CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
+        .metaData(GET_COLUMNS)
+        .returns(CalciteAssert.checkResultContains("COLUMN_NAME=EMPNO"));
+  }
+
+  @Test public void testRemoteTableTypes() throws Exception {
+    CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
+        .metaData(GET_TABLE_TYPES)
+        .returns("TABLE_TYPE=TABLE\n"
+            + "TABLE_TYPE=VIEW\n");
+  }
+
   @Test public void testRemoteExecuteQuery() throws Exception {
     CalciteAssert.hr().with(REMOTE_CONNECTION_FACTORY)
         .query("values (1, 'a'), (cast(null as integer), 'b')")


[9/9] incubator-calcite git commit: [CALCITE-335] Remove uses of linq4j Functions.adapt

Posted by jh...@apache.org.
[CALCITE-335] Remove uses of linq4j Functions.adapt


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

Branch: refs/heads/master
Commit: 574dc7cc89c6319ed51629f316d3a87eedfb1c0f
Parents: 0fe2637
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 23 02:51:56 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 02:51:56 2015 -0700

----------------------------------------------------------------------
 .../calcite/adapter/clone/ColumnLoader.java     | 33 ++++++++++----------
 .../apache/calcite/adapter/jdbc/JdbcTable.java  | 14 ++++-----
 .../materialize/MaterializationService.java     | 12 +++----
 .../org/apache/calcite/rel/core/Project.java    |  9 +++---
 .../org/apache/calcite/rel/core/Values.java     | 17 +++++-----
 .../calcite/linq4j/function/Functions.java      | 20 +++++++-----
 .../calcite/linq4j/tree/ConstantExpression.java | 13 ++++----
 .../linq4j/tree/ConstructorDeclaration.java     |  8 ++---
 .../calcite/linq4j/tree/MethodDeclaration.java  |  8 ++---
 .../calcite/linq4j/function/FunctionTest.java   | 15 ---------
 10 files changed, 66 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java b/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java
index 86bb77f..d33ee61 100644
--- a/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java
+++ b/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java
@@ -21,13 +21,14 @@ import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rel.type.RelProtoDataType;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
 import java.lang.reflect.Type;
 import java.sql.Date;
 import java.sql.Time;
@@ -52,15 +53,15 @@ class ColumnLoader<T> {
     0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000L};
   static final int[] LONG_S = {1, 2, 4, 8, 16, 32};
 
-  private static final Function1<Timestamp, Long> TIMESTAMP_TO_LONG =
-      new Function1<Timestamp, Long>() {
+  private static final Function<Timestamp, Long> TIMESTAMP_TO_LONG =
+      new Function<Timestamp, Long>() {
         public Long apply(Timestamp a0) {
           return a0 == null ? null : a0.getTime();
         }
       };
 
-  private static final Function1<Time, Integer> TIME_TO_INT =
-      new Function1<Time, Integer>() {
+  private static final Function<Time, Integer> TIME_TO_INT =
+      new Function<Time, Integer>() {
         public Integer apply(Time a0) {
           return a0 == null
               ? null
@@ -68,8 +69,8 @@ class ColumnLoader<T> {
         }
       };
 
-  private static final Function1<Date, Integer> DATE_TO_INT =
-      new Function1<Date, Integer>() {
+  private static final Function<Date, Integer> DATE_TO_INT =
+      new Function<Date, Integer>() {
         public Integer apply(Date a0) {
           return a0 == null
               ? null
@@ -77,9 +78,8 @@ class ColumnLoader<T> {
         }
       };
 
-  public final List<T> list = new ArrayList<T>();
-  public final List<ArrayTable.Column> representationValues =
-      new ArrayList<ArrayTable.Column>();
+  public final List<T> list = new ArrayList<>();
+  public final List<ArrayTable.Column> representationValues = new ArrayList<>();
   private final JavaTypeFactory typeFactory;
   public final int sortField;
 
@@ -264,21 +264,21 @@ class ColumnLoader<T> {
       switch (rep) {
       case OBJECT:
       case JAVA_SQL_TIMESTAMP:
-        return Functions.adapt(list, TIMESTAMP_TO_LONG);
+        return Lists.transform(list, TIMESTAMP_TO_LONG);
       }
       break;
     case TIME:
       switch (rep) {
       case OBJECT:
       case JAVA_SQL_TIME:
-        return Functions.adapt(list, TIME_TO_INT);
+        return Lists.transform(list, TIME_TO_INT);
       }
       break;
     case DATE:
       switch (rep) {
       case OBJECT:
       case JAVA_SQL_DATE:
-        return Functions.adapt(list, DATE_TO_INT);
+        return Lists.transform(list, DATE_TO_INT);
       }
       break;
     }
@@ -291,9 +291,8 @@ class ColumnLoader<T> {
    */
   static class ValueSet {
     final Class clazz;
-    final Map<Comparable, Comparable> map =
-        new HashMap<Comparable, Comparable>();
-    final List<Comparable> values = new ArrayList<Comparable>();
+    final Map<Comparable, Comparable> map = new HashMap<>();
+    final List<Comparable> values = new ArrayList<>();
     Comparable min;
     Comparable max;
     boolean containsNull;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index 7e68c52..976e311 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -24,8 +24,6 @@ import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.linq4j.Queryable;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.linq4j.tree.Primitive;
 import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.RelNode;
@@ -48,6 +46,9 @@ import org.apache.calcite.sql.util.SqlString;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -110,9 +111,8 @@ class JdbcTable extends AbstractQueryableTable
   private List<Pair<Primitive, Integer>> fieldClasses(
       final JavaTypeFactory typeFactory) {
     final RelDataType rowType = protoRowType.apply(typeFactory);
-    return Functions.adapt(
-        rowType.getFieldList(),
-        new Function1<RelDataTypeField, Pair<Primitive, Integer>>() {
+    return Lists.transform(rowType.getFieldList(),
+        new Function<RelDataTypeField, Pair<Primitive, Integer>>() {
           public Pair<Primitive, Integer> apply(RelDataTypeField field) {
             RelDataType type = field.getType();
             Class clazz = (Class) typeFactory.getJavaClass(type);
@@ -137,7 +137,7 @@ class JdbcTable extends AbstractQueryableTable
   }
 
   SqlIdentifier tableName() {
-    final List<String> strings = new ArrayList<String>();
+    final List<String> strings = new ArrayList<>();
     if (jdbcSchema.catalog != null) {
       strings.add(jdbcSchema.catalog);
     }
@@ -156,7 +156,7 @@ class JdbcTable extends AbstractQueryableTable
 
   public <T> Queryable<T> asQueryable(QueryProvider queryProvider,
       SchemaPlus schema, String tableName) {
-    return new JdbcTableQueryable<T>(queryProvider, schema, tableName);
+    return new JdbcTableQueryable<>(queryProvider, schema, tableName);
   }
 
   public Enumerable<Object[]> scan(DataContext root) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 2d4c3f2..3d98567 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -28,8 +28,6 @@ import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.linq4j.AbstractQueryable;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.QueryProvider;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.linq4j.tree.Expression;
 import org.apache.calcite.prepare.Prepare;
 import org.apache.calcite.rel.type.RelDataType;
@@ -41,6 +39,7 @@ import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
@@ -123,8 +122,8 @@ public class MaterializationService {
       materializedTable =
           CloneSchema.createCloneTable(typeFactory,
               RelDataTypeImpl.proto(calciteSignature.rowType),
-              Functions.adapt(calciteSignature.columns,
-                  new Function1<ColumnMetaData, ColumnMetaData.Rep>() {
+              Lists.transform(calciteSignature.columns,
+                  new Function<ColumnMetaData, ColumnMetaData.Rep>() {
                     public ColumnMetaData.Rep apply(ColumnMetaData column) {
                       return column.type.rep;
                     }
@@ -245,7 +244,7 @@ public class MaterializationService {
     // through all tiles.
     if (!exact) {
       final PriorityQueue<Pair<CalciteSchema.TableEntry, TileKey>> queue =
-          new PriorityQueue<Pair<CalciteSchema.TableEntry, TileKey>>(1, C);
+          new PriorityQueue<>(1, C);
       for (Map.Entry<TileKey, MaterializationKey> entry
           : actor.keyByTile.entrySet()) {
         final TileKey tileKey2 = entry.getKey();
@@ -327,8 +326,7 @@ public class MaterializationService {
    * with the current schema. Especially in a test run, the contents of two
    * root schemas may look similar.) */
   public List<Prepare.Materialization> query(CalciteSchema rootSchema) {
-    final List<Prepare.Materialization> list =
-        new ArrayList<Prepare.Materialization>();
+    final List<Prepare.Materialization> list = new ArrayList<>();
     for (MaterializationActor.Materialization materialization
         : actor.keyMap.values()) {
       if (materialization.rootSchema == rootSchema

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index af24c58..09c2ec9 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -17,8 +17,6 @@
 package org.apache.calcite.rel.core;
 
 import org.apache.calcite.linq4j.Ord;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
@@ -46,7 +44,9 @@ import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.MappingType;
 import org.apache.calcite.util.mapping.Mappings;
 
+import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
@@ -202,9 +202,8 @@ public abstract class Project extends SingleRel {
     }
     //CHECKSTYLE: IGNORE 1
     if (false && !Util.isDistinct(
-        Functions.adapt(
-            exps,
-            new Function1<RexNode, Object>() {
+        Lists.transform(exps,
+            new Function<RexNode, Object>() {
               public Object apply(RexNode a0) {
                 return a0.toString();
               }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/core/src/main/java/org/apache/calcite/rel/core/Values.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Values.java b/core/src/main/java/org/apache/calcite/rel/core/Values.java
index e6a3bfe..2f4b6ba 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Values.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Values.java
@@ -16,8 +16,6 @@
  */
 package org.apache.calcite.rel.core;
 
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.plan.RelOptPlanner;
@@ -34,8 +32,10 @@ import org.apache.calcite.sql.SqlExplainLevel;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.Pair;
 
+import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
@@ -47,8 +47,8 @@ public abstract class Values extends AbstractRelNode {
   /**
    * Lambda that helps render tuples as strings.
    */
-  private static final Function1<ImmutableList<RexLiteral>, Object> F =
-      new Function1<ImmutableList<RexLiteral>, Object>() {
+  private static final Function<ImmutableList<RexLiteral>, Object> F =
+      new Function<ImmutableList<RexLiteral>, Object>() {
         public Object apply(ImmutableList<RexLiteral> tuple) {
           String s = tuple.toString();
           assert s.startsWith("[");
@@ -171,13 +171,10 @@ public abstract class Values extends AbstractRelNode {
     return super.explainTerms(pw)
         // For rel digest, include the row type since a rendered
         // literal may leave the type ambiguous (e.g. "null").
-        .itemIf(
-            "type", rowType,
+        .itemIf("type", rowType,
             pw.getDetailLevel() == SqlExplainLevel.DIGEST_ATTRIBUTES)
-        .itemIf(
-            "type", rowType.getFieldList(),
-            pw.nest())
-        .itemIf("tuples", Functions.adapt(tuples, F), !pw.nest())
+        .itemIf("type", rowType.getFieldList(), pw.nest())
+        .itemIf("tuples", Lists.transform(tuples, F), !pw.nest())
         .itemIf("tuples", tuples, pw.nest());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java
index 129c9a2..bd7a446 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java
@@ -54,8 +54,7 @@ public abstract class Functions {
 
   private static final Map<Class, Class<? extends Function>> FUNCTION1_CLASSES =
       Collections.unmodifiableMap(
-          new HashMap<Class, Class<? extends Function>>(
-              inverse(FUNCTION_RESULT_TYPES)));
+          new HashMap<>(inverse(FUNCTION_RESULT_TYPES)));
 
   private static final Comparator NULLS_FIRST_COMPARATOR =
       new NullsFirstComparator();
@@ -91,7 +90,7 @@ public abstract class Functions {
 
   @SuppressWarnings("unchecked")
   private static <K, V> Map<K, V> map(K k, V v, Object... rest) {
-    final Map<K, V> map = new HashMap<K, V>();
+    final Map<K, V> map = new HashMap<>();
     map.put(k, v);
     for (int i = 0; i < rest.length; i++) {
       map.put((K) rest[i++], (V) rest[i++]);
@@ -100,7 +99,7 @@ public abstract class Functions {
   }
 
   private static <K, V> Map<V, K> inverse(Map<K, V> map) {
-    HashMap<V, K> inverseMap = new HashMap<V, K>();
+    HashMap<V, K> inverseMap = new HashMap<>();
     for (Map.Entry<K, V> entry : map.entrySet()) {
       inverseMap.put(entry.getValue(), entry.getKey());
     }
@@ -306,7 +305,10 @@ public abstract class Functions {
 
   /**
    * Creates a view of a list that applies a function to each element.
+   *
+   * @deprecated Use {@link com.google.common.collect.Lists#transform}
    */
+  @Deprecated // to be removed before 2.0
   public static <T1, R> List<R> adapt(final List<T1> list,
       final Function1<T1, R> f) {
     return new AbstractList<R>() {
@@ -322,7 +324,11 @@ public abstract class Functions {
 
   /**
    * Creates a view of an array that applies a function to each element.
+   *
+   * @deprecated Use {@link com.google.common.collect.Lists#transform}
+   * and {@link Arrays#asList(Object[])}
    */
+  @Deprecated // to be removed before 2.0
   public static <T, R> List<R> adapt(final T[] ts,
       final Function1<T, R> f) {
     return new AbstractList<R>() {
@@ -341,7 +347,7 @@ public abstract class Functions {
    */
   public static <T1, R> List<R> apply(final List<T1> list,
       final Function1<T1, R> f) {
-    final ArrayList<R> list2 = new ArrayList<R>(list.size());
+    final List<R> list2 = new ArrayList<>(list.size());
     for (T1 t : list) {
       list2.add(f.apply(t));
     }
@@ -376,7 +382,7 @@ public abstract class Functions {
         return list;
       }
     }
-    final List<E> list2 = new ArrayList<E>(list.size());
+    final List<E> list2 = new ArrayList<>(list.size());
     for (E e : list) {
       if (predicate.apply(e)) {
         list2.add(e);
@@ -504,7 +510,7 @@ public abstract class Functions {
    */
   public static <T, T2> EqualityComparer<T> selectorComparer(
       Function1<T, T2> selector) {
-    return new SelectorEqualityComparer<T, T2>(selector);
+    return new SelectorEqualityComparer<>(selector);
   }
 
   /** Array equality comparer. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
index dcc1962..c9a22de 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstantExpression.java
@@ -16,14 +16,15 @@
  */
 package org.apache.calcite.linq4j.tree;
 
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -89,8 +90,7 @@ public class ConstantExpression extends Expression {
       case BYTE:
         return writer.append("(byte)").append(((Byte) value).intValue());
       case CHAR:
-        return writer.append("(char)")
-            .append((int) ((Character) value).charValue());
+        return writer.append("(char)").append((int) (Character) value);
       case SHORT:
         return writer.append("(short)").append(((Short) value).intValue());
       case LONG:
@@ -149,11 +149,10 @@ public class ConstantExpression extends Expression {
     }
     Constructor constructor = matchingConstructor(value);
     if (constructor != null) {
-      final Field[] fields = value.getClass().getFields();
       writer.append("new ").append(value.getClass());
       list(writer,
-          Functions.adapt(fields,
-              new Function1<Field, Object>() {
+          Lists.transform(Arrays.asList(value.getClass().getFields()),
+              new Function<Field, Object>() {
                 public Object apply(Field field) {
                   try {
                     return field.get(value);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
index 95b4f1c..835e94e 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/ConstructorDeclaration.java
@@ -16,8 +16,8 @@
  */
 package org.apache.calcite.linq4j.tree;
 
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
 
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
@@ -63,8 +63,8 @@ public class ConstructorDeclaration extends MemberDeclaration {
     writer
         .append(resultType)
         .list("(", ", ", ")",
-            Functions.adapt(parameters,
-                new Function1<ParameterExpression, String>() {
+            Lists.transform(parameters,
+                new Function<ParameterExpression, String>() {
                   public String apply(ParameterExpression parameter) {
                     final String modifiers =
                         Modifier.toString(parameter.modifier);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
----------------------------------------------------------------------
diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
index 0e4c99a..646a9cd 100644
--- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
+++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/MethodDeclaration.java
@@ -16,8 +16,8 @@
  */
 package org.apache.calcite.linq4j.tree;
 
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.function.Functions;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
 
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
@@ -64,8 +64,8 @@ public class MethodDeclaration extends MemberDeclaration {
         .append(' ')
         .append(name)
         .list("(", ", ", ")",
-            Functions.adapt(parameters,
-                new Function1<ParameterExpression, String>() {
+            Lists.transform(parameters,
+                new Function<ParameterExpression, String>() {
                   public String apply(ParameterExpression a0) {
                     return a0.declString();
                   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/574dc7cc/linq4j/src/test/java/org/apache/calcite/linq4j/function/FunctionTest.java
----------------------------------------------------------------------
diff --git a/linq4j/src/test/java/org/apache/calcite/linq4j/function/FunctionTest.java b/linq4j/src/test/java/org/apache/calcite/linq4j/function/FunctionTest.java
index 9db57a5..998aed3 100644
--- a/linq4j/src/test/java/org/apache/calcite/linq4j/function/FunctionTest.java
+++ b/linq4j/src/test/java/org/apache/calcite/linq4j/function/FunctionTest.java
@@ -129,21 +129,6 @@ public class FunctionTest {
       // ok
     }
   }
-
-  /** Unit test for {@link Functions#adapt(Object[], Function1)}. */
-  @Test public void testAdaptArray() {
-    String[] abc = {"a", "b", "c"};
-    final Function1<String, String> toUpper =
-        new Function1<String, String>() {
-          public String apply(String s) {
-            return s.toUpperCase();
-          }
-        };
-    Assert.assertEquals("[A, B, C]",
-        Functions.adapt(abc, toUpper).toString());
-    Assert.assertEquals("[]",
-        Functions.adapt(new String[0], toUpper).toString());
-  }
 }
 
 // End FunctionTest.java


[7/9] incubator-calcite git commit: [CALCITE-638] SQL standard REAL is 4 bytes, FLOAT is 8 bytes

Posted by jh...@apache.org.
[CALCITE-638] SQL standard REAL is 4 bytes, FLOAT is 8 bytes

Add tests for [CALCITE-630] Flesh out AvaticaParameter#setObject

Move class SqlType to top-level, and add metadata about conversions allowed by JDBC spec


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

Branch: refs/heads/master
Commit: 76a0665c071fe127a514e4425e875bfe2a9d0e1f
Parents: 8b9a577
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Mar 22 22:56:06 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 02:16:28 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/AvaticaParameter.java       |  63 ++-
 .../apache/calcite/avatica/ColumnMetaData.java  |  55 --
 .../org/apache/calcite/avatica/SqlType.java     | 532 +++++++++++++++++++
 .../apache/calcite/avatica/remote/Service.java  |   2 +-
 .../calcite/avatica/util/AbstractCursor.java    |   2 +-
 .../calcite/jdbc/JavaTypeFactoryImpl.java       |   2 +-
 .../apache/calcite/rel/metadata/RelMdSize.java  |   2 +-
 .../apache/calcite/runtime/SqlFunctions.java    |   8 +
 .../calcite/jdbc/CalciteRemoteDriverTest.java   | 311 +++++++++++
 .../org/apache/calcite/sql/test/SqlTests.java   |   2 +-
 .../java/org/apache/calcite/test/JdbcTest.java  | 111 ----
 11 files changed, 900 insertions(+), 190 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
index c2c0992..8cbe5e4 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
@@ -248,14 +248,6 @@ public class AvaticaParameter {
         setBlob(slots, index, (InputStream) x);
       }
       throw unsupportedCast(x.getClass(), Blob.class);
-    case Types.CHAR:
-    case Types.NCHAR:
-      String s = toString(x);
-      if (s.length() == 1) {
-        setChar(slots, index, s.charAt(0));
-        break;
-      }
-      throw unsupportedCast(x.getClass(), Character.TYPE);
     case Types.DATE:
       setDate(slots, index, toDate(x));
       break;
@@ -266,7 +258,7 @@ public class AvaticaParameter {
     case Types.DISTINCT:
       throw notImplemented();
     case Types.DOUBLE:
-    case Types.FLOAT:
+    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes
       setDouble(slots, index, toDouble(x));
       break;
     case Types.INTEGER:
@@ -279,6 +271,8 @@ public class AvaticaParameter {
     case Types.LONGVARCHAR:
     case Types.NVARCHAR:
     case Types.VARCHAR:
+    case Types.CHAR:
+    case Types.NCHAR:
       setString(slots, index, toString(x));
       break;
     case Types.REAL:
@@ -366,7 +360,13 @@ public class AvaticaParameter {
     } else if (x instanceof BigInteger) {
       return new BigDecimal((BigInteger) x);
     } else if (x instanceof Number) {
-      return new BigDecimal(x.toString());
+      if (x instanceof Double || x instanceof Float) {
+        return new BigDecimal(((Number) x).doubleValue());
+      } else {
+        return new BigDecimal(((Number) x).longValue());
+      }
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? BigDecimal.ONE : BigDecimal.ZERO;
     } else if (x instanceof String) {
       return new BigDecimal((String) x);
     }
@@ -392,6 +392,8 @@ public class AvaticaParameter {
   private static byte toByte(Object x) {
     if (x instanceof Number) {
       return ((Number) x).byteValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? (byte) 1 : (byte) 0;
     } else if (x instanceof String) {
       return Byte.parseByte((String) x);
     } else {
@@ -403,16 +405,38 @@ public class AvaticaParameter {
     if (x instanceof byte[]) {
       return (byte[]) x;
     }
+    if (x instanceof String) {
+      return ((String) x).getBytes();
+    }
     throw unsupportedCast(x.getClass(), byte[].class);
   }
 
   private static Date toDate(Object x) {
+    if (x instanceof String) {
+      return Date.valueOf((String) x);
+    }
     return new Date(toLong(x));
   }
 
+  private static Time toTime(Object x) {
+    if (x instanceof String) {
+      return Time.valueOf((String) x);
+    }
+    return new Time(toLong(x));
+  }
+
+  private static Timestamp toTimestamp(Object x) {
+    if (x instanceof String) {
+      return Timestamp.valueOf((String) x);
+    }
+    return new Timestamp(toLong(x));
+  }
+
   private static double toDouble(Object x) {
     if (x instanceof Number) {
       return ((Number) x).doubleValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1D : 0D;
     } else if (x instanceof String) {
       return Double.parseDouble((String) x);
     } else {
@@ -423,6 +447,8 @@ public class AvaticaParameter {
   private static float toFloat(Object x) {
     if (x instanceof Number) {
       return ((Number) x).floatValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1F : 0F;
     } else if (x instanceof String) {
       return Float.parseFloat((String) x);
     } else {
@@ -433,6 +459,8 @@ public class AvaticaParameter {
   private static int toInt(Object x) {
     if (x instanceof Number) {
       return ((Number) x).intValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1 : 0;
     } else if (x instanceof String) {
       return Integer.parseInt((String) x);
     } else {
@@ -443,6 +471,8 @@ public class AvaticaParameter {
   private static long toLong(Object x) {
     if (x instanceof Number) {
       return ((Number) x).longValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1L : 0L;
     } else if (x instanceof String) {
       return Long.parseLong((String) x);
     } else {
@@ -453,6 +483,8 @@ public class AvaticaParameter {
   private static short toShort(Object x) {
     if (x instanceof Number) {
       return ((Number) x).shortValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? (short) 1 : (short) 0;
     } else if (x instanceof String) {
       return Short.parseShort((String) x);
     } else {
@@ -463,20 +495,13 @@ public class AvaticaParameter {
   private static String toString(Object x) {
     if (x instanceof String) {
       return (String) x;
-    } else if (x instanceof Character) {
+    } else if (x instanceof Character
+        || x instanceof Boolean) {
       return x.toString();
     }
     throw unsupportedCast(x.getClass(), String.class);
   }
 
-  private static Time toTime(Object x) {
-    return new Time(toLong(x));
-  }
-
-  private static Timestamp toTimestamp(Object x) {
-    return new Timestamp(toLong(x));
-  }
-
   /** Singleton value to denote parameters that have been set to null (as
    * opposed to not set).
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java b/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
index 8e9930f..0a4f90a 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
@@ -22,8 +22,6 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
 import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.sql.Array;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSetMetaData;
 import java.sql.Time;
@@ -284,59 +282,6 @@ public class ColumnMetaData {
       this.component = component;
     }
   }
-
-  /** Extends the information in {@link java.sql.Types}. */
-  private enum SqlType {
-    BOOLEAN(Types.BOOLEAN, Boolean.class),
-    TINYINT(Types.TINYINT, Byte.class),
-    SMALLINT(Types.SMALLINT, Short.class),
-    INTEGER(Types.INTEGER, Integer.class),
-    BIGINT(Types.BIGINT, Long.class),
-    DECIMAL(Types.DECIMAL, BigDecimal.class),
-    FLOAT(Types.FLOAT, Float.class),
-    REAL(Types.REAL, Float.class),
-    DOUBLE(Types.DOUBLE, Double.class),
-    DATE(Types.DATE, java.sql.Date.class),
-    TIME(Types.TIME, Time.class),
-    TIMESTAMP(Types.TIMESTAMP, Timestamp.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),
-    BINARY(Types.BINARY, byte[].class),
-    VARBINARY(Types.VARBINARY, byte[].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),
-    MAP(Types.OTHER, Map.class),
-    DISTINCT(Types.DISTINCT, Object.class),
-    STRUCTURED(Types.STRUCT, Object.class),
-    ROW(Types.STRUCT, Object.class),
-    OTHER(Types.OTHER, Object.class),
-    CURSOR(2012, Object.class),
-    COLUMN_LIST(Types.OTHER + 2, Object.class);
-
-    private final int type;
-    private final Class clazz;
-
-    private static final Map<Integer, SqlType> BY_ID = new HashMap<>();
-    static {
-      for (SqlType sqlType : values()) {
-        BY_ID.put(sqlType.type, sqlType);
-      }
-    }
-
-    SqlType(int type, Class clazz) {
-      this.type = type;
-      this.clazz = clazz;
-    }
-
-    public static SqlType valueOf(int type) {
-      return BY_ID.get(type);
-    }
-  }
 }
 
 // End ColumnMetaData.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/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
new file mode 100644
index 0000000..90e9cba
--- /dev/null
+++ b/avatica/src/main/java/org/apache/calcite/avatica/SqlType.java
@@ -0,0 +1,532 @@
+/*
+ * 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.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, Integer.class),
+  BIGINT(Types.BIGINT, Long.class),
+  NUMERIC(Types.NUMERIC, Object.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),
+  TIME(Types.TIME, Time.class),
+  TIMESTAMP(Types.TIMESTAMP, Timestamp.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),
+  VARBINARY(Types.VARBINARY, byte[].class),
+  LONGVARBINARY(Types.LONGVARBINARY, byte[].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, Object.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;
+  public final Class clazz;
+
+  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) {
+    this.id = id;
+    this.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 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 aClass, SqlType sqlType) {
+    final EnumSet<SqlType> sqlTypes = GET_LIST.get(aClass);
+    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/incubator-calcite/blob/76a0665c/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 ed2c332..da897da 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
@@ -171,7 +171,7 @@ public interface Service {
    * <p>Several types of request, including
    * {@link org.apache.calcite.avatica.Meta#getCatalogs()} and
    * {@link org.apache.calcite.avatica.Meta#getSchemas(String, org.apache.calcite.avatica.Meta.Pat)}
-   * {@link Meta#getTables(String, org.apache.calcite.avatica.Meta.Pat, org.apache.calcite.avatica.Meta.Pat, List<String>)}
+   * {@link Meta#getTables(String, Meta.Pat, Meta.Pat, List)}
    * {@link Meta#getTableTypes()}
    * return this response. */
   class ResultSetResponse extends Response {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
index 42731ba..fec143e 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -88,9 +88,9 @@ public abstract class AbstractCursor implements Cursor {
       return new LongAccessor(getter);
     case Types.BOOLEAN:
       return new BooleanAccessor(getter);
-    case Types.FLOAT:
     case Types.REAL:
       return new FloatAccessor(getter);
+    case Types.FLOAT:
     case Types.DOUBLE:
       return new DoubleAccessor(getter);
     case Types.NUMERIC:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
index 7349b07..0ef9128 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java
@@ -152,9 +152,9 @@ public class JavaTypeFactoryImpl
       case BOOLEAN:
         return type.isNullable() ? Boolean.class : boolean.class;
       case DOUBLE:
+      case FLOAT: // sic
         return type.isNullable() ? Double.class : double.class;
       case REAL:
-      case FLOAT:
         return type.isNullable() ? Float.class : float.class;
       case BINARY:
       case VARBINARY:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
index 41c21ab..1a42f01 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
@@ -265,13 +265,13 @@ public class RelMdSize {
     case SMALLINT:
       return 2d;
     case INTEGER:
-    case FLOAT:
     case REAL:
     case DATE:
     case TIME:
       return 4d;
     case BIGINT:
     case DOUBLE:
+    case FLOAT: // sic
     case TIMESTAMP:
     case INTERVAL_DAY_TIME:
     case INTERVAL_YEAR_MONTH:

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
index 77e6827..256d15a 100644
--- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
+++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java
@@ -693,6 +693,10 @@ public class SqlFunctions {
     return Math.floor(b0);
   }
 
+  public static float floor(float b0) {
+    return (float) Math.floor(b0);
+  }
+
   public static BigDecimal floor(BigDecimal b0) {
     return b0.setScale(0, BigDecimal.ROUND_FLOOR);
   }
@@ -750,6 +754,10 @@ public class SqlFunctions {
     return Math.ceil(b0);
   }
 
+  public static float ceil(float b0) {
+    return (float) Math.ceil(b0);
+  }
+
   public static BigDecimal ceil(BigDecimal b0) {
     return b0.setScale(0, BigDecimal.ROUND_CEILING);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/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 8d10a98..05f54b7 100644
--- a/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
+++ b/core/src/test/java/org/apache/calcite/jdbc/CalciteRemoteDriverTest.java
@@ -18,27 +18,53 @@ package org.apache.calcite.jdbc;
 
 import org.apache.calcite.avatica.AvaticaConnection;
 import org.apache.calcite.avatica.Meta;
+import org.apache.calcite.avatica.SqlType;
 import org.apache.calcite.avatica.remote.LocalJsonService;
 import org.apache.calcite.avatica.remote.LocalService;
 import org.apache.calcite.avatica.remote.Service;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.calcite.avatica.server.Main;
+import org.apache.calcite.prepare.CalcitePrepareImpl;
 import org.apache.calcite.test.CalciteAssert;
 
 import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import org.hamcrest.CoreMatchers;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+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.Connection;
 import java.sql.DriverManager;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.Ref;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
+import java.sql.RowId;
 import java.sql.SQLException;
+import java.sql.SQLXML;
 import java.sql.Statement;
+import java.sql.Struct;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
@@ -53,6 +79,10 @@ import static org.junit.Assert.assertTrue;
 public class CalciteRemoteDriverTest {
   public static final String LJS = Factory2.class.getName();
 
+  private final PrintStream out =
+      CalcitePrepareImpl.DEBUG ? System.out
+          : new PrintStream(new ByteArrayOutputStream());
+
   private static final CalciteAssert.ConnectionFactory
   REMOTE_CONNECTION_FACTORY =
       new CalciteAssert.ConnectionFactory() {
@@ -211,6 +241,287 @@ public class CalciteRemoteDriverTest {
     assertThat(n, equalTo(2));
   }
 
+  /** For each (source, destination) type, make sure that we can convert bind
+   * variables. */
+  @Test public void testParameterConvert() throws Exception {
+    final StringBuilder sql = new StringBuilder("select 1");
+    final Map<SqlType, Integer> map = Maps.newHashMap();
+    for (Map.Entry<Class, SqlType> entry : SqlType.getSetConversions()) {
+      final SqlType sqlType = entry.getValue();
+      switch (sqlType) {
+      case BIT:
+      case LONGVARCHAR:
+      case LONGVARBINARY:
+      case NCHAR:
+      case NVARCHAR:
+      case LONGNVARCHAR:
+      case BLOB:
+      case CLOB:
+      case NCLOB:
+      case ARRAY:
+      case REF:
+      case STRUCT:
+      case DATALINK:
+      case ROWID:
+      case JAVA_OBJECT:
+      case SQLXML:
+        continue;
+      }
+      if (!map.containsKey(sqlType)) {
+        sql.append(", cast(? as ").append(sqlType).append(")");
+        map.put(sqlType, map.size() + 1);
+      }
+    }
+    sql.append(" from (values 1)");
+    final PreparedStatement statement =
+        localConnection.prepareStatement(sql.toString());
+    for (Map.Entry<SqlType, Integer> entry : map.entrySet()) {
+      statement.setNull(entry.getValue(), entry.getKey().id);
+    }
+    for (Map.Entry<Class, SqlType> entry : SqlType.getSetConversions()) {
+      final SqlType sqlType = entry.getValue();
+      if (!map.containsKey(sqlType)) {
+        continue;
+      }
+      int param = map.get(sqlType);
+      Class clazz = entry.getKey();
+      for (Object sampleValue : values(sqlType.clazz)) {
+        switch (sqlType) {
+        case DATE:
+        case TIME:
+        case TIMESTAMP:
+          continue; // FIXME
+        }
+        if (clazz == Calendar.class) {
+          continue; // FIXME
+        }
+        final Object o;
+        try {
+          o = convert(sampleValue, clazz);
+        } catch (IllegalArgumentException | ParseException e) {
+          continue;
+        }
+        out.println("check " + o + " (originally "
+            + sampleValue.getClass() + ", now " + o.getClass()
+            + ") converted to " + sqlType);
+        if (o instanceof Double && o.equals(Double.POSITIVE_INFINITY)
+            || o instanceof Float && o.equals(Float.POSITIVE_INFINITY)) {
+          continue;
+        }
+        statement.setObject(param, o, sqlType.id);
+        final ResultSet resultSet = statement.executeQuery();
+        assertThat(resultSet.next(), is(true));
+        out.println(resultSet.getString(param + 1));
+      }
+    }
+    statement.close();
+  }
+
+  /** Check that the "set" conversion table looks like Table B-5 in JDBC 4.1
+   * specification */
+  @Test public void testTableB5() {
+    SqlType[] columns = {
+      SqlType.TINYINT, SqlType.SMALLINT, SqlType.INTEGER, SqlType.BIGINT,
+      SqlType.REAL, SqlType.FLOAT, SqlType.DOUBLE, SqlType.DECIMAL,
+      SqlType.NUMERIC, SqlType.BIT, SqlType.BOOLEAN, SqlType.CHAR,
+      SqlType.VARCHAR, SqlType.LONGVARCHAR, SqlType.BINARY, SqlType.VARBINARY,
+      SqlType.LONGVARBINARY, SqlType.DATE, SqlType.TIME, SqlType.TIMESTAMP,
+      SqlType.ARRAY, SqlType.BLOB, SqlType.CLOB, SqlType.STRUCT, SqlType.REF,
+      SqlType.DATALINK, SqlType.JAVA_OBJECT, SqlType.ROWID, SqlType.NCHAR,
+      SqlType.NVARCHAR, SqlType.LONGNVARCHAR, SqlType.NCLOB, SqlType.SQLXML
+    };
+    Class[] rows = {
+      String.class, BigDecimal.class, Boolean.class, Byte.class, Short.class,
+      Integer.class, Long.class, Float.class, Double.class, byte[].class,
+      BigInteger.class, java.sql.Date.class, Time.class, Timestamp.class,
+      Array.class, Blob.class, Clob.class, Struct.class, Ref.class,
+      URL.class, Class.class, RowId.class, NClob.class, SQLXML.class,
+      Calendar.class, java.util.Date.class
+    };
+    for (Class row : rows) {
+      final String s = row == Date.class ? row.getName() : row.getSimpleName();
+      out.print(pad(s));
+      for (SqlType column : columns) {
+        out.print(SqlType.canSet(row, column) ? "x " : ". ");
+      }
+      out.println();
+    }
+  }
+
+  private String pad(String x) {
+    while (x.length() < 20) {
+      x = x + " ";
+    }
+    return x;
+  }
+
+  /** Check that the "get" conversion table looks like Table B-5 in JDBC 4.1
+   * specification */
+  @Test public void testTableB6() {
+    SqlType[] columns = {
+      SqlType.TINYINT, SqlType.SMALLINT, SqlType.INTEGER, SqlType.BIGINT,
+      SqlType.REAL, SqlType.FLOAT, SqlType.DOUBLE, SqlType.DECIMAL,
+      SqlType.NUMERIC, SqlType.BIT, SqlType.BOOLEAN, SqlType.CHAR,
+      SqlType.VARCHAR, SqlType.LONGVARCHAR, SqlType.BINARY, SqlType.VARBINARY,
+      SqlType.LONGVARBINARY, SqlType.DATE, SqlType.TIME, SqlType.TIMESTAMP,
+      SqlType.CLOB, SqlType.BLOB, SqlType.ARRAY, SqlType.REF,
+      SqlType.DATALINK, SqlType.STRUCT, SqlType.JAVA_OBJECT, SqlType.ROWID,
+      SqlType.NCHAR, SqlType.NVARCHAR, SqlType.LONGNVARCHAR, SqlType.NCLOB,
+      SqlType.SQLXML
+    };
+    final PrintStream out =
+        CalcitePrepareImpl.DEBUG ? System.out
+            : new PrintStream(new ByteArrayOutputStream());
+    for (SqlType.Method row : SqlType.Method.values()) {
+      out.print(pad(row.methodName));
+      for (SqlType column : columns) {
+        out.print(SqlType.canGet(row, column) ? "x " : ". ");
+      }
+      out.println();
+    }
+  }
+
+  /** A bunch of sample values of various types. */
+  private static final List<Object> SAMPLE_VALUES =
+      ImmutableList.<Object>of(false, true,
+          // byte
+          (byte) 0, (byte) 1, Byte.MIN_VALUE, Byte.MAX_VALUE,
+          // short
+          (short) 0, (short) 1, Short.MIN_VALUE, Short.MAX_VALUE,
+          (short) Byte.MIN_VALUE, (short) Byte.MAX_VALUE,
+          // int
+          0, 1, -3, Integer.MIN_VALUE, Integer.MAX_VALUE,
+          (int) Short.MIN_VALUE, (int) Short.MAX_VALUE,
+          (int) Byte.MIN_VALUE, (int) Byte.MAX_VALUE,
+          // long
+          0L, 1L, -2L, Long.MIN_VALUE, Long.MAX_VALUE,
+          (long) Integer.MIN_VALUE, (long) Integer.MAX_VALUE,
+          (long) Short.MIN_VALUE, (long) Short.MAX_VALUE,
+          (long) Byte.MIN_VALUE, (long) Byte.MAX_VALUE,
+          // float
+          0F, 1.5F, -10F, Float.MIN_VALUE, Float.MAX_VALUE,
+          // double
+          0D, Math.PI, Double.MIN_VALUE, Double.MAX_VALUE,
+          (double) Float.MIN_VALUE, (double) Float.MAX_VALUE,
+          (double) Integer.MIN_VALUE, (double) Integer.MAX_VALUE,
+          // BigDecimal
+          BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.valueOf(2.5D),
+          BigDecimal.valueOf(Double.MAX_VALUE),
+          BigDecimal.valueOf(Long.MIN_VALUE),
+          // datetime
+          new Timestamp(0),
+          new java.sql.Date(0),
+          new Time(0),
+          // string
+          "", "foo", " foo! Baz ",
+          // byte[]
+          new byte[0], "hello".getBytes());
+
+  private static List<Object> values(Class clazz) {
+    final List<Object> list = Lists.newArrayList();
+    for (Object sampleValue : SAMPLE_VALUES) {
+      if (sampleValue.getClass() == clazz) {
+        list.add(sampleValue);
+      }
+    }
+    return list;
+  }
+
+  private Object convert(Object o, Class clazz) throws ParseException {
+    if (o.getClass() == clazz) {
+      return o;
+    }
+    if (clazz == String.class) {
+      return o.toString();
+    }
+    if (clazz == Boolean.class) {
+      return o instanceof Number
+          && ((Number) o).intValue() != 0
+          || o instanceof String
+          && ((String) o).equalsIgnoreCase("true");
+    }
+    if (clazz == byte[].class) {
+      if (o instanceof String) {
+        return ((String) o).getBytes();
+      }
+    }
+    if (clazz == Timestamp.class) {
+      if (o instanceof String) {
+        return Timestamp.valueOf((String) o);
+      }
+    }
+    if (clazz == Time.class) {
+      if (o instanceof String) {
+        return Time.valueOf((String) o);
+      }
+    }
+    if (clazz == java.sql.Date.class) {
+      if (o instanceof String) {
+        return java.sql.Date.valueOf((String) o);
+      }
+    }
+    if (clazz == java.util.Date.class) {
+      if (o instanceof String) {
+        return DateFormat.getInstance().parse((String) o);
+      }
+    }
+    if (clazz == Calendar.class) {
+      if (o instanceof String) {
+        return Calendar.getInstance(); // TODO:
+      }
+    }
+    if (o instanceof Boolean) {
+      o = (Boolean) o ? 1 : 0;
+    }
+    if (o instanceof Number) {
+      final Number number = (Number) o;
+      if (Number.class.isAssignableFrom(clazz)) {
+        if (clazz == BigDecimal.class) {
+          if (o instanceof Double || o instanceof Float) {
+            return new BigDecimal(number.doubleValue());
+          } else {
+            return new BigDecimal(number.longValue());
+          }
+        } else if (clazz == BigInteger.class) {
+          return new BigInteger(o.toString());
+        } else if (clazz == Byte.class || clazz == byte.class) {
+          return number.byteValue();
+        } else if (clazz == Short.class || clazz == short.class) {
+          return number.shortValue();
+        } else if (clazz == Integer.class || clazz == int.class) {
+          return number.intValue();
+        } else if (clazz == Long.class || clazz == long.class) {
+          return number.longValue();
+        } else if (clazz == Float.class || clazz == float.class) {
+          return number.floatValue();
+        } else if (clazz == Double.class || clazz == double.class) {
+          return number.doubleValue();
+        }
+      }
+    }
+    if (Number.class.isAssignableFrom(clazz)) {
+      if (clazz == BigDecimal.class) {
+        return new BigDecimal(o.toString());
+      } else if (clazz == BigInteger.class) {
+        return new BigInteger(o.toString());
+      } else if (clazz == Byte.class || clazz == byte.class) {
+        return Byte.valueOf(o.toString());
+      } else if (clazz == Short.class || clazz == short.class) {
+        return Short.valueOf(o.toString());
+      } else if (clazz == Integer.class || clazz == int.class) {
+        return Integer.valueOf(o.toString());
+      } else if (clazz == Long.class || clazz == long.class) {
+        return Long.valueOf(o.toString());
+      } else if (clazz == Float.class || clazz == float.class) {
+        return Float.valueOf(o.toString());
+      } else if (clazz == Double.class || clazz == double.class) {
+        return Double.valueOf(o.toString());
+      }
+    }
+    throw new AssertionError("cannot convert " + o + "(" + o.getClass()
+        + ") to " + clazz);
+  }
+
   /** Creates a {@link Meta} that can see the test databases. */
   public static class Factory implements Meta.Factory {
     public Meta create(List<String> args) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
index b5c2fd6..4f15f7d 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlTests.java
@@ -187,7 +187,7 @@ public abstract class SqlTests {
       return ColumnMetaData.Rep.INTEGER;
     case Types.BIGINT:
       return ColumnMetaData.Rep.LONG;
-    case Types.FLOAT:
+    case Types.REAL:
       return ColumnMetaData.Rep.FLOAT;
     case Types.DOUBLE:
       return ColumnMetaData.Rep.DOUBLE;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/76a0665c/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 989243f..6eed428 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -86,7 +86,6 @@ import org.apache.calcite.util.Util;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
 
 import net.hydromatic.quidem.Quidem;
 
@@ -2381,116 +2380,6 @@ public class JdbcTest {
         .returns("EXPR$0=-3\n");
   }
 
-  /**
-   * Conversions table, per JDBC 1.1 specification, table 6.
-   *
-   * <pre>
-   *                    T S I B R F D D N B C V L B V L D T T
-   *                    I M N I E L O E U I H A O I A O A I I
-   *                    N A T G A O U C M T A R N N R N T M M
-   *                    Y L E I L A B I E   R C G A B G E E E
-   *                    I L G N     L M R     H V R I V E   S
-   *                    N I E T     E A I     A A Y   A     T
-   *                    T N R         L C     R R     R     A
-   *                      T                     C     B     M
-   *                                            H     I     P
-   * Java type
-   * ================== = = = = = = = = = = = = = = = = = = =
-   * String             x x x x x x x x x x x x x x x x x x x
-   * BigDecimal         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 . . . . . . .
-   * Integer            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 . . . . . . .
-   * Float              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 . . . . . . .
-   * byte[]             . . . . . . . . . . . . . x x x . . .
-   * java.sql.Date      . . . . . . . . . . x x x . . . x . x
-   * java.sql.Time      . . . . . . . . . . x x x . . . . x .
-   * java.sql.Timestamp . . . . . . . . . . x x x . . . x x x
-   * </pre>
-   */
-  public static final ImmutableMultimap<Class, Integer> CONVERSIONS = x();
-
-  private static ImmutableMultimap<Class, Integer> x() {
-    final ImmutableMultimap.Builder<Class, Integer> builder =
-        ImmutableMultimap.builder();
-    int[] allTypes = {
-      java.sql.Types.TINYINT,
-      java.sql.Types.SMALLINT,
-      java.sql.Types.INTEGER,
-      java.sql.Types.BIGINT,
-      java.sql.Types.REAL,
-      java.sql.Types.FLOAT,
-      java.sql.Types.DOUBLE,
-      java.sql.Types.DECIMAL,
-      java.sql.Types.NUMERIC,
-      java.sql.Types.BIT,
-      java.sql.Types.CHAR,
-      java.sql.Types.VARCHAR,
-      java.sql.Types.LONGVARCHAR,
-      java.sql.Types.BINARY,
-      java.sql.Types.VARBINARY,
-      java.sql.Types.LONGVARBINARY,
-      java.sql.Types.DATE,
-      java.sql.Types.TIME,
-      java.sql.Types.TIMESTAMP
-    };
-    int[] numericTypes = {
-      java.sql.Types.TINYINT,
-      java.sql.Types.SMALLINT,
-      java.sql.Types.INTEGER,
-      java.sql.Types.BIGINT,
-      java.sql.Types.REAL,
-      java.sql.Types.FLOAT,
-      java.sql.Types.DOUBLE,
-      java.sql.Types.DECIMAL,
-      java.sql.Types.NUMERIC,
-      java.sql.Types.BIT
-    };
-    Class[] numericClasses = {
-      BigDecimal.class, Boolean.class, Integer.class, Long.class, Float.class,
-      Double.class
-    };
-    Class[] allClasses = {
-      String.class, BigDecimal.class, Boolean.class, Integer.class,
-      Long.class, Float.class, Double.class, byte[].class,
-      java.sql.Date.class, java.sql.Time.class, java.sql.Timestamp.class,
-    };
-    int[] charTypes = {
-      java.sql.Types.CHAR,
-      java.sql.Types.VARCHAR,
-      java.sql.Types.LONGVARCHAR
-    };
-    int[] binaryTypes = {
-      java.sql.Types.BINARY,
-      java.sql.Types.VARBINARY,
-      java.sql.Types.LONGVARBINARY
-    };
-    for (int type : allTypes) {
-      builder.put(String.class, type);
-    }
-    for (Class clazz : numericClasses) {
-      for (int type : numericTypes) {
-        builder.put(clazz, type);
-      }
-    }
-    for (int type : charTypes) {
-      for (Class clazz : allClasses) {
-        builder.put(clazz, type);
-      }
-    }
-    for (int type : binaryTypes) {
-      builder.put(byte[].class, type);
-    }
-    builder.put(java.sql.Date.class, java.sql.Types.DATE);
-    builder.put(java.sql.Date.class, java.sql.Types.TIMESTAMP);
-    builder.put(java.sql.Time.class, java.sql.Types.TIME);
-    builder.put(java.sql.Timestamp.class, java.sql.Types.DATE);
-    builder.put(java.sql.Time.class, java.sql.Types.TIME);
-    builder.put(java.sql.Timestamp.class, java.sql.Types.TIMESTAMP);
-    return builder.build();
-  }
-
   /** Tests a table constructor that has multiple rows and multiple columns.
    *
    * <p>Note that the character literals become CHAR(3) and that the first is


[3/9] incubator-calcite git commit: [CALCITE-618] Add Avatica support for getTables (Julian Hyde and Nick Dimiduk)

Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/test/java/org/apache/calcite/avatica/test/RemoteDriverTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/RemoteDriverTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/RemoteDriverTest.java
index 5cf1ea5..c007f02 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/RemoteDriverTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/RemoteDriverTest.java
@@ -16,21 +16,34 @@
  */
 package org.apache.calcite.avatica.test;
 
+import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.jdbc.JdbcMeta;
 import org.apache.calcite.avatica.remote.LocalJsonService;
+import org.apache.calcite.avatica.remote.LocalService;
 import org.apache.calcite.avatica.remote.MockJsonService;
+import org.apache.calcite.avatica.remote.Service;
+
+import net.hydromatic.scott.data.hsqldb.ScottHsqldb;
 
 import org.junit.Ignore;
 import org.junit.Test;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * Unit test for Avatica Remote JDBC driver.
@@ -40,7 +53,20 @@ public class RemoteDriverTest {
       MockJsonService.Factory.class.getName();
 
   public static final String LJS =
-      LocalJsonService.Factory.class.getName();
+      LocalJdbcServiceFactory.class.getName();
+
+  public static final String QRJS =
+      QuasiRemoteJdbcServiceFactory.class.getName();
+
+  private static final ConnectionSpec CONNECTION_SPEC = ConnectionSpec.HSQLDB;
+
+  private Connection mjs() throws SQLException {
+    return DriverManager.getConnection("jdbc:avatica:remote:factory=" + MJS);
+  }
+
+  private Connection ljs() throws SQLException {
+    return DriverManager.getConnection("jdbc:avatica:remote:factory=" + QRJS);
+  }
 
   @Test public void testRegister() throws Exception {
     final Connection connection =
@@ -50,6 +76,33 @@ public class RemoteDriverTest {
     assertThat(connection.isClosed(), is(true));
   }
 
+  @Test public void testSchemas() throws Exception {
+    final Connection connection = mjs();
+    final ResultSet resultSet =
+        connection.getMetaData().getSchemas(null, null);
+    assertFalse(resultSet.next());
+    final ResultSetMetaData metaData = resultSet.getMetaData();
+    assertTrue(metaData.getColumnCount() >= 2);
+    assertEquals("TABLE_CATALOG", metaData.getColumnName(1));
+    assertEquals("TABLE_SCHEM", metaData.getColumnName(2));
+    resultSet.close();
+    connection.close();
+  }
+
+  @Test public void testTables() throws Exception {
+    final Connection connection = mjs();
+    final ResultSet resultSet =
+        connection.getMetaData().getTables(null, null, null, new String[0]);
+    assertFalse(resultSet.next());
+    final ResultSetMetaData metaData = resultSet.getMetaData();
+    assertTrue(metaData.getColumnCount() >= 3);
+    assertEquals("TABLE_CAT", metaData.getColumnName(1));
+    assertEquals("TABLE_SCHEM", metaData.getColumnName(2));
+    assertEquals("TABLE_NAME", metaData.getColumnName(3));
+    resultSet.close();
+    connection.close();
+  }
+
   @Ignore
   @Test public void testNoFactory() throws Exception {
     final Connection connection =
@@ -68,8 +121,7 @@ public class RemoteDriverTest {
 
   @Ignore
   @Test public void testCatalogsMock() throws Exception {
-    final Connection connection =
-        DriverManager.getConnection("jdbc:avatica:remote:factory=" + MJS);
+    final Connection connection = mjs();
     assertThat(connection.isClosed(), is(false));
     final ResultSet resultSet = connection.getMetaData().getSchemas();
     assertFalse(resultSet.next());
@@ -81,6 +133,164 @@ public class RemoteDriverTest {
     connection.close();
     assertThat(connection.isClosed(), is(true));
   }
+
+  @Test public void testStatementExecuteQueryLocal() throws Exception {
+    checkStatementExecuteQuery(ljs(), false);
+  }
+
+  @Ignore
+  @Test public void testStatementExecuteQueryMock() throws Exception {
+    checkStatementExecuteQuery(mjs(), false);
+  }
+
+  @Ignore
+  @Test public void testPrepareExecuteQueryLocal() throws Exception {
+    checkStatementExecuteQuery(ljs(), true);
+  }
+
+  @Ignore
+  @Test public void testPrepareExecuteQueryMock() throws Exception {
+    checkStatementExecuteQuery(mjs(), true);
+  }
+
+  private void checkStatementExecuteQuery(Connection connection,
+      boolean prepare) throws SQLException {
+    final String sql = "select * from (\n"
+        + "  values (1, 'a'), (null, 'b'), (3, 'c')) as t (c1, c2)";
+    final Statement statement;
+    final ResultSet resultSet;
+    final ParameterMetaData parameterMetaData;
+    if (prepare) {
+      final PreparedStatement ps = connection.prepareStatement(sql);
+      statement = ps;
+      parameterMetaData = ps.getParameterMetaData();
+      resultSet = ps.executeQuery();
+    } else {
+      statement = connection.createStatement();
+      parameterMetaData = null;
+      resultSet = statement.executeQuery(sql);
+    }
+    if (parameterMetaData != null) {
+      assertThat(parameterMetaData.getParameterCount(), equalTo(2));
+    }
+    final ResultSetMetaData metaData = resultSet.getMetaData();
+    assertEquals(2, metaData.getColumnCount());
+    assertEquals("C1", metaData.getColumnName(1));
+    assertEquals("C2", metaData.getColumnName(2));
+    assertTrue(resultSet.next());
+    assertTrue(resultSet.next());
+    assertTrue(resultSet.next());
+    assertFalse(resultSet.next());
+    resultSet.close();
+    statement.close();
+    connection.close();
+  }
+
+  @Test public void testPrepareBindExecuteFetch() throws Exception {
+    checkPrepareBindExecuteFetch(ljs());
+  }
+
+  private void checkPrepareBindExecuteFetch(Connection connection)
+      throws SQLException {
+    final String sql = "select cast(? as integer) * 3 as c, 'x' as x\n"
+        + "from (values (1, 'a'))";
+    final PreparedStatement ps =
+        connection.prepareStatement(sql);
+    final ResultSetMetaData metaData = ps.getMetaData();
+    assertEquals(2, metaData.getColumnCount());
+    assertEquals("C", metaData.getColumnName(1));
+    assertEquals("X", metaData.getColumnName(2));
+    try {
+      final ResultSet resultSet = ps.executeQuery();
+      fail("expected error, got " + resultSet);
+    } catch (SQLException e) {
+      assertThat(e.getMessage(),
+          equalTo("exception while executing query: unbound parameter"));
+    }
+
+    final ParameterMetaData parameterMetaData = ps.getParameterMetaData();
+    assertThat(parameterMetaData.getParameterCount(), equalTo(1));
+
+    ps.setInt(1, 10);
+    final ResultSet resultSet = ps.executeQuery();
+    assertTrue(resultSet.next());
+    assertThat(resultSet.getInt(1), equalTo(30));
+    assertFalse(resultSet.next());
+    resultSet.close();
+
+    ps.setInt(1, 20);
+    final ResultSet resultSet2 = ps.executeQuery();
+    assertFalse(resultSet2.isClosed());
+    assertTrue(resultSet2.next());
+    assertThat(resultSet2.getInt(1), equalTo(60));
+    assertThat(resultSet2.wasNull(), is(false));
+    assertFalse(resultSet2.next());
+    resultSet2.close();
+
+    ps.setObject(1, null);
+    final ResultSet resultSet3 = ps.executeQuery();
+    assertTrue(resultSet3.next());
+    assertThat(resultSet3.getInt(1), equalTo(0));
+    assertThat(resultSet3.wasNull(), is(true));
+    assertFalse(resultSet3.next());
+    resultSet3.close();
+
+    ps.close();
+    connection.close();
+  }
+
+  /** Factory that creates a service based on a local JDBC connection. */
+  public static class LocalJdbcServiceFactory implements Service.Factory {
+    @Override public Service create(AvaticaConnection connection) {
+      try {
+        Connection connection1 =
+            DriverManager.getConnection(CONNECTION_SPEC.url,
+                CONNECTION_SPEC.username, CONNECTION_SPEC.password);
+        return new LocalService(new JdbcMeta(connection1));
+      } catch (SQLException e) {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
+  /** Factory that creates a service based on a local JDBC connection. */
+  public static class QuasiRemoteJdbcServiceFactory implements Service.Factory {
+    @Override public Service create(AvaticaConnection connection) {
+      try {
+        Connection connection1 =
+            DriverManager.getConnection(CONNECTION_SPEC.url,
+                CONNECTION_SPEC.username, CONNECTION_SPEC.password);
+        final JdbcMeta jdbcMeta = new JdbcMeta(connection1);
+        final LocalService localService = new LocalService(jdbcMeta);
+        final LocalJsonService localJsonService =
+            new LocalJsonService(localService);
+        return localJsonService;
+      } catch (SQLException e) {
+        throw new RuntimeException(e);
+      }
+    }
+  }
+
+  /** Information necessary to create a JDBC connection. Specify one to run
+   * tests against a different database. (hsqldb is the default.) */
+  public static class ConnectionSpec {
+    public final String url;
+    public final String username;
+    public final String password;
+    public final String driver;
+
+    public ConnectionSpec(String url, String username, String password,
+        String driver) {
+      this.url = url;
+      this.username = username;
+      this.password = password;
+      this.driver = driver;
+    }
+
+    public static final ConnectionSpec HSQLDB =
+        new ConnectionSpec(ScottHsqldb.URI, ScottHsqldb.USER,
+            ScottHsqldb.PASSWORD, "org.hsqldb.jdbcDriver");
+  }
 }
 
 // End RemoteDriverTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 36a88f5..34059f7 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -89,6 +89,11 @@ limitations under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>net.hydromatic</groupId>
+      <artifactId>scott-data-hsqldb</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.codehaus.janino</groupId>
       <artifactId>janino</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java
index 0b87f0f..e5a567c 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java
@@ -91,13 +91,13 @@ public class CalciteJdbc41Factory extends CalciteFactory {
   }
 
   public CalciteResultSet newResultSet(AvaticaStatement statement,
-      Meta.Signature signature, TimeZone timeZone, Iterable<Object> iterable) {
+      Meta.Signature signature, TimeZone timeZone, Meta.Frame firstFrame) {
     final ResultSetMetaData metaData =
         newResultSetMetaData(statement, signature);
     final CalcitePrepare.CalciteSignature calciteSignature =
         (CalcitePrepare.CalciteSignature) signature;
     return new CalciteResultSet(statement, calciteSignature, metaData, timeZone,
-        iterable);
+        firstFrame);
   }
 
   public ResultSetMetaData newResultSetMetaData(AvaticaStatement statement,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 152e918..cf395f6 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java
@@ -157,7 +157,7 @@ public class CalciteMetaImpl extends MetaImpl {
     final Iterable<Object> iterable = (Iterable<Object>) (Iterable) enumerable;
     return createResultSet(Collections.<String, Object>emptyMap(),
         columns, CursorFactory.record(clazz, fields, fieldNames),
-        iterable);
+        new Frame(0, true, iterable));
   }
 
   @Override protected <E> MetaResultSet
@@ -165,12 +165,12 @@ public class CalciteMetaImpl extends MetaImpl {
     final List<ColumnMetaData> columns = fieldMetaData(clazz).columns;
     final CursorFactory cursorFactory = CursorFactory.deduce(columns, clazz);
     return createResultSet(Collections.<String, Object>emptyMap(), columns,
-        cursorFactory, Collections.emptyList());
+        cursorFactory, Frame.EMPTY);
   }
 
   protected MetaResultSet createResultSet(
       Map<String, Object> internalParameters, List<ColumnMetaData> columns,
-      CursorFactory cursorFactory, final Iterable<Object> iterable) {
+      CursorFactory cursorFactory, final Frame firstFrame) {
     try {
       final CalciteConnectionImpl connection = getConnection();
       final AvaticaStatement statement = connection.createStatement();
@@ -180,10 +180,10 @@ public class CalciteMetaImpl extends MetaImpl {
               columns, cursorFactory, -1, null) {
             @Override public Enumerable<Object> enumerable(
                 DataContext dataContext) {
-              return Linq4j.asEnumerable(iterable);
+              return Linq4j.asEnumerable(firstFrame.rows);
             }
           };
-      return new MetaResultSet(statement.getId(), true, signature, iterable);
+      return new MetaResultSet(statement.getId(), true, signature, firstFrame);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -441,7 +441,7 @@ public class CalciteMetaImpl extends MetaImpl {
   }
 
   @Override public Iterable<Object> createIterable(StatementHandle handle,
-      Signature signature, Iterable<Object> iterable) {
+      Signature signature, List<Object> parameterValues, Frame firstFrame) {
     try {
       //noinspection unchecked
       final CalcitePrepare.CalciteSignature<Object> calciteSignature =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
index 72f31ef..777524b 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteResultSet.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.AvaticaResultSet;
 import org.apache.calcite.avatica.AvaticaStatement;
 import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.Handler;
+import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.util.Cursor;
 import org.apache.calcite.linq4j.Enumerator;
 import org.apache.calcite.linq4j.Linq4j;
@@ -42,8 +43,8 @@ public class CalciteResultSet extends AvaticaResultSet {
   CalciteResultSet(AvaticaStatement statement,
       CalcitePrepare.CalciteSignature calciteSignature,
       ResultSetMetaData resultSetMetaData, TimeZone timeZone,
-      Iterable<Object> iterable) {
-    super(statement, calciteSignature, resultSetMetaData, timeZone, iterable);
+      Meta.Frame firstFrame) {
+    super(statement, calciteSignature, resultSetMetaData, timeZone, firstFrame);
   }
 
   @Override protected CalciteResultSet execute() throws SQLException {
@@ -68,7 +69,7 @@ public class CalciteResultSet extends AvaticaResultSet {
     final CalciteResultSet resultSet =
         new CalciteResultSet(statement,
             (CalcitePrepare.CalciteSignature) signature, resultSetMetaData,
-            localCalendar.getTimeZone(), iterable);
+            localCalendar.getTimeZone(), new Meta.Frame(0, true, iterable));
     final Cursor cursor = resultSet.createCursor(elementType, iterable);
     final List<ColumnMetaData> columnMetaDataList;
     if (elementType instanceof ColumnMetaData.StructType) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 0819dcf..2d4c3f2 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -126,7 +126,7 @@ public class MaterializationService {
               Functions.adapt(calciteSignature.columns,
                   new Function1<ColumnMetaData, ColumnMetaData.Rep>() {
                     public ColumnMetaData.Rep apply(ColumnMetaData column) {
-                      return column.type.representation;
+                      return column.type.rep;
                     }
                   }),
               new AbstractQueryable<Object>() {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
index 97eb68a..298f8d6 100644
--- a/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
+++ b/core/src/test/java/org/apache/calcite/test/CalciteAssert.java
@@ -50,6 +50,7 @@ import com.google.common.collect.ImmutableMultiset;
 import com.google.common.collect.Lists;
 
 import net.hydromatic.foodmart.data.hsqldb.FoodmartHsqldb;
+import net.hydromatic.scott.data.hsqldb.ScottHsqldb;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -100,11 +101,11 @@ public class CalciteAssert {
    * MySQL manually with the foodmart data set, otherwise there will be test
    * failures.  To run against MySQL, specify '-Dcalcite.test.db=mysql' on the
    * java command line. */
-  public static final ConnectionSpec CONNECTION_SPEC =
+  public static final DatabaseInstance DB =
       Util.first(System.getProperty("calcite.test.db"), "hsqldb")
           .equals("mysql")
-          ? ConnectionSpec.MYSQL
-          : ConnectionSpec.HSQLDB;
+          ? DatabaseInstance.MYSQL
+          : DatabaseInstance.HSQLDB;
 
   /** Whether to enable slow tests. Default is false. */
   public static final boolean ENABLE_SLOW =
@@ -633,12 +634,9 @@ public class CalciteAssert {
       return rootSchema.add("foodmart",
           new ReflectiveSchema(new JdbcTest.FoodmartSchema()));
     case JDBC_FOODMART:
+      final ConnectionSpec cs = DB.foodmart;
       final DataSource dataSource =
-          JdbcSchema.dataSource(
-              CONNECTION_SPEC.url,
-              CONNECTION_SPEC.driver,
-              CONNECTION_SPEC.username,
-              CONNECTION_SPEC.password);
+          JdbcSchema.dataSource(cs.url, cs.driver, cs.username, cs.password);
       return rootSchema.add("foodmart",
           JdbcSchema.create(rootSchema, "foodmart", dataSource, null,
               "foodmart"));
@@ -1438,23 +1436,22 @@ public class CalciteAssert {
 
   /** Information necessary to create a JDBC connection. Specify one to run
    * tests against a different database. (hsqldb is the default.) */
-  public enum ConnectionSpec {
-    HSQLDB(FoodmartHsqldb.URI, "FOODMART", "FOODMART",
-        "org.hsqldb.jdbcDriver"),
-    MYSQL("jdbc:mysql://localhost/foodmart", "foodmart", "foodmart",
-        "com.mysql.jdbc.Driver");
-
-    public final String url;
-    public final String username;
-    public final String password;
-    public final String driver;
-
-    ConnectionSpec(String url, String username, String password,
-        String driver) {
-      this.url = url;
-      this.username = username;
-      this.password = password;
-      this.driver = driver;
+  public enum DatabaseInstance {
+    HSQLDB(
+        new ConnectionSpec(FoodmartHsqldb.URI, "FOODMART", "FOODMART",
+            "org.hsqldb.jdbcDriver"),
+        new ConnectionSpec(ScottHsqldb.URI, ScottHsqldb.USER,
+            ScottHsqldb.PASSWORD, "org.hsqldb.jdbcDriver")),
+    MYSQL(
+        new ConnectionSpec("jdbc:mysql://localhost/foodmart", "foodmart",
+            "foodmart", "com.mysql.jdbc.Driver"), null);
+
+    public final ConnectionSpec foodmart;
+    public final ConnectionSpec scott;
+
+    DatabaseInstance(ConnectionSpec foodmart, ConnectionSpec scott) {
+      this.foodmart = foodmart;
+      this.scott = scott;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/test/java/org/apache/calcite/test/ConnectionSpec.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/ConnectionSpec.java b/core/src/test/java/org/apache/calcite/test/ConnectionSpec.java
new file mode 100644
index 0000000..4142083
--- /dev/null
+++ b/core/src/test/java/org/apache/calcite/test/ConnectionSpec.java
@@ -0,0 +1,37 @@
+/*
+ * 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.test;
+
+/** Information necessary to create a JDBC connection.
+ *
+ * <p>Specify one to run tests against a different database. */
+public class ConnectionSpec {
+  public final String url;
+  public final String username;
+  public final String password;
+  public final String driver;
+
+  public ConnectionSpec(String url, String username, String password,
+      String driver) {
+    this.url = url;
+    this.username = username;
+    this.password = password;
+    this.driver = driver;
+  }
+}
+
+// End ConnectionSpec.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
index 08d2903..78c1249 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcAdapterTest.java
@@ -32,7 +32,7 @@ public class JdbcAdapterTest {
             + "    JdbcTableScan(table=[[foodmart, sales_fact_1997]])\n"
             + "    JdbcTableScan(table=[[foodmart, sales_fact_1998]])")
         .runs()
-        .enable(CalciteAssert.CONNECTION_SPEC.url.startsWith("jdbc:hsqldb:"))
+        .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql("SELECT *\n"
             + "FROM \"foodmart\".\"sales_fact_1997\"\n"
             + "UNION ALL\n"
@@ -48,7 +48,7 @@ public class JdbcAdapterTest {
             + "  select * from \"sales_fact_1998\")\n"
             + "where \"product_id\" = 1")
         .runs()
-        .enable(CalciteAssert.CONNECTION_SPEC.url.startsWith("jdbc:hsqldb:"))
+        .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql("SELECT *\n"
             + "FROM \"foodmart\".\"sales_fact_1997\"\n"
             + "WHERE \"product_id\" = 1\n"
@@ -63,7 +63,7 @@ public class JdbcAdapterTest {
         .query("select \"store_id\", \"store_name\" from \"store\"\n"
             + "where \"store_name\" in ('Store 1', 'Store 10', 'Store 11', 'Store 15', 'Store 16', 'Store 24', 'Store 3', 'Store 7')")
         .runs()
-        .enable(CalciteAssert.CONNECTION_SPEC.url.startsWith("jdbc:hsqldb:"))
+        .enable(CalciteAssert.DB == CalciteAssert.DatabaseInstance.HSQLDB)
         .planHasSql(
             "SELECT \"store_id\", \"store_name\"\n"
             + "FROM \"foodmart\".\"store\"\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 0024bf1..989243f 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -177,10 +177,10 @@ public class JdbcTest {
   public static final String FOODMART_SCHEMA = "     {\n"
       + "       type: 'jdbc',\n"
       + "       name: 'foodmart',\n"
-      + "       jdbcDriver: '" + CalciteAssert.CONNECTION_SPEC.driver + "',\n"
-      + "       jdbcUser: '" + CalciteAssert.CONNECTION_SPEC.username + "',\n"
-      + "       jdbcPassword: '" + CalciteAssert.CONNECTION_SPEC.password + "',\n"
-      + "       jdbcUrl: '" + CalciteAssert.CONNECTION_SPEC.url + "',\n"
+      + "       jdbcDriver: '" + CalciteAssert.DB.foodmart.driver + "',\n"
+      + "       jdbcUser: '" + CalciteAssert.DB.foodmart.username + "',\n"
+      + "       jdbcPassword: '" + CalciteAssert.DB.foodmart.password + "',\n"
+      + "       jdbcUrl: '" + CalciteAssert.DB.foodmart.url + "',\n"
       + "       jdbcCatalog: null,\n"
       + "       jdbcSchema: 'foodmart'\n"
       + "     }\n";
@@ -4644,8 +4644,21 @@ public class JdbcTest {
                           + "from \"hr\".\"emps\"\n"
                           + "where \"deptno\" < ? and \"name\" like ?");
 
+                  // execute with vars unbound - gives error
+                  ResultSet resultSet;
+                  try {
+                    resultSet = preparedStatement.executeQuery();
+                    fail("expected error, got " + resultSet);
+                  } catch (SQLException e) {
+                    assertThat(e.getMessage(),
+                        equalTo(
+                            "exception while executing query: unbound parameter"));
+                  }
+
                   // execute with both vars null - no results
-                  ResultSet resultSet = preparedStatement.executeQuery();
+                  preparedStatement.setNull(1, java.sql.Types.INTEGER);
+                  preparedStatement.setNull(2, java.sql.Types.VARCHAR);
+                  resultSet = preparedStatement.executeQuery();
                   assertFalse(resultSet.next());
 
                   // execute with ?0=15, ?1='%' - 3 rows
@@ -5943,7 +5956,7 @@ public class JdbcTest {
               }
             })
         .returns("C=0\n");
-    switch (CalciteAssert.CONNECTION_SPEC) {
+    switch (CalciteAssert.DB) {
     case HSQLDB:
       assertThat(Util.toLinux(sqls[0]),
           equalTo("SELECT COUNT(*) AS \"C\"\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/doc/avatica.md
----------------------------------------------------------------------
diff --git a/doc/avatica.md b/doc/avatica.md
new file mode 100644
index 0000000..32cc905
--- /dev/null
+++ b/doc/avatica.md
@@ -0,0 +1,81 @@
+# Avatica
+
+## Introduction
+
+Avatica is a framework for building JDBC and ODBC drivers for databases,
+and an RPC wire protocol.
+
+![Avatica Architecture]
+(https://raw.githubusercontent.com/julianhyde/share/master/slides/avatica-architecture.png)
+
+Avatica's Java binding has very few dependencies.
+Even though it is part of Apache Calcite it does not depend on other parts of
+Calcite. It depends only on JDK 1.7+ and Jackson.
+
+Avatica's wire protocol is JSON over HTTP.
+The Java implementation uses Jackson to convert request/response command
+objects to/from JSON.
+
+Avatica-Server is a Java implementation of Avatica RPC.
+It embeds the Jetty HTTP server.
+
+Core concepts:
+* Meta is a local API sufficient to implement any Avatica provider
+* Factory creates implementations of the JDBC classes (Driver, Connection,
+  Statement, ResultSet) on top of a Meta
+* Service is an interface that implements the functions of Meta in terms
+  of request and response command objects
+
+## JDBC
+
+Avatica implements JDBC by means of Factory.
+Factory creates implementations of the JDBC classes (Driver, Connection,
+Statement, PreparedStatement, ResultSet) on top of a Meta.
+
+## ODBC
+
+Work has not started on Avatica ODBC.
+
+Avatica ODBC would use the same wire protocol and could use the same server
+implementation in Java. The ODBC client would be written in C or C++.
+
+Since the Avatica protocol abstracts many of the differences between providers,
+the same ODBC client could be used for different databases.
+
+## Project structure
+
+We know that it is important that client libraries have minimal dependencies.
+
+Avatica is currently part of Apache Calcite.
+It does not depend upon any other part of Calcite.
+At some point Avatica could become a separate project.
+
+Packages:
+* [org.apache.calcite.avatica](http://www.hydromatic.net/calcite/apidocs/org/apache/calcite/avatica/package-summary.html) Core framework
+* [org.apache.calcite.avatica.remote](http://www.hydromatic.net/calcite/apidocs/org/apache/calcite/avatica/remote/package-summary.html) JDBC driver that uses remote procedure calls
+* [org.apache.calcite.avatica.server](http://www.hydromatic.net/calcite/apidocs/org/apache/calcite/avatica/server/package-summary.html) HTTP server
+* [org.apache.calcite.avatica.util](http://www.hydromatic.net/calcite/apidocs/org/apache/calcite/avatica/util/package-summary.html) Utilities
+
+## Status
+
+### Implemented
+* Create connection, create statement, metadata, prepare, bind, execute, fetch
+* RPC using JSON over HTTP
+* Local implementation
+* Implementation over an existing JDBC driver
+* Composite RPCs (combining several requests into one round trip)
+  * Execute-Fetch
+  * Metadata-Fetch (metadata calls such as getTables return all rows)
+
+### Not implemented
+* ODBC
+* RPCs
+  * CloseStatement
+  * CloseConnection
+* Composite RPCs
+  * CreateStatement-Prepare
+  * CloseStatement-CloseConnection
+  * Prepare-Execute-Fetch (Statement.executeQuery should fetch first N rows)
+* Remove statements from statement table
+* DML (INSERT, UPDATE, DELETE)
+* Statement.execute applied to SELECT statement

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 54fd593..683f173 100644
--- a/pom.xml
+++ b/pom.xml
@@ -131,6 +131,11 @@ limitations under the License.
         <version>11.0.2</version>
       </dependency>
       <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.11</version>
+      </dependency>
+      <dependency>
         <groupId>io.airlift.tpch</groupId>
         <artifactId>tpch</artifactId>
         <version>0.1</version>
@@ -159,7 +164,21 @@ limitations under the License.
         <groupId>net.hydromatic</groupId>
         <artifactId>quidem</artifactId>
         <version>0.3</version>
-        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>net.hydromatic</groupId>
+        <artifactId>scott-data-hsqldb</artifactId>
+        <version>0.1</version>
+      </dependency>
+      <dependency>
+        <groupId>net.hydromatic</groupId>
+        <artifactId>tpcds</artifactId>
+        <version>0.3</version>
+      </dependency>
+      <dependency>
+        <groupId>net.sf.opencsv</groupId>
+        <artifactId>opencsv</artifactId>
+        <version>2.3</version>
       </dependency>
       <dependency>
         <groupId>org.apache.commons</groupId>
@@ -192,17 +211,6 @@ limitations under the License.
         <version>5.1.5-jhyde</version>
       </dependency>
       <dependency>
-        <groupId>net.hydromatic</groupId>
-        <artifactId>tpcds</artifactId>
-        <version>0.3</version>
-        <type>jar</type>
-      </dependency>
-      <dependency>
-        <groupId>net.sf.opencsv</groupId>
-        <artifactId>opencsv</artifactId>
-        <version>2.3</version>
-      </dependency>
-      <dependency>
         <groupId>org.apache.spark</groupId>
         <artifactId>spark-core_2.10</artifactId>
         <version>0.9.0-incubating</version>
@@ -228,11 +236,6 @@ limitations under the License.
         <version>0.7.1</version>
       </dependency>
       <dependency>
-        <groupId>junit</groupId>
-        <artifactId>junit</artifactId>
-        <version>4.11</version>
-      </dependency>
-      <dependency>
         <groupId>xerces</groupId>
         <artifactId>xercesImpl</artifactId>
         <version>2.9.1</version>


[2/9] incubator-calcite git commit: [CALCITE-596] JDBC adapter incorrectly reads null values as 0 (Ng Jiunn Jye)

Posted by jh...@apache.org.
[CALCITE-596] JDBC adapter incorrectly reads null values as 0 (Ng Jiunn Jye)


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

Branch: refs/heads/master
Commit: 2b07a9e9680e662a6d9785deb2a4ed140026e95f
Parents: 3b10a6a
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 23 01:39:12 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 01:39:12 2015 -0700

----------------------------------------------------------------------
 .../adapter/jdbc/JdbcToEnumerableConverter.java | 11 ++++
 .../java/org/apache/calcite/test/JdbcTest.java  | 60 ++++++++++++++++++++
 2 files changed, 71 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2b07a9e9/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java
index 3fbf778..125d61b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java
@@ -232,6 +232,17 @@ public class JdbcToEnumerableConverter
         Expressions.statement(
             Expressions.assign(
                 target, source)));
+
+    // [CALCITE-596] If primitive type columns contain null value, returns null
+    // object
+    if (primitive != null) {
+      builder.add(
+          Expressions.ifThen(
+              Expressions.call(resultSet_, "wasNull"),
+              Expressions.statement(
+                  Expressions.assign(target,
+                      Expressions.constant(null)))));
+    }
   }
 
   private Method getMethod(SqlTypeName sqlTypeName, boolean nullable,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/2b07a9e9/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 0942334..0024bf1 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -6137,6 +6137,66 @@ public class JdbcTest {
         .returnsUnordered("DID=1", "DID=2");
   }
 
+  /**
+   * Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-596">[CALCITE-596]
+   * JDBC adapter incorrectly reads null values as 0</a>.
+   */
+  @Test public void testPrimitiveColumnsWithNullValues() throws Exception {
+    String hsqldbMemUrl = "jdbc:hsqldb:mem:.";
+    Connection baseConnection = DriverManager.getConnection(hsqldbMemUrl);
+    Statement baseStmt = baseConnection.createStatement();
+    baseStmt.execute("CREATE TABLE T1 (\n"
+        + "ID INTEGER,\n"
+        + "VALS DOUBLE)");
+    baseStmt.execute("INSERT INTO T1 VALUES (1, 1.0)");
+    baseStmt.execute("INSERT INTO T1 VALUES (2, null)");
+    baseStmt.execute("INSERT INTO T1 VALUES (null, 2.0)");
+
+    baseStmt.close();
+    baseConnection.commit();
+
+    Properties info = new Properties();
+    info.put("model",
+      "inline:"
+      + "{\n"
+      + "  version: '1.0',\n"
+      + "  defaultSchema: 'BASEJDBC',\n"
+      + "  schemas: [\n"
+      + "     {\n"
+      + "       type: 'jdbc',\n"
+      + "       name: 'BASEJDBC',\n"
+      + "       jdbcDriver: '" + jdbcDriver.class.getName() + "',\n"
+      + "       jdbcUrl: '" + hsqldbMemUrl + "',\n"
+      + "       jdbcCatalog: null,\n"
+      + "       jdbcSchema: null\n"
+      + "     }\n"
+      + "  ]\n"
+      + "}");
+
+    Connection calciteConnection = DriverManager.getConnection(
+      "jdbc:calcite:", info);
+
+    ResultSet rs = calciteConnection.prepareStatement("select * from t1")
+      .executeQuery();
+
+    assertThat(rs.next(), is(true));
+    assertThat((Integer) rs.getObject("ID"), equalTo(1));
+    assertThat((Double) rs.getObject("VALS"), equalTo(1.0));
+
+    assertThat(rs.next(), is(true));
+    assertThat((Integer) rs.getObject("ID"), equalTo(2));
+    assertThat((Double) rs.getObject("VALS"), nullValue());
+
+    assertThat(rs.next(), is(true));
+    assertThat(rs.getObject("ID"), nullValue());
+    assertThat((Double) rs.getObject("VALS"), equalTo(2.0));
+
+    rs.close();
+    calciteConnection.close();
+
+  }
+
   // Disable checkstyle, so it doesn't complain about fields like "customer_id".
   //CHECKSTYLE: OFF
 


[4/9] incubator-calcite git commit: [CALCITE-618] Add Avatica support for getTables (Julian Hyde and Nick Dimiduk)

Posted by jh...@apache.org.
[CALCITE-618] Add Avatica support for getTables (Julian Hyde and Nick Dimiduk)

Also add getSchemas.

Remove dependencies on Guava. (Avatica depends only on JDK and Jackson.)

Add JdbcMeta; implement remote execute query

Rename some fields of AvaticaType to prevent clash between JSON "type" and type field.

Add FetchRequest; if FetchRequest has parameters, executes first.

Document Avatica

Move class ConnectionSpec to top-level

Use scott-data-hsqldb rather than foodmart-data-hsqldb for testing Avatica; it is smaller and therefore loads faster

Work around JSON's mangling of small longs into ints


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

Branch: refs/heads/master
Commit: 4d2f647a6d397a4a7c99fcc2d3d6359baf937943
Parents: 2b07a9e
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Mar 12 14:51:14 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 01:44:36 2015 -0700

----------------------------------------------------------------------
 avatica/pom.xml                                 |  11 +
 .../calcite/avatica/AvaticaConnection.java      |  30 +-
 .../apache/calcite/avatica/AvaticaFactory.java  |  11 +-
 .../calcite/avatica/AvaticaJdbc41Factory.java   |   4 +-
 .../avatica/AvaticaPreparedStatement.java       |  12 +-
 .../calcite/avatica/AvaticaResultSet.java       |  12 +-
 .../avatica/AvaticaResultSetMetaData.java       |   4 +-
 .../calcite/avatica/AvaticaStatement.java       |  33 +-
 .../apache/calcite/avatica/ColumnMetaData.java  |  46 +-
 .../java/org/apache/calcite/avatica/Meta.java   |  90 +++-
 .../org/apache/calcite/avatica/MetaImpl.java    | 131 ++++--
 .../calcite/avatica/UnregisteredDriver.java     |   2 +-
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   | 442 +++++++++++++++++++
 .../calcite/avatica/jdbc/JdbcResultSet.java     | 105 +++++
 .../calcite/avatica/jdbc/package-info.java      |  22 +
 .../calcite/avatica/remote/JsonService.java     |  23 +-
 .../calcite/avatica/remote/LocalService.java    |  78 +++-
 .../calcite/avatica/remote/MockJsonService.java |  44 +-
 .../calcite/avatica/remote/RemoteMeta.java      |  45 +-
 .../apache/calcite/avatica/remote/Service.java  |  75 +++-
 .../calcite/avatica/util/AbstractCursor.java    |  75 +++-
 .../apache/calcite/avatica/util/ArrayImpl.java  |   8 +-
 .../calcite/avatica/test/RemoteDriverTest.java  | 216 ++++++++-
 core/pom.xml                                    |   5 +
 .../calcite/jdbc/CalciteJdbc41Factory.java      |   4 +-
 .../apache/calcite/jdbc/CalciteMetaImpl.java    |  12 +-
 .../apache/calcite/jdbc/CalciteResultSet.java   |   7 +-
 .../materialize/MaterializationService.java     |   2 +-
 .../org/apache/calcite/test/CalciteAssert.java  |  47 +-
 .../org/apache/calcite/test/ConnectionSpec.java |  37 ++
 .../apache/calcite/test/JdbcAdapterTest.java    |   6 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |  25 +-
 doc/avatica.md                                  |  81 ++++
 pom.xml                                         |  37 +-
 34 files changed, 1566 insertions(+), 216 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/pom.xml
----------------------------------------------------------------------
diff --git a/avatica/pom.xml b/avatica/pom.xml
index 58aec3c..3e6040c 100644
--- a/avatica/pom.xml
+++ b/avatica/pom.xml
@@ -45,6 +45,17 @@ limitations under the License.
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>net.hydromatic</groupId>
+      <artifactId>scott-data-hsqldb</artifactId>
+      <version>0.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hsqldb</groupId>
+      <artifactId>hsqldb</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
index 492ec5f..bc8c3eb 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
@@ -269,7 +269,17 @@ public abstract class AvaticaConnection implements Connection {
       int resultSetType,
       int resultSetConcurrency,
       int resultSetHoldability) throws SQLException {
-    throw new UnsupportedOperationException(); // TODO:
+    try {
+      // TODO: cut out round-trip to create a statement handle
+      final Meta.ConnectionHandle ch = new Meta.ConnectionHandle(id);
+      final Meta.StatementHandle h = meta.createStatement(ch);
+
+      final Meta.Signature x = meta.prepare(h, sql, -1);
+      return factory.newPreparedStatement(this, h, x, resultSetType,
+          resultSetConcurrency, resultSetHoldability);
+    } catch (RuntimeException e) {
+      throw helper.createException("while preparing SQL: " + sql, e);
+    }
   }
 
   public CallableStatement prepareCall(
@@ -391,12 +401,12 @@ public abstract class AvaticaConnection implements Connection {
    *
    * @param statement     Statement
    * @param signature     Prepared query
-   * @param iterable      List of rows, or null if we need to execute
+   * @param firstFrame    First frame of rows, or null if we need to execute
    * @return Result set
    * @throws java.sql.SQLException if a database error occurs
    */
   protected ResultSet executeQueryInternal(AvaticaStatement statement,
-      Meta.Signature signature, Iterable<Object> iterable) throws SQLException {
+      Meta.Signature signature, Meta.Frame firstFrame) throws SQLException {
     // Close the previous open result set, if there is one.
     synchronized (statement) {
       if (statement.openResultSet != null) {
@@ -412,7 +422,7 @@ public abstract class AvaticaConnection implements Connection {
 
       final TimeZone timeZone = getTimeZone();
       statement.openResultSet =
-          factory.newResultSet(statement, signature, timeZone, iterable);
+          factory.newResultSet(statement, signature, timeZone, firstFrame);
     }
     // Release the monitor before executing, to give another thread the
     // opportunity to call cancel.
@@ -447,11 +457,12 @@ public abstract class AvaticaConnection implements Connection {
             }
           }
 
-          public void assign(Meta.Signature signature,
-              Iterable<Object> iterable) throws SQLException {
+          public void assign(Meta.Signature signature, Meta.Frame firstFrame)
+              throws SQLException {
             final TimeZone timeZone = getTimeZone();
             statement.openResultSet =
-                factory.newResultSet(statement, signature, timeZone, iterable);
+                factory.newResultSet(statement, signature, timeZone,
+                    firstFrame);
           }
 
           public void execute() throws SQLException {
@@ -467,9 +478,8 @@ public abstract class AvaticaConnection implements Connection {
     final Meta.StatementHandle h =
         new Meta.StatementHandle(metaResultSet.statementId);
     final AvaticaStatement statement = lookupStatement(h);
-    return executeQueryInternal(statement,
-        metaResultSet.signature,
-        metaResultSet.iterable);
+    return executeQueryInternal(statement, metaResultSet.signature.sanitize(),
+        metaResultSet.firstFrame);
   }
 
   /** Creates a statement wrapper around an existing handle. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaFactory.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaFactory.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaFactory.java
index 0139ef3..c6d2ede 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaFactory.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaFactory.java
@@ -50,20 +50,15 @@ public interface AvaticaFactory {
    * Creates a result set. You will then need to call
    * {@link AvaticaResultSet#execute()} on it.
    *
-   * <p>If {@code signature} implements
-   * {@link org.apache.calcite.avatica.MetaImpl.WithIterable} we do not need
-   * to execute; we can use pre-canned data. This mechanism is used for
-   * metadata requests such as {@code getTables}.
-   *
    * @param statement Statement
    * @param signature Prepared statement
    * @param timeZone Time zone
-   * @param iterable Iterable over rows in result, or null if an execute/fetch
-   *                 is required
+   * @param firstFrame Frame containing the first (or perhaps only) rows in the
+   *                   result, or null if an execute/fetch is required
    * @return Result set
    */
   AvaticaResultSet newResultSet(AvaticaStatement statement,
-      Meta.Signature signature, TimeZone timeZone, Iterable<Object> iterable)
+      Meta.Signature signature, TimeZone timeZone, Meta.Frame firstFrame)
       throws SQLException;
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaJdbc41Factory.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaJdbc41Factory.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaJdbc41Factory.java
index 4b2f721..6a70a26 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaJdbc41Factory.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaJdbc41Factory.java
@@ -84,11 +84,11 @@ class AvaticaJdbc41Factory implements AvaticaFactory {
   }
 
   public AvaticaResultSet newResultSet(AvaticaStatement statement,
-      Meta.Signature signature, TimeZone timeZone, Iterable<Object> iterable) {
+      Meta.Signature signature, TimeZone timeZone, Meta.Frame firstFrame) {
     final ResultSetMetaData metaData =
         newResultSetMetaData(statement, signature);
     return new AvaticaResultSet(statement, signature, metaData, timeZone,
-        iterable);
+        firstFrame);
   }
 
   public AvaticaResultSetMetaData newResultSetMetaData(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
index a40e8d1..9324db7 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaPreparedStatement.java
@@ -32,7 +32,7 @@ import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 
@@ -76,11 +76,7 @@ public abstract class AvaticaPreparedStatement
   }
 
   @Override protected List<Object> getParameterValues() {
-    final List<Object> list = new ArrayList<Object>();
-    for (Object o : slots) {
-      list.add(o == AvaticaParameter.DUMMY_VALUE ? null : o);
-    }
-    return list;
+    return Arrays.asList(slots);
   }
 
   // implement PreparedStatement
@@ -174,7 +170,9 @@ public abstract class AvaticaPreparedStatement
   }
 
   public void clearParameters() throws SQLException {
-    throw new UnsupportedOperationException();
+    for (int i = 0; i < slots.length; i++) {
+      slots[i] = null;
+    }
   }
 
   public void setObject(int parameterIndex, Object x, int targetSqlType)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java
index 8d2fbee..fca227f 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSet.java
@@ -49,7 +49,7 @@ import java.util.TimeZone;
 public class AvaticaResultSet implements ResultSet, ArrayImpl.Factory {
   protected final AvaticaStatement statement;
   protected final Meta.Signature signature;
-  protected final Iterable<Object> iterable;
+  protected final Meta.Frame firstFrame;
   protected final List<ColumnMetaData> columnMetaDataList;
   protected final ResultSetMetaData resultSetMetaData;
   protected final Calendar localCalendar;
@@ -71,10 +71,10 @@ public class AvaticaResultSet implements ResultSet, ArrayImpl.Factory {
       Meta.Signature signature,
       ResultSetMetaData resultSetMetaData,
       TimeZone timeZone,
-      Iterable<Object> iterable) {
+      Meta.Frame firstFrame) {
     this.statement = statement;
     this.signature = signature;
-    this.iterable = iterable;
+    this.firstFrame = firstFrame;
     this.columnMetaDataList = signature.columns;
     this.type = statement.resultSetType;
     this.concurrency = statement.resultSetConcurrency;
@@ -179,9 +179,11 @@ public class AvaticaResultSet implements ResultSet, ArrayImpl.Factory {
    * @throws SQLException if execute fails for some reason.
    */
   protected AvaticaResultSet execute() throws SQLException {
-    this.cursor = MetaImpl.createCursor(signature.cursorFactory,
+    final List<Object> parameterValues = statement.getBoundParameterValues();
+    final Iterable<Object> iterable1 =
         statement.connection.meta.createIterable(statement.handle, signature,
-            iterable));
+            parameterValues, firstFrame);
+    this.cursor = MetaImpl.createCursor(signature.cursorFactory, iterable1);
     this.accessorList =
         cursor.createAccessors(columnMetaDataList, localCalendar, this);
     this.row = -1;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSetMetaData.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSetMetaData.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSetMetaData.java
index cb67a89..b4e8892 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSetMetaData.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaResultSetMetaData.java
@@ -104,11 +104,11 @@ public class AvaticaResultSetMetaData implements ResultSetMetaData {
   }
 
   public int getColumnType(int column) throws SQLException {
-    return getColumnMetaData(column).type.type;
+    return getColumnMetaData(column).type.id;
   }
 
   public String getColumnTypeName(int column) throws SQLException {
-    return getColumnMetaData(column).type.typeName;
+    return getColumnMetaData(column).type.name;
   }
 
   public boolean isReadOnly(int column) throws SQLException {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
index fb0a6f5..6df3528 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaStatement.java
@@ -20,6 +20,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
 import java.sql.Statement;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -53,7 +54,7 @@ public abstract class AvaticaStatement
   final int resultSetHoldability;
   private int fetchSize;
   private int fetchDirection;
-  protected int maxRowCount;
+  protected int maxRowCount = 0;
 
   /**
    * Creates an AvaticaStatement.
@@ -98,17 +99,6 @@ public abstract class AvaticaStatement
     }
   }
 
-  public ResultSet executeQueryOld(String sql) throws SQLException {
-    try {
-      final int maxRowCount1 = maxRowCount <= 0 ? -1 : maxRowCount;
-      Meta.Signature x = connection.meta.prepare(handle, sql, maxRowCount1);
-      return executeQueryInternal(x);
-    } catch (RuntimeException e) {
-      throw connection.helper.createException(
-        "error while executing SQL \"" + sql + "\": " + e.getMessage(), e);
-    }
-  }
-
   public ResultSet executeQuery(String sql) throws SQLException {
     try {
       // In JDBC, maxRowCount = 0 means no limit; in prepare it means LIMIT 0
@@ -417,6 +407,25 @@ public abstract class AvaticaStatement
   protected List<Object> getParameterValues() {
     return Collections.emptyList();
   }
+
+  /** Returns a list of bound parameter values.
+   *
+   * <p>If any of the parameters have not been bound, throws.
+   * If parameters have been bound to null, the value in the list is null.
+   */
+  protected List<Object> getBoundParameterValues() throws SQLException {
+    final List<Object> list = new ArrayList<>();
+    for (Object parameterValue : getParameterValues()) {
+      if (parameterValue == null) {
+        throw new SQLException("unbound parameter");
+      }
+      if (parameterValue == AvaticaParameter.DUMMY_VALUE) {
+        parameterValue = null;
+      }
+      list.add(parameterValue);
+    }
+    return list;
+  }
 }
 
 // End AvaticaStatement.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java b/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
index 0b6856d..8e9930f 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
@@ -160,6 +160,13 @@ public class ColumnMetaData {
         type.columnClassName());
   }
 
+  public ColumnMetaData setTypeId(int typeId) {
+    return new ColumnMetaData(ordinal, autoIncrement, caseSensitive, searchable,
+        currency, nullable, signed, displaySize, label, columnName, schemaName,
+        precision, scale, tableName, catalogName, type.setId(typeId), readOnly,
+        writable, definitelyWritable, columnClassName);
+  }
+
   /** Description of the type used to internally represent a value. For example,
    * a {@link java.sql.Date} might be represented as a {@link #PRIMITIVE_INT}
    * if not nullable, or a {@link #JAVA_SQL_DATE}. */
@@ -192,7 +199,7 @@ public class ColumnMetaData {
     public static final Map<Class, Rep> VALUE_MAP;
 
     static {
-      Map<Class, Rep> builder = new HashMap<Class, Rep>();
+      Map<Class, Rep> builder = new HashMap<>();
       for (Rep rep : values()) {
         builder.put(rep.clazz, rep);
       }
@@ -220,31 +227,39 @@ public class ColumnMetaData {
       @JsonSubTypes.Type(value = StructType.class, name = "struct"),
       @JsonSubTypes.Type(value = ArrayType.class, name = "array") })
   public static class AvaticaType {
-    public final int type;
-    public final String typeName;
+    public final int id;
+    public final String name;
 
     /** The type of the field that holds the value. Not a JDBC property. */
-    public final Rep representation;
+    public final Rep rep;
 
-    protected AvaticaType(int type, String typeName, Rep representation) {
-      this.type = type;
-      this.typeName = typeName;
-      this.representation = representation;
-      assert representation != null;
+    protected AvaticaType(int id, String name, Rep rep) {
+      this.id = id;
+      this.name = name;
+      this.rep = rep;
+      assert rep != null;
     }
 
     public String columnClassName() {
-      return SqlType.valueOf(type).clazz.getName();
+      return SqlType.valueOf(id).clazz.getName();
+    }
+
+    public AvaticaType setId(int rep) {
+      throw new UnsupportedOperationException();
     }
   }
 
   /** Scalar type. */
   public static class ScalarType extends AvaticaType {
     @JsonCreator
-    public ScalarType(@JsonProperty("type") int type,
-        @JsonProperty("typeName") String typeName,
-        @JsonProperty("representation") Rep representation) {
-      super(type, typeName, representation);
+    public ScalarType(@JsonProperty("id") int id,
+        @JsonProperty("name") String name,
+        @JsonProperty("rep") Rep rep) {
+      super(id, name, rep);
+    }
+
+    @Override public AvaticaType setId(int id) {
+      return new ScalarType(id, name, rep);
     }
   }
 
@@ -306,8 +321,7 @@ public class ColumnMetaData {
     private final int type;
     private final Class clazz;
 
-    private static final Map<Integer, SqlType> BY_ID =
-        new HashMap<Integer, SqlType>();
+    private static final Map<Integer, SqlType> BY_ID = new HashMap<>();
     static {
       for (SqlType sqlType : values()) {
         BY_ID.put(sqlType.type, sqlType);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 107c4c9..f7f3b80 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Command handler for getting various metadata. Should be implemented by each
@@ -148,7 +149,7 @@ public interface Meta {
    * requires to be not null; derived classes may instead choose to execute the
    * relational expression in {@code signature}. */
   Iterable<Object> createIterable(StatementHandle handle, Signature signature,
-      Iterable<Object> iterable);
+      List<Object> parameterValues, Frame firstFrame);
 
   /** Prepares a statement.
    *
@@ -170,6 +171,25 @@ public interface Meta {
   MetaResultSet prepareAndExecute(StatementHandle h, String sql,
       int maxRowCount, PrepareCallback callback);
 
+  /** Returns a frame of rows.
+   *
+   * <p>The frame describes whether there may be another frame. If there is not
+   * another frame, the current iteration is done when we have finished the
+   * rows in the this frame.
+   *
+   * <p>The default implementation always returns null.
+   *
+   * @param h Statement handle
+   * @param parameterValues A list of parameter values, if statement is to be
+   *                        executed; otherwise null
+   * @param offset Zero-based offset of first row in the requested frame
+   * @param fetchMaxRowCount Maximum number of rows to return; negative means
+   * no limit
+   * @return Frame, or null if there are no more
+   */
+  Frame fetch(StatementHandle h, List<Object> parameterValues, int offset,
+      int fetchMaxRowCount);
+
   /** Called during the creation of a statement to allocate a new handle.
    *
    * @param ch Connection handle
@@ -201,15 +221,15 @@ public interface Meta {
   class MetaResultSet {
     public final int statementId;
     public final boolean ownStatement;
-    public final Iterable<Object> iterable;
+    public final Frame firstFrame;
     public final Signature signature;
 
     public MetaResultSet(int statementId, boolean ownStatement,
-        Signature signature, Iterable<Object> iterable) {
-      this.signature = signature;
+        Signature signature, Frame firstFrame) {
+      this.signature = Objects.requireNonNull(signature);
       this.statementId = statementId;
       this.ownStatement = ownStatement;
-      this.iterable = iterable;
+      this.firstFrame = firstFrame; // may be null
     }
   }
 
@@ -227,7 +247,7 @@ public interface Meta {
       assert (fieldNames != null)
           == (style == Style.RECORD_PROJECTION || style == Style.MAP);
       assert (fields != null) == (style == Style.RECORD_PROJECTION);
-      this.style = style;
+      this.style = Objects.requireNonNull(style);
       this.clazz = clazz;
       this.fields = fields;
       this.fieldNames = fieldNames;
@@ -271,7 +291,7 @@ public interface Meta {
     public static CursorFactory record(Class resultClass, List<Field> fields,
         List<String> fieldNames) {
       if (fields == null) {
-        fields = new ArrayList<Field>();
+        fields = new ArrayList<>();
         for (String fieldName : fieldNames) {
           try {
             fields.add(resultClass.getField(fieldName));
@@ -348,6 +368,60 @@ public interface Meta {
       return new Signature(columns, sql, parameters, internalParameters,
           cursorFactory);
     }
+
+    /** Creates a copy of this Signature with null lists and maps converted to
+     * empty. */
+    public Signature sanitize() {
+      if (columns == null || parameters == null || internalParameters == null) {
+        return new Signature(sanitize(columns), sql, sanitize(parameters),
+            sanitize(internalParameters), cursorFactory);
+      }
+      return this;
+    }
+
+    private <E> List<E> sanitize(List<E> list) {
+      return list == null ? Collections.<E>emptyList() : list;
+    }
+
+    private <K, V> Map<K, V> sanitize(Map<K, V> map) {
+      return map == null ? Collections.<K, V>emptyMap() : map;
+    }
+  }
+
+  /** A collection of rows. */
+  class Frame {
+    /** Frame that has zero rows and is the last frame. */
+    public static final Frame EMPTY =
+        new Frame(0, true, Collections.emptyList());
+
+    /** Frame that has zero rows but may have another frame. */
+    public static final Frame MORE =
+        new Frame(0, false, Collections.emptyList());
+
+    /** Zero-based offset of first row. */
+    public final int offset;
+    /** Whether this is definitely the last frame of rows.
+     * If true, there are no more rows.
+     * If false, there may or may not be more rows. */
+    public final boolean done;
+    /** The rows. */
+    public final Iterable<Object> rows;
+
+    public Frame(int offset, boolean done, Iterable<Object> rows) {
+      this.offset = offset;
+      this.done = done;
+      this.rows = rows;
+    }
+
+    @JsonCreator
+    public static Frame create(@JsonProperty("offset") int offset,
+        @JsonProperty("done") boolean done,
+        @JsonProperty("rows") List<Object> rows) {
+      if (offset == 0 && done && rows.isEmpty()) {
+        return EMPTY;
+      }
+      return new Frame(offset, done, rows);
+    }
   }
 
   /** Connection handle. */
@@ -383,7 +457,7 @@ public interface Meta {
   interface PrepareCallback {
     Object getMonitor();
     void clear() throws SQLException;
-    void assign(Signature signature, Iterable<Object> iterable)
+    void assign(Signature signature, Frame firstFrame)
         throws SQLException;
     void execute() throws SQLException;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 9b2be07..a6c5f3c 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/MetaImpl.java
@@ -36,8 +36,10 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 /**
  * Basic implementation of {@link Meta}.
@@ -171,7 +173,7 @@ public abstract class MetaImpl implements Meta {
     return createResultSet(Collections.<String, Object>emptyMap(),
         fieldMetaData(clazz).columns,
         CursorFactory.deduce(fieldMetaData(clazz).columns, null),
-        Collections.emptyList());
+        Frame.EMPTY);
   }
 
   protected static ColumnMetaData columnMetaData(String name, int index,
@@ -207,14 +209,13 @@ public abstract class MetaImpl implements Meta {
 
   protected MetaResultSet createResultSet(
       Map<String, Object> internalParameters, List<ColumnMetaData> columns,
-      CursorFactory cursorFactory, Iterable<Object> iterable) {
+      CursorFactory cursorFactory, Frame firstFrame) {
     try {
       final AvaticaStatement statement = connection.createStatement();
-      final SignatureWithIterable signature =
-          new SignatureWithIterable(internalParameters, columns, "",
-              Collections.<AvaticaParameter>emptyList(), cursorFactory,
-              iterable);
-      return new MetaResultSet(statement.getId(), true, signature, iterable);
+      final Signature signature =
+          new Signature(columns, "", Collections.<AvaticaParameter>emptyList(),
+              internalParameters, cursorFactory);
+      return new MetaResultSet(statement.getId(), true, signature, firstFrame);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -646,8 +647,16 @@ public abstract class MetaImpl implements Meta {
   }
 
   public Iterable<Object> createIterable(StatementHandle handle,
-      Signature signature, Iterable<Object> iterable) {
-    return iterable;
+      Signature signature, List<Object> parameterValues, Frame firstFrame) {
+    if (firstFrame != null && firstFrame.done) {
+      return firstFrame.rows;
+    }
+    return new FetchIterable(handle, firstFrame, parameterValues);
+  }
+
+  public Frame fetch(StatementHandle h, List<Object> parameterValues,
+      int offset, int fetchMaxRowCount) {
+    return null;
   }
 
   /** Information about a type. */
@@ -691,27 +700,99 @@ public abstract class MetaImpl implements Meta {
     }
   }
 
-  /** Prepare result with a iterable. Use this for simple statements
-   * that have a canned response and don't need to be executed. */
-  protected interface WithIterable {
-    Iterable getIterable();
+  /** Iterator that never returns any elements. */
+  private static class EmptyIterator implements Iterator<Object> {
+    public static final Iterator<Object> INSTANCE = new EmptyIterator();
+
+    public void remove() {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean hasNext() {
+      return false;
+    }
+
+    public Object next() {
+      throw new NoSuchElementException();
+    }
+  }
+
+  /** Iterable that yields an iterator over rows coming from a sequence of
+   * {@link Frame}s. */
+  private class FetchIterable implements Iterable<Object> {
+    private final StatementHandle handle;
+    private final Frame firstFrame;
+    private final List<Object> parameterValues;
+
+    public FetchIterable(StatementHandle handle, Frame firstFrame,
+        List<Object> parameterValues) {
+      this.handle = handle;
+      this.firstFrame = firstFrame;
+      this.parameterValues = parameterValues;
+    }
+
+    public Iterator<Object> iterator() {
+      return new FetchIterator(handle, firstFrame, parameterValues);
+    }
   }
 
-  /** Prepare result that contains an iterable. */
-  protected static class SignatureWithIterable extends Signature
-      implements WithIterable {
-    private final Iterable iterable;
+  /** Iterator over rows coming from a sequence of {@link Frame}s. */
+  private class FetchIterator implements Iterator<Object> {
+    private final StatementHandle handle;
+    private Frame frame;
+    private Iterator<Object> rows;
+    private List<Object> parameterValues;
+
+    public FetchIterator(StatementHandle handle, Frame firstFrame,
+        List<Object> parameterValues) {
+      this.handle = handle;
+      this.parameterValues = parameterValues;
+      if (firstFrame == null) {
+        frame = Frame.MORE;
+        rows = EmptyIterator.INSTANCE;
+      } else {
+        frame = firstFrame;
+        rows = firstFrame.rows.iterator();
+      }
+      moveNext();
+    }
 
-    public SignatureWithIterable(Map<String, Object> internalParameters,
-        List<ColumnMetaData> columns, String sql,
-        List<AvaticaParameter> parameters, CursorFactory cursorFactory,
-        Iterable<Object> iterable) {
-      super(columns, sql, parameters, internalParameters, cursorFactory);
-      this.iterable = iterable;
+    public void remove() {
+      throw new UnsupportedOperationException("remove");
     }
 
-    public Iterable getIterable() {
-      return iterable;
+    public boolean hasNext() {
+      return rows != null;
+    }
+
+    public Object next() {
+      if (rows == null) {
+        throw new NoSuchElementException();
+      }
+      final Object o = rows.next();
+      moveNext();
+      return o;
+    }
+
+    private void moveNext() {
+      for (;;) {
+        if (rows.hasNext()) {
+          break;
+        }
+        if (frame.done) {
+          rows = null;
+          break;
+        }
+        frame = fetch(handle, parameterValues, frame.offset, 100);
+        parameterValues = null; // don't execute next time
+        if (frame == null) {
+          rows = null;
+          break;
+        }
+        // It is valid for rows to be empty, so we go around the loop again to
+        // check
+        rows = frame.rows.iterator();
+      }
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java b/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
index 07883f6..fefd5f4 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java
@@ -43,7 +43,7 @@ import java.util.logging.Logger;
  * <p>The provider must implement:</p>
  * <ul>
  *   <li>{@link Meta#prepare(org.apache.calcite.avatica.Meta.StatementHandle, String, int)}
- *   <li>{@link Meta#createIterable(org.apache.calcite.avatica.Meta.StatementHandle, org.apache.calcite.avatica.Meta.Signature, Iterable)}
+ *   <li>{@link Meta#createIterable(org.apache.calcite.avatica.Meta.StatementHandle, org.apache.calcite.avatica.Meta.Signature, java.util.List, Meta.Frame)}
  * </ul>
  */
 public abstract class UnregisteredDriver implements java.sql.Driver {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
new file mode 100644
index 0000000..56c20c4
--- /dev/null
+++ b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -0,0 +1,442 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.Meta;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/** Implementation of {@link Meta} upon an existing JDBC data source. */
+public class JdbcMeta implements Meta {
+  /**
+   * JDBC Types Mapped to Java Types
+   *
+   * @see <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/jdbc/getstart/mapping.html#1051555">JDBC Types Mapped to Java Types</a>
+   */
+  protected static final Map<Integer, Type> SQL_TYPE_TO_JAVA_TYPE =
+      new HashMap<>();
+  static {
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.CHAR, String.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.VARCHAR, String.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.LONGNVARCHAR, String.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.NUMERIC, BigDecimal.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.DECIMAL, BigDecimal.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.BIT, Boolean.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.TINYINT, Byte.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.SMALLINT, Short.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.INTEGER, Integer.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.BIGINT, Long.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.REAL, Float.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.FLOAT, Double.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.DOUBLE, Double.TYPE);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.BINARY, byte[].class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.VARBINARY, byte[].class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.LONGVARBINARY, byte[].class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.DATE, java.sql.Date.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.TIME, java.sql.Time.class);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.TIMESTAMP, java.sql.Timestamp.class);
+    //put(Types.CLOB, Clob);
+    //put(Types.BLOB, Blob);
+    SQL_TYPE_TO_JAVA_TYPE.put(Types.ARRAY, Array.class);
+  }
+
+  private final Map<Integer, StatementInfo> statementMap = new HashMap<>();
+
+  /**
+   * Convert from JDBC metadata to Avatica columns.
+   */
+  protected static List<ColumnMetaData>
+  columns(ResultSetMetaData metaData) throws SQLException {
+    final List<ColumnMetaData> columns = new ArrayList<>();
+    for (int i = 1; i <= metaData.getColumnCount(); i++) {
+      final Type javaType =
+          SQL_TYPE_TO_JAVA_TYPE.get(metaData.getColumnType(i));
+      ColumnMetaData.AvaticaType t =
+          ColumnMetaData.scalar(metaData.getColumnType(i),
+              metaData.getColumnTypeName(i), ColumnMetaData.Rep.of(javaType));
+      ColumnMetaData md =
+          new ColumnMetaData(i - 1, metaData.isAutoIncrement(i),
+              metaData.isCaseSensitive(i), metaData.isSearchable(i),
+              metaData.isCurrency(i), metaData.isNullable(i),
+              metaData.isSigned(i), metaData.getColumnDisplaySize(i),
+              metaData.getColumnLabel(i), metaData.getColumnName(i),
+              metaData.getSchemaName(i), metaData.getPrecision(i),
+              metaData.getScale(i), metaData.getTableName(i),
+              metaData.getCatalogName(i), t, metaData.isReadOnly(i),
+              metaData.isWritable(i), metaData.isDefinitelyWritable(i),
+              metaData.getColumnClassName(i));
+      columns.add(md);
+    }
+    return columns;
+  }
+
+  /**
+   * Converts from JDBC metadata to AvaticaParameters
+   */
+  protected static List<AvaticaParameter> parameters(ParameterMetaData metaData)
+      throws SQLException {
+    if (metaData == null) {
+      return Collections.emptyList();
+    }
+    final List<AvaticaParameter> params = new ArrayList<>();
+    for (int i = 1; i <= metaData.getParameterCount(); i++) {
+      params.add(
+          new AvaticaParameter(metaData.isSigned(i), metaData.getPrecision(i),
+              metaData.getScale(i), metaData.getParameterType(i),
+              metaData.getParameterTypeName(i),
+              metaData.getParameterClassName(i), "?" + i));
+    }
+    return params;
+  }
+
+  protected static Signature signature(ResultSetMetaData metaData,
+      ParameterMetaData parameterMetaData, String sql) throws  SQLException {
+    return new Signature(columns(metaData), sql, parameters(parameterMetaData),
+        null, CursorFactory.ARRAY);
+  }
+
+  protected static Signature signature(ResultSetMetaData metaData)
+      throws SQLException {
+    return signature(metaData, null, null);
+  }
+
+  protected final Connection connection;
+
+  public JdbcMeta(Connection connection) {
+    this.connection = connection;
+  }
+
+  public String getSqlKeywords() {
+    try {
+      return connection.getMetaData().getSQLKeywords();
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public String getNumericFunctions() {
+    try {
+      return connection.getMetaData().getNumericFunctions();
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public String getStringFunctions() {
+    return null;
+  }
+
+  public String getSystemFunctions() {
+    return null;
+  }
+
+  public String getTimeDateFunctions() {
+    return null;
+  }
+
+  public MetaResultSet getTables(String catalog, Pat schemaPattern,
+      Pat tableNamePattern, List<String> typeList) {
+    try {
+      String[] types = new String[typeList == null ? 0 : typeList.size()];
+      return JdbcResultSet.create(
+          connection.getMetaData().getTables(catalog, schemaPattern.s,
+              tableNamePattern.s,
+              typeList == null ? types : typeList.toArray(types)));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getColumns(String catalog, Pat schemaPattern,
+      Pat tableNamePattern, Pat columnNamePattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getColumns(catalog, schemaPattern.s,
+              tableNamePattern.s, columnNamePattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getSchemas(String catalog, Pat schemaPattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getSchemas(catalog, schemaPattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getCatalogs() {
+    try {
+      return JdbcResultSet.create(connection.getMetaData().getCatalogs());
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getTableTypes() {
+    try {
+      return JdbcResultSet.create(connection.getMetaData().getTableTypes());
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getProcedures(String catalog, Pat schemaPattern,
+      Pat procedureNamePattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getProcedures(catalog, schemaPattern.s,
+              procedureNamePattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getProcedureColumns(String catalog, Pat schemaPattern,
+      Pat procedureNamePattern, Pat columnNamePattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getProcedureColumns(catalog,
+              schemaPattern.s, procedureNamePattern.s, columnNamePattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getColumnPrivileges(String catalog, String schema,
+      String table, Pat columnNamePattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getColumnPrivileges(catalog, schema,
+              table, columnNamePattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getTablePrivileges(String catalog, Pat schemaPattern,
+      Pat tableNamePattern) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getTablePrivileges(catalog,
+              schemaPattern.s, tableNamePattern.s));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getBestRowIdentifier(String catalog, String schema,
+      String table, int scope, boolean nullable) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getBestRowIdentifier(catalog, schema,
+              table, scope, nullable));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getVersionColumns(String catalog, String schema,
+      String table) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getVersionColumns(catalog, schema, table));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getPrimaryKeys(String catalog, String schema,
+      String table) {
+    try {
+      return JdbcResultSet.create(
+          connection.getMetaData().getPrimaryKeys(catalog, schema, table));
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public MetaResultSet getImportedKeys(String catalog, String schema,
+      String table) {
+    return null;
+  }
+
+  public MetaResultSet getExportedKeys(String catalog, String schema,
+      String table) {
+    return null;
+  }
+
+  public MetaResultSet getCrossReference(String parentCatalog,
+      String parentSchema, String parentTable, String foreignCatalog,
+      String foreignSchema, String foreignTable) {
+    return null;
+  }
+
+  public MetaResultSet getTypeInfo() {
+    return null;
+  }
+
+  public MetaResultSet getIndexInfo(String catalog, String schema, String table,
+      boolean unique, boolean approximate) {
+    return null;
+  }
+
+  public MetaResultSet getUDTs(String catalog, Pat schemaPattern,
+      Pat typeNamePattern, int[] types) {
+    return null;
+  }
+
+  public MetaResultSet getSuperTypes(String catalog, Pat schemaPattern,
+      Pat typeNamePattern) {
+    return null;
+  }
+
+  public MetaResultSet getSuperTables(String catalog, Pat schemaPattern,
+      Pat tableNamePattern) {
+    return null;
+  }
+
+  public MetaResultSet getAttributes(String catalog, Pat schemaPattern,
+      Pat typeNamePattern, Pat attributeNamePattern) {
+    return null;
+  }
+
+  public MetaResultSet getClientInfoProperties() {
+    return null;
+  }
+
+  public MetaResultSet getFunctions(String catalog, Pat schemaPattern,
+      Pat functionNamePattern) {
+    return null;
+  }
+
+  public MetaResultSet getFunctionColumns(String catalog, Pat schemaPattern,
+      Pat functionNamePattern, Pat columnNamePattern) {
+    return null;
+  }
+
+  public MetaResultSet getPseudoColumns(String catalog, Pat schemaPattern,
+      Pat tableNamePattern, Pat columnNamePattern) {
+    return null;
+  }
+
+  public Iterable<Object> createIterable(StatementHandle handle,
+      Signature signature, List<Object> parameterValues, Frame firstFrame) {
+    return null;
+  }
+
+  public StatementHandle createStatement(ConnectionHandle ch) {
+    try {
+      final Statement statement = connection.createStatement();
+      final int id = statementMap.size();
+      statementMap.put(id, new StatementInfo(statement));
+      return new StatementHandle(id);
+    } catch (SQLException e) {
+      throw propagate(e);
+    }
+  }
+
+  private RuntimeException propagate(Throwable e) {
+    if (e instanceof RuntimeException) {
+      throw (RuntimeException) e;
+    } else if (e instanceof Error) {
+      throw (Error) e;
+    } else {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public Signature prepare(StatementHandle h, String sql, int maxRowCount) {
+    // TODO: can't actually prepare an existing statement...
+    try {
+      PreparedStatement statement = connection.prepareStatement(sql);
+      statementMap.put(h.id, new StatementInfo(statement));
+      return signature(statement.getMetaData(),
+          statement.getParameterMetaData(), sql);
+    } catch (SQLException e) {
+      throw propagate(e);
+    }
+  }
+
+  public MetaResultSet prepareAndExecute(StatementHandle h, String sql,
+      int maxRowCount, PrepareCallback callback) {
+    final StatementInfo statementInfo = statementMap.get(h.id);
+    try {
+      statementInfo.resultSet = statementInfo.statement.executeQuery(sql);
+      return JdbcResultSet.create(statementInfo.resultSet);
+    } catch (SQLException e) {
+      throw propagate(e);
+    }
+  }
+
+  public Frame fetch(StatementHandle h, List<Object> parameterValues,
+      int offset, int fetchMaxRowCount) {
+    final StatementInfo statementInfo = statementMap.get(h.id);
+    try {
+      if (statementInfo.resultSet == null || parameterValues != null) {
+        if (statementInfo.resultSet != null) {
+          statementInfo.resultSet.close();
+        }
+        final PreparedStatement preparedStatement =
+            (PreparedStatement) statementInfo.statement;
+        if (parameterValues != null) {
+          for (int i = 0; i < parameterValues.size(); i++) {
+            Object o = parameterValues.get(i);
+            preparedStatement.setObject(i + 1, o);
+          }
+        }
+        statementInfo.resultSet = preparedStatement.executeQuery();
+      }
+      return JdbcResultSet.frame(statementInfo.resultSet, offset,
+          fetchMaxRowCount);
+    } catch (SQLException e) {
+      throw propagate(e);
+    }
+  }
+
+  /** All we know about a statement. */
+  private static class StatementInfo {
+    final Statement statement; // sometimes a PreparedStatement
+    ResultSet resultSet;
+
+    private StatementInfo(Statement statement) {
+      this.statement = Objects.requireNonNull(statement);
+    }
+  }
+}
+
+// End JdbcMeta.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
new file mode 100644
index 0000000..ac4aeb5
--- /dev/null
+++ b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
@@ -0,0 +1,105 @@
+/*
+ * 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.jdbc;
+
+import org.apache.calcite.avatica.Meta;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Implementation of {@link org.apache.calcite.avatica.Meta.MetaResultSet}
+ *  upon a JDBC {@link java.sql.ResultSet}.
+ *
+ *  @see org.apache.calcite.avatica.jdbc.JdbcMeta */
+class JdbcResultSet extends Meta.MetaResultSet {
+  protected JdbcResultSet(int statementId, boolean ownStatement,
+      Meta.Signature signature, Meta.Frame firstFrame) {
+    super(statementId, ownStatement, signature, firstFrame);
+  }
+
+  /** Creates a result set. */
+  public static JdbcResultSet create(ResultSet resultSet) {
+    try {
+      int id = resultSet.getStatement().hashCode();
+      Meta.Signature sig = JdbcMeta.signature(resultSet.getMetaData());
+      final Meta.Frame firstFrame = frame(resultSet, 0, -1);
+      resultSet.close();
+      return new JdbcResultSet(id, true, sig, firstFrame);
+    } catch (SQLException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /** Creates a frame containing a given number or unlimited number of rows
+   * from a result set. */
+  static Meta.Frame frame(ResultSet resultSet, int offset,
+      int fetchMaxRowCount) throws SQLException {
+    final ResultSetMetaData metaData = resultSet.getMetaData();
+    final int columnCount = metaData.getColumnCount();
+    final int[] types = new int[columnCount];
+    for (int i = 0; i < types.length; i++) {
+      types[i] = metaData.getColumnType(i + 1);
+    }
+    final List<Object> rows = new ArrayList<>();
+    boolean done = false;
+    for (int i = 0; fetchMaxRowCount < 0 || i < fetchMaxRowCount; i++) {
+      if (!resultSet.next()) {
+        done = true;
+        break;
+      }
+      Object[] columns = new Object[columnCount];
+      for (int j = 0; j < columnCount; j++) {
+        columns[j] = getValue(resultSet, types[j], j);
+      }
+      rows.add(columns);
+    }
+    return new Meta.Frame(offset, done, rows);
+  }
+
+  private static Object getValue(ResultSet resultSet, int type, int j)
+      throws SQLException {
+    switch (type) {
+    case Types.BIGINT:
+      final long aLong = resultSet.getLong(j + 1);
+      return aLong == 0 && resultSet.wasNull() ? null : aLong;
+    case Types.INTEGER:
+      final int anInt = resultSet.getInt(j + 1);
+      return anInt == 0 && resultSet.wasNull() ? null : anInt;
+    case Types.SMALLINT:
+      final short aShort = resultSet.getShort(j + 1);
+      return aShort == 0 && resultSet.wasNull() ? null : aShort;
+    case Types.TINYINT:
+      final byte aByte = resultSet.getByte(j + 1);
+      return aByte == 0 && resultSet.wasNull() ? null : aByte;
+    case Types.DOUBLE:
+    case Types.FLOAT:
+      final double aDouble = resultSet.getDouble(j + 1);
+      return aDouble == 0D && resultSet.wasNull() ? null : aDouble;
+    case Types.REAL:
+      final float aFloat = resultSet.getFloat(j + 1);
+      return aFloat == 0D && resultSet.wasNull() ? null : aFloat;
+    default:
+      return resultSet.getObject(j + 1);
+    }
+  }
+}
+
+// End JdbcResultSet.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java
new file mode 100644
index 0000000..8b8fb76
--- /dev/null
+++ b/avatica/src/main/java/org/apache/calcite/avatica/jdbc/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/** Implements an Avatica provider on top of an existing JDBC data source. */
+package org.apache.calcite.avatica.jdbc;
+
+
+// End package-info.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
index 3de4ef0..7e110ff 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonService.java
@@ -41,11 +41,14 @@ public abstract class JsonService implements Service {
    * responses to and from the peer service. */
   public abstract String apply(String request);
 
-  private <T> T decode(String response, Class<T> valueType) throws IOException {
+  //@VisibleForTesting
+  protected static <T> T decode(String response, Class<T> valueType)
+      throws IOException {
     return MAPPER.readValue(response, valueType);
   }
 
-  private <T> String encode(T request) throws IOException {
+  //@VisibleForTesting
+  protected static <T> String encode(T request) throws IOException {
     final StringWriter w = new StringWriter();
     MAPPER.writeValue(w, request);
     return w.toString();
@@ -71,6 +74,14 @@ public abstract class JsonService implements Service {
     }
   }
 
+  public ResultSetResponse apply(TablesRequest request) {
+    try {
+      return decode(apply(encode(request)), ResultSetResponse.class);
+    } catch (IOException e) {
+      throw handle(e);
+    }
+  }
+
   public PrepareResponse apply(PrepareRequest request) {
     try {
       return decode(apply(encode(request)), PrepareResponse.class);
@@ -87,6 +98,14 @@ public abstract class JsonService implements Service {
     }
   }
 
+  public FetchResponse apply(FetchRequest request) {
+    try {
+      return decode(apply(encode(request)), FetchResponse.class);
+    } catch (IOException e) {
+      throw handle(e);
+    }
+  }
+
   public CreateStatementResponse apply(CreateStatementRequest request) {
     try {
       return decode(apply(encode(request)), CreateStatementResponse.class);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 5ee3d16..faf60b8 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
@@ -16,10 +16,13 @@
  */
 package org.apache.calcite.avatica.remote;
 
+import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.MetaImpl;
 
+import java.sql.Types;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -27,6 +30,8 @@ import java.util.List;
  */
 public class LocalService implements Service {
   final Meta meta;
+  /** Whether output is going to JSON. */
+  private final boolean json = true;
 
   public LocalService(Meta meta) {
     this.meta = meta;
@@ -47,8 +52,8 @@ public class LocalService implements Service {
   public ResultSetResponse toResponse(Meta.MetaResultSet resultSet) {
     Meta.CursorFactory cursorFactory = resultSet.signature.cursorFactory;
     final List<Object> list;
-    if (resultSet.iterable != null) {
-      list = list(resultSet.iterable);
+    if (resultSet.firstFrame != null) {
+      list = list(resultSet.firstFrame.rows);
       switch (cursorFactory.style) {
       case ARRAY:
         cursorFactory = Meta.CursorFactory.LIST;
@@ -68,16 +73,16 @@ public class LocalService implements Service {
       signature = signature.setCursorFactory(cursorFactory);
     }
     return new ResultSetResponse(resultSet.statementId, resultSet.ownStatement,
-        signature, list);
+        signature, new Meta.Frame(0, true, list));
   }
 
   private List<List<Object>> list2(Meta.MetaResultSet resultSet) {
-    List<List<Object>> list = new ArrayList<List<Object>>();
-    return MetaImpl.collect(resultSet.signature.cursorFactory,
-        meta.createIterable(new Meta.StatementHandle(resultSet.statementId),
-            resultSet.signature,
-            resultSet.iterable),
-        list);
+    final Meta.StatementHandle h =
+        new Meta.StatementHandle(resultSet.statementId);
+    final Iterable<Object> iterable = meta.createIterable(h,
+        resultSet.signature, Collections.emptyList(), resultSet.firstFrame);
+    final List<List<Object>> list = new ArrayList<>();
+    return MetaImpl.collect(resultSet.signature.cursorFactory, iterable, list);
   }
 
   public ResultSetResponse apply(CatalogsRequest request) {
@@ -91,11 +96,43 @@ public class LocalService implements Service {
     return toResponse(resultSet);
   }
 
+  public ResultSetResponse apply(TablesRequest request) {
+    final Meta.MetaResultSet resultSet =
+        meta.getTables(request.catalog, Meta.Pat.of(request.schemaPattern),
+            Meta.Pat.of(request.tableNamePattern), request.typeList);
+    return toResponse(resultSet);
+  }
+
   public PrepareResponse apply(PrepareRequest request) {
     final Meta.StatementHandle h =
         new Meta.StatementHandle(request.statementId);
-    final Meta.Signature signature =
-        meta.prepare(h, request.sql, request.maxRowCount);
+    Meta.Signature signature =
+        meta.prepare(h, request.sql, request.maxRowCount)
+            .setCursorFactory(Meta.CursorFactory.LIST);
+    if (json) {
+      final List<ColumnMetaData> columns = new ArrayList<>();
+      for (ColumnMetaData column : signature.columns) {
+        switch (column.type.rep) {
+        case BYTE:
+        case PRIMITIVE_BYTE:
+        case DOUBLE:
+        case PRIMITIVE_DOUBLE:
+        case FLOAT:
+        case PRIMITIVE_FLOAT:
+        case INTEGER:
+        case PRIMITIVE_INT:
+        case SHORT:
+        case PRIMITIVE_SHORT:
+        case LONG:
+        case PRIMITIVE_LONG:
+          column = column.setTypeId(Types.NUMERIC);
+        }
+        columns.add(column);
+      }
+      signature = new Meta.Signature(columns, signature.sql,
+          signature.parameters, signature.internalParameters,
+          signature.cursorFactory);
+    }
     return new PrepareResponse(signature);
   }
 
@@ -105,20 +142,29 @@ public class LocalService implements Service {
     final Meta.MetaResultSet resultSet =
         meta.prepareAndExecute(h, request.sql, request.maxRowCount,
             new Meta.PrepareCallback() {
-              public Object getMonitor() {
+              @Override public Object getMonitor() {
                 return LocalService.class;
               }
 
-              public void clear() {}
+              @Override public void clear() {}
 
-              public void assign(Meta.Signature signature,
-                  Iterable<Object> iterable) {}
+              @Override public void assign(Meta.Signature signature,
+                  Meta.Frame firstFrame) {}
 
-              public void execute() {}
+              @Override public void execute() {}
             });
     return toResponse(resultSet);
   }
 
+  public FetchResponse apply(FetchRequest request) {
+    final Meta.StatementHandle h =
+        new Meta.StatementHandle(request.statementId);
+    final Meta.Frame frame =
+        meta.fetch(h, request.parameterValues, request.offset,
+            request.fetchMaxRowCount);
+    return new FetchResponse(frame);
+  }
+
   public CreateStatementResponse apply(CreateStatementRequest request) {
     final Meta.StatementHandle h =
         meta.createStatement(new Meta.ConnectionHandle(request.connectionId));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockJsonService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockJsonService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockJsonService.java
index 7fe7ea8..19e59e3 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockJsonService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockJsonService.java
@@ -18,6 +18,8 @@ package org.apache.calcite.avatica.remote;
 
 import org.apache.calcite.avatica.AvaticaConnection;
 
+import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -44,10 +46,44 @@ public class MockJsonService extends JsonService {
   /** Factory that creates a {@code MockJsonService}. */
   public static class Factory implements Service.Factory {
     public Service create(AvaticaConnection connection) {
-      final Map<String, String> map1 = new HashMap<String, String>();
-      map1.put(
-          "{\"request\":\"getSchemas\",\"catalog\":null,\"schemaPattern\":{\"s\":null}}",
-          "{\"response\":\"resultSet\", rows: []}");
+      final Map<String, String> map1 = new HashMap<>();
+      try {
+        map1.put(
+            "{\"request\":\"getSchemas\",\"catalog\":null,\"schemaPattern\":{\"s\":null}}",
+            "{\"response\":\"resultSet\", firstFrame: {offset: 0, done: true, rows: []}}");
+        map1.put(
+            JsonService.encode(new SchemasRequest(null, null)),
+            "{\"response\":\"resultSet\", firstFrame: {offset: 0, done: true, rows: []}}");
+        map1.put(
+            JsonService.encode(
+                new TablesRequest(null, null, null, Arrays.<String>asList())),
+            "{\"response\":\"resultSet\", firstFrame: {offset: 0, done: true, rows: []}}");
+        map1.put(
+            "{\"request\":\"createStatement\",\"connectionId\":0}",
+            "{\"response\":\"createStatement\",\"id\":0}");
+        map1.put(
+            "{\"request\":\"prepareAndExecute\",\"statementId\":0,"
+                + "\"sql\":\"select * from (\\n  values (1, 'a'), (null, 'b'), (3, 'c')) as t (c1, c2)\",\"maxRowCount\":-1}",
+            "{\"response\":\"resultSet\",\"signature\": {\n"
+                + " \"columns\": [\n"
+                + "   {\"columnName\": \"C1\", \"type\": {type: \"scalar\", id: 4, rep: \"INTEGER\"}},\n"
+                + "   {\"columnName\": \"C2\", \"type\": {type: \"scalar\", id: 12, rep: \"STRING\"}}\n"
+                + " ], \"cursorFactory\": {\"style\": \"ARRAY\"}\n"
+                + "}, \"rows\": [[1, \"a\"], [null, \"b\"], [3, \"c\"]]}");
+        map1.put(
+            "{\"request\":\"prepare\",\"statementId\":0,"
+                + "\"sql\":\"select * from (\\n  values (1, 'a'), (null, 'b'), (3, 'c')) as t (c1, c2)\",\"maxRowCount\":-1}",
+            "{\"response\":\"prepare\",\"signature\": {\n"
+                + " \"columns\": [\n"
+                + "   {\"columnName\": \"C1\", \"type\": {type: \"scalar\", id: 4, rep: \"INTEGER\"}},\n"
+                + "   {\"columnName\": \"C2\", \"type\": {type: \"scalar\", id: 12, rep: \"STRING\"}}\n"
+                + " ],\n"
+                + " \"parameters\": [],\n"
+                + " \"cursorFactory\": {\"style\": \"ARRAY\"}\n"
+                + "}}");
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
       return new MockJsonService(map1);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 89ef490..83dd28c 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
@@ -17,10 +17,14 @@
 package org.apache.calcite.avatica.remote;
 
 import org.apache.calcite.avatica.AvaticaConnection;
+import org.apache.calcite.avatica.AvaticaParameter;
+import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.MetaImpl;
 
 import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Implementation of {@link Meta} for the remote driver.
@@ -33,10 +37,19 @@ class RemoteMeta extends MetaImpl {
     this.service = service;
   }
 
-  private MetaResultSet toResultSet(Service.ResultSetResponse response) {
-    final Signature signature0 = response.signature;
+  private MetaResultSet toResultSet(Class clazz,
+      Service.ResultSetResponse response) {
+    Signature signature0 = response.signature;
+    if (signature0 == null) {
+      final List<ColumnMetaData> columns =
+          clazz == null
+              ? Collections.<ColumnMetaData>emptyList()
+              : fieldMetaData(clazz).columns;
+      signature0 = Signature.create(columns,
+          "?", Collections.<AvaticaParameter>emptyList(), CursorFactory.ARRAY);
+    }
     return new MetaResultSet(response.statementId, response.ownStatement,
-        signature0, response.rows);
+        signature0, response.firstFrame);
   }
 
   @Override public StatementHandle createStatement(ConnectionHandle ch) {
@@ -48,13 +61,22 @@ class RemoteMeta extends MetaImpl {
   @Override public MetaResultSet getCatalogs() {
     final Service.ResultSetResponse response =
         service.apply(new Service.CatalogsRequest());
-    return toResultSet(response);
+    return toResultSet(MetaCatalog.class, response);
   }
 
   @Override public MetaResultSet getSchemas(String catalog, Pat schemaPattern) {
     final Service.ResultSetResponse response =
         service.apply(new Service.SchemasRequest(catalog, schemaPattern.s));
-    return toResultSet(response);
+    return toResultSet(MetaSchema.class, response);
+  }
+
+  @Override public MetaResultSet getTables(String catalog, Pat schemaPattern,
+      Pat tableNamePattern, List<String> typeList) {
+    final Service.ResultSetResponse response =
+        service.apply(
+            new Service.TablesRequest(catalog, schemaPattern.s,
+                tableNamePattern.s, typeList));
+    return toResultSet(MetaTable.class, response);
   }
 
   @Override public Signature prepare(StatementHandle h, String sql,
@@ -72,14 +94,23 @@ class RemoteMeta extends MetaImpl {
         callback.clear();
         response = service.apply(
             new Service.PrepareAndExecuteRequest(h.id, sql, maxRowCount));
-        callback.assign(response.signature, response.rows);
+        callback.assign(response.signature, response.firstFrame);
       }
       callback.execute();
-      return toResultSet(response);
+      return toResultSet(null, response);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
   }
+
+  @Override public Frame fetch(StatementHandle h, List<Object> parameterValues,
+      int offset, int fetchMaxRowCount) {
+    final Service.FetchResponse response =
+        service.apply(
+            new Service.FetchRequest(h.id, parameterValues, offset,
+                fetchMaxRowCount));
+    return response.frame;
+  }
 }
 
 // End RemoteMeta.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/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 cad38dd..cf73b49 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
@@ -32,8 +32,10 @@ import java.util.List;
 public interface Service {
   ResultSetResponse apply(CatalogsRequest request);
   ResultSetResponse apply(SchemasRequest request);
+  ResultSetResponse apply(TablesRequest request);
   PrepareResponse apply(PrepareRequest request);
   ResultSetResponse apply(PrepareAndExecuteRequest request);
+  FetchResponse apply(FetchRequest request);
   CreateStatementResponse apply(CreateStatementRequest request);
 
   /** Factory that creates a {@code Service}. */
@@ -49,9 +51,11 @@ public interface Service {
   @JsonSubTypes({
       @JsonSubTypes.Type(value = CatalogsRequest.class, name = "getCatalogs"),
       @JsonSubTypes.Type(value = SchemasRequest.class, name = "getSchemas"),
+      @JsonSubTypes.Type(value = TablesRequest.class, name = "getTables"),
       @JsonSubTypes.Type(value = PrepareRequest.class, name = "prepare"),
       @JsonSubTypes.Type(value = PrepareAndExecuteRequest.class,
           name = "prepareAndExecute"),
+      @JsonSubTypes.Type(value = FetchRequest.class, name = "fetch"),
       @JsonSubTypes.Type(value = CreateStatementRequest.class,
           name = "createStatement") })
   abstract class Request {
@@ -66,6 +70,7 @@ public interface Service {
   @JsonSubTypes({
       @JsonSubTypes.Type(value = ResultSetResponse.class, name = "resultSet"),
       @JsonSubTypes.Type(value = PrepareResponse.class, name = "prepare"),
+      @JsonSubTypes.Type(value = FetchResponse.class, name = "fetch"),
       @JsonSubTypes.Type(value = CreateStatementResponse.class,
           name = "createStatement") })
   abstract class Response {
@@ -97,6 +102,31 @@ public interface Service {
     }
   }
 
+  /** Request for
+   * {@link Meta#getTables(String, org.apache.calcite.avatica.Meta.Pat, org.apache.calcite.avatica.Meta.Pat, java.util.List)}
+   */
+  class TablesRequest extends Request {
+    public final String catalog;
+    public final String schemaPattern;
+    public final String tableNamePattern;
+    public final List<String> typeList;
+
+    @JsonCreator
+    public TablesRequest(@JsonProperty("catalog") String catalog,
+        @JsonProperty("schemaPattern") String schemaPattern,
+        @JsonProperty("tableNamePattern") String tableNamePattern,
+        @JsonProperty("typeList") List<String> typeList) {
+      this.catalog = catalog;
+      this.schemaPattern = schemaPattern;
+      this.tableNamePattern = tableNamePattern;
+      this.typeList = typeList;
+    }
+
+    @Override Response accept(Service service) {
+      return service.apply(this);
+    }
+  }
+
   /** Response that contains a result set.
    *
    * <p>Several types of request, including
@@ -107,17 +137,17 @@ public interface Service {
     public final int statementId;
     public final boolean ownStatement;
     public final Meta.Signature signature;
-    public final List<Object> rows;
+    public final Meta.Frame firstFrame;
 
     @JsonCreator
     public ResultSetResponse(@JsonProperty("statementId") int statementId,
         @JsonProperty("ownStatement") boolean ownStatement,
         @JsonProperty("signature") Meta.Signature signature,
-        @JsonProperty("rows") List<Object> rows) {
+        @JsonProperty("firstFrame") Meta.Frame firstFrame) {
       this.statementId = statementId;
       this.ownStatement = ownStatement;
       this.signature = signature;
-      this.rows = rows;
+      this.firstFrame = firstFrame;
     }
   }
 
@@ -177,6 +207,45 @@ public interface Service {
   }
 
   /** Request for
+   * {@link org.apache.calcite.avatica.Meta#fetch(Meta.StatementHandle, List, int, int)}. */
+  class FetchRequest extends Request {
+    public final int statementId;
+    public final int offset;
+    /** Maximum number of rows to be returned in the frame. Negative means no
+     * limit. */
+    public final int fetchMaxRowCount;
+    /** A list of parameter values, if statement is to be executed; otherwise
+     * null. */
+    public final List<Object> parameterValues;
+
+    @JsonCreator
+    public FetchRequest(@JsonProperty("statementId") int statementId,
+        @JsonProperty("parameterValues") List<Object> parameterValues,
+        @JsonProperty("offset") int offset,
+        @JsonProperty("fetchMaxRowCount") int fetchMaxRowCount) {
+      this.statementId = statementId;
+      this.parameterValues = parameterValues;
+      this.offset = offset;
+      this.fetchMaxRowCount = fetchMaxRowCount;
+    }
+
+    @Override FetchResponse accept(Service service) {
+      return service.apply(this);
+    }
+  }
+
+  /** Response from
+   * {@link org.apache.calcite.avatica.remote.Service.FetchRequest}. */
+  class FetchResponse extends Response {
+    public final Meta.Frame frame;
+
+    @JsonCreator
+    public FetchResponse(@JsonProperty("frame") Meta.Frame frame) {
+      this.frame = frame;
+    }
+  }
+
+  /** Request for
    * {@link org.apache.calcite.avatica.Meta#createStatement(org.apache.calcite.avatica.Meta.ConnectionHandle)}. */
   class CreateStatementRequest extends Request {
     public final int connectionId;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
index 301352f..42731ba 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -22,6 +22,7 @@ import org.apache.calcite.avatica.ColumnMetaData;
 import java.io.InputStream;
 import java.io.Reader;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.net.URL;
 import java.sql.Array;
@@ -71,12 +72,12 @@ public abstract class AbstractCursor implements Cursor {
     return accessors;
   }
 
-  protected Accessor createAccessor(ColumnMetaData type, int ordinal,
+  protected Accessor createAccessor(ColumnMetaData columnMetaData, int ordinal,
       Calendar localCalendar, ArrayImpl.Factory factory) {
     // Create an accessor appropriate to the underlying type; the accessor
     // can convert to any type in the same family.
     Getter getter = createGetter(ordinal);
-    switch (type.type.type) {
+    switch (columnMetaData.type.id) {
     case Types.TINYINT:
       return new ByteAccessor(getter);
     case Types.SMALLINT:
@@ -92,15 +93,17 @@ public abstract class AbstractCursor implements Cursor {
       return new FloatAccessor(getter);
     case Types.DOUBLE:
       return new DoubleAccessor(getter);
+    case Types.NUMERIC:
+      return new NumberAccessor(getter);
     case Types.DECIMAL:
       return new BigDecimalAccessor(getter);
     case Types.CHAR:
-      switch (type.type.representation) {
+      switch (columnMetaData.type.rep) {
       case PRIMITIVE_CHAR:
       case CHARACTER:
-        return new StringFromCharAccessor(getter, type.displaySize);
+        return new StringFromCharAccessor(getter, columnMetaData.displaySize);
       default:
-        return new FixedStringAccessor(getter, type.displaySize);
+        return new FixedStringAccessor(getter, columnMetaData.displaySize);
       }
     case Types.VARCHAR:
       return new StringAccessor(getter);
@@ -108,27 +111,27 @@ public abstract class AbstractCursor implements Cursor {
     case Types.VARBINARY:
       return new BinaryAccessor(getter);
     case Types.DATE:
-      switch (type.type.representation) {
+      switch (columnMetaData.type.rep) {
       case PRIMITIVE_INT:
       case INTEGER:
         return new DateFromIntAccessor(getter, localCalendar);
       case JAVA_SQL_DATE:
         return new DateAccessor(getter, localCalendar);
       default:
-        throw new AssertionError("bad " + type.type.representation);
+        throw new AssertionError("bad " + columnMetaData.type.rep);
       }
     case Types.TIME:
-      switch (type.type.representation) {
+      switch (columnMetaData.type.rep) {
       case PRIMITIVE_INT:
       case INTEGER:
         return new TimeFromIntAccessor(getter, localCalendar);
       case JAVA_SQL_TIME:
         return new TimeAccessor(getter, localCalendar);
       default:
-        throw new AssertionError("bad " + type.type.representation);
+        throw new AssertionError("bad " + columnMetaData.type.rep);
       }
     case Types.TIMESTAMP:
-      switch (type.type.representation) {
+      switch (columnMetaData.type.rep) {
       case PRIMITIVE_LONG:
       case LONG:
         return new TimestampFromLongAccessor(getter, localCalendar);
@@ -137,31 +140,32 @@ public abstract class AbstractCursor implements Cursor {
       case JAVA_UTIL_DATE:
         return new TimestampFromUtilDateAccessor(getter, localCalendar);
       default:
-        throw new AssertionError("bad " + type.type.representation);
+        throw new AssertionError("bad " + columnMetaData.type.rep);
       }
     case Types.ARRAY:
       return new ArrayAccessor(getter,
-          ((ColumnMetaData.ArrayType) type.type).component, factory);
+          ((ColumnMetaData.ArrayType) columnMetaData.type).component, factory);
     case Types.JAVA_OBJECT:
     case Types.STRUCT:
     case Types.OTHER: // e.g. map
-      if (type.type.typeName.startsWith("INTERVAL_")) {
-        int end = type.type.typeName.indexOf("(");
+      if (columnMetaData.type.name.startsWith("INTERVAL_")) {
+        int end = columnMetaData.type.name.indexOf("(");
         if (end < 0) {
-          end = type.type.typeName.length();
+          end = columnMetaData.type.name.length();
         }
         TimeUnitRange range =
             TimeUnitRange.valueOf(
-                type.type.typeName.substring("INTERVAL_".length(), end));
+                columnMetaData.type.name.substring("INTERVAL_".length(), end));
         if (range.monthly()) {
           return new IntervalYearMonthAccessor(getter, range);
         } else {
-          return new IntervalDayTimeAccessor(getter, range, type.scale);
+          return new IntervalDayTimeAccessor(getter, range,
+              columnMetaData.scale);
         }
       }
       return new ObjectAccessor(getter);
     default:
-      throw new RuntimeException("unknown type " + type.type.type);
+      throw new RuntimeException("unknown type " + columnMetaData.type.id);
     }
   }
 
@@ -617,6 +621,41 @@ public abstract class AbstractCursor implements Cursor {
   }
 
   /**
+   * Accessor that assumes that the underlying value is a {@link Number};
+   * corresponds to {@link java.sql.Types#NUMERIC}.
+   *
+   * <p>This is useful when numbers have been translated over JSON. JSON
+   * converts a 0L (0 long) value to the string "0" and back to 0 (0 int).
+   * So you cannot be sure that the source and target type are the same.
+   */
+  private static class NumberAccessor extends BigNumberAccessor {
+    public NumberAccessor(Getter getter) {
+      super(getter);
+    }
+
+    protected Number getNumber() {
+      return (Number) getObject();
+    }
+
+    public BigDecimal getBigDecimal(int scale) {
+      return getBigDecimal();
+    }
+
+    public BigDecimal getBigDecimal() {
+      Number n = getNumber();
+      return n == null ? null
+          : n instanceof BigDecimal ? (BigDecimal) n
+          : n instanceof BigInteger ? new BigDecimal((BigInteger) n)
+          : n instanceof Long ? new BigDecimal((long) n)
+          : n instanceof Integer ? new BigDecimal((int) n)
+          : n instanceof Short ? new BigDecimal((short) n)
+          : n instanceof Byte ? new BigDecimal((byte) n)
+          : n instanceof Double ? new BigDecimal((double) n)
+          : new BigDecimal((float) n);
+    }
+  }
+
+  /**
    * Accessor that assumes that the underlying value is a {@link String};
    * corresponds to {@link java.sql.Types#CHAR}
    * and {@link java.sql.Types#VARCHAR}.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/4d2f647a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java
index e953e6a..385f733 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java
@@ -39,11 +39,11 @@ public class ArrayImpl implements Array {
   }
 
   public String getBaseTypeName() throws SQLException {
-    return elementType.typeName;
+    return elementType.name;
   }
 
   public int getBaseType() throws SQLException {
-    return elementType.type;
+    return elementType.id;
   }
 
   public Object getArray() throws SQLException {
@@ -65,7 +65,7 @@ public class ArrayImpl implements Array {
   @SuppressWarnings("unchecked")
   protected Object getArray(List list) throws SQLException {
     int i = 0;
-    switch (elementType.representation) {
+    switch (elementType.rep) {
     case PRIMITIVE_DOUBLE:
       final double[] doubles = new double[list.size()];
       for (double v : (List<Double>) list) {
@@ -118,7 +118,7 @@ public class ArrayImpl implements Array {
       // fall through
     }
     final Object[] objects = list.toArray();
-    switch (elementType.type) {
+    switch (elementType.id) {
     case Types.ARRAY:
       final ColumnMetaData.ArrayType arrayType =
           (ColumnMetaData.ArrayType) elementType;


[8/9] incubator-calcite git commit: [CALCITE-592] Upgrade to Guava 14.0.1

Posted by jh...@apache.org.
[CALCITE-592] Upgrade to Guava 14.0.1


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

Branch: refs/heads/master
Commit: 0fe2637d66d3c263d507fc2ef98366238707dfea
Parents: 76a0665
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Mar 23 02:18:37 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 02:18:37 2015 -0700

----------------------------------------------------------------------
 core/pom.xml | 4 ++++
 pom.xml      | 9 +++++++--
 2 files changed, 11 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0fe2637d/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 34059f7..5533984 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -60,6 +60,10 @@ limitations under the License.
       <artifactId>jackson-databind</artifactId>
     </dependency>
     <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+    </dependency>
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/0fe2637d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 683f173..f870774 100644
--- a/pom.xml
+++ b/pom.xml
@@ -124,11 +124,16 @@ limitations under the License.
         <version>2.1.1</version>
       </dependency>
       <dependency>
+        <groupId>com.google.code.findbugs</groupId>
+        <artifactId>jsr305</artifactId>
+        <version>1.3.9</version>
+      </dependency>
+      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
-        <!-- We support versions as old as 11.0.2 (the version used by Hadoop)
+        <!-- We support versions as old as 14.0.1 (the version used by Hive)
              but prefer more recent versions. -->
-        <version>11.0.2</version>
+        <version>14.0.1</version>
       </dependency>
       <dependency>
         <groupId>junit</groupId>


[5/9] incubator-calcite git commit: [CALCITE-630] Flesh out AvaticaParameter#setObject (Nick Dimiduk)

Posted by jh...@apache.org.
[CALCITE-630] Flesh out AvaticaParameter#setObject (Nick Dimiduk)

Close apache/incubator-calcite#62


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

Branch: refs/heads/master
Commit: 8b9a57768fdd429b849fc1add1057a8b6399e15e
Parents: fe13dd3
Author: Julian Hyde <jh...@apache.org>
Authored: Sun Mar 22 23:00:53 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Mar 23 01:45:01 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/AvaticaParameter.java       | 228 +++++++++++++++++++
 1 file changed, 228 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/8b9a5776/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
index 03fa4dc..c2c0992 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaParameter.java
@@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 import java.io.InputStream;
 import java.io.Reader;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.net.URL;
 import java.sql.Array;
 import java.sql.Blob;
@@ -35,6 +36,7 @@ import java.sql.RowId;
 import java.sql.SQLXML;
 import java.sql.Time;
 import java.sql.Timestamp;
+import java.sql.Types;
 import java.util.Calendar;
 
 /**
@@ -210,6 +212,99 @@ public class AvaticaParameter {
 
   public void setObject(Object[] slots, int index, Object x,
       int targetSqlType) {
+    if (x == null || Types.NULL == targetSqlType) {
+      setNull(slots, index, targetSqlType);
+      return;
+    }
+    switch (targetSqlType) {
+    case Types.CLOB:
+    case Types.DATALINK:
+    case Types.NCLOB:
+    case Types.OTHER:
+    case Types.REF:
+    case Types.SQLXML:
+    case Types.STRUCT:
+      throw notImplemented();
+    case Types.ARRAY:
+      setArray(slots, index, toArray(x));
+      break;
+    case Types.BIGINT:
+      setLong(slots, index, toLong(x));
+      break;
+    case Types.BINARY:
+    case Types.LONGVARBINARY:
+    case Types.VARBINARY:
+      setBytes(slots, index, toBytes(x));
+      break;
+    case Types.BIT:
+    case Types.BOOLEAN:
+      setBoolean(slots, index, toBoolean(x));
+      break;
+    case Types.BLOB:
+      if (x instanceof Blob) {
+        setBlob(slots, index, (Blob) x);
+        break;
+      } else if (x instanceof InputStream) {
+        setBlob(slots, index, (InputStream) x);
+      }
+      throw unsupportedCast(x.getClass(), Blob.class);
+    case Types.CHAR:
+    case Types.NCHAR:
+      String s = toString(x);
+      if (s.length() == 1) {
+        setChar(slots, index, s.charAt(0));
+        break;
+      }
+      throw unsupportedCast(x.getClass(), Character.TYPE);
+    case Types.DATE:
+      setDate(slots, index, toDate(x));
+      break;
+    case Types.DECIMAL:
+    case Types.NUMERIC:
+      setBigDecimal(slots, index, toBigDecimal(x));
+      break;
+    case Types.DISTINCT:
+      throw notImplemented();
+    case Types.DOUBLE:
+    case Types.FLOAT:
+      setDouble(slots, index, toDouble(x));
+      break;
+    case Types.INTEGER:
+      setInt(slots, index, toInt(x));
+      break;
+    case Types.JAVA_OBJECT:
+      setObject(slots, index, x);
+      break;
+    case Types.LONGNVARCHAR:
+    case Types.LONGVARCHAR:
+    case Types.NVARCHAR:
+    case Types.VARCHAR:
+      setString(slots, index, toString(x));
+      break;
+    case Types.REAL:
+      setFloat(slots, index, toFloat(x));
+      break;
+    case Types.ROWID:
+      if (x instanceof RowId) {
+        setRowId(slots, index, (RowId) x);
+        break;
+      }
+      throw unsupportedCast(x.getClass(), RowId.class);
+    case Types.SMALLINT:
+      setShort(slots, index, toShort(x));
+      break;
+    case Types.TIME:
+      setTime(slots, index, toTime(x));
+      break;
+    case Types.TIMESTAMP:
+      setTimestamp(slots, index, toTimestamp(x));
+      break;
+    case Types.TINYINT:
+      setByte(slots, index, toByte(x));
+      break;
+    default:
+      throw notImplemented();
+    }
   }
 
   public void setObject(Object[] slots, int index, Object x) {
@@ -249,6 +344,139 @@ public class AvaticaParameter {
       int scaleOrLength) {
   }
 
+  private static RuntimeException unsupportedCast(Class<?> from, Class<?> to) {
+    return new UnsupportedOperationException("Cannot convert from "
+        + from.getCanonicalName() + " to " + to.getCanonicalName());
+  }
+
+  private static RuntimeException notImplemented() {
+    return new RuntimeException("not implemented");
+  }
+
+  private static Array toArray(Object x) {
+    if (x instanceof Array) {
+      return (Array) x;
+    }
+    throw unsupportedCast(x.getClass(), Array.class);
+  }
+
+  private static BigDecimal toBigDecimal(Object x) {
+    if (x instanceof BigDecimal) {
+      return (BigDecimal) x;
+    } else if (x instanceof BigInteger) {
+      return new BigDecimal((BigInteger) x);
+    } else if (x instanceof Number) {
+      return new BigDecimal(x.toString());
+    } else if (x instanceof String) {
+      return new BigDecimal((String) x);
+    }
+    throw unsupportedCast(x.getClass(), BigDecimal.class);
+  }
+
+  private static boolean toBoolean(Object x) {
+    if (x instanceof Boolean) {
+      return (Boolean) x;
+    } else if (x instanceof Number) {
+      return ((Number) x).intValue() != 0;
+    } else if (x instanceof String) {
+      String s = (String) x;
+      if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) {
+        return true;
+      } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) {
+        return false;
+      }
+    }
+    throw unsupportedCast(x.getClass(), Boolean.TYPE);
+  }
+
+  private static byte toByte(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).byteValue();
+    } else if (x instanceof String) {
+      return Byte.parseByte((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Byte.TYPE);
+    }
+  }
+
+  private static byte[] toBytes(Object x) {
+    if (x instanceof byte[]) {
+      return (byte[]) x;
+    }
+    throw unsupportedCast(x.getClass(), byte[].class);
+  }
+
+  private static Date toDate(Object x) {
+    return new Date(toLong(x));
+  }
+
+  private static double toDouble(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).doubleValue();
+    } else if (x instanceof String) {
+      return Double.parseDouble((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Double.TYPE);
+    }
+  }
+
+  private static float toFloat(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).floatValue();
+    } else if (x instanceof String) {
+      return Float.parseFloat((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Float.TYPE);
+    }
+  }
+
+  private static int toInt(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).intValue();
+    } else if (x instanceof String) {
+      return Integer.parseInt((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Integer.TYPE);
+    }
+  }
+
+  private static long toLong(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).longValue();
+    } else if (x instanceof String) {
+      return Long.parseLong((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Long.TYPE);
+    }
+  }
+
+  private static short toShort(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).shortValue();
+    } else if (x instanceof String) {
+      return Short.parseShort((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Short.TYPE);
+    }
+  }
+
+  private static String toString(Object x) {
+    if (x instanceof String) {
+      return (String) x;
+    } else if (x instanceof Character) {
+      return x.toString();
+    }
+    throw unsupportedCast(x.getClass(), String.class);
+  }
+
+  private static Time toTime(Object x) {
+    return new Time(toLong(x));
+  }
+
+  private static Timestamp toTimestamp(Object x) {
+    return new Timestamp(toLong(x));
+  }
+
   /** Singleton value to denote parameters that have been set to null (as
    * opposed to not set).
    *