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/10/26 23:36:14 UTC

[1/6] incubator-calcite git commit: [CALCITE-935] Improve how ReduceExpressionsRule handles duplicate constraints (Pengcheng Xiong)

Repository: incubator-calcite
Updated Branches:
  refs/heads/master c5f2599f4 -> 52b06213d


[CALCITE-935] Improve how ReduceExpressionsRule handles duplicate constraints (Pengcheng Xiong)

Add a test case making sure that non-equi constraints and identical constraints
do not prevent constant reduction.

Some fix up (Julian Hyde)


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

Branch: refs/heads/master
Commit: 690faa55f553fdaa86aa91a3f2c731d6c16007ca
Parents: c5f2599
Author: Pengcheng Xiong <px...@hortonworks.com>
Authored: Sat Oct 24 08:53:57 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 10:20:09 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 92 ++++++++++++++++++--
 .../apache/calcite/test/RelOptRulesTest.java    | 17 ++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 26 +++++-
 3 files changed, 125 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/690faa55/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 4e2d890..75943b8 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -62,12 +62,14 @@ import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
 
 /**
@@ -510,17 +512,91 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     // We cannot use an ImmutableMap.Builder here. If there are multiple entries
     // with the same key (e.g. "WHERE deptno = 1 AND deptno = 2"), it doesn't
     // matter which we take, so the latter will replace the former.
-    final Map<RexNode, RexLiteral> builder = Maps.newHashMap();
+    // The basic idea is to find all the pairs of RexNode = RexLiteral
+    // (1) If 'predicates' contain a non-EQUALS, we bail out.
+    // (2) It is OK if a RexNode is equal to the same RexLiteral several times,
+    // (e.g. "WHERE deptno = 1 AND deptno = 1")
+    // (3) It will return false if there are inconsistent constraints (e.g.
+    // "WHERE deptno = 1 AND deptno = 2")
+    final Map<RexNode, RexLiteral> map = new HashMap<>();
+    final Set<RexNode> excludeSet = new HashSet<>();
     for (RexNode predicate : predicates.pulledUpPredicates) {
-      switch (predicate.getKind()) {
-      case EQUALS:
-        final List<RexNode> operands = ((RexCall) predicate).getOperands();
-        if (operands.get(1) instanceof RexLiteral) {
-          builder.put(operands.get(0), (RexLiteral) operands.get(1));
+      gatherConstraints(map, predicate, excludeSet);
+    }
+    final ImmutableMap.Builder<RexNode, RexLiteral> builder =
+        ImmutableMap.builder();
+    for (Map.Entry<RexNode, RexLiteral> entry : map.entrySet()) {
+      RexNode rexNode = entry.getKey();
+      if (!overlap(rexNode, excludeSet)) {
+        builder.put(rexNode, entry.getValue());
+      }
+    }
+    return builder.build();
+  }
+
+  private static boolean overlap(RexNode rexNode, Set<RexNode> set) {
+    if (rexNode instanceof RexCall) {
+      for (RexNode r : ((RexCall) rexNode).getOperands()) {
+        if (overlap(r, set)) {
+          return true;
+        }
+      }
+      return false;
+    } else {
+      return set.contains(rexNode);
+    }
+  }
+
+  /** Tries to decompose the RexNode which is a RexCall into non-literal
+   * RexNodes. */
+  private static void decompose(Set<RexNode> set, RexNode rexNode) {
+    if (rexNode instanceof RexCall) {
+      for (RexNode r : ((RexCall) rexNode).getOperands()) {
+        decompose(set, r);
+      }
+    } else if (!(rexNode instanceof RexLiteral)) {
+      set.add(rexNode);
+    }
+  }
+
+  private static void gatherConstraints(Map<RexNode, RexLiteral> map,
+      RexNode predicate, Set<RexNode> excludeSet) {
+    if (predicate.getKind() != SqlKind.EQUALS) {
+      decompose(excludeSet, predicate);
+      return;
+    }
+    final List<RexNode> operands = ((RexCall) predicate).getOperands();
+    if (operands.size() != 2) {
+      decompose(excludeSet, predicate);
+      return;
+    }
+    // if it reaches here, we have rexNode equals rexNode
+    final RexNode left = operands.get(0);
+    final RexNode right = operands.get(1);
+    // note that literals are immutable too and they can only be compared through
+    // values.
+    if (right instanceof RexLiteral && !excludeSet.contains(left)) {
+      RexLiteral existedValue = map.get(left);
+      if (existedValue == null) {
+        map.put(left, (RexLiteral) right);
+      } else {
+        if (!existedValue.getValue().equals(((RexLiteral) right).getValue())) {
+          // we found conflict values.
+          map.remove(left);
+          excludeSet.add(left);
+        }
+      }
+    } else if (left instanceof RexLiteral && !excludeSet.contains(right)) {
+      RexLiteral existedValue = map.get(right);
+      if (existedValue == null) {
+        map.put(right, (RexLiteral) left);
+      } else {
+        if (!existedValue.getValue().equals(((RexLiteral) left).getValue())) {
+          map.remove(right);
+          excludeSet.add(right);
         }
       }
     }
-    return ImmutableMap.copyOf(builder);
   }
 
   /** Pushes predicates into a CASE.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/690faa55/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index cce90b8..c237ece 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -817,6 +817,23 @@ public class RelOptRulesTest extends RelOptTestBase {
             + " where d.deptno=7 and d.deptno=8");
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-935">[CALCITE-935]
+   * Improve how ReduceExpressionsRule handles duplicate constraints</a>. */
+  @Test public void testReduceConstantsDup2() throws Exception {
+    HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+        .addRuleInstance(ReduceExpressionsRule.JOIN_INSTANCE)
+        .build();
+
+    final String sql = "select *\n"
+        + "from emp\n"
+        + "where deptno=7 and deptno=8\n"
+        + "and empno = 10 and mgr is null and empno = 10";
+    checkPlanning(program, sql);
+  }
+
   @Test public void testReduceConstants2() throws Exception {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(ReduceExpressionsRule.PROJECT_INSTANCE)

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/690faa55/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index ddfefbb..f51e4e9 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -646,7 +646,7 @@ LogicalProject(DEPTNO=[$0])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(DEPTNO=[8])
+LogicalProject(DEPTNO=[$0])
   LogicalFilter(condition=[AND(=($0, 7), =($0, 8))])
     LogicalTableScan(table=[[CATALOG, SALES, DEPT]])
 ]]>
@@ -2909,7 +2909,7 @@ LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$
         <Resource name="planAfter">
             <![CDATA[
 LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10])
-  LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$10], NAME=[$11])
+  LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[10], NAME=[$11])
     LogicalJoin(condition=[AND(=(10, $10), =($9, $12))], joinType=[inner])
       LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], $f9=[+($7, $0)])
         LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
@@ -4213,4 +4213,26 @@ LogicalSort(sort0=[$0], dir0=[ASC], fetch=[10])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testReduceConstantsDup2">
+        <Resource name="sql">
+            <![CDATA[select *
+from emp
+where deptno=7 and deptno=8
+and empno = 10 and mgr is null and empno = 10]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+  LogicalFilter(condition=[AND(=($7, 7), =($7, 8), =($0, 10), IS NULL($3), =($0, 10))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EMPNO=[10], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+  LogicalFilter(condition=[AND(=($7, 7), =($7, 8), =($0, 10), IS NULL($3), =($0, 10))])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
 </Root>


[3/6] incubator-calcite git commit: [CALCITE-871] In JdbcMeta, register each statement using an id from a generator (Bruno Dumon)

Posted by jh...@apache.org.
[CALCITE-871] In JdbcMeta, register each statement using an id from a generator (Bruno Dumon)


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

Branch: refs/heads/master
Commit: 00517e7afa60377214ad4bb84720d12557be1931
Parents: 57e1b4c
Author: Bruno Dumon <br...@ngdata.com>
Authored: Fri Oct 23 12:57:29 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 12:12:10 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   | 56 ++++++++++++++------
 .../calcite/avatica/remote/RemoteMetaTest.java  | 17 ++++++
 .../calcite/avatica/AvaticaConnection.java      |  6 ++-
 3 files changed, 61 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/00517e7a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index 3f00dcb..be885ce 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -52,7 +52,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
-import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -64,9 +63,6 @@ public class JdbcMeta implements Meta {
 
   private static final String STMT_CACHE_KEY_BASE = "avatica.statementcache";
 
-  private static final String DEFAULT_CONN_ID =
-      UUID.fromString("00000000-0000-0000-0000-000000000000").toString();
-
   /** Special value for {@link Statement#getLargeMaxRows()} that means fetch
    * an unlimited number of rows in a single batch.
    *
@@ -273,19 +269,34 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getTables(catalog, schemaPattern.s,
               tableNamePattern.s, toArray(typeList));
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
   }
 
+  /**
+    * Registers a StatementInfo for the given ResultSet, returning the id under
+    * which it is registered. This should be used for metadata ResultSets, which
+    * have an implicit statement created.
+    */
+  private int registerMetaStatement(ResultSet rs) throws SQLException {
+    final int id = statementIdGenerator.getAndIncrement();
+    StatementInfo statementInfo = new StatementInfo(rs.getStatement());
+    statementInfo.resultSet = rs;
+    statementCache.put(id, statementInfo);
+    return id;
+  }
+
   public MetaResultSet getColumns(ConnectionHandle ch, String catalog, Pat schemaPattern,
       Pat tableNamePattern, Pat columnNamePattern) {
     try {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getColumns(catalog, schemaPattern.s,
               tableNamePattern.s, columnNamePattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -295,7 +306,8 @@ public class JdbcMeta implements Meta {
     try {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getSchemas(catalog, schemaPattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -304,7 +316,8 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getCatalogs(ConnectionHandle ch) {
     try {
       final ResultSet rs = getConnection(ch.id).getMetaData().getCatalogs();
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -313,7 +326,8 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getTableTypes(ConnectionHandle ch) {
     try {
       final ResultSet rs = getConnection(ch.id).getMetaData().getTableTypes();
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -325,7 +339,8 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getProcedures(catalog, schemaPattern.s,
               procedureNamePattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -337,7 +352,8 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getProcedureColumns(catalog,
               schemaPattern.s, procedureNamePattern.s, columnNamePattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -349,7 +365,8 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getColumnPrivileges(catalog, schema,
               table, columnNamePattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -361,7 +378,8 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getTablePrivileges(catalog,
               schemaPattern.s, tableNamePattern.s);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -377,7 +395,8 @@ public class JdbcMeta implements Meta {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getBestRowIdentifier(catalog, schema,
               table, scope, nullable);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -391,7 +410,8 @@ public class JdbcMeta implements Meta {
     try {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getVersionColumns(catalog, schema, table);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -405,7 +425,8 @@ public class JdbcMeta implements Meta {
     try {
       final ResultSet rs =
           getConnection(ch.id).getMetaData().getPrimaryKeys(catalog, schema, table);
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }
@@ -430,7 +451,8 @@ public class JdbcMeta implements Meta {
   public MetaResultSet getTypeInfo(ConnectionHandle ch) {
     try {
       final ResultSet rs = getConnection(ch.id).getMetaData().getTypeInfo();
-      return JdbcResultSet.create(DEFAULT_CONN_ID, -1, rs, UNLIMITED_COUNT);
+      int stmtId = registerMetaStatement(rs);
+      return JdbcResultSet.create(ch.id, stmtId, rs);
     } catch (SQLException e) {
       throw new RuntimeException(e);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/00517e7a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 5e14427..903167e 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -378,6 +378,23 @@ public class RemoteMetaTest {
       ConnectionSpec.getDatabaseLock().unlock();
     }
   }
+
+  @Test public void testRemoteColumnsMeta() throws Exception {
+    // Verify all columns are retrieved, thus that frame-based fetching works correctly for columns
+    int rowCount = 0;
+    try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) {
+      ResultSet rs = conn.getMetaData().getColumns(null, null, null, null);
+      while (rs.next()) {
+        rowCount++;
+      }
+      rs.close();
+
+      // The implicitly created statement should have been closed
+      assertTrue(rs.getStatement().isClosed());
+    }
+    // default fetch size is 100, we are well beyond it
+    assertTrue(rowCount > 900);
+  }
 }
 
 // End RemoteMetaTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/00517e7a/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 5386543..a8867c8 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java
@@ -551,8 +551,12 @@ public abstract class AvaticaConnection implements Connection {
     final Meta.StatementHandle h = new Meta.StatementHandle(
         metaResultSet.connectionId, metaResultSet.statementId, null);
     final AvaticaStatement statement = lookupStatement(h);
-    return executeQueryInternal(statement, metaResultSet.signature.sanitize(),
+    ResultSet resultSet = executeQueryInternal(statement, metaResultSet.signature.sanitize(),
         metaResultSet.firstFrame);
+    if (metaResultSet.ownStatement) {
+      resultSet.getStatement().closeOnCompletion();
+    }
+    return resultSet;
   }
 
   /** Creates a statement wrapper around an existing handle. */


[6/6] incubator-calcite git commit: [CALCITE-938] More accurate rowCount for Aggregate applied to already unique keys (Maryann Xue)

Posted by jh...@apache.org.
[CALCITE-938] More accurate rowCount for Aggregate applied to already unique keys (Maryann Xue)


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

Branch: refs/heads/master
Commit: 52b06213d02ff3fce981b1c23ab545029b5d4767
Parents: 6f326d0
Author: maryannxue <we...@intel.com>
Authored: Mon Oct 26 12:56:41 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 12:56:41 2015 -0700

----------------------------------------------------------------------
 .../rel/metadata/RelMdColumnUniqueness.java     | 41 +++-----------------
 .../calcite/rel/metadata/RelMdRowCount.java     |  2 +-
 core/src/test/resources/sql/agg.oq              | 34 ++++++++++++++++
 3 files changed, 40 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/52b06213/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
index f627774..2a6431d 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
@@ -366,46 +366,15 @@ public class RelMdColumnUniqueness {
   }
 
   public Boolean areColumnsUnique(
-      boolean dummy, // prevent method from being used
       RelSubset rel,
       ImmutableBitSet columns,
       boolean ignoreNulls) {
-    int nullCount = 0;
-    for (RelNode rel2 : rel.getRels()) {
-      if (rel2 instanceof Aggregate || simplyProjects(rel2, columns)) {
-        final Boolean unique =
-            RelMetadataQuery.areColumnsUnique(rel2, columns, ignoreNulls);
-        if (unique != null) {
-          if (unique) {
-            return true;
-          }
-        } else {
-          ++nullCount;
-        }
-      }
-    }
-    return nullCount == 0 ? false : null;
-  }
-
-  private boolean simplyProjects(RelNode rel, ImmutableBitSet columns) {
-    if (!(rel instanceof Project)) {
-      return false;
-    }
-    Project project = (Project) rel;
-    final List<RexNode> projects = project.getProjects();
-    for (int column : columns) {
-      if (column >= projects.size()) {
-        return false;
-      }
-      if (!(projects.get(column) instanceof RexInputRef)) {
-        return false;
-      }
-      final RexInputRef ref = (RexInputRef) projects.get(column);
-      if (ref.getIndex() != column) {
-        return false;
-      }
+    final RelNode best = rel.getBest();
+    if (best == null) {
+      return null;
+    } else {
+      return RelMetadataQuery.areColumnsUnique(best, columns, ignoreNulls);
     }
-    return true;
   }
 
   /** Aggregate and Calc are "safe" children of a RelSubset to delve into. */

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/52b06213/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
index cc90395..2d7beaf 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
@@ -94,7 +94,7 @@ public class RelMdRowCount {
   }
 
   public Double getRowCount(Aggregate rel) {
-    ImmutableBitSet groupKey = ImmutableBitSet.range(rel.getGroupCount());
+    ImmutableBitSet groupKey = rel.getGroupSet();
 
     // rowcount is the cardinality of the group by columns
     Double distinctRowCount =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/52b06213/core/src/test/resources/sql/agg.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/agg.oq b/core/src/test/resources/sql/agg.oq
index 3787ac2..e92f08d 100644
--- a/core/src/test/resources/sql/agg.oq
+++ b/core/src/test/resources/sql/agg.oq
@@ -1209,6 +1209,40 @@ order by sum_cnt;
 
 !ok
 
+# [CALCITE-938] Aggregate row count
+select empno, d.deptno
+from "scott".emp
+join (select distinct deptno from "scott".dept) d
+using (deptno);
++-------+--------+
+| EMPNO | DEPTNO |
++-------+--------+
+|  7369 |     20 |
+|  7499 |     30 |
+|  7521 |     30 |
+|  7566 |     20 |
+|  7654 |     30 |
+|  7698 |     30 |
+|  7782 |     10 |
+|  7788 |     20 |
+|  7839 |     10 |
+|  7844 |     30 |
+|  7876 |     20 |
+|  7900 |     30 |
+|  7902 |     20 |
+|  7934 |     10 |
++-------+--------+
+(14 rows)
+
+!ok
+EnumerableCalc(expr#0..2=[{inputs}], EMPNO=[$t1], DEPTNO=[$t0])
+  EnumerableJoin(condition=[=($0, $2)], joinType=[inner])
+    EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
+      EnumerableTableScan(table=[[scott, DEPT]])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
+      EnumerableTableScan(table=[[scott, EMP]])
+!plan
+
 # [CALCITE-729] IndexOutOfBoundsException in ROLLUP query on JDBC data source
 !use jdbc_scott
 select deptno, job, count(*) as c


[5/6] incubator-calcite git commit: [CALCITE-921] Fix incorrectness when calling getString() on binary data (Josh Elser)

Posted by jh...@apache.org.
[CALCITE-921] Fix incorrectness when calling getString() on binary data (Josh Elser)

Close apache/incubator-calcite#160


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

Branch: refs/heads/master
Commit: 6f326d0391923f4c4af5f9e60eb2ce263fdad081
Parents: bf178d5
Author: Josh Elser <el...@apache.org>
Authored: Tue Oct 13 19:31:47 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 12:13:43 2015 -0700

----------------------------------------------------------------------
 .../calcite/avatica/remote/RemoteMetaTest.java  | 31 +++++++++++++++++
 .../calcite/avatica/remote/AbstractService.java | 22 +++++++++++-
 .../calcite/avatica/remote/JsonService.java     |  4 +++
 .../calcite/avatica/remote/ProtobufService.java |  5 +++
 .../calcite/avatica/util/AbstractCursor.java    | 35 ++++++++++++++++++--
 5 files changed, 93 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6f326d03/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 3ccebf8..e4d8690 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -42,13 +42,16 @@ import org.junit.runners.Parameterized.Parameters;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
 import java.sql.Array;
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
@@ -416,6 +419,34 @@ public class RemoteMetaTest {
       ConnectionSpec.getDatabaseLock().unlock();
     }
   }
+
+  @Test public void testBinaryAndStrings() throws Exception {
+    final String tableName = "testbinaryandstrs";
+    final byte[] data = "asdf".getBytes(StandardCharsets.UTF_8);
+    ConnectionSpec.getDatabaseLock().lock();
+    try (final Connection conn = DriverManager.getConnection(url);
+        final Statement stmt = conn.createStatement()) {
+      assertFalse(stmt.execute("DROP TABLE IF EXISTS " + tableName));
+      assertFalse(stmt.execute("CREATE TABLE " + tableName + "(id int, bin BINARY(4))"));
+      try (final PreparedStatement prepStmt = conn.prepareStatement(
+          "INSERT INTO " + tableName + " values(1, ?)")) {
+        prepStmt.setBytes(1, data);
+        assertFalse(prepStmt.execute());
+      }
+      try (ResultSet results = stmt.executeQuery("SELECT id, bin from " + tableName)) {
+        assertTrue(results.next());
+        assertEquals(1, results.getInt(1));
+        // byte comparison should work
+        assertArrayEquals("Bytes were " + Arrays.toString(results.getBytes(2)),
+            data, results.getBytes(2));
+        // as should string
+        assertEquals(new String(data, StandardCharsets.UTF_8), results.getString(2));
+        assertFalse(results.next());
+      }
+    } finally {
+      ConnectionSpec.getDatabaseLock().unlock();
+    }
+  }
 }
 
 // End RemoteMetaTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6f326d03/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
index e88a47c..93ad3ef 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/AbstractService.java
@@ -29,6 +29,19 @@ import java.util.List;
  */
 public abstract class AbstractService implements Service {
 
+  /**
+   * Represents the serialization of the data over a transport.
+   */
+  enum SerializationType {
+    JSON,
+    PROTOBUF
+  }
+
+  /**
+   * @return The manner in which the data is serialized.
+   */
+  abstract SerializationType getSerializationType();
+
   /** Modifies a signature, changing the representation of numeric columns
    * within it. This deals with the fact that JSON transmits a small long value,
    * or a float which is a whole number, as an integer. Thus the accessors need
@@ -68,7 +81,14 @@ public abstract class AbstractService implements Service {
     switch (column.type.id) {
     case Types.VARBINARY:
     case Types.BINARY:
-      return column.setRep(ColumnMetaData.Rep.STRING);
+      switch (getSerializationType()) {
+      case JSON:
+        return column.setRep(ColumnMetaData.Rep.STRING);
+      case PROTOBUF:
+        return column;
+      default:
+        throw new IllegalStateException("Unhadled case statement");
+      }
     case Types.DECIMAL:
     case Types.NUMERIC:
       return column.setRep(ColumnMetaData.Rep.NUMBER);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6f326d03/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 86d69f1..a223069 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
@@ -43,6 +43,10 @@ public abstract class JsonService extends AbstractService {
    * responses to and from the peer service. */
   public abstract String apply(String request);
 
+  @Override SerializationType getSerializationType() {
+    return SerializationType.JSON;
+  }
+
   //@VisibleForTesting
   protected static <T> T decode(String response, Class<T> expectedType)
       throws IOException {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6f326d03/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufService.java
index 35cb35a..8414708 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufService.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.avatica.remote;
 
 import com.google.protobuf.Descriptors.Descriptor;
+
 import com.google.protobuf.Message;
 
 /**
@@ -30,6 +31,10 @@ public abstract class ProtobufService extends AbstractService {
    */
   public abstract Response _apply(Request request);
 
+  @Override SerializationType getSerializationType() {
+    return SerializationType.PROTOBUF;
+  }
+
   @Override public ResultSetResponse apply(CatalogsRequest request) {
     return finagle((ResultSetResponse) _apply(request));
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/6f326d03/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 cd65199..dd38da0 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
@@ -26,6 +26,7 @@ import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.sql.Array;
 import java.sql.Blob;
 import java.sql.Clob;
@@ -782,7 +783,7 @@ public abstract class AbstractCursor implements Cursor {
     }
 
     //FIXME: Protobuf gets byte[]
-    public byte[] getBytes() {
+    @Override public byte[] getBytes() {
       Object obj = getObject();
       try {
         final ByteString o = (ByteString) obj;
@@ -791,6 +792,19 @@ public abstract class AbstractCursor implements Cursor {
         return obj == null ? null : (byte[]) obj;
       }
     }
+
+    @Override public String getString() {
+      Object o = getObject();
+      if (null == o) {
+        return null;
+      }
+      if (o instanceof byte[]) {
+        return new String((byte[]) o, StandardCharsets.UTF_8);
+      } else if (o instanceof ByteString) {
+        return ((ByteString) o).toString();
+      }
+      throw new IllegalStateException("Unhandled value type: " + o.getClass());
+    }
   }
 
   /**
@@ -810,17 +824,32 @@ public abstract class AbstractCursor implements Cursor {
     @Override public byte[] getBytes() {
       // JSON sends this as a base64-enc string, protobuf can do binary.
       Object obj = getObject();
+
       if (obj instanceof byte[]) {
         // If we already have bytes, just send them back.
         return (byte[]) obj;
       }
 
-      final String string = getString();
-      if (string == null) {
+      return getBase64Decoded();
+    }
+
+    private byte[] getBase64Decoded() {
+      final String string = super.getString();
+      if (null == string) {
         return null;
       }
+      // Need to base64 decode the string.
       return ByteString.parseBase64(string);
     }
+
+    @Override public String getString() {
+      final byte[] bytes = getBase64Decoded();
+      if (null == bytes) {
+        return null;
+      }
+      // Need to base64 decode the string.
+      return new String(bytes, StandardCharsets.UTF_8);
+    }
   }
 
   /**


[4/6] incubator-calcite git commit: [CALCITE-913] Construct proper ColumnMetaData for arrays (Josh Elser)

Posted by jh...@apache.org.
[CALCITE-913] Construct proper ColumnMetaData for arrays (Josh Elser)


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

Branch: refs/heads/master
Commit: bf178d55f88c317f36c68807649d35d3e0614e6a
Parents: 00517e7
Author: Josh Elser <el...@apache.org>
Authored: Fri Oct 9 20:24:49 2015 -0400
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 12:13:42 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   |   14 +-
 .../calcite/avatica/jdbc/JdbcResultSet.java     |   28 +
 .../calcite/avatica/remote/RemoteMetaTest.java  |   21 +
 .../apache/calcite/avatica/ColumnMetaData.java  |   19 +-
 .../java/org/apache/calcite/avatica/Meta.java   |  188 +--
 .../apache/calcite/avatica/proto/Common.java    | 1204 ++++++++++++++----
 .../avatica/remote/MockProtobufService.java     |    6 +-
 avatica/src/main/protobuf/common.proto          |   10 +-
 .../avatica/remote/ProtobufHandlerTest.java     |   15 +-
 9 files changed, 1167 insertions(+), 338 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index be885ce..b8e4ea4 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -44,6 +44,7 @@ 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.Calendar;
 import java.util.Collections;
@@ -190,9 +191,14 @@ public class JdbcMeta implements Meta {
     for (int i = 1; i <= metaData.getColumnCount(); i++) {
       final SqlType sqlType = SqlType.valueOf(metaData.getColumnType(i));
       final ColumnMetaData.Rep rep = ColumnMetaData.Rep.of(sqlType.internal);
-      ColumnMetaData.AvaticaType t =
-          ColumnMetaData.scalar(metaData.getColumnType(i),
-              metaData.getColumnTypeName(i), rep);
+      final ColumnMetaData.AvaticaType t;
+      if (sqlType == SqlType.ARRAY || sqlType == SqlType.STRUCT || sqlType == SqlType.MULTISET) {
+        ColumnMetaData.AvaticaType arrayValueType = ColumnMetaData.scalar(Types.JAVA_OBJECT,
+            metaData.getColumnTypeName(i), ColumnMetaData.Rep.OBJECT);
+        t = ColumnMetaData.array(arrayValueType, metaData.getColumnTypeName(i), rep);
+      } else {
+        t = ColumnMetaData.scalar(metaData.getColumnType(i), metaData.getColumnTypeName(i), rep);
+      }
       ColumnMetaData md =
           new ColumnMetaData(i - 1, metaData.isAutoIncrement(i),
               metaData.isCaseSensitive(i), metaData.isSearchable(i),
@@ -210,7 +216,7 @@ public class JdbcMeta implements Meta {
   }
 
   /**
-   * Converts from JDBC metadata to Avatica parameters.
+   * Converts from JDBC metadata to Avatica parameters
    */
   protected static List<AvaticaParameter> parameters(ParameterMetaData metaData)
       throws SQLException {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
index d0a57ab..30ee7f4 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcResultSet.java
@@ -20,16 +20,19 @@ import org.apache.calcite.avatica.AvaticaStatement;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 
+import java.sql.Array;
 import java.sql.Date;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
+import java.sql.Struct;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
+import java.util.TreeMap;
 
 /** Implementation of {@link org.apache.calcite.avatica.Meta.MetaResultSet}
  *  upon a JDBC {@link java.sql.ResultSet}.
@@ -172,6 +175,31 @@ class JdbcResultSet extends Meta.MetaResultSet {
     case Types.TIMESTAMP:
       final Timestamp aTimestamp = resultSet.getTimestamp(j + 1, calendar);
       return aTimestamp == null ? null : aTimestamp.getTime();
+    case Types.ARRAY:
+      final Array array = resultSet.getArray(j + 1);
+      if (null == array) {
+        return null;
+      }
+      ResultSet arrayValues = array.getResultSet();
+      TreeMap<Integer, Object> map = new TreeMap<>();
+      while (arrayValues.next()) {
+        // column 1 is the index in the array, column 2 is the value.
+        // Recurse on `getValue` to unwrap nested types correctly.
+        // `j` is zero-indexed and incremented for us, thus we have `1` being used twice.
+        map.put(arrayValues.getInt(1), getValue(arrayValues, array.getBaseType(), 1, calendar));
+      }
+      // If the result set is not in the same order as the actual Array, TreeMap fixes that.
+      // Need to make a concrete list to ensure Jackson serialization.
+      //return new ListLike<Object>(new ArrayList<>(map.values()), ListLikeType.ARRAY);
+      return new ArrayList<>(map.values());
+    case Types.STRUCT:
+      Struct struct = resultSet.getObject(j + 1, Struct.class);
+      Object[] attrs = struct.getAttributes();
+      List<Object> list = new ArrayList<>(attrs.length);
+      for (Object o : attrs) {
+        list.add(o);
+      }
+      return list;
     default:
       return resultSet.getObject(j + 1);
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index 903167e..3ccebf8 100644
--- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -29,6 +29,7 @@ import org.apache.calcite.avatica.server.AvaticaProtobufHandler;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.calcite.avatica.server.Main;
 import org.apache.calcite.avatica.server.Main.HandlerFactory;
+import org.apache.calcite.avatica.util.ArrayImpl;
 
 import com.google.common.cache.Cache;
 
@@ -41,6 +42,7 @@ import org.junit.runners.Parameterized.Parameters;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.sql.Array;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
@@ -54,6 +56,7 @@ import java.util.UUID;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
@@ -395,6 +398,24 @@ public class RemoteMetaTest {
     // default fetch size is 100, we are well beyond it
     assertTrue(rowCount > 900);
   }
+
+  @Test public void testArrays() throws SQLException {
+    ConnectionSpec.getDatabaseLock().lock();
+    try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url);
+         Statement stmt = conn.createStatement()) {
+      ResultSet resultSet =
+          stmt.executeQuery("select * from (values ('a', array['b', 'c']));");
+
+      assertTrue(resultSet.next());
+      assertEquals("a", resultSet.getString(1));
+      Array arr = resultSet.getArray(2);
+      assertTrue(arr instanceof ArrayImpl);
+      Object[] values = (Object[]) ((ArrayImpl) arr).getArray();
+      assertArrayEquals(new String[]{"b", "c"}, values);
+    } finally {
+      ConnectionSpec.getDatabaseLock().unlock();
+    }
+  }
 }
 
 // End RemoteMetaTest.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/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 b1e70c4..170c310 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
@@ -26,9 +26,11 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.google.protobuf.Descriptors.Descriptor;
 
 import java.lang.reflect.Type;
+import java.sql.Array;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Struct;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
@@ -444,6 +446,11 @@ public class ColumnMetaData {
     /** Values are represented as some sub-class of {@link Number}.
      * The JSON encoding does this. */
     NUMBER(Number.class),
+
+    ARRAY(Array.class),
+    MULTISET(List.class),
+    STRUCT(Struct.class),
+
     OBJECT(Object.class);
 
     public final Class clazz;
@@ -512,6 +519,10 @@ public class ColumnMetaData {
         return resultSet.getTime(i);
       case JAVA_SQL_TIMESTAMP:
         return resultSet.getTimestamp(i);
+      case ARRAY:
+        return resultSet.getArray(i);
+      case STRUCT:
+        return resultSet.getObject(i, Struct.class);
       default:
         return resultSet.getObject(i);
       }
@@ -694,8 +705,12 @@ public class ColumnMetaData {
   public static class ArrayType extends AvaticaType {
     public final AvaticaType component;
 
-    private ArrayType(int type, String typeName, Rep representation,
-        AvaticaType component) {
+    /**
+     * Not for public use. Use {@link ColumnMetaData#array(AvaticaType, String, Rep)}.
+     */
+    @JsonCreator
+    public ArrayType(@JsonProperty("type") int type, @JsonProperty("name") String typeName,
+        @JsonProperty("rep") Rep representation, @JsonProperty("component") AvaticaType component) {
       super(type, typeName, representation);
       this.component = component;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/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 c5c8030..6c51b1c 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -864,49 +864,21 @@ public interface Meta {
           final Common.Row.Builder rowBuilder = Common.Row.newBuilder();
 
           for (Object element : (Object[]) row) {
-            final Common.TypedValue.Builder valueBuilder = Common.TypedValue.newBuilder();
-
-            // Numbers
-            if (element instanceof Byte) {
-              valueBuilder.setType(Common.Rep.BYTE).setNumberValue(((Byte) element).longValue());
-            } else if (element instanceof Short) {
-              valueBuilder.setType(Common.Rep.SHORT).setNumberValue(((Short) element).longValue());
-            } else if (element instanceof Integer) {
-              valueBuilder.setType(Common.Rep.INTEGER)
-                .setNumberValue(((Integer) element).longValue());
-            } else if (element instanceof Long) {
-              valueBuilder.setType(Common.Rep.LONG).setNumberValue((Long) element);
-            } else if (element instanceof Double) {
-              valueBuilder.setType(Common.Rep.DOUBLE)
-                .setDoubleValue(((Double) element).doubleValue());
-            } else if (element instanceof Float) {
-              valueBuilder.setType(Common.Rep.FLOAT).setNumberValue(((Float) element).longValue());
-            } else if (element instanceof BigDecimal) {
-              valueBuilder.setType(Common.Rep.NUMBER)
-                .setDoubleValue(((BigDecimal) element).doubleValue());
-            // Strings
-            } else if (element instanceof String) {
-              valueBuilder.setType(Common.Rep.STRING)
-                .setStringValue((String) element);
-            } else if (element instanceof Character) {
-              valueBuilder.setType(Common.Rep.CHARACTER)
-                .setStringValue(((Character) element).toString());
-            // Bytes
-            } else if (element instanceof byte[]) {
-              valueBuilder.setType(Common.Rep.BYTE_STRING)
-                .setBytesValues(ByteString.copyFrom((byte[]) element));
-            // Boolean
-            } else if (element instanceof Boolean) {
-              valueBuilder.setType(Common.Rep.BOOLEAN).setBoolValue((boolean) element);
-            } else if (null == element) {
-              valueBuilder.setType(Common.Rep.NULL);
-            // Unhandled
+            final Common.ColumnValue.Builder columnBuilder = Common.ColumnValue.newBuilder();
+
+            if (element instanceof List) {
+              List<?> list = (List<?>) element;
+              // Add each element in the list/array to the column's value
+              for (Object listItem : list) {
+                columnBuilder.addValue(serializeScalar(listItem));
+              }
             } else {
-              throw new RuntimeException("Unhandled type in Frame: " + element.getClass());
+              // Only one value for this column, a scalar.
+              columnBuilder.addValue(serializeScalar(element));
             }
 
             // Add value to row
-            rowBuilder.addValue(valueBuilder.build());
+            rowBuilder.addValue(columnBuilder.build());
           }
 
           // Collect all rows
@@ -920,58 +892,70 @@ public interface Meta {
       return builder.build();
     }
 
+    static Common.TypedValue serializeScalar(Object element) {
+      final Common.TypedValue.Builder valueBuilder = Common.TypedValue.newBuilder();
+
+      // Numbers
+      if (element instanceof Byte) {
+        valueBuilder.setType(Common.Rep.BYTE).setNumberValue(((Byte) element).longValue());
+      } else if (element instanceof Short) {
+        valueBuilder.setType(Common.Rep.SHORT).setNumberValue(((Short) element).longValue());
+      } else if (element instanceof Integer) {
+        valueBuilder.setType(Common.Rep.INTEGER)
+          .setNumberValue(((Integer) element).longValue());
+      } else if (element instanceof Long) {
+        valueBuilder.setType(Common.Rep.LONG).setNumberValue((Long) element);
+      } else if (element instanceof Double) {
+        valueBuilder.setType(Common.Rep.DOUBLE)
+          .setDoubleValue(((Double) element).doubleValue());
+      } else if (element instanceof Float) {
+        valueBuilder.setType(Common.Rep.FLOAT).setNumberValue(((Float) element).longValue());
+      } else if (element instanceof BigDecimal) {
+        valueBuilder.setType(Common.Rep.NUMBER)
+          .setDoubleValue(((BigDecimal) element).doubleValue());
+      // Strings
+      } else if (element instanceof String) {
+        valueBuilder.setType(Common.Rep.STRING)
+          .setStringValue((String) element);
+      } else if (element instanceof Character) {
+        valueBuilder.setType(Common.Rep.CHARACTER)
+          .setStringValue(((Character) element).toString());
+      // Bytes
+      } else if (element instanceof byte[]) {
+        valueBuilder.setType(Common.Rep.BYTE_STRING)
+          .setBytesValues(ByteString.copyFrom((byte[]) element));
+      // Boolean
+      } else if (element instanceof Boolean) {
+        valueBuilder.setType(Common.Rep.BOOLEAN).setBoolValue((boolean) element);
+      } else if (null == element) {
+        valueBuilder.setType(Common.Rep.NULL);
+      // Unhandled
+      } else {
+        throw new RuntimeException("Unhandled type in Frame: " + element.getClass());
+      }
+
+      return valueBuilder.build();
+    }
+
     public static Frame fromProto(Common.Frame proto) {
       List<Object> parsedRows = new ArrayList<>(proto.getRowsCount());
       for (Common.Row protoRow : proto.getRowsList()) {
         ArrayList<Object> row = new ArrayList<>(protoRow.getValueCount());
-        for (Common.TypedValue protoElement : protoRow.getValueList()) {
-          Object element;
-
-          // TODO Should these be primitives or Objects?
-          switch (protoElement.getType()) {
-          case BYTE:
-            element = Long.valueOf(protoElement.getNumberValue()).byteValue();
-            break;
-          case SHORT:
-            element = Long.valueOf(protoElement.getNumberValue()).shortValue();
-            break;
-          case INTEGER:
-            element = Long.valueOf(protoElement.getNumberValue()).intValue();
-            break;
-          case LONG:
-            element = protoElement.getNumberValue();
-            break;
-          case FLOAT:
-            element = Long.valueOf(protoElement.getNumberValue()).floatValue();
-            break;
-          case DOUBLE:
-            element = Double.valueOf(protoElement.getDoubleValue());
-            break;
-          case NUMBER:
-            // TODO more cases here to expand on? BigInteger?
-            element = BigDecimal.valueOf(protoElement.getDoubleValue());
-            break;
-          case STRING:
-            element = protoElement.getStringValue();
-            break;
-          case CHARACTER:
-            // A single character in the string
-            element = protoElement.getStringValue().charAt(0);
-            break;
-          case BYTE_STRING:
-            element = protoElement.getBytesValues().toByteArray();
-            break;
-          case BOOLEAN:
-            element = protoElement.getBoolValue();
-            break;
-          case NULL:
-            element = null;
-            break;
-          default:
-            throw new RuntimeException("Unhandled type: " + protoElement.getType());
+        for (Common.ColumnValue protoColumn : protoRow.getValueList()) {
+          Object value;
+          if (protoColumn.getValueCount() > 1) {
+            // Array
+            List<Object> array = new ArrayList<>(protoColumn.getValueCount());
+            for (Common.TypedValue columnValue : protoColumn.getValueList()) {
+              array.add(getScalarValue(columnValue));
+            }
+            value = array;
+          } else {
+            // Scalar
+            value = getScalarValue(protoColumn.getValue(0));
           }
 
-          row.add(element);
+          row.add(value);
         }
 
         parsedRows.add(row);
@@ -980,6 +964,40 @@ public interface Meta {
       return new Frame(proto.getOffset(), proto.getDone(), parsedRows);
     }
 
+    static Object getScalarValue(Common.TypedValue protoElement) {
+      // TODO Should these be primitives or Objects?
+      switch (protoElement.getType()) {
+      case BYTE:
+        return Long.valueOf(protoElement.getNumberValue()).byteValue();
+      case SHORT:
+        return Long.valueOf(protoElement.getNumberValue()).shortValue();
+      case INTEGER:
+        return Long.valueOf(protoElement.getNumberValue()).intValue();
+      case LONG:
+        return protoElement.getNumberValue();
+      case FLOAT:
+        return Long.valueOf(protoElement.getNumberValue()).floatValue();
+      case DOUBLE:
+        return Double.valueOf(protoElement.getDoubleValue());
+      case NUMBER:
+        // TODO more cases here to expand on? BigInteger?
+        return BigDecimal.valueOf(protoElement.getDoubleValue());
+      case STRING:
+        return protoElement.getStringValue();
+      case CHARACTER:
+        // A single character in the string
+        return protoElement.getStringValue().charAt(0);
+      case BYTE_STRING:
+        return protoElement.getBytesValues().toByteArray();
+      case BOOLEAN:
+        return protoElement.getBoolValue();
+      case NULL:
+        return null;
+      default:
+        throw new RuntimeException("Unhandled type: " + protoElement.getType());
+      }
+    }
+
     @Override public int hashCode() {
       final int prime = 31;
       int result = 1;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica/src/main/java/org/apache/calcite/avatica/proto/Common.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/proto/Common.java b/avatica/src/main/java/org/apache/calcite/avatica/proto/Common.java
index c63355d..b693b77 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/proto/Common.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/proto/Common.java
@@ -323,6 +323,18 @@ package org.apache.calcite.avatica.proto;
      * <code>NULL = 24;</code>
      */
     NULL(26, 24),
+    /**
+     * <code>ARRAY = 27;</code>
+     */
+    ARRAY(27, 27),
+    /**
+     * <code>STRUCT = 28;</code>
+     */
+    STRUCT(28, 28),
+    /**
+     * <code>MULTISET = 29;</code>
+     */
+    MULTISET(29, 29),
     UNRECOGNIZED(-1, -1),
     ;
 
@@ -434,6 +446,18 @@ package org.apache.calcite.avatica.proto;
      * <code>NULL = 24;</code>
      */
     public static final int NULL_VALUE = 24;
+    /**
+     * <code>ARRAY = 27;</code>
+     */
+    public static final int ARRAY_VALUE = 27;
+    /**
+     * <code>STRUCT = 28;</code>
+     */
+    public static final int STRUCT_VALUE = 28;
+    /**
+     * <code>MULTISET = 29;</code>
+     */
+    public static final int MULTISET_VALUE = 29;
 
 
     public final int getNumber() {
@@ -473,6 +497,9 @@ package org.apache.calcite.avatica.proto;
         case 22: return NUMBER;
         case 23: return OBJECT;
         case 24: return NULL;
+        case 27: return ARRAY;
+        case 28: return STRUCT;
+        case 29: return MULTISET;
         default: return null;
       }
     }
@@ -9809,27 +9836,27 @@ package org.apache.calcite.avatica.proto;
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> 
+    java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue> 
         getValueList();
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index);
+    org.apache.calcite.avatica.proto.Common.ColumnValue getValue(int index);
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
     int getValueCount();
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+    java.util.List<? extends org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder> 
         getValueOrBuilderList();
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+    org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder getValueOrBuilder(
         int index);
   }
   /**
@@ -9877,10 +9904,10 @@ package org.apache.calcite.avatica.proto;
             }
             case 10: {
               if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
-                value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>();
+                value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.ColumnValue>();
                 mutable_bitField0_ |= 0x00000001;
               }
-              value_.add(input.readMessage(org.apache.calcite.avatica.proto.Common.TypedValue.parser(), extensionRegistry));
+              value_.add(input.readMessage(org.apache.calcite.avatica.proto.Common.ColumnValue.parser(), extensionRegistry));
               break;
             }
           }
@@ -9911,36 +9938,36 @@ package org.apache.calcite.avatica.proto;
     }
 
     public static final int VALUE_FIELD_NUMBER = 1;
-    private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> value_;
+    private java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue> value_;
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
+    public java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue> getValueList() {
       return value_;
     }
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+    public java.util.List<? extends org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder> 
         getValueOrBuilderList() {
       return value_;
     }
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
     public int getValueCount() {
       return value_.size();
     }
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
+    public org.apache.calcite.avatica.proto.Common.ColumnValue getValue(int index) {
       return value_.get(index);
     }
     /**
-     * <code>repeated .TypedValue value = 1;</code>
+     * <code>repeated .ColumnValue value = 1;</code>
      */
-    public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+    public org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder getValueOrBuilder(
         int index) {
       return value_.get(index);
     }
@@ -10193,22 +10220,22 @@ package org.apache.calcite.avatica.proto;
       }
       private int bitField0_;
 
-      private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> value_ =
+      private java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue> value_ =
         java.util.Collections.emptyList();
       private void ensureValueIsMutable() {
         if (!((bitField0_ & 0x00000001) == 0x00000001)) {
-          value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>(value_);
+          value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.ColumnValue>(value_);
           bitField0_ |= 0x00000001;
          }
       }
 
       private com.google.protobuf.RepeatedFieldBuilder<
-          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> valueBuilder_;
+          org.apache.calcite.avatica.proto.Common.ColumnValue, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder, org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder> valueBuilder_;
 
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
+      public java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue> getValueList() {
         if (valueBuilder_ == null) {
           return java.util.Collections.unmodifiableList(value_);
         } else {
@@ -10216,7 +10243,7 @@ package org.apache.calcite.avatica.proto;
         }
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public int getValueCount() {
         if (valueBuilder_ == null) {
@@ -10226,9 +10253,9 @@ package org.apache.calcite.avatica.proto;
         }
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
+      public org.apache.calcite.avatica.proto.Common.ColumnValue getValue(int index) {
         if (valueBuilder_ == null) {
           return value_.get(index);
         } else {
@@ -10236,10 +10263,10 @@ package org.apache.calcite.avatica.proto;
         }
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder setValue(
-          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+          int index, org.apache.calcite.avatica.proto.Common.ColumnValue value) {
         if (valueBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -10253,10 +10280,10 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder setValue(
-          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+          int index, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder builderForValue) {
         if (valueBuilder_ == null) {
           ensureValueIsMutable();
           value_.set(index, builderForValue.build());
@@ -10267,9 +10294,9 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public Builder addValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
+      public Builder addValue(org.apache.calcite.avatica.proto.Common.ColumnValue value) {
         if (valueBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -10283,10 +10310,10 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder addValue(
-          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+          int index, org.apache.calcite.avatica.proto.Common.ColumnValue value) {
         if (valueBuilder_ == null) {
           if (value == null) {
             throw new NullPointerException();
@@ -10300,10 +10327,10 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder addValue(
-          org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+          org.apache.calcite.avatica.proto.Common.ColumnValue.Builder builderForValue) {
         if (valueBuilder_ == null) {
           ensureValueIsMutable();
           value_.add(builderForValue.build());
@@ -10314,10 +10341,10 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder addValue(
-          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+          int index, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder builderForValue) {
         if (valueBuilder_ == null) {
           ensureValueIsMutable();
           value_.add(index, builderForValue.build());
@@ -10328,10 +10355,10 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder addAllValue(
-          java.lang.Iterable<? extends org.apache.calcite.avatica.proto.Common.TypedValue> values) {
+          java.lang.Iterable<? extends org.apache.calcite.avatica.proto.Common.ColumnValue> values) {
         if (valueBuilder_ == null) {
           ensureValueIsMutable();
           com.google.protobuf.AbstractMessageLite.Builder.addAll(
@@ -10343,7 +10370,7 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder clearValue() {
         if (valueBuilder_ == null) {
@@ -10356,7 +10383,7 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
       public Builder removeValue(int index) {
         if (valueBuilder_ == null) {
@@ -10369,16 +10396,16 @@ package org.apache.calcite.avatica.proto;
         return this;
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder getValueBuilder(
+      public org.apache.calcite.avatica.proto.Common.ColumnValue.Builder getValueBuilder(
           int index) {
         return getValueFieldBuilder().getBuilder(index);
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+      public org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder getValueOrBuilder(
           int index) {
         if (valueBuilder_ == null) {
           return value_.get(index);  } else {
@@ -10386,9 +10413,9 @@ package org.apache.calcite.avatica.proto;
         }
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+      public java.util.List<? extends org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder> 
            getValueOrBuilderList() {
         if (valueBuilder_ != null) {
           return valueBuilder_.getMessageOrBuilderList();
@@ -10397,33 +10424,33 @@ package org.apache.calcite.avatica.proto;
         }
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder() {
+      public org.apache.calcite.avatica.proto.Common.ColumnValue.Builder addValueBuilder() {
         return getValueFieldBuilder().addBuilder(
-            org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+            org.apache.calcite.avatica.proto.Common.ColumnValue.getDefaultInstance());
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder(
+      public org.apache.calcite.avatica.proto.Common.ColumnValue.Builder addValueBuilder(
           int index) {
         return getValueFieldBuilder().addBuilder(
-            index, org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+            index, org.apache.calcite.avatica.proto.Common.ColumnValue.getDefaultInstance());
       }
       /**
-       * <code>repeated .TypedValue value = 1;</code>
+       * <code>repeated .ColumnValue value = 1;</code>
        */
-      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue.Builder> 
+      public java.util.List<org.apache.calcite.avatica.proto.Common.ColumnValue.Builder> 
            getValueBuilderList() {
         return getValueFieldBuilder().getBuilderList();
       }
       private com.google.protobuf.RepeatedFieldBuilder<
-          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+          org.apache.calcite.avatica.proto.Common.ColumnValue, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder, org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder> 
           getValueFieldBuilder() {
         if (valueBuilder_ == null) {
           valueBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
-              org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder>(
+              org.apache.calcite.avatica.proto.Common.ColumnValue, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder, org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder>(
                   value_,
                   ((bitField0_ & 0x00000001) == 0x00000001),
                   getParentForChildren(),
@@ -11654,113 +11681,51 @@ package org.apache.calcite.avatica.proto;
 
   }
 
-  public interface TypedValueOrBuilder extends
-      // @@protoc_insertion_point(interface_extends:TypedValue)
+  public interface ColumnValueOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:ColumnValue)
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>optional .Rep type = 1;</code>
-     *
-     * <pre>
-     * The actual type that was serialized in the general attribute below
-     * </pre>
-     */
-    int getTypeValue();
-    /**
-     * <code>optional .Rep type = 1;</code>
-     *
-     * <pre>
-     * The actual type that was serialized in the general attribute below
-     * </pre>
-     */
-    org.apache.calcite.avatica.proto.Common.Rep getType();
-
-    /**
-     * <code>optional bool bool_value = 2;</code>
-     *
-     * <pre>
-     * boolean
-     * </pre>
-     */
-    boolean getBoolValue();
-
-    /**
-     * <code>optional string string_value = 3;</code>
-     *
-     * <pre>
-     * char/varchar
-     * </pre>
-     */
-    java.lang.String getStringValue();
-    /**
-     * <code>optional string string_value = 3;</code>
-     *
-     * <pre>
-     * char/varchar
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    com.google.protobuf.ByteString
-        getStringValueBytes();
-
+    java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> 
+        getValueList();
     /**
-     * <code>optional sint64 number_value = 4;</code>
-     *
-     * <pre>
-     * var-len encoding lets us shove anything from byte to long
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    long getNumberValue();
-
+    org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index);
     /**
-     * <code>optional bytes bytes_values = 5;</code>
-     *
-     * <pre>
-     * includes numeric types and date/time types.
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    com.google.protobuf.ByteString getBytesValues();
-
+    int getValueCount();
     /**
-     * <code>optional double double_value = 6;</code>
-     *
-     * <pre>
-     * big numbers
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    double getDoubleValue();
-
+    java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+        getValueOrBuilderList();
     /**
-     * <code>optional bool null = 7;</code>
-     *
-     * <pre>
-     * a null object
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    boolean getNull();
+    org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+        int index);
   }
   /**
-   * Protobuf type {@code TypedValue}
+   * Protobuf type {@code ColumnValue}
    *
    * <pre>
-   * Generic wrapper to support any SQL type. Struct-like to work around no polymorphism construct.
+   * A value might be a TypedValue or an Array of TypedValue's
    * </pre>
    */
-  public  static final class TypedValue extends
+  public  static final class ColumnValue extends
       com.google.protobuf.GeneratedMessage implements
-      // @@protoc_insertion_point(message_implements:TypedValue)
-      TypedValueOrBuilder {
-    // Use TypedValue.newBuilder() to construct.
-    private TypedValue(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      // @@protoc_insertion_point(message_implements:ColumnValue)
+      ColumnValueOrBuilder {
+    // Use ColumnValue.newBuilder() to construct.
+    private ColumnValue(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
       super(builder);
     }
-    private TypedValue() {
-      type_ = 0;
-      boolValue_ = false;
-      stringValue_ = "";
-      numberValue_ = 0L;
-      bytesValues_ = com.google.protobuf.ByteString.EMPTY;
-      doubleValue_ = 0D;
-      null_ = false;
+    private ColumnValue() {
+      value_ = java.util.Collections.emptyList();
     }
 
     @java.lang.Override
@@ -11768,7 +11733,7 @@ package org.apache.calcite.avatica.proto;
     getUnknownFields() {
       return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
     }
-    private TypedValue(
+    private ColumnValue(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
       this();
@@ -11787,41 +11752,12 @@ package org.apache.calcite.avatica.proto;
               }
               break;
             }
-            case 8: {
-              int rawValue = input.readEnum();
-
-              type_ = rawValue;
-              break;
-            }
-            case 16: {
-
-              boolValue_ = input.readBool();
-              break;
-            }
-            case 26: {
-              String s = input.readStringRequireUtf8();
-
-              stringValue_ = s;
-              break;
-            }
-            case 32: {
-
-              numberValue_ = input.readSInt64();
-              break;
-            }
-            case 42: {
-
-              bytesValues_ = input.readBytes();
-              break;
-            }
-            case 49: {
-
-              doubleValue_ = input.readDouble();
-              break;
-            }
-            case 56: {
-
-              null_ = input.readBool();
+            case 10: {
+              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+                value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>();
+                mutable_bitField0_ |= 0x00000001;
+              }
+              value_.add(input.readMessage(org.apache.calcite.avatica.proto.Common.TypedValue.parser(), extensionRegistry));
               break;
             }
           }
@@ -11833,53 +11769,830 @@ package org.apache.calcite.avatica.proto;
             new com.google.protobuf.InvalidProtocolBufferException(
                 e.getMessage()).setUnfinishedMessage(this));
       } finally {
+        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+          value_ = java.util.Collections.unmodifiableList(value_);
+        }
         makeExtensionsImmutable();
       }
     }
     public static final com.google.protobuf.Descriptors.Descriptor
         getDescriptor() {
-      return org.apache.calcite.avatica.proto.Common.internal_static_TypedValue_descriptor;
+      return org.apache.calcite.avatica.proto.Common.internal_static_ColumnValue_descriptor;
     }
 
     protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
         internalGetFieldAccessorTable() {
-      return org.apache.calcite.avatica.proto.Common.internal_static_TypedValue_fieldAccessorTable
+      return org.apache.calcite.avatica.proto.Common.internal_static_ColumnValue_fieldAccessorTable
           .ensureFieldAccessorsInitialized(
-              org.apache.calcite.avatica.proto.Common.TypedValue.class, org.apache.calcite.avatica.proto.Common.TypedValue.Builder.class);
+              org.apache.calcite.avatica.proto.Common.ColumnValue.class, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder.class);
     }
 
-    public static final int TYPE_FIELD_NUMBER = 1;
-    private int type_;
+    public static final int VALUE_FIELD_NUMBER = 1;
+    private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> value_;
     /**
-     * <code>optional .Rep type = 1;</code>
-     *
-     * <pre>
-     * The actual type that was serialized in the general attribute below
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    public int getTypeValue() {
-      return type_;
+    public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
+      return value_;
     }
     /**
-     * <code>optional .Rep type = 1;</code>
-     *
-     * <pre>
-     * The actual type that was serialized in the general attribute below
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
      */
-    public org.apache.calcite.avatica.proto.Common.Rep getType() {
-      org.apache.calcite.avatica.proto.Common.Rep result = org.apache.calcite.avatica.proto.Common.Rep.valueOf(type_);
-      return result == null ? org.apache.calcite.avatica.proto.Common.Rep.UNRECOGNIZED : result;
+    public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+        getValueOrBuilderList() {
+      return value_;
     }
-
-    public static final int BOOL_VALUE_FIELD_NUMBER = 2;
-    private boolean boolValue_;
     /**
-     * <code>optional bool bool_value = 2;</code>
-     *
-     * <pre>
-     * boolean
-     * </pre>
+     * <code>repeated .TypedValue value = 1;</code>
+     */
+    public int getValueCount() {
+      return value_.size();
+    }
+    /**
+     * <code>repeated .TypedValue value = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
+      return value_.get(index);
+    }
+    /**
+     * <code>repeated .TypedValue value = 1;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+        int index) {
+      return value_.get(index);
+    }
+
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      for (int i = 0; i < value_.size(); i++) {
+        output.writeMessage(1, value_.get(i));
+      }
+    }
+
+    public int getSerializedSize() {
+      int size = memoizedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      for (int i = 0; i < value_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, value_.get(i));
+      }
+      memoizedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder() {
+      return DEFAULT_INSTANCE.toBuilder();
+    }
+    public static Builder newBuilder(org.apache.calcite.avatica.proto.Common.ColumnValue prototype) {
+      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() {
+      return this == DEFAULT_INSTANCE
+          ? new Builder() : new Builder().mergeFrom(this);
+    }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code ColumnValue}
+     *
+     * <pre>
+     * A value might be a TypedValue or an Array of TypedValue's
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:ColumnValue)
+        org.apache.calcite.avatica.proto.Common.ColumnValueOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.apache.calcite.avatica.proto.Common.internal_static_ColumnValue_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.apache.calcite.avatica.proto.Common.internal_static_ColumnValue_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.apache.calcite.avatica.proto.Common.ColumnValue.class, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder.class);
+      }
+
+      // Construct using org.apache.calcite.avatica.proto.Common.ColumnValue.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getValueFieldBuilder();
+        }
+      }
+      public Builder clear() {
+        super.clear();
+        if (valueBuilder_ == null) {
+          value_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          valueBuilder_.clear();
+        }
+        return this;
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.apache.calcite.avatica.proto.Common.internal_static_ColumnValue_descriptor;
+      }
+
+      public org.apache.calcite.avatica.proto.Common.ColumnValue getDefaultInstanceForType() {
+        return org.apache.calcite.avatica.proto.Common.ColumnValue.getDefaultInstance();
+      }
+
+      public org.apache.calcite.avatica.proto.Common.ColumnValue build() {
+        org.apache.calcite.avatica.proto.Common.ColumnValue result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.apache.calcite.avatica.proto.Common.ColumnValue buildPartial() {
+        org.apache.calcite.avatica.proto.Common.ColumnValue result = new org.apache.calcite.avatica.proto.Common.ColumnValue(this);
+        int from_bitField0_ = bitField0_;
+        if (valueBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001)) {
+            value_ = java.util.Collections.unmodifiableList(value_);
+            bitField0_ = (bitField0_ & ~0x00000001);
+          }
+          result.value_ = value_;
+        } else {
+          result.value_ = valueBuilder_.build();
+        }
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.apache.calcite.avatica.proto.Common.ColumnValue) {
+          return mergeFrom((org.apache.calcite.avatica.proto.Common.ColumnValue)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.apache.calcite.avatica.proto.Common.ColumnValue other) {
+        if (other == org.apache.calcite.avatica.proto.Common.ColumnValue.getDefaultInstance()) return this;
+        if (valueBuilder_ == null) {
+          if (!other.value_.isEmpty()) {
+            if (value_.isEmpty()) {
+              value_ = other.value_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+            } else {
+              ensureValueIsMutable();
+              value_.addAll(other.value_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.value_.isEmpty()) {
+            if (valueBuilder_.isEmpty()) {
+              valueBuilder_.dispose();
+              valueBuilder_ = null;
+              value_ = other.value_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+              valueBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getValueFieldBuilder() : null;
+            } else {
+              valueBuilder_.addAllMessages(other.value_);
+            }
+          }
+        }
+        onChanged();
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.apache.calcite.avatica.proto.Common.ColumnValue parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.apache.calcite.avatica.proto.Common.ColumnValue) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> value_ =
+        java.util.Collections.emptyList();
+      private void ensureValueIsMutable() {
+        if (!((bitField0_ & 0x00000001) == 0x00000001)) {
+          value_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>(value_);
+          bitField0_ |= 0x00000001;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> valueBuilder_;
+
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
+        if (valueBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(value_);
+        } else {
+          return valueBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public int getValueCount() {
+        if (valueBuilder_ == null) {
+          return value_.size();
+        } else {
+          return valueBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
+        if (valueBuilder_ == null) {
+          return value_.get(index);
+        } else {
+          return valueBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder setValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (valueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureValueIsMutable();
+          value_.set(index, value);
+          onChanged();
+        } else {
+          valueBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder setValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (valueBuilder_ == null) {
+          ensureValueIsMutable();
+          value_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          valueBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder addValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (valueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureValueIsMutable();
+          value_.add(value);
+          onChanged();
+        } else {
+          valueBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder addValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (valueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureValueIsMutable();
+          value_.add(index, value);
+          onChanged();
+        } else {
+          valueBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder addValue(
+          org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (valueBuilder_ == null) {
+          ensureValueIsMutable();
+          value_.add(builderForValue.build());
+          onChanged();
+        } else {
+          valueBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder addValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (valueBuilder_ == null) {
+          ensureValueIsMutable();
+          value_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          valueBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder addAllValue(
+          java.lang.Iterable<? extends org.apache.calcite.avatica.proto.Common.TypedValue> values) {
+        if (valueBuilder_ == null) {
+          ensureValueIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, value_);
+          onChanged();
+        } else {
+          valueBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder clearValue() {
+        if (valueBuilder_ == null) {
+          value_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+          onChanged();
+        } else {
+          valueBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public Builder removeValue(int index) {
+        if (valueBuilder_ == null) {
+          ensureValueIsMutable();
+          value_.remove(index);
+          onChanged();
+        } else {
+          valueBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder getValueBuilder(
+          int index) {
+        return getValueFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
+          int index) {
+        if (valueBuilder_ == null) {
+          return value_.get(index);  } else {
+          return valueBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+           getValueOrBuilderList() {
+        if (valueBuilder_ != null) {
+          return valueBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(value_);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder() {
+        return getValueFieldBuilder().addBuilder(
+            org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder(
+          int index) {
+        return getValueFieldBuilder().addBuilder(
+            index, org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .TypedValue value = 1;</code>
+       */
+      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue.Builder> 
+           getValueBuilderList() {
+        return getValueFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+          getValueFieldBuilder() {
+        if (valueBuilder_ == null) {
+          valueBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder>(
+                  value_,
+                  ((bitField0_ & 0x00000001) == 0x00000001),
+                  getParentForChildren(),
+                  isClean());
+          value_ = null;
+        }
+        return valueBuilder_;
+      }
+      public final Builder setUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+      public final Builder mergeUnknownFields(
+          final com.google.protobuf.UnknownFieldSet unknownFields) {
+        return this;
+      }
+
+
+      // @@protoc_insertion_point(builder_scope:ColumnValue)
+    }
+
+    // @@protoc_insertion_point(class_scope:ColumnValue)
+    private static final org.apache.calcite.avatica.proto.Common.ColumnValue DEFAULT_INSTANCE;
+    static {
+      DEFAULT_INSTANCE = new org.apache.calcite.avatica.proto.Common.ColumnValue();
+    }
+
+    public static org.apache.calcite.avatica.proto.Common.ColumnValue getDefaultInstance() {
+      return DEFAULT_INSTANCE;
+    }
+
+    private static final com.google.protobuf.Parser<ColumnValue>
+        PARSER = new com.google.protobuf.AbstractParser<ColumnValue>() {
+      public ColumnValue parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        try {
+          return new ColumnValue(input, extensionRegistry);
+        } catch (RuntimeException e) {
+          if (e.getCause() instanceof
+              com.google.protobuf.InvalidProtocolBufferException) {
+            throw (com.google.protobuf.InvalidProtocolBufferException)
+                e.getCause();
+          }
+          throw e;
+        }
+      }
+    };
+
+    public static com.google.protobuf.Parser<ColumnValue> parser() {
+      return PARSER;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<ColumnValue> getParserForType() {
+      return PARSER;
+    }
+
+    public org.apache.calcite.avatica.proto.Common.ColumnValue getDefaultInstanceForType() {
+      return DEFAULT_INSTANCE;
+    }
+
+  }
+
+  public interface TypedValueOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:TypedValue)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .Rep type = 1;</code>
+     *
+     * <pre>
+     * The actual type that was serialized in the general attribute below
+     * </pre>
+     */
+    int getTypeValue();
+    /**
+     * <code>optional .Rep type = 1;</code>
+     *
+     * <pre>
+     * The actual type that was serialized in the general attribute below
+     * </pre>
+     */
+    org.apache.calcite.avatica.proto.Common.Rep getType();
+
+    /**
+     * <code>optional bool bool_value = 2;</code>
+     *
+     * <pre>
+     * boolean
+     * </pre>
+     */
+    boolean getBoolValue();
+
+    /**
+     * <code>optional string string_value = 3;</code>
+     *
+     * <pre>
+     * char/varchar
+     * </pre>
+     */
+    java.lang.String getStringValue();
+    /**
+     * <code>optional string string_value = 3;</code>
+     *
+     * <pre>
+     * char/varchar
+     * </pre>
+     */
+    com.google.protobuf.ByteString
+        getStringValueBytes();
+
+    /**
+     * <code>optional sint64 number_value = 4;</code>
+     *
+     * <pre>
+     * var-len encoding lets us shove anything from byte to long
+     * </pre>
+     */
+    long getNumberValue();
+
+    /**
+     * <code>optional bytes bytes_values = 5;</code>
+     *
+     * <pre>
+     * includes numeric types and date/time types.
+     * </pre>
+     */
+    com.google.protobuf.ByteString getBytesValues();
+
+    /**
+     * <code>optional double double_value = 6;</code>
+     *
+     * <pre>
+     * big numbers
+     * </pre>
+     */
+    double getDoubleValue();
+
+    /**
+     * <code>optional bool null = 7;</code>
+     *
+     * <pre>
+     * a null object
+     * </pre>
+     */
+    boolean getNull();
+  }
+  /**
+   * Protobuf type {@code TypedValue}
+   *
+   * <pre>
+   * Generic wrapper to support any SQL type. Struct-like to work around no polymorphism construct.
+   * </pre>
+   */
+  public  static final class TypedValue extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:TypedValue)
+      TypedValueOrBuilder {
+    // Use TypedValue.newBuilder() to construct.
+    private TypedValue(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+    }
+    private TypedValue() {
+      type_ = 0;
+      boolValue_ = false;
+      stringValue_ = "";
+      numberValue_ = 0L;
+      bytesValues_ = com.google.protobuf.ByteString.EMPTY;
+      doubleValue_ = 0D;
+      null_ = false;
+    }
+
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+    getUnknownFields() {
+      return com.google.protobuf.UnknownFieldSet.getDefaultInstance();
+    }
+    private TypedValue(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry) {
+      this();
+      int mutable_bitField0_ = 0;
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!input.skipField(tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 8: {
+              int rawValue = input.readEnum();
+
+              type_ = rawValue;
+              break;
+            }
+            case 16: {
+
+              boolValue_ = input.readBool();
+              break;
+            }
+            case 26: {
+              String s = input.readStringRequireUtf8();
+
+              stringValue_ = s;
+              break;
+            }
+            case 32: {
+
+              numberValue_ = input.readSInt64();
+              break;
+            }
+            case 42: {
+
+              bytesValues_ = input.readBytes();
+              break;
+            }
+            case 49: {
+
+              doubleValue_ = input.readDouble();
+              break;
+            }
+            case 56: {
+
+              null_ = input.readBool();
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw new RuntimeException(e.setUnfinishedMessage(this));
+      } catch (java.io.IOException e) {
+        throw new RuntimeException(
+            new com.google.protobuf.InvalidProtocolBufferException(
+                e.getMessage()).setUnfinishedMessage(this));
+      } finally {
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.apache.calcite.avatica.proto.Common.internal_static_TypedValue_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.apache.calcite.avatica.proto.Common.internal_static_TypedValue_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.apache.calcite.avatica.proto.Common.TypedValue.class, org.apache.calcite.avatica.proto.Common.TypedValue.Builder.class);
+    }
+
+    public static final int TYPE_FIELD_NUMBER = 1;
+    private int type_;
+    /**
+     * <code>optional .Rep type = 1;</code>
+     *
+     * <pre>
+     * The actual type that was serialized in the general attribute below
+     * </pre>
+     */
+    public int getTypeValue() {
+      return type_;
+    }
+    /**
+     * <code>optional .Rep type = 1;</code>
+     *
+     * <pre>
+     * The actual type that was serialized in the general attribute below
+     * </pre>
+     */
+    public org.apache.calcite.avatica.proto.Common.Rep getType() {
+      org.apache.calcite.avatica.proto.Common.Rep result = org.apache.calcite.avatica.proto.Common.Rep.valueOf(type_);
+      return result == null ? org.apache.calcite.avatica.proto.Common.Rep.UNRECOGNIZED : result;
+    }
+
+    public static final int BOOL_VALUE_FIELD_NUMBER = 2;
+    private boolean boolValue_;
+    /**
+     * <code>optional bool bool_value = 2;</code>
+     *
+     * <pre>
+     * boolean
+     * </pre>
      */
     public boolean getBoolValue() {
       return boolValue_;
@@ -12726,6 +13439,11 @@ package org.apache.calcite.avatica.proto;
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_WireMessage_fieldAccessorTable;
   private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_ColumnValue_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_ColumnValue_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
     internal_static_TypedValue_descriptor;
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
@@ -12774,33 +13492,35 @@ package org.apache.calcite.avatica.proto;
       "Style\022\n\n\006OBJECT\020\000\022\n\n\006RECORD\020\001\022\025\n\021RECORD_" +
       "PROJECTION\020\002\022\t\n\005ARRAY\020\003\022\010\n\004LIST\020\004\022\007\n\003MAP" +
       "\020\005\"9\n\005Frame\022\016\n\006offset\030\001 \001(\004\022\014\n\004done\030\002 \001(" +
-      "\010\022\022\n\004rows\030\003 \003(\0132\004.Row\"!\n\003Row\022\032\n\005value\030\001 " +
-      "\003(\0132\013.TypedValue\"3\n\020DatabaseProperty\022\014\n\004" +
-      "name\030\001 \001(\t\022\021\n\tfunctions\030\002 \003(\t\"4\n\013WireMes" +
-      "sage\022\014\n\004name\030\001 \001(\t\022\027\n\017wrapped_message\030\002 " +
-      "\001(\014\"\232\001\n\nTypedValue\022\022\n\004type\030\001 \001(\0162\004.Rep\022\022",
-      "\n\nbool_value\030\002 \001(\010\022\024\n\014string_value\030\003 \001(\t" +
-      "\022\024\n\014number_value\030\004 \001(\022\022\024\n\014bytes_values\030\005" +
-      " \001(\014\022\024\n\014double_value\030\006 \001(\001\022\014\n\004null\030\007 \001(\010" +
-      "*\237\001\n\rStatementType\022\n\n\006SELECT\020\000\022\n\n\006INSERT" +
-      "\020\001\022\n\n\006UPDATE\020\002\022\n\n\006DELETE\020\003\022\n\n\006UPSERT\020\004\022\t" +
-      "\n\005MERGE\020\005\022\r\n\tOTHER_DML\020\006\022\n\n\006CREATE\020\007\022\010\n\004" +
-      "DROP\020\010\022\t\n\005ALTER\020\t\022\r\n\tOTHER_DDL\020\n\022\010\n\004CALL" +
-      "\020\013*\275\003\n\003Rep\022\025\n\021PRIMITIVE_BOOLEAN\020\000\022\022\n\016PRI" +
-      "MITIVE_BYTE\020\001\022\022\n\016PRIMITIVE_CHAR\020\002\022\023\n\017PRI" +
-      "MITIVE_SHORT\020\003\022\021\n\rPRIMITIVE_INT\020\004\022\022\n\016PRI",
-      "MITIVE_LONG\020\005\022\023\n\017PRIMITIVE_FLOAT\020\006\022\024\n\020PR" +
-      "IMITIVE_DOUBLE\020\007\022\013\n\007BOOLEAN\020\010\022\010\n\004BYTE\020\t\022" +
-      "\r\n\tCHARACTER\020\n\022\t\n\005SHORT\020\013\022\013\n\007INTEGER\020\014\022\010" +
-      "\n\004LONG\020\r\022\t\n\005FLOAT\020\016\022\n\n\006DOUBLE\020\017\022\017\n\013BIG_I" +
-      "NTEGER\020\031\022\017\n\013BIG_DECIMAL\020\032\022\021\n\rJAVA_SQL_TI" +
-      "ME\020\020\022\026\n\022JAVA_SQL_TIMESTAMP\020\021\022\021\n\rJAVA_SQL" +
-      "_DATE\020\022\022\022\n\016JAVA_UTIL_DATE\020\023\022\017\n\013BYTE_STRI" +
-      "NG\020\024\022\n\n\006STRING\020\025\022\n\n\006NUMBER\020\026\022\n\n\006OBJECT\020\027" +
-      "\022\010\n\004NULL\020\030*^\n\010Severity\022\024\n\020UNKNOWN_SEVERI" +
-      "TY\020\000\022\022\n\016FATAL_SEVERITY\020\001\022\022\n\016ERROR_SEVERI",
-      "TY\020\002\022\024\n\020WARNING_SEVERITY\020\003B\"\n org.apache" +
-      ".calcite.avatica.protob\006proto3"
+      "\010\022\022\n\004rows\030\003 \003(\0132\004.Row\"\"\n\003Row\022\033\n\005value\030\001 " +
+      "\003(\0132\014.ColumnValue\"3\n\020DatabaseProperty\022\014\n" +
+      "\004name\030\001 \001(\t\022\021\n\tfunctions\030\002 \003(\t\"4\n\013WireMe" +
+      "ssage\022\014\n\004name\030\001 \001(\t\022\027\n\017wrapped_message\030\002" +
+      " \001(\014\")\n\013ColumnValue\022\032\n\005value\030\001 \003(\0132\013.Typ",
+      "edValue\"\232\001\n\nTypedValue\022\022\n\004type\030\001 \001(\0162\004.R" +
+      "ep\022\022\n\nbool_value\030\002 \001(\010\022\024\n\014string_value\030\003" +
+      " \001(\t\022\024\n\014number_value\030\004 \001(\022\022\024\n\014bytes_valu" +
+      "es\030\005 \001(\014\022\024\n\014double_value\030\006 \001(\001\022\014\n\004null\030\007" +
+      " \001(\010*\237\001\n\rStatementType\022\n\n\006SELECT\020\000\022\n\n\006IN" +
+      "SERT\020\001\022\n\n\006UPDATE\020\002\022\n\n\006DELETE\020\003\022\n\n\006UPSERT" +
+      "\020\004\022\t\n\005MERGE\020\005\022\r\n\tOTHER_DML\020\006\022\n\n\006CREATE\020\007" +
+      "\022\010\n\004DROP\020\010\022\t\n\005ALTER\020\t\022\r\n\tOTHER_DDL\020\n\022\010\n\004" +
+      "CALL\020\013*\342\003\n\003Rep\022\025\n\021PRIMITIVE_BOOLEAN\020\000\022\022\n" +
+      "\016PRIMITIVE_BYTE\020\001\022\022\n\016PRIMITIVE_CHAR\020\002\022\023\n",
+      "\017PRIMITIVE_SHORT\020\003\022\021\n\rPRIMITIVE_INT\020\004\022\022\n" +
+      "\016PRIMITIVE_LONG\020\005\022\023\n\017PRIMITIVE_FLOAT\020\006\022\024" +
+      "\n\020PRIMITIVE_DOUBLE\020\007\022\013\n\007BOOLEAN\020\010\022\010\n\004BYT" +
+      "E\020\t\022\r\n\tCHARACTER\020\n\022\t\n\005SHORT\020\013\022\013\n\007INTEGER" +
+      "\020\014\022\010\n\004LONG\020\r\022\t\n\005FLOAT\020\016\022\n\n\006DOUBLE\020\017\022\017\n\013B" +
+      "IG_INTEGER\020\031\022\017\n\013BIG_DECIMAL\020\032\022\021\n\rJAVA_SQ" +
+      "L_TIME\020\020\022\026\n\022JAVA_SQL_TIMESTAMP\020\021\022\021\n\rJAVA" +
+      "_SQL_DATE\020\022\022\022\n\016JAVA_UTIL_DATE\020\023\022\017\n\013BYTE_" +
+      "STRING\020\024\022\n\n\006STRING\020\025\022\n\n\006NUMBER\020\026\022\n\n\006OBJE" +
+      "CT\020\027\022\010\n\004NULL\020\030\022\t\n\005ARRAY\020\033\022\n\n\006STRUCT\020\034\022\014\n",
+      "\010MULTISET\020\035*^\n\010Severity\022\024\n\020UNKNOWN_SEVER" +
+      "ITY\020\000\022\022\n\016FATAL_SEVERITY\020\001\022\022\n\016ERROR_SEVER" +
+      "ITY\020\002\022\024\n\020WARNING_SEVERITY\020\003B\"\n org.apach" +
+      "e.calcite.avatica.protob\006proto3"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -12880,8 +13600,14 @@ package org.apache.calcite.avatica.proto;
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_WireMessage_descriptor,
         new java.lang.String[] { "Name", "WrappedMessage", });
-    internal_static_TypedValue_descriptor =
+    internal_static_ColumnValue_descriptor =
       getDescriptor().getMessageTypes().get(11);
+    internal_static_ColumnValue_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_ColumnValue_descriptor,
+        new java.lang.String[] { "Value", });
+    internal_static_TypedValue_descriptor =
+      getDescriptor().getMessageTypes().get(12);
     internal_static_TypedValue_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_TypedValue_descriptor,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
index 8cca9d9..3ca21f7 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/MockProtobufService.java
@@ -54,11 +54,13 @@ public class MockProtobufService extends ProtobufService {
     // Get the schema, no.. schema..?
     mappings.put(
         new SchemasRequest(connectionId, null, null),
-        new ResultSetResponse(null, 1, true, null, Meta.Frame.EMPTY, -1));
+        // ownStatement=false just to avoid the extra close statement call.
+        new ResultSetResponse(null, 1, false, null, Meta.Frame.EMPTY, -1));
 
     // Get the tables, no tables exist
     mappings.put(new TablesRequest(connectionId, null, null, null, Collections.<String>emptyList()),
-        new ResultSetResponse(null, 150, true, null, Meta.Frame.EMPTY, -1));
+        // ownStatement=false just to avoid the extra close statement call.
+        new ResultSetResponse(null, 150, false, null, Meta.Frame.EMPTY, -1));
 
     // Create a statement, get back an id
     mappings.put(new CreateStatementRequest("0"), new CreateStatementResponse("0", 1));

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica/src/main/protobuf/common.proto
----------------------------------------------------------------------
diff --git a/avatica/src/main/protobuf/common.proto b/avatica/src/main/protobuf/common.proto
index 3716c7e..f4de1f9 100644
--- a/avatica/src/main/protobuf/common.proto
+++ b/avatica/src/main/protobuf/common.proto
@@ -114,6 +114,9 @@ enum Rep {
   NUMBER = 22;
   OBJECT = 23;
   NULL = 24;
+  ARRAY = 27;
+  STRUCT = 28;
+  MULTISET = 29;
 }
 
 // Base class for a column type
@@ -162,7 +165,7 @@ message Frame {
 
 // A row is a collection of values
 message Row {
-  repeated TypedValue value = 1;
+  repeated ColumnValue value = 1;
 }
 
 // Database property, list of functions the database provides for a certain operation
@@ -177,6 +180,11 @@ message WireMessage {
   bytes wrapped_message = 2;
 }
 
+// A value might be a TypedValue or an Array of TypedValue's
+message ColumnValue {
+  repeated TypedValue value = 1;
+}
+
 // Generic wrapper to support any SQL type. Struct-like to work around no polymorphism construct.
 message TypedValue {
   Rep type = 1; // The actual type that was serialized in the general attribute below

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/bf178d55/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
index aa03c3c..f91f597 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
@@ -105,17 +105,22 @@ public class ProtobufHandlerTest {
     List<Common.Row> rows = protoFrame.getRowsList();
     assertEquals(1, rows.size());
     Common.Row row = rows.get(0);
-    List<Common.TypedValue> rowValues = row.getValueList();
-    assertEquals(2, rowValues.size());
+    List<Common.ColumnValue> columnValues = row.getValueList();
+    assertEquals(2, columnValues.size());
 
-    Iterator<Common.TypedValue> iter = rowValues.iterator();
+    Iterator<Common.ColumnValue> iter = columnValues.iterator();
     assertTrue(iter.hasNext());
-    Common.TypedValue value = iter.next();
+    Common.ColumnValue column = iter.next();
+    assertEquals(1, column.getValueCount());
+
+    Common.TypedValue value = column.getValue(0);
     assertEquals(Common.Rep.BOOLEAN, value.getType());
     assertEquals(true, value.getBoolValue());
 
     assertTrue(iter.hasNext());
-    value = iter.next();
+    column = iter.next();
+    assertEquals(1, column.getValueCount());
+    value = column.getValue(0);
     assertEquals(Common.Rep.STRING, value.getType());
     assertEquals("my_string", value.getStringValue());
   }


[2/6] incubator-calcite git commit: [CALCITE-933] RelBuilder.scan() now gives a nice exception if the table does not exist (Andy Grove)

Posted by jh...@apache.org.
[CALCITE-933] RelBuilder.scan() now gives a nice exception if the table does not exist (Andy Grove)

Close apache/incubator-calcite#159


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

Branch: refs/heads/master
Commit: 57e1b4c14f0369e9b40df99435c6525fea9d1c96
Parents: 690faa5
Author: Andy Grove <an...@gmail.com>
Authored: Thu Oct 22 15:44:54 2015 -0600
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 26 11:39:34 2015 -0700

----------------------------------------------------------------------
 .../apache/calcite/runtime/CalciteResource.java |  3 ++
 .../org/apache/calcite/tools/RelBuilder.java    |  4 +++
 .../calcite/runtime/CalciteResource.properties  |  1 +
 .../org/apache/calcite/test/RelBuilderTest.java | 30 ++++++++++++++++++++
 4 files changed, 38 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/57e1b4c1/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index e74f915..0670948 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -591,6 +591,9 @@ public interface CalciteResource {
 
   @BaseMessage("View is not modifiable. No value is supplied for NOT NULL column ''{0}'' of base table ''{1}''")
   ExInst<SqlValidatorException> noValueSuppliedForViewColumn(String columnName, String tableName);
+
+  @BaseMessage("Table ''{0}'' not found")
+  ExInst<CalciteException> tableNotFound(String tableName);
 }
 
 // End CalciteResource.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/57e1b4c1/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index a403c6a..5e6ea45 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -57,6 +57,7 @@ import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Stacks;
+import org.apache.calcite.util.Static;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.mapping.Mapping;
 import org.apache.calcite.util.mapping.Mappings;
@@ -650,6 +651,9 @@ public class RelBuilder {
   public RelBuilder scan(String tableName) {
     final RelOptTable relOptTable =
         relOptSchema.getTableForMember(ImmutableList.of(tableName));
+    if (relOptTable == null) {
+      throw Static.RESOURCE.tableNotFound(tableName).ex();
+    }
     final RelNode scan = scanFactory.createScan(cluster, relOptTable);
     push(scan);
     return this;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/57e1b4c1/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index b3f9cce..9703e1d 100644
--- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -193,4 +193,5 @@ CannotStreamValues=Cannot stream VALUES
 ModifiableViewMustBeBasedOnSingleTable=Modifiable view must be based on a single table
 MoreThanOneMappedColumn=View is not modifiable. More than one expression maps to column ''{0}'' of base table ''{1}''
 NoValueSuppliedForViewColumn=View is not modifiable. No value is supplied for NOT NULL column ''{0}'' of base table ''{1}''
+TableNotFound=Table ''{0}'' not found
 # End CalciteResource.properties

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/57e1b4c1/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index 5e11fd1..7ce40c8 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -116,6 +116,36 @@ public class RelBuilderTest {
         is("LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testScanInvalidTable() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM zzz
+    try {
+      final RelNode root =
+          RelBuilder.create(config().build())
+              .scan("ZZZ") // this relation does not exist
+              .build();
+      fail("expected error, got " + root);
+    } catch (Exception e) {
+      assertThat(e.getMessage(), is("Table 'ZZZ' not found"));
+    }
+  }
+
+  @Test public void testScanValidTableWrongCase() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM "emp"
+    try {
+      final RelNode root =
+          RelBuilder.create(config().build())
+              .scan("emp") // the table is named 'EMP', not 'emp'
+              .build();
+      fail("Expected error (table names are case-sensitive), but got " + root);
+    } catch (Exception e) {
+      assertThat(e.getMessage(), is("Table 'emp' not found"));
+    }
+  }
+
   @Test public void testScanFilterTrue() {
     // Equivalent SQL:
     //   SELECT *