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 2016/01/15 00:05:23 UTC

[01/13] calcite git commit: [CALCITE-996] Simplify predicate when we create a Filter operator [Forced Update!]

Repository: calcite
Updated Branches:
  refs/heads/branch-1.6 be7f4ff7a -> 3d12a4f0d (forced update)


[CALCITE-996] Simplify predicate when we create a Filter operator

Close apache/calcite#171


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

Branch: refs/heads/branch-1.6
Commit: a67b4a976bef6c104212732c6a8f8ce364c372ba
Parents: ebcba3b
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Mon Jan 11 21:12:30 2016 +0100
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 10:21:49 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/tools/RelBuilder.java    |  6 +++---
 .../org/apache/calcite/test/RelBuilderTest.java | 22 ++++++++++++++++++++
 .../calcite/test/SqlToRelConverterTest.xml      | 11 ++++------
 3 files changed, 29 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/a67b4a97/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 916f0dd..00ce6d1 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -692,9 +692,9 @@ public class RelBuilder {
    * and optimized in a similar way to the {@link #and} method.
    * If the result is TRUE no filter is created. */
   public RelBuilder filter(Iterable<? extends RexNode> predicates) {
-    final RexNode x = RexUtil.composeConjunction(cluster.getRexBuilder(),
-        predicates, true);
-    if (x != null) {
+    final RexNode x = RexUtil.simplify(cluster.getRexBuilder(),
+            RexUtil.composeConjunction(cluster.getRexBuilder(), predicates, false));
+    if (!x.isAlwaysTrue()) {
       final Frame frame = Stacks.pop(stack);
       final RelNode filter = filterFactory.createFilter(frame.rel, x);
       Stacks.push(stack, new Frame(filter, frame.right));

http://git-wip-us.apache.org/repos/asf/calcite/blob/a67b4a97/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 bb53728..0b232f4 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -202,6 +202,28 @@ public class RelBuilderTest {
             + "  LogicalTableScan(table=[[scott, EMP]])\n"));
   }
 
+  @Test public void testScanFilterOr2() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   WHERE deptno = 20 OR deptno = 20
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("EMP")
+            .filter(
+                builder.call(SqlStdOperatorTable.OR,
+                    builder.call(SqlStdOperatorTable.GREATER_THAN,
+                        builder.field("DEPTNO"),
+                        builder.literal(20)),
+                    builder.call(SqlStdOperatorTable.GREATER_THAN,
+                        builder.field("DEPTNO"),
+                        builder.literal(20))))
+            .build();
+    assertThat(str(root),
+        is("LogicalFilter(condition=[>($7, 20)])\n"
+            + "  LogicalTableScan(table=[[scott, EMP]])\n"));
+  }
+
   @Test public void testBadFieldName() {
     final RelBuilder builder = RelBuilder.create(config().build());
     try {

http://git-wip-us.apache.org/repos/asf/calcite/blob/a67b4a97/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
index 764dde2..a02eb60 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -511,8 +511,7 @@ LogicalProject(EXPR$0=[1])
     <TestCase name="testIntervalLiteralYearToMonth">
         <Resource name="sql">
             <![CDATA[select cast(empno as Integer) * (INTERVAL '1-1' YEAR TO MONTH)
-from emp
-]]>
+from emp]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -524,8 +523,7 @@ LogicalProject(EXPR$0=[*(CAST($0):INTEGER NOT NULL, 13)])
     <TestCase name="testIntervalLiteralHourToMinute">
         <Resource name="sql">
             <![CDATA[select cast(empno as Integer) * (INTERVAL '1:1' HOUR TO MINUTE)
-from emp
-]]>
+from emp]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2394,8 +2392,7 @@ LogicalProject(EXPR$0=[$2], EXPR$1=[RANK() OVER (ORDER BY $1 RANGE BETWEEN UNBOU
         <Resource name="sql">
             <![CDATA[select avg(deptno) over ()
 from emp
-group by deptno
-]]>
+group by deptno]]>
         </Resource>
         <Resource name="plan">
             <![CDATA[
@@ -2562,7 +2559,7 @@ and not exists (select * from emp e2 where e1.empno = e2.empno)]]>
             <![CDATA[
 LogicalProject(EMPNO=[$0])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8], DEPTNO0=[$9], NAME=[$10], $f0=[$12])
-    LogicalFilter(condition=[NOT(IS NOT NULL($12))])
+    LogicalFilter(condition=[IS NULL($12)])
       LogicalJoin(condition=[=($0, $11)], joinType=[left])
         LogicalJoin(condition=[=($7, $9)], joinType=[inner])
           LogicalFilter(condition=[<($7, 10)])


[07/13] calcite git commit: [CALCITE-1053] CPU spin in ReflectiveRelMetadataProvider.apply -> HashMap.get

Posted by jh...@apache.org.
[CALCITE-1053] CPU spin in ReflectiveRelMetadataProvider.apply -> HashMap.get

The map in question is shared between multiple threads and updated at the same time.
Thus the map should be a ConcurrentMap.

Problem was reported here: https://mail-archives.apache.org/mod_mbox/calcite-dev/201601.mbox/%3C56952E8F.7090705%40gmail.com%3E


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

Branch: refs/heads/branch-1.6
Commit: 2712d7dafc1b724c33b0c29846666c1903d5afb2
Parents: 5323d8d
Author: Vladimir Sitnikov <si...@gmail.com>
Authored: Wed Jan 13 11:36:19 2016 +0300
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jan 13 08:42:52 2016 -0800

----------------------------------------------------------------------
 .../rel/metadata/ReflectiveRelMetadataProvider.java    | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/2712d7da/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
index beaedfe..8cdb55a 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
@@ -39,10 +39,11 @@ import java.lang.reflect.Proxy;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * Implementation of the {@link RelMetadataProvider} interface that dispatches
@@ -60,7 +61,7 @@ public class ReflectiveRelMetadataProvider
     implements RelMetadataProvider, ReflectiveVisitor {
 
   //~ Instance fields --------------------------------------------------------
-  private final Map<Class<RelNode>, UnboundMetadata> map;
+  private final ConcurrentMap<Class<RelNode>, UnboundMetadata> map;
   private final Class<? extends Metadata> metadataClass0;
 
   //~ Constructors -----------------------------------------------------------
@@ -72,7 +73,7 @@ public class ReflectiveRelMetadataProvider
    * @param metadataClass0 Metadata class
    */
   protected ReflectiveRelMetadataProvider(
-      Map<Class<RelNode>, UnboundMetadata> map,
+      ConcurrentMap<Class<RelNode>, UnboundMetadata> map,
       Class<? extends Metadata> metadataClass0) {
     assert !map.isEmpty() : "are your methods named wrong?";
     this.map = map;
@@ -135,7 +136,11 @@ public class ReflectiveRelMetadataProvider
       }
     }
 
-    final Map<Class<RelNode>, UnboundMetadata> methodsMap = new HashMap<>();
+    // This needs to be a councurrent map since RelMetadataProvider are cached in static
+    // fields, thus the map is subject to concurrent modifications later.
+    // See map.put in org.apache.calcite.rel.metadata.ReflectiveRelMetadataProvider.apply(
+    // java.lang.Class<? extends org.apache.calcite.rel.RelNode>)
+    final ConcurrentMap<Class<RelNode>, UnboundMetadata> methodsMap = new ConcurrentHashMap<>();
     for (Class<RelNode> key : classes) {
       ImmutableNullableList.Builder<Method> builder =
           ImmutableNullableList.builder();


[13/13] calcite git commit: Add release notes for version 1.6.0

Posted by jh...@apache.org.
Add release notes for version 1.6.0


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

Branch: refs/heads/branch-1.6
Commit: 3d12a4f0dddb51e8f8468d4d9b65f9880e25609a
Parents: af77ec8
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jan 14 14:17:56 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jan 14 14:52:57 2016 -0800

----------------------------------------------------------------------
 README                |   2 +-
 pom.xml               |   2 +-
 site/_docs/history.md | 232 +++++++++++++++++++++++++++++++++++++++++++++
 site/_docs/howto.md   |   6 +-
 4 files changed, 237 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/3d12a4f0/README
----------------------------------------------------------------------
diff --git a/README b/README
index a68be99..b492f4d 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Apache Calcite release 1.5.0
+Apache Calcite release 1.6.0
 
 This is a source or binary distribution of Apache Calcite.
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/3d12a4f0/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2d83845..5c23392 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@ limitations under the License.
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <top.dir>${project.basedir}</top.dir>
     <version.major>1</version.major>
-    <version.minor>5</version.minor>
+    <version.minor>6</version.minor>
   </properties>
 
   <issueManagement>

http://git-wip-us.apache.org/repos/asf/calcite/blob/3d12a4f0/site/_docs/history.md
----------------------------------------------------------------------
diff --git a/site/_docs/history.md b/site/_docs/history.md
index 6769758..1ffd2ab 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -28,6 +28,236 @@ For a full list of releases, see
 Downloads are available on the
 [downloads page]({{ site.baseurl }}/downloads/).
 
+## <a href="https://github.com/apache/calcite/releases/tag/calcite-1.6.0">1.6.0</a> / 2016-01-14
+{: #v1-6-0}
+
+As usual in this release, there are new SQL features, improvements to
+planning rules and Avatica, and lots of bug fixes. We'll spotlight a
+couple of features make it easier to handle complex queries.
+
+[<a href="https://issues.apache.org/jira/browse/CALCITE-816">CALCITE-816</a>]
+allows you to represent sub-queries (`EXISTS`, `IN` and scalar) as
+`RexSubQuery`, a kind of expression in the relational algebra. Until
+now, the sql-to-rel converter was burdened with expanding sub-queries,
+and people creating relational algebra directly (or via RelBuilder)
+could only create 'flat' relational expressions. Now we have planner
+rules to expand and de-correlate sub-queries.
+
+Metadata is the fuel that powers query planning. It includes
+traditional query-planning statistics such as cost and row-count
+estimates, but also information such as which columns form unique
+keys, unique and what predicates are known to apply to a relational
+expression's output rows. From the predicates we can deduce which
+columns are constant, and following
+[<a href="https://issues.apache.org/jira/browse/CALCITE-1023">CALCITE-1023</a>]
+we can now remove constant columns from `GROUP BY` keys.
+
+Metadata is often computed recursively, and it is hard to safely and
+efficiently calculate metadata on a graph of `RelNode`s that is large,
+frequently cyclic, and constantly changing.
+[<a href="https://issues.apache.org/jira/browse/CALCITE-794">CALCITE-794</a>]
+introduces a context to each metadata call. That context can detect
+cyclic metadata calls and produce a safe answer to the metadata
+request. It will also allow us to add finer-grained caching and
+further tune the metadata layer.
+
+New features
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-816">CALCITE-816</a>]
+  Represent sub-query as a `RexNode`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-854">CALCITE-854</a>]
+  Implement `UNNEST ... WITH ORDINALITY`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1003">CALCITE-1003</a>]
+  Utility to convert `RelNode` to SQL (Amogh Margoor)
+  * [<a href="https://issues.apache.org/jira/browse/CALCITE-1010">CALCITE-1010</a>]
+    `FETCH/LIMIT` and `OFFSET` in RelToSqlConverter (Amogh Margoor)
+  * Move code from `JdbcImplementor` and `JdbcRules` to new class
+    `SqlImplementor`
+  * Deduce dialect's null collation from `DatabaseMetaData`
+  * Fix `RelToSqlConverterTest` on Windows
+* Following
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-897">CALCITE-897</a>],
+  empty string for `boolean` properties means true
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-992">CALCITE-992</a>]
+  Validate and resolve sequence reference as a `Table` object
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-968">CALCITE-968</a>]
+  Stream-to-relation and stream-to-stream joins (Milinda Pathirage)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1041">CALCITE-1041</a>]
+  User-defined function that returns `DATE` or `TIMESTAMP` value
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-986">CALCITE-986</a>]
+  User-defined function with `DATE` or `TIMESTAMP` parameters
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-958">CALCITE-958</a>]
+  Overloaded Table Functions with named arguments (Julien Le Dem)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-970">CALCITE-970</a>]
+  If `NULLS FIRST`/`NULLS LAST` not specified, sort `NULL` values high
+
+Avatica features and bug fixes
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1040">CALCITE-1040</a>]
+  Differentiate better between arrays and scalars in protobuf
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-934">CALCITE-934</a>]
+  Use an OS-assigned ephemeral port for `CalciteRemoteDriverTest`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-767">CALCITE-767</a>]
+  Create Avatica RPC endpoints for commit and rollback commands
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-983">CALCITE-983</a>]
+  Handle nulls in `ErrorResponse`'s protobuf representation better
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-989">CALCITE-989</a>]
+  Add server's address in each response
+* Fix some bugs found by static analysis
+* Make all `equals` and `hashCode` methods uniform
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-962">CALCITE-962</a>]
+  Propagate the cause, not just the cause's message, from `JdbcMeta`
+
+Planner rules
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1057">CALCITE-1057</a>]
+  Add `RelMetadataProvider` parameter to standard planner `Program`s
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1055">CALCITE-1055</a>]
+  `SubQueryRemoveRule` should create `Correlate`, not `Join`, for correlated
+  sub-queries
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-978">CALCITE-978</a>]
+  Enable customizing constant folding rule behavior when a `Filter` simplifies
+  to false (Jason Altekruse)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-977">CALCITE-977</a>]
+  Make the constant expression `Executor` configurable in `FrameworkConfig`
+  (Jason Altekruse)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1058">CALCITE-1058</a>]
+  Add method `RelBuilder.empty`, and rewrite LIMIT 0 and WHERE FALSE to it
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-996">CALCITE-996</a>]
+  Simplify predicate when we create a `Filter` operator
+* Simplify `RexProgram`, in particular `(NOT CASE ... END) IS TRUE`, which
+  occurs in when `NOT IN` is expanded
+* Fix variant of
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-923">CALCITE-923</a>]
+  that occurs in `RelOptRulesTest.testPushFilterPastProject`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1023">CALCITE-1023</a>]
+  and
+  [<a href="https://issues.apache.org/jira/browse/CALCITE-1038">CALCITE-1038</a>]
+  Planner rule that removes `Aggregate` keys that are constant
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1018">CALCITE-1018</a>]
+  `SortJoinTransposeRule` not firing due to `getMaxRowCount(RelSubset)` returning
+  null
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1019">CALCITE-1019</a>]
+  `RelMdUtil.checkInputForCollationAndLimit()` was wrong with `alreadySorted`
+  check
+* Not safe to use '=' for predicates on constant expressions that might be null
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-993">CALCITE-993</a>]
+  Pull up all constant expressions, not just literals, as predicates
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1005">CALCITE-1005</a>]
+  Handle null in `getMaxRowCount` for `Aggregate` (Mike Hinchey)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-995">CALCITE-995</a>]
+  Sort transpose rules might fall in an infinite loop
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-987">CALCITE-987</a>]
+  Pushing `LIMIT 0` results in an infinite loop (Pengcheng Xiong)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-988">CALCITE-988</a>]
+  `FilterToProjectUnifyRule.invert(MutableRel, MutableRel, MutableProject)`
+  works incorrectly
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-969">CALCITE-969</a>]
+  Composite `EnumerableSort` with `DESC` wrongly sorts `NULL` values low
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-959">CALCITE-959</a>]
+  Add description to `SortProjectTransposeRule`'s constructor
+
+Bug fixes, API changes and minor enhancements
+
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1047">CALCITE-1047</a>]
+  `ChunkList.clear` throws `AssertionError`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1053">CALCITE-1053</a>]
+  CPU spin, `ReflectiveRelMetadataProvider.apply` waiting for `HashMap.get`
+* Upgrade toolbox, to fix line length issue on Windows
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1051">CALCITE-1051</a>]
+  Underflow exception due to scaling IN clause literals (Frankie Bollaert)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-975">CALCITE-975</a>]
+  Allow Planner to return validated row type together with SqlNode
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1020">CALCITE-1020</a>]
+  Add `MILLISECOND` in `TimeUnit` (Pengcheng Xiong)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-794">CALCITE-794</a>]
+  Detect cycles when computing statistics
+  (**This is a breaking change**.)
+* Tune algorithm that deduces the return type of `AND` expression
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-842">CALCITE-842</a>]
+  Decorrelator gets field offsets confused if fields have been trimmed
+* Fix `NullPointerException` in `SqlJoin.toString()`
+* Add `ImmutableBitSet.rebuild()`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-915">CALCITE-915</a>]
+  Tests now unset `ThreadLocal` values on exit
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1036">CALCITE-1036</a>]
+  `DiffRepository` should not insert new resources at the end of the repository
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-955">CALCITE-955</a>]
+  `Litmus` (continuation-passing style for methods that check invariants)
+* `RelBuilder.project` now does nothing if asked to project the identity with
+  the same field names
+* Deprecate some `Util` methods, and upgrade last Maven modules to JDK 1.7
+* Document `RelOptPredicateList`
+* Add `ImmutableNullableList.copyOf(Iterable)`
+* Fix "endPosTable already set" error from `javac`
+* Add benchmark of `Parser.create(sql).parseQuery()`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1042">CALCITE-1042</a>]
+  Ensure that `FILTER` is `BOOLEAN NOT NULL`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1039">CALCITE-1039</a>]
+  Assign a `SqlKind` value for each built-in aggregate function
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1030">CALCITE-1030</a>]
+  JSON `ModelHandler` calling `SchemaPlus.setCacheEnabled()` causes
+  `UnsupportedOperationException` when using `SimpleCalciteSchema`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1028">CALCITE-1028</a>]
+  Move populate materializations after sql-to-rel conversion
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1034">CALCITE-1034</a>]
+  Use a custom checker for code style rules that Checkstyle cannot express
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1032">CALCITE-1032</a>]
+  Verify javadoc of private methods
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1015">CALCITE-1015</a>]
+  `OFFSET 0` causes `AssertionError` (Zhen Wang)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1024">CALCITE-1024</a>]
+  In a planner test, if a rule should have no effect, state that explicitly
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1016">CALCITE-1016</a>]
+  `GROUP BY *constant*` on empty relation should return 0 rows
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1022">CALCITE-1022</a>]
+  Rename `.oq` Quidem files to `.iq`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-980">CALCITE-980</a>]
+  Fix `AND` and `OR` implementation in `Enumerable` convention
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-459">CALCITE-459</a>]
+  When parsing SQL, allow single line comment on last line (Zhen Wang)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1009">CALCITE-1009</a>]
+  `SelfPopulatingList` is not thread-safe
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1008">CALCITE-1008</a>]
+  Replace `Closeable` with `AutoCloseable`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-1001">CALCITE-1001</a>]
+  Upgrade to quidem-0.7
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-990">CALCITE-990</a>]
+  In `VolcanoPlanner`, populate `RelOptRuleCall.nodeInputs` for operands of type
+  "any"
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-966">CALCITE-966</a>]
+  `VolcanoPlanner` now clears `ruleNames` in order to avoid rule name
+  conflicting error
+* Factor user-defined function tests from `JdbcTest` to `UdfTest`, and classes
+  into `Smalls`
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-974">CALCITE-974</a>]
+  Exception while validating `DELETE` (Yuri Au Yong)
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-964">CALCITE-964</a>]
+  Rename `timezone` connection property to `timeZone`
+
+Web site and documentation
+
+* Avatica
+  * [<a href="https://issues.apache.org/jira/browse/CALCITE-1033">CALCITE-1033</a>]
+    Introduce Avatica protobuf documentation
+  * [<a href="https://issues.apache.org/jira/browse/CALCITE-1029">CALCITE-1029</a>]
+     Add "purpose" descriptions to Avatica JSON docs
+  * [<a href="https://issues.apache.org/jira/browse/CALCITE-984">CALCITE-984</a>]
+    Massive cleanup of Avatica JSON docs
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-861">CALCITE-861</a>]
+  Be explicit that `mvn test` needs to be invoked
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-997">CALCITE-997</a>]
+  Document keywords
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-979">CALCITE-979</a>]
+  Broken links in web site
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-961">CALCITE-961</a>]
+  Web site: Add downloads and Apache navigation links
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-960">CALCITE-960</a>]
+  Download links for pgp, md5, `KEYS` files, and direct from mirrors
+* Remove embedded date-stamps from javadoc; add javadoc for test classes
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-965">CALCITE-965</a>]
+  Link to downloads page from each release news item
+
 ## <a href="https://github.com/apache/calcite/releases/tag/calcite-1.5.0">1.5.0</a> / 2015-11-06
 {: #v1-5-0}
 
@@ -201,6 +431,8 @@ RelBuilder and Piglet
 * Multisets and `COLLECT` in Piglet
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-785">CALCITE-785</a>]
   Add "Piglet", a subset of Pig Latin on top of Calcite algebra
+* [<a href="https://issues.apache.org/jira/browse/CALCITE-869">CALCITE-869</a>]
+  Add `VALUES` command to Piglet
 * [<a href="https://issues.apache.org/jira/browse/CALCITE-868">CALCITE-868</a>]
   Add API to execute queries expressed as `RelNode`
 * In RelBuilder, build expressions by table alias

http://git-wip-us.apache.org/repos/asf/calcite/blob/3d12a4f0/site/_docs/howto.md
----------------------------------------------------------------------
diff --git a/site/_docs/howto.md b/site/_docs/howto.md
index 2f2bddc..5389147 100644
--- a/site/_docs/howto.md
+++ b/site/_docs/howto.md
@@ -39,8 +39,8 @@ Unpack the source distribution `.tar.gz` or `.zip` file,
 then build using maven:
 
 {% highlight bash %}
-$ tar xvfz calcite-1.5.0-source.tar.gz
-$ cd calcite-1.5.0
+$ tar xvfz calcite-1.6.0-source.tar.gz
+$ cd calcite-1.6.0
 $ mvn install
 {% endhighlight %}
 
@@ -414,7 +414,7 @@ Before you start:
 
 * Set up signing keys as described above.
 * Make sure you are using JDK 1.7 (not 1.8).
-* Check that `README`, `README.md` and `doc/howto.md` have the correct version number.
+* Check that `README` and `site/_docs/howto.md` have the correct version number.
 * Set `version.major` and `version.minor` in `pom.xml`.
 * Make sure build and tests succeed, including with
   -Dcalcite.test.db={mysql,hsqldb}, -Dcalcite.test.slow,


[11/13] calcite git commit: [CALCITE-1055] SubQueryRemoveRule should create Correlate, not Join, for correlated sub-queries

Posted by jh...@apache.org.
[CALCITE-1055] SubQueryRemoveRule should create Correlate, not Join, for correlated sub-queries


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

Branch: refs/heads/branch-1.6
Commit: cecef9d3209cbd092a6e9b578bc063a52007b99f
Parents: 898fdfc
Author: maryannxue <ma...@gmail.com>
Authored: Thu Jan 14 13:46:07 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jan 14 14:05:17 2016 -0800

----------------------------------------------------------------------
 .../calcite/rel/rules/SubQueryRemoveRule.java   |  4 +-
 .../apache/calcite/test/RelOptRulesTest.java    |  8 ++++
 .../org/apache/calcite/test/RelOptRulesTest.xml | 39 ++++++++++++++++++--
 3 files changed, 46 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/cecef9d3/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
index 56b362d..6eec2fc 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
@@ -156,7 +156,7 @@ public abstract class SubQueryRemoveRule extends RelOptRule {
             builder.aggregateCall(SqlStdOperatorTable.SINGLE_VALUE, false, null,
                 null, builder.field(0)));
       }
-      builder.join(JoinRelType.LEFT);
+      builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet);
       return field(builder, inputCount, offset);
 
     case IN:
@@ -247,7 +247,7 @@ public abstract class SubQueryRemoveRule extends RelOptRule {
             builder.aggregateCall(SqlStdOperatorTable.COUNT, false, null, "ck",
                 builder.fields()));
         builder.as("ct");
-        builder.join(JoinRelType.INNER);
+        builder.join(JoinRelType.INNER, builder.literal(true), variablesSet);
         offset += 2;
         builder.push(e.rel);
         break;

http://git-wip-us.apache.org/repos/asf/calcite/blob/cecef9d3/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 6300579..f59b9e7 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -2216,6 +2216,14 @@ public class RelOptRulesTest extends RelOptTestBase {
     checkSubQuery(sql).check();
   }
 
+  @Test public void testExpandWhereComparisonCorrelated() throws Exception {
+    final String sql = "select empno\n"
+        + "from sales.emp as e\n"
+        + "where sal = (\n"
+        + "  select max(sal) from sales.emp e2 where e2.empno = e.empno)";
+    checkSubQuery(sql).check();
+  }
+
 }
 
 // End RelOptRulesTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/cecef9d3/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 e45b82c..45ea111 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -1064,6 +1064,39 @@ LogicalValues(tuples=[[]])
 ]]>
         </Resource>
     </TestCase>
+    <TestCase name="testExpandWhereComparisonCorrelated">
+        <Resource name="sql">
+            <![CDATA[select empno
+from sales.emp as e
+where sal = (
+  select max(sal) from sales.emp e2 where e2.empno = e.empno)]]>
+        </Resource>
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalProject(EMPNO=[$0])
+  LogicalFilter(condition=[=($5, $SCALAR_QUERY({
+LogicalAggregate(group=[{}], EXPR$0=[MAX($0)])
+  LogicalProject(SAL=[$5])
+    LogicalFilter(condition=[=($0, $cor0.EMPNO)])
+      LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+}))], variablesSet=[[$cor0]])
+    LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalProject(EMPNO=[$0])
+  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
+    LogicalFilter(condition=[=($5, $9)])
+      LogicalCorrelate(correlation=[$cor0], joinType=[LEFT], requiredColumns=[{0}])
+        LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+        LogicalAggregate(group=[{}], EXPR$0=[MAX($0)])
+          LogicalProject(SAL=[$5])
+            LogicalFilter(condition=[=($0, $cor0.EMPNO)])
+              LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+        </Resource>
+    </TestCase>
     <TestCase name="testPushSumConstantThroughUnion">
         <Resource name="sql">
             <![CDATA[select ename, sum(u) from
@@ -4944,9 +4977,9 @@ LogicalFilter(condition=[<($0, 20)])
 })])
     LogicalTableScan(table=[[CATALOG, SALES, EMP]])
 ]]>
-    </Resource>
-    <Resource name="planAfter">
-      <![CDATA[
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
 LogicalProject(EMPNO=[$0])
   LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
     LogicalJoin(condition=[true], joinType=[inner])


[02/13] calcite git commit: [CALCITE-975] Allow Planner to return validated row type together with SqlNode

Posted by jh...@apache.org.
[CALCITE-975] Allow Planner to return validated row type together with SqlNode

close apache/calcite#184


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

Branch: refs/heads/branch-1.6
Commit: 0045e01f6178df5bcc8caf780040f3cff159bb20
Parents: a67b4a9
Author: Jinfeng Ni <jn...@maprtech.com>
Authored: Tue Apr 7 03:34:06 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 10:22:09 2016 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/prepare/PlannerImpl.java     |  9 +++++++++
 core/src/main/java/org/apache/calcite/tools/Planner.java | 11 +++++++++++
 2 files changed, 20 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/0045e01f/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index d75d9c9..18d9746 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -44,6 +44,7 @@ import org.apache.calcite.tools.Planner;
 import org.apache.calcite.tools.Program;
 import org.apache.calcite.tools.RelConversionException;
 import org.apache.calcite.tools.ValidationException;
+import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -180,6 +181,14 @@ public class PlannerImpl implements Planner {
     return validatedSqlNode;
   }
 
+  public Pair<SqlNode, RelDataType> validateAndGetType(SqlNode sqlNode)
+      throws ValidationException {
+    final SqlNode validatedNode = this.validate(sqlNode);
+    final RelDataType type =
+        this.validator.getValidatedNodeType(validatedNode);
+    return Pair.of(validatedNode, type);
+  }
+
   public final RelNode convert(SqlNode sql) throws RelConversionException {
     return rel(sql).rel;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/0045e01f/core/src/main/java/org/apache/calcite/tools/Planner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Planner.java b/core/src/main/java/org/apache/calcite/tools/Planner.java
index 73c8047..8b2b25d 100644
--- a/core/src/main/java/org/apache/calcite/tools/Planner.java
+++ b/core/src/main/java/org/apache/calcite/tools/Planner.java
@@ -19,9 +19,11 @@ package org.apache.calcite.tools;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelRoot;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.calcite.util.Pair;
 
 /**
  * A fa&ccedil;ade that covers Calcite's query planning process: parse SQL,
@@ -53,6 +55,15 @@ public interface Planner {
   SqlNode validate(SqlNode sqlNode) throws ValidationException;
 
   /**
+   * Validates a SQL statement.
+   *
+   * @param sqlNode Root node of the SQL parse tree.
+   * @return Validated node and its validated type.
+   * @throws ValidationException if not valid
+   */
+  Pair<SqlNode, RelDataType> validateAndGetType(SqlNode sqlNode) throws ValidationException;
+
+  /**
    * Converts a SQL parse tree into a tree of relational expressions.
    *
    * <p>You must call {@link #validate(org.apache.calcite.sql.SqlNode)} first.


[04/13] calcite git commit: Upgrade toolbox, to fix line length issue on Windows

Posted by jh...@apache.org.
Upgrade toolbox, to fix line length issue on Windows


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

Branch: refs/heads/branch-1.6
Commit: e15f89e5823104f0890ee92675cc0da45dcec4ca
Parents: b4b04d2
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jan 11 18:49:50 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 13:47:17 2016 -0800

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/e15f89e5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 3253f25..2d83845 100644
--- a/pom.xml
+++ b/pom.xml
@@ -400,7 +400,7 @@ limitations under the License.
           <dependency>
             <groupId>net.hydromatic</groupId>
             <artifactId>toolbox</artifactId>
-            <version>0.2</version>
+            <version>0.3</version>
           </dependency>
         </dependencies>
       </plugin>


[09/13] calcite git commit: [CALCITE-1058] Add method RelBuilder.empty, and rewrite LIMIT 0 to it

Posted by jh...@apache.org.
[CALCITE-1058] Add method RelBuilder.empty, and rewrite LIMIT 0 to it


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

Branch: refs/heads/branch-1.6
Commit: ee283cadf17d8add8e8ea2bf1f8dd5735f05dc1d
Parents: 3cba705
Author: Julian Hyde <jh...@apache.org>
Authored: Wed Jan 13 21:37:27 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jan 14 13:51:44 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/tools/RelBuilder.java    | 21 +++++++++++++
 .../org/apache/calcite/test/RelBuilderTest.java | 33 ++++++++++++++++++++
 2 files changed, 54 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/ee283cad/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 00ce6d1..cf9fcb6 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -1155,6 +1155,24 @@ public class RelBuilder {
     return true;
   }
 
+  /** Creates a relational expression that reads from an input and throws
+   * all of the rows away.
+   *
+   * <p>Note that this method always pops one relational expression from the
+   * stack. {@code values}, in contrast, does not pop any relational
+   * expressions, and always produces a leaf.
+   *
+   * <p>The default implementation creates a {@link Values} with the same
+   * specified row type as the input, and ignores the input entirely.
+   * But schema-on-query systems such as Drill might override this method to
+   * create a relation expression that retains the input, just to read its
+   * schema.
+   */
+  public RelBuilder empty() {
+    final Frame frame = Stacks.pop(stack);
+    return values(frame.rel.getRowType());
+  }
+
   /** Creates a {@link Values} with a specified row type.
    *
    * <p>This method can handle cases that {@link #values(String[], Object...)}
@@ -1274,6 +1292,9 @@ public class RelBuilder {
     }
     final RexNode offsetNode = offset <= 0 ? null : literal(offset);
     final RexNode fetchNode = fetch < 0 ? null : literal(fetch);
+    if (offsetNode == null && fetch == 0) {
+      return empty();
+    }
     if (offsetNode == null && fetchNode == null && fieldCollations.isEmpty()) {
       return this; // sort is trivial
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/ee283cad/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 0b232f4..db13a02 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -873,6 +873,25 @@ public class RelBuilderTest {
     assertThat(str(root), is(expected));
   }
 
+  @Test public void testEmpty() {
+    // Equivalent SQL:
+    //   SELECT deptno, true FROM dept LIMIT 0
+    // optimized to
+    //   VALUES
+    final RelBuilder builder = RelBuilder.create(config().build());
+    RelNode root =
+        builder.scan("DEPT")
+            .project(builder.field(0), builder.literal(false))
+            .empty()
+            .build();
+    final String expected =
+        "LogicalValues(tuples=[[]])\n";
+    assertThat(str(root), is(expected));
+    final String expectedType =
+        "RecordType(TINYINT NOT NULL DEPTNO, BOOLEAN NOT NULL $f1) NOT NULL";
+    assertThat(root.getRowType().getFullTypeString(), is(expectedType));
+  }
+
   @Test public void testValues() {
     // Equivalent SQL:
     //   VALUES (true, 1), (false, -50) AS t(a, b)
@@ -1071,6 +1090,20 @@ public class RelBuilderTest {
     assertThat(str(root), is(expected));
   }
 
+  @Test public void testSortLimit0() {
+    // Equivalent SQL:
+    //   SELECT *
+    //   FROM emp
+    //   ORDER BY deptno DESC FETCH 0
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder.scan("EMP")
+            .sortLimit(-1, 0, builder.desc(builder.field("DEPTNO")))
+            .build();
+    final String expected = "LogicalValues(tuples=[[]])\n";
+    assertThat(str(root), is(expected));
+  }
+
   /** Tests that a sort on a field followed by a limit gives the same
    * effect as calling sortLimit.
    *


[05/13] calcite git commit: [CALCITE-1051] Underflow exception due to scaling IN clause literals (Frankie Bollaert)

Posted by jh...@apache.org.
[CALCITE-1051] Underflow exception due to scaling IN clause literals (Frankie Bollaert)

Literals in the IN clause value list are scaled during SqlToRel
conversion.  When the type of the literal does not have a scale set,
as happens with a java.lang.Integer, the default value of the
type.scale is chosen, which is Integer.MIN_VALUE.  Scaling to this
value causes an underflow.


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

Branch: refs/heads/branch-1.6
Commit: b4b04d29cb63ceea123ec41dd3247a0555f9c150
Parents: 361096b
Author: Frankie Bollaert <fr...@ngdata.com>
Authored: Mon Jan 11 11:23:46 2016 +0100
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 13:47:17 2016 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/sql/type/SqlTypeUtil.java    |  5 +++++
 .../org/apache/calcite/sql2rel/SqlToRelConverter.java    |  2 +-
 .../src/test/java/org/apache/calcite/test/CsvTest.java   | 11 +++++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/b4b04d29/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
index 204b7ea..d8a437d 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java
@@ -414,6 +414,11 @@ public abstract class SqlTypeUtil {
     }
   }
 
+  /** Returns whether a type's scale is set. */
+  public static boolean hasScale(RelDataType type) {
+    return type.getScale() != Integer.MIN_VALUE;
+  }
+
   /**
    * Returns the maximum value of an integral type, as a long value
    */

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4b04d29/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index bb37de1..d9189a5 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1650,7 +1650,7 @@ public class SqlToRelConverter {
 
     Comparable value = literal.getValue();
 
-    if (SqlTypeUtil.isExactNumeric(type)) {
+    if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.hasScale(type)) {
       BigDecimal roundedValue =
           NumberUtil.rescaleBigDecimal(
               (BigDecimal) value,

http://git-wip-us.apache.org/repos/asf/calcite/blob/b4b04d29/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
----------------------------------------------------------------------
diff --git a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
index a048319..650dce1 100644
--- a/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
+++ b/example/csv/src/test/java/org/apache/calcite/test/CsvTest.java
@@ -362,6 +362,17 @@ public class CsvTest {
         "smart", expect("NAME=Alice"));
   }
 
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-1051">[CALCITE-1051]
+   * Underflow exception due to scaling IN clause literals</a>. */
+  @Test public void testInToSemiJoinWithoutCast() throws SQLException {
+    final String sql = "SELECT e.name\n"
+        + "FROM emps AS e\n"
+        + "WHERE e.empno in "
+        + range(130, SqlToRelConverter.IN_SUBQUERY_THRESHOLD);
+    checkSql(sql, "smart", expect("NAME=Alice"));
+  }
+
   private String range(int first, int count) {
     final StringBuilder sb = new StringBuilder();
     for (int i = 0; i < count; i++) {


[06/13] calcite git commit: [CALCITE-1040] Differentiate better between arrays and scalars in protobuf

Posted by jh...@apache.org.
[CALCITE-1040] Differentiate better between arrays and scalars in protobuf

The original implementation of ColumnValue tried to always use a repeated
field to serialize the value of a column in a row. This was flawed for
multiple reasons. Instead, go the "struct" approach like TypedValue.

Since we're using protobuf, make the attempt to support the Calcite
1.5 structure (avoid removing the old field).


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

Branch: refs/heads/branch-1.6
Commit: 361096ba1d0436f588e4c7a3290560059882223f
Parents: 0045e01
Author: Josh Elser <el...@apache.org>
Authored: Mon Jan 11 23:08:48 2016 -0500
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 13:47:17 2016 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   | 102 ++-
 .../apache/calcite/avatica/proto/Common.java    | 849 +++++++++++++++++--
 avatica/src/main/protobuf/common.proto          |   5 +-
 .../org/apache/calcite/avatica/FrameTest.java   |  66 ++
 .../avatica/remote/ProtobufHandlerTest.java     |  13 +-
 .../remote/ProtobufTranslationImplTest.java     |  23 +-
 site/_docs/avatica_protobuf_reference.md        |  15 +-
 7 files changed, 995 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/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 a859608..e9b28d5 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -892,14 +892,17 @@ public interface Meta {
             final Common.ColumnValue.Builder columnBuilder = Common.ColumnValue.newBuilder();
 
             if (element instanceof List) {
+              columnBuilder.setHasArrayValue(true);
               List<?> list = (List<?>) element;
               // Add each element in the list/array to the column's value
               for (Object listItem : list) {
-                columnBuilder.addValue(serializeScalar(listItem));
+                columnBuilder.addArrayValue(serializeScalar(listItem));
               }
             } else {
+              // The default value, but still explicit.
+              columnBuilder.setHasArrayValue(false);
               // Only one value for this column, a scalar.
-              columnBuilder.addValue(serializeScalar(element));
+              columnBuilder.setScalarValue(serializeScalar(element));
             }
 
             // Add value to row
@@ -931,8 +934,7 @@ public interface Meta {
       } 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());
+        valueBuilder.setType(Common.Rep.DOUBLE).setDoubleValue((Double) element);
       } else if (element instanceof Float) {
         valueBuilder.setType(Common.Rep.FLOAT).setNumberValue(((Float) element).longValue());
       } else if (element instanceof BigDecimal) {
@@ -967,17 +969,13 @@ public interface Meta {
       for (Common.Row protoRow : proto.getRowsList()) {
         ArrayList<Object> row = new ArrayList<>(protoRow.getValueCount());
         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;
+          final Object value;
+          if (!isNewStyleColumn(protoColumn)) {
+            // Backward compatibility
+            value = parseOldStyleColumn(protoColumn);
           } else {
-            // Scalar
-            value = getScalarValue(protoColumn.getValue(0));
+            // Current style parsing (separate scalar and array values)
+            value = parseColumn(protoColumn);
           }
 
           row.add(value);
@@ -989,6 +987,82 @@ public interface Meta {
       return new Frame(proto.getOffset(), proto.getDone(), parsedRows);
     }
 
+    /**
+     * Determines whether this message contains the new attributes in the
+     * message. We can't directly test for the negative because our
+     * {@code hasField} trick does not work on repeated fields.
+     *
+     * @param column The protobuf column object
+     * @return True if the message is the new style, false otherwise.
+     */
+    static boolean isNewStyleColumn(Common.ColumnValue column) {
+      final Descriptor desc = column.getDescriptorForType();
+      return ProtobufService.hasField(column, desc, Common.ColumnValue.HAS_ARRAY_VALUE_FIELD_NUMBER)
+          || ProtobufService.hasField(column, desc, Common.ColumnValue.SCALAR_VALUE_FIELD_NUMBER);
+    }
+
+    /**
+     * For Calcite 1.5, we made the mistake of using array length to determine when the value for a
+     * column is a scalar or an array. This method performs the old parsing for backwards
+     * compatibility.
+     *
+     * @param column The protobuf ColumnValue object
+     * @return The parsed value for this column
+     */
+    static Object parseOldStyleColumn(Common.ColumnValue column) {
+      if (column.getValueCount() > 1) {
+        List<Object> array = new ArrayList<>(column.getValueCount());
+        for (Common.TypedValue columnValue : column.getValueList()) {
+          array.add(getScalarValue(columnValue));
+        }
+        return array;
+      } else {
+        return getScalarValue(column.getValue(0));
+      }
+    }
+
+    /**
+     * Parses the value for a ColumnValue using the separated array and scalar attributes.
+     *
+     * @param column The protobuf ColumnValue object
+     * @return The parse value for this column
+     */
+    static Object parseColumn(Common.ColumnValue column) {
+      // Verify that we have one or the other (scalar or array)
+      validateColumnValue(column);
+
+      if (!ProtobufService.hasField(column, column.getDescriptorForType(),
+          Common.ColumnValue.SCALAR_VALUE_FIELD_NUMBER)) {
+        // Array
+        List<Object> array = new ArrayList<>(column.getArrayValueCount());
+        for (Common.TypedValue arrayValue : column.getArrayValueList()) {
+          array.add(getScalarValue(arrayValue));
+        }
+        return array;
+      } else {
+        // Scalar
+        return getScalarValue(column.getScalarValue());
+      }
+    }
+
+    /**
+     * Verifies that a ColumnValue has only a scalar or array value, not both and not neither.
+     *
+     * @param column The protobuf ColumnValue object
+     * @throws IllegalArgumentException When the above condition is not met
+     */
+    static void validateColumnValue(Common.ColumnValue column) {
+      final boolean hasScalar = ProtobufService.hasField(column, column.getDescriptorForType(),
+          Common.ColumnValue.SCALAR_VALUE_FIELD_NUMBER);
+      final boolean hasArrayValue = column.getHasArrayValue();
+
+      // These should always be different
+      if (hasScalar == hasArrayValue) {
+        throw new IllegalArgumentException("A column must have a scalar or array value, not "
+            + (hasScalar ? "both" : "neither"));
+      }
+    }
+
     static Object getScalarValue(Common.TypedValue protoElement) {
       // TODO Should these be primitives or Objects?
       switch (protoElement.getType()) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/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 1dbe093..7d5cef9 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
@@ -12091,27 +12091,93 @@ package org.apache.calcite.avatica.proto;
 
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> 
         getValueList();
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index);
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     int getValueCount();
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
         getValueOrBuilderList();
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
         int index);
+
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> 
+        getArrayValueList();
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Common.TypedValue getArrayValue(int index);
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    int getArrayValueCount();
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+        getArrayValueOrBuilderList();
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getArrayValueOrBuilder(
+        int index);
+
+    /**
+     * <code>optional bool has_array_value = 3;</code>
+     *
+     * <pre>
+     * Is an array value set?
+     * </pre>
+     */
+    boolean getHasArrayValue();
+
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    boolean hasScalarValue();
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    org.apache.calcite.avatica.proto.Common.TypedValue getScalarValue();
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getScalarValueOrBuilder();
   }
   /**
    * Protobuf type {@code ColumnValue}
@@ -12130,6 +12196,8 @@ package org.apache.calcite.avatica.proto;
     }
     private ColumnValue() {
       value_ = java.util.Collections.emptyList();
+      arrayValue_ = java.util.Collections.emptyList();
+      hasArrayValue_ = false;
     }
 
     @java.lang.Override
@@ -12164,6 +12232,32 @@ package org.apache.calcite.avatica.proto;
               value_.add(input.readMessage(org.apache.calcite.avatica.proto.Common.TypedValue.parser(), extensionRegistry));
               break;
             }
+            case 18: {
+              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+                arrayValue_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>();
+                mutable_bitField0_ |= 0x00000002;
+              }
+              arrayValue_.add(input.readMessage(org.apache.calcite.avatica.proto.Common.TypedValue.parser(), extensionRegistry));
+              break;
+            }
+            case 24: {
+
+              hasArrayValue_ = input.readBool();
+              break;
+            }
+            case 34: {
+              org.apache.calcite.avatica.proto.Common.TypedValue.Builder subBuilder = null;
+              if (scalarValue_ != null) {
+                subBuilder = scalarValue_.toBuilder();
+              }
+              scalarValue_ = input.readMessage(org.apache.calcite.avatica.proto.Common.TypedValue.parser(), extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(scalarValue_);
+                scalarValue_ = subBuilder.buildPartial();
+              }
+
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -12176,6 +12270,9 @@ package org.apache.calcite.avatica.proto;
         if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
           value_ = java.util.Collections.unmodifiableList(value_);
         }
+        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+          arrayValue_ = java.util.Collections.unmodifiableList(arrayValue_);
+        }
         makeExtensionsImmutable();
       }
     }
@@ -12191,16 +12288,25 @@ package org.apache.calcite.avatica.proto;
               org.apache.calcite.avatica.proto.Common.ColumnValue.class, org.apache.calcite.avatica.proto.Common.ColumnValue.Builder.class);
     }
 
+    private int bitField0_;
     public static final int VALUE_FIELD_NUMBER = 1;
     private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> value_;
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
       return value_;
     }
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
         getValueOrBuilderList() {
@@ -12208,24 +12314,105 @@ package org.apache.calcite.avatica.proto;
     }
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     public int getValueCount() {
       return value_.size();
     }
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
       return value_.get(index);
     }
     /**
      * <code>repeated .TypedValue value = 1;</code>
+     *
+     * <pre>
+     * deprecated, use array_value or scalar_value
+     * </pre>
      */
     public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
         int index) {
       return value_.get(index);
     }
 
+    public static final int ARRAY_VALUE_FIELD_NUMBER = 2;
+    private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> arrayValue_;
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getArrayValueList() {
+      return arrayValue_;
+    }
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+        getArrayValueOrBuilderList() {
+      return arrayValue_;
+    }
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    public int getArrayValueCount() {
+      return arrayValue_.size();
+    }
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValue getArrayValue(int index) {
+      return arrayValue_.get(index);
+    }
+    /**
+     * <code>repeated .TypedValue array_value = 2;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getArrayValueOrBuilder(
+        int index) {
+      return arrayValue_.get(index);
+    }
+
+    public static final int HAS_ARRAY_VALUE_FIELD_NUMBER = 3;
+    private boolean hasArrayValue_;
+    /**
+     * <code>optional bool has_array_value = 3;</code>
+     *
+     * <pre>
+     * Is an array value set?
+     * </pre>
+     */
+    public boolean getHasArrayValue() {
+      return hasArrayValue_;
+    }
+
+    public static final int SCALAR_VALUE_FIELD_NUMBER = 4;
+    private org.apache.calcite.avatica.proto.Common.TypedValue scalarValue_;
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    public boolean hasScalarValue() {
+      return scalarValue_ != null;
+    }
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValue getScalarValue() {
+      return scalarValue_ == null ? org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance() : scalarValue_;
+    }
+    /**
+     * <code>optional .TypedValue scalar_value = 4;</code>
+     */
+    public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getScalarValueOrBuilder() {
+      return getScalarValue();
+    }
+
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
       byte isInitialized = memoizedIsInitialized;
@@ -12241,6 +12428,15 @@ package org.apache.calcite.avatica.proto;
       for (int i = 0; i < value_.size(); i++) {
         output.writeMessage(1, value_.get(i));
       }
+      for (int i = 0; i < arrayValue_.size(); i++) {
+        output.writeMessage(2, arrayValue_.get(i));
+      }
+      if (hasArrayValue_ != false) {
+        output.writeBool(3, hasArrayValue_);
+      }
+      if (scalarValue_ != null) {
+        output.writeMessage(4, getScalarValue());
+      }
     }
 
     public int getSerializedSize() {
@@ -12252,6 +12448,18 @@ package org.apache.calcite.avatica.proto;
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(1, value_.get(i));
       }
+      for (int i = 0; i < arrayValue_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(2, arrayValue_.get(i));
+      }
+      if (hasArrayValue_ != false) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(3, hasArrayValue_);
+      }
+      if (scalarValue_ != null) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(4, getScalarValue());
+      }
       memoizedSize = size;
       return size;
     }
@@ -12364,6 +12572,7 @@ package org.apache.calcite.avatica.proto;
       private void maybeForceBuilderInitialization() {
         if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
           getValueFieldBuilder();
+          getArrayValueFieldBuilder();
         }
       }
       public Builder clear() {
@@ -12374,6 +12583,20 @@ package org.apache.calcite.avatica.proto;
         } else {
           valueBuilder_.clear();
         }
+        if (arrayValueBuilder_ == null) {
+          arrayValue_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+        } else {
+          arrayValueBuilder_.clear();
+        }
+        hasArrayValue_ = false;
+
+        if (scalarValueBuilder_ == null) {
+          scalarValue_ = null;
+        } else {
+          scalarValue_ = null;
+          scalarValueBuilder_ = null;
+        }
         return this;
       }
 
@@ -12397,6 +12620,7 @@ package org.apache.calcite.avatica.proto;
       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_;
+        int to_bitField0_ = 0;
         if (valueBuilder_ == null) {
           if (((bitField0_ & 0x00000001) == 0x00000001)) {
             value_ = java.util.Collections.unmodifiableList(value_);
@@ -12406,6 +12630,22 @@ package org.apache.calcite.avatica.proto;
         } else {
           result.value_ = valueBuilder_.build();
         }
+        if (arrayValueBuilder_ == null) {
+          if (((bitField0_ & 0x00000002) == 0x00000002)) {
+            arrayValue_ = java.util.Collections.unmodifiableList(arrayValue_);
+            bitField0_ = (bitField0_ & ~0x00000002);
+          }
+          result.arrayValue_ = arrayValue_;
+        } else {
+          result.arrayValue_ = arrayValueBuilder_.build();
+        }
+        result.hasArrayValue_ = hasArrayValue_;
+        if (scalarValueBuilder_ == null) {
+          result.scalarValue_ = scalarValue_;
+        } else {
+          result.scalarValue_ = scalarValueBuilder_.build();
+        }
+        result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
       }
@@ -12447,6 +12687,38 @@ package org.apache.calcite.avatica.proto;
             }
           }
         }
+        if (arrayValueBuilder_ == null) {
+          if (!other.arrayValue_.isEmpty()) {
+            if (arrayValue_.isEmpty()) {
+              arrayValue_ = other.arrayValue_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+            } else {
+              ensureArrayValueIsMutable();
+              arrayValue_.addAll(other.arrayValue_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.arrayValue_.isEmpty()) {
+            if (arrayValueBuilder_.isEmpty()) {
+              arrayValueBuilder_.dispose();
+              arrayValueBuilder_ = null;
+              arrayValue_ = other.arrayValue_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+              arrayValueBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getArrayValueFieldBuilder() : null;
+            } else {
+              arrayValueBuilder_.addAllMessages(other.arrayValue_);
+            }
+          }
+        }
+        if (other.getHasArrayValue() != false) {
+          setHasArrayValue(other.getHasArrayValue());
+        }
+        if (other.hasScalarValue()) {
+          mergeScalarValue(other.getScalarValue());
+        }
         onChanged();
         return this;
       }
@@ -12488,6 +12760,10 @@ package org.apache.calcite.avatica.proto;
 
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getValueList() {
         if (valueBuilder_ == null) {
@@ -12498,6 +12774,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public int getValueCount() {
         if (valueBuilder_ == null) {
@@ -12508,6 +12788,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public org.apache.calcite.avatica.proto.Common.TypedValue getValue(int index) {
         if (valueBuilder_ == null) {
@@ -12518,6 +12802,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder setValue(
           int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
@@ -12535,6 +12823,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder setValue(
           int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
@@ -12549,6 +12841,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder addValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
         if (valueBuilder_ == null) {
@@ -12565,6 +12861,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder addValue(
           int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
@@ -12582,6 +12882,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder addValue(
           org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
@@ -12596,6 +12900,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder addValue(
           int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
@@ -12610,6 +12918,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder addAllValue(
           java.lang.Iterable<? extends org.apache.calcite.avatica.proto.Common.TypedValue> values) {
@@ -12625,6 +12937,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder clearValue() {
         if (valueBuilder_ == null) {
@@ -12638,6 +12954,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public Builder removeValue(int index) {
         if (valueBuilder_ == null) {
@@ -12651,6 +12971,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public org.apache.calcite.avatica.proto.Common.TypedValue.Builder getValueBuilder(
           int index) {
@@ -12658,6 +12982,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getValueOrBuilder(
           int index) {
@@ -12668,6 +12996,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
            getValueOrBuilderList() {
@@ -12679,6 +13011,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder() {
         return getValueFieldBuilder().addBuilder(
@@ -12686,6 +13022,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addValueBuilder(
           int index) {
@@ -12694,6 +13034,10 @@ package org.apache.calcite.avatica.proto;
       }
       /**
        * <code>repeated .TypedValue value = 1;</code>
+       *
+       * <pre>
+       * deprecated, use array_value or scalar_value
+       * </pre>
        */
       public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue.Builder> 
            getValueBuilderList() {
@@ -12713,6 +13057,401 @@ package org.apache.calcite.avatica.proto;
         }
         return valueBuilder_;
       }
+
+      private java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> arrayValue_ =
+        java.util.Collections.emptyList();
+      private void ensureArrayValueIsMutable() {
+        if (!((bitField0_ & 0x00000002) == 0x00000002)) {
+          arrayValue_ = new java.util.ArrayList<org.apache.calcite.avatica.proto.Common.TypedValue>(arrayValue_);
+          bitField0_ |= 0x00000002;
+         }
+      }
+
+      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> arrayValueBuilder_;
+
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue> getArrayValueList() {
+        if (arrayValueBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(arrayValue_);
+        } else {
+          return arrayValueBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public int getArrayValueCount() {
+        if (arrayValueBuilder_ == null) {
+          return arrayValue_.size();
+        } else {
+          return arrayValueBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue getArrayValue(int index) {
+        if (arrayValueBuilder_ == null) {
+          return arrayValue_.get(index);
+        } else {
+          return arrayValueBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder setArrayValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (arrayValueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureArrayValueIsMutable();
+          arrayValue_.set(index, value);
+          onChanged();
+        } else {
+          arrayValueBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder setArrayValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (arrayValueBuilder_ == null) {
+          ensureArrayValueIsMutable();
+          arrayValue_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          arrayValueBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder addArrayValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (arrayValueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureArrayValueIsMutable();
+          arrayValue_.add(value);
+          onChanged();
+        } else {
+          arrayValueBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder addArrayValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (arrayValueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureArrayValueIsMutable();
+          arrayValue_.add(index, value);
+          onChanged();
+        } else {
+          arrayValueBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder addArrayValue(
+          org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (arrayValueBuilder_ == null) {
+          ensureArrayValueIsMutable();
+          arrayValue_.add(builderForValue.build());
+          onChanged();
+        } else {
+          arrayValueBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder addArrayValue(
+          int index, org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (arrayValueBuilder_ == null) {
+          ensureArrayValueIsMutable();
+          arrayValue_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          arrayValueBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder addAllArrayValue(
+          java.lang.Iterable<? extends org.apache.calcite.avatica.proto.Common.TypedValue> values) {
+        if (arrayValueBuilder_ == null) {
+          ensureArrayValueIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, arrayValue_);
+          onChanged();
+        } else {
+          arrayValueBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder clearArrayValue() {
+        if (arrayValueBuilder_ == null) {
+          arrayValue_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+          onChanged();
+        } else {
+          arrayValueBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public Builder removeArrayValue(int index) {
+        if (arrayValueBuilder_ == null) {
+          ensureArrayValueIsMutable();
+          arrayValue_.remove(index);
+          onChanged();
+        } else {
+          arrayValueBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder getArrayValueBuilder(
+          int index) {
+        return getArrayValueFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getArrayValueOrBuilder(
+          int index) {
+        if (arrayValueBuilder_ == null) {
+          return arrayValue_.get(index);  } else {
+          return arrayValueBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public java.util.List<? extends org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+           getArrayValueOrBuilderList() {
+        if (arrayValueBuilder_ != null) {
+          return arrayValueBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(arrayValue_);
+        }
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addArrayValueBuilder() {
+        return getArrayValueFieldBuilder().addBuilder(
+            org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder addArrayValueBuilder(
+          int index) {
+        return getArrayValueFieldBuilder().addBuilder(
+            index, org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .TypedValue array_value = 2;</code>
+       */
+      public java.util.List<org.apache.calcite.avatica.proto.Common.TypedValue.Builder> 
+           getArrayValueBuilderList() {
+        return getArrayValueFieldBuilder().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> 
+          getArrayValueFieldBuilder() {
+        if (arrayValueBuilder_ == null) {
+          arrayValueBuilder_ = 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>(
+                  arrayValue_,
+                  ((bitField0_ & 0x00000002) == 0x00000002),
+                  getParentForChildren(),
+                  isClean());
+          arrayValue_ = null;
+        }
+        return arrayValueBuilder_;
+      }
+
+      private boolean hasArrayValue_ ;
+      /**
+       * <code>optional bool has_array_value = 3;</code>
+       *
+       * <pre>
+       * Is an array value set?
+       * </pre>
+       */
+      public boolean getHasArrayValue() {
+        return hasArrayValue_;
+      }
+      /**
+       * <code>optional bool has_array_value = 3;</code>
+       *
+       * <pre>
+       * Is an array value set?
+       * </pre>
+       */
+      public Builder setHasArrayValue(boolean value) {
+        
+        hasArrayValue_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool has_array_value = 3;</code>
+       *
+       * <pre>
+       * Is an array value set?
+       * </pre>
+       */
+      public Builder clearHasArrayValue() {
+        
+        hasArrayValue_ = false;
+        onChanged();
+        return this;
+      }
+
+      private org.apache.calcite.avatica.proto.Common.TypedValue scalarValue_ = null;
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> scalarValueBuilder_;
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public boolean hasScalarValue() {
+        return scalarValueBuilder_ != null || scalarValue_ != null;
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue getScalarValue() {
+        if (scalarValueBuilder_ == null) {
+          return scalarValue_ == null ? org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance() : scalarValue_;
+        } else {
+          return scalarValueBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public Builder setScalarValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (scalarValueBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          scalarValue_ = value;
+          onChanged();
+        } else {
+          scalarValueBuilder_.setMessage(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public Builder setScalarValue(
+          org.apache.calcite.avatica.proto.Common.TypedValue.Builder builderForValue) {
+        if (scalarValueBuilder_ == null) {
+          scalarValue_ = builderForValue.build();
+          onChanged();
+        } else {
+          scalarValueBuilder_.setMessage(builderForValue.build());
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public Builder mergeScalarValue(org.apache.calcite.avatica.proto.Common.TypedValue value) {
+        if (scalarValueBuilder_ == null) {
+          if (scalarValue_ != null) {
+            scalarValue_ =
+              org.apache.calcite.avatica.proto.Common.TypedValue.newBuilder(scalarValue_).mergeFrom(value).buildPartial();
+          } else {
+            scalarValue_ = value;
+          }
+          onChanged();
+        } else {
+          scalarValueBuilder_.mergeFrom(value);
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public Builder clearScalarValue() {
+        if (scalarValueBuilder_ == null) {
+          scalarValue_ = null;
+          onChanged();
+        } else {
+          scalarValue_ = null;
+          scalarValueBuilder_ = null;
+        }
+
+        return this;
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValue.Builder getScalarValueBuilder() {
+        
+        onChanged();
+        return getScalarValueFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      public org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder getScalarValueOrBuilder() {
+        if (scalarValueBuilder_ != null) {
+          return scalarValueBuilder_.getMessageOrBuilder();
+        } else {
+          return scalarValue_ == null ?
+              org.apache.calcite.avatica.proto.Common.TypedValue.getDefaultInstance() : scalarValue_;
+        }
+      }
+      /**
+       * <code>optional .TypedValue scalar_value = 4;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder> 
+          getScalarValueFieldBuilder() {
+        if (scalarValueBuilder_ == null) {
+          scalarValueBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.apache.calcite.avatica.proto.Common.TypedValue, org.apache.calcite.avatica.proto.Common.TypedValue.Builder, org.apache.calcite.avatica.proto.Common.TypedValueOrBuilder>(
+                  getScalarValue(),
+                  getParentForChildren(),
+                  isClean());
+          scalarValue_ = null;
+        }
+        return scalarValueBuilder_;
+      }
       public final Builder setUnknownFields(
           final com.google.protobuf.UnknownFieldSet unknownFields) {
         return this;
@@ -16225,59 +16964,61 @@ package org.apache.calcite.avatica.proto;
       "\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\"\246\002\n\031MetaDataOperationArgument\022\024\n\014st" +
-      "ring_value\030\001 \001(\t\022\022\n\nbool_value\030\002 \001(\010\022\021\n\t" +
-      "int_value\030\003 \001(\021\022\033\n\023string_array_values\030\004" +
-      " \003(\t\022\030\n\020int_array_values\030\005 \003(\021\0225\n\004type\030\006" +
-      " \001(\0162\'.MetaDataOperationArgument.Argumen" +
-      "tType\"^\n\014ArgumentType\022\n\n\006STRING\020\000\022\010\n\004BOO",
-      "L\020\001\022\007\n\003INT\020\002\022\023\n\017REPEATED_STRING\020\003\022\020\n\014REP" +
-      "EATED_INT\020\004\022\010\n\004NULL\020\005\"\260\001\n\nQueryState\022\030\n\004" +
-      "type\030\001 \001(\0162\n.StateType\022\013\n\003sql\030\002 \001(\t\022\036\n\002o" +
-      "p\030\003 \001(\0162\022.MetaDataOperation\022(\n\004args\030\004 \003(" +
-      "\0132\032.MetaDataOperationArgument\022\020\n\010has_arg" +
-      "s\030\005 \001(\010\022\017\n\007has_sql\030\006 \001(\010\022\016\n\006has_op\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*\342\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\022\t\n\005ARRAY\020\033\022\n\n\006STRUCT\020\034\022\014\n\010MUL" +
-      "TISET\020\035*^\n\010Severity\022\024\n\020UNKNOWN_SEVERITY\020" +
-      "\000\022\022\n\016FATAL_SEVERITY\020\001\022\022\n\016ERROR_SEVERITY\020" +
-      "\002\022\024\n\020WARNING_SEVERITY\020\003*\327\004\n\021MetaDataOper" +
-      "ation\022\022\n\016GET_ATTRIBUTES\020\000\022\033\n\027GET_BEST_RO" +
-      "W_IDENTIFIER\020\001\022\020\n\014GET_CATALOGS\020\002\022\036\n\032GET_" +
-      "CLIENT_INFO_PROPERTIES\020\003\022\031\n\025GET_COLUMN_P" +
-      "RIVILEGES\020\004\022\017\n\013GET_COLUMNS\020\005\022\027\n\023GET_CROS" +
-      "S_REFERENCE\020\006\022\025\n\021GET_EXPORTED_KEYS\020\007\022\030\n\024",
-      "GET_FUNCTION_COLUMNS\020\010\022\021\n\rGET_FUNCTIONS\020" +
-      "\t\022\025\n\021GET_IMPORTED_KEYS\020\n\022\022\n\016GET_INDEX_IN" +
-      "FO\020\013\022\024\n\020GET_PRIMARY_KEYS\020\014\022\031\n\025GET_PROCED" +
-      "URE_COLUMNS\020\r\022\022\n\016GET_PROCEDURES\020\016\022\026\n\022GET" +
-      "_PSEUDO_COLUMNS\020\017\022\017\n\013GET_SCHEMAS\020\020\022\031\n\025GE" +
-      "T_SCHEMAS_WITH_ARGS\020\021\022\024\n\020GET_SUPER_TABLE" +
-      "S\020\022\022\023\n\017GET_SUPER_TYPES\020\023\022\030\n\024GET_TABLE_PR" +
-      "IVILEGES\020\024\022\016\n\nGET_TABLES\020\025\022\023\n\017GET_TABLE_" +
-      "TYPES\020\026\022\021\n\rGET_TYPE_INFO\020\027\022\014\n\010GET_UDTS\020\030" +
-      "\022\027\n\023GET_VERSION_COLUMNS\020\031*\"\n\tStateType\022\007",
-      "\n\003SQL\020\000\022\014\n\010METADATA\020\001B\"\n org.apache.calc" +
-      "ite.avatica.protob\006proto3"
+      " \001(\014\"\207\001\n\013ColumnValue\022\032\n\005value\030\001 \003(\0132\013.Ty",
+      "pedValue\022 \n\013array_value\030\002 \003(\0132\013.TypedVal" +
+      "ue\022\027\n\017has_array_value\030\003 \001(\010\022!\n\014scalar_va" +
+      "lue\030\004 \001(\0132\013.TypedValue\"\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\"\246\002\n\031MetaDataOperatio" +
+      "nArgument\022\024\n\014string_value\030\001 \001(\t\022\022\n\nbool_" +
+      "value\030\002 \001(\010\022\021\n\tint_value\030\003 \001(\021\022\033\n\023string" +
+      "_array_values\030\004 \003(\t\022\030\n\020int_array_values\030",
+      "\005 \003(\021\0225\n\004type\030\006 \001(\0162\'.MetaDataOperationA" +
+      "rgument.ArgumentType\"^\n\014ArgumentType\022\n\n\006" +
+      "STRING\020\000\022\010\n\004BOOL\020\001\022\007\n\003INT\020\002\022\023\n\017REPEATED_" +
+      "STRING\020\003\022\020\n\014REPEATED_INT\020\004\022\010\n\004NULL\020\005\"\260\001\n" +
+      "\nQueryState\022\030\n\004type\030\001 \001(\0162\n.StateType\022\013\n" +
+      "\003sql\030\002 \001(\t\022\036\n\002op\030\003 \001(\0162\022.MetaDataOperati" +
+      "on\022(\n\004args\030\004 \003(\0132\032.MetaDataOperationArgu" +
+      "ment\022\020\n\010has_args\030\005 \001(\010\022\017\n\007has_sql\030\006 \001(\010\022" +
+      "\016\n\006has_op\030\007 \001(\010*\237\001\n\rStatementType\022\n\n\006SEL" +
+      "ECT\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\004DROP\020\010\022\t\n\005ALTER\020\t\022\r\n\tOTHE" +
+      "R_DDL\020\n\022\010\n\004CALL\020\013*\342\003\n\003Rep\022\025\n\021PRIMITIVE_B" +
+      "OOLEAN\020\000\022\022\n\016PRIMITIVE_BYTE\020\001\022\022\n\016PRIMITIV" +
+      "E_CHAR\020\002\022\023\n\017PRIMITIVE_SHORT\020\003\022\021\n\rPRIMITI" +
+      "VE_INT\020\004\022\022\n\016PRIMITIVE_LONG\020\005\022\023\n\017PRIMITIV" +
+      "E_FLOAT\020\006\022\024\n\020PRIMITIVE_DOUBLE\020\007\022\013\n\007BOOLE" +
+      "AN\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\006DO" +
+      "UBLE\020\017\022\017\n\013BIG_INTEGER\020\031\022\017\n\013BIG_DECIMAL\020\032",
+      "\022\021\n\rJAVA_SQL_TIME\020\020\022\026\n\022JAVA_SQL_TIMESTAM" +
+      "P\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\006NUMBE" +
+      "R\020\026\022\n\n\006OBJECT\020\027\022\010\n\004NULL\020\030\022\t\n\005ARRAY\020\033\022\n\n\006" +
+      "STRUCT\020\034\022\014\n\010MULTISET\020\035*^\n\010Severity\022\024\n\020UN" +
+      "KNOWN_SEVERITY\020\000\022\022\n\016FATAL_SEVERITY\020\001\022\022\n\016" +
+      "ERROR_SEVERITY\020\002\022\024\n\020WARNING_SEVERITY\020\003*\327" +
+      "\004\n\021MetaDataOperation\022\022\n\016GET_ATTRIBUTES\020\000" +
+      "\022\033\n\027GET_BEST_ROW_IDENTIFIER\020\001\022\020\n\014GET_CAT" +
+      "ALOGS\020\002\022\036\n\032GET_CLIENT_INFO_PROPERTIES\020\003\022",
+      "\031\n\025GET_COLUMN_PRIVILEGES\020\004\022\017\n\013GET_COLUMN" +
+      "S\020\005\022\027\n\023GET_CROSS_REFERENCE\020\006\022\025\n\021GET_EXPO" +
+      "RTED_KEYS\020\007\022\030\n\024GET_FUNCTION_COLUMNS\020\010\022\021\n" +
+      "\rGET_FUNCTIONS\020\t\022\025\n\021GET_IMPORTED_KEYS\020\n\022" +
+      "\022\n\016GET_INDEX_INFO\020\013\022\024\n\020GET_PRIMARY_KEYS\020" +
+      "\014\022\031\n\025GET_PROCEDURE_COLUMNS\020\r\022\022\n\016GET_PROC" +
+      "EDURES\020\016\022\026\n\022GET_PSEUDO_COLUMNS\020\017\022\017\n\013GET_" +
+      "SCHEMAS\020\020\022\031\n\025GET_SCHEMAS_WITH_ARGS\020\021\022\024\n\020" +
+      "GET_SUPER_TABLES\020\022\022\023\n\017GET_SUPER_TYPES\020\023\022" +
+      "\030\n\024GET_TABLE_PRIVILEGES\020\024\022\016\n\nGET_TABLES\020",
+      "\025\022\023\n\017GET_TABLE_TYPES\020\026\022\021\n\rGET_TYPE_INFO\020" +
+      "\027\022\014\n\010GET_UDTS\020\030\022\027\n\023GET_VERSION_COLUMNS\020\031" +
+      "*\"\n\tStateType\022\007\n\003SQL\020\000\022\014\n\010METADATA\020\001B\"\n " +
+      "org.apache.calcite.avatica.protob\006proto3"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -16362,7 +17103,7 @@ package org.apache.calcite.avatica.proto;
     internal_static_ColumnValue_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_ColumnValue_descriptor,
-        new java.lang.String[] { "Value", });
+        new java.lang.String[] { "Value", "ArrayValue", "HasArrayValue", "ScalarValue", });
     internal_static_TypedValue_descriptor =
       getDescriptor().getMessageTypes().get(12);
     internal_static_TypedValue_fieldAccessorTable = new

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/avatica/src/main/protobuf/common.proto
----------------------------------------------------------------------
diff --git a/avatica/src/main/protobuf/common.proto b/avatica/src/main/protobuf/common.proto
index 5421ffc..bd116c3 100644
--- a/avatica/src/main/protobuf/common.proto
+++ b/avatica/src/main/protobuf/common.proto
@@ -182,7 +182,10 @@ message WireMessage {
 
 // A value might be a TypedValue or an Array of TypedValue's
 message ColumnValue {
-  repeated TypedValue value = 1;
+  repeated TypedValue value = 1; // deprecated, use array_value or scalar_value
+  repeated TypedValue array_value = 2;
+  bool has_array_value = 3; // Is an array value set?
+  TypedValue scalar_value = 4;
 }
 
 // Generic wrapper to support any SQL type. Struct-like to work around no polymorphism construct.

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/avatica/src/test/java/org/apache/calcite/avatica/FrameTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/FrameTest.java b/avatica/src/test/java/org/apache/calcite/avatica/FrameTest.java
index e4d524c..bdd989b 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/FrameTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/FrameTest.java
@@ -17,23 +17,32 @@
 package org.apache.calcite.avatica;
 
 import org.apache.calcite.avatica.Meta.Frame;
+import org.apache.calcite.avatica.proto.Common;
+import org.apache.calcite.avatica.proto.Common.ColumnValue;
+import org.apache.calcite.avatica.proto.Common.TypedValue;
 
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * Tests serialization of {@link Frame}.
  */
 public class FrameTest {
 
+  private static final TypedValue NUMBER_VALUE = TypedValue.newBuilder().setNumberValue(1)
+      .setType(Common.Rep.LONG).build();
+
   private void serializeAndTestEquality(Frame frame) {
     Frame frameCopy = Frame.fromProto(frame.toProto());
 
@@ -94,6 +103,63 @@ public class FrameTest {
 
     serializeAndTestEquality(singleRow);
   }
+
+  @Test public void testMalformedColumnValue() {
+    // Invalid ColumnValue: has an array and scalar
+    final ColumnValue bothAttributesColumnValue = ColumnValue.newBuilder().setHasArrayValue(true)
+        .setScalarValue(NUMBER_VALUE).build();
+    // Note omission of setScalarValue(TypedValue).
+    final ColumnValue neitherAttributeColumnValue = ColumnValue.newBuilder().setHasArrayValue(false)
+        .build();
+
+    try {
+      Frame.validateColumnValue(bothAttributesColumnValue);
+      fail("Validating the ColumnValue should have failed as it has an array and scalar");
+    } catch (IllegalArgumentException e) {
+      // Pass
+    }
+
+    try {
+      Frame.validateColumnValue(neitherAttributeColumnValue);
+      fail("Validating the ColumnValue should have failed as it has neither an array nor scalar");
+    } catch (IllegalArgumentException e) {
+      // Pass
+    }
+  }
+
+  @Test public void testColumnValueBackwardsCompatibility() {
+    // 1
+    final ColumnValue oldStyleScalarValue = ColumnValue.newBuilder().addValue(NUMBER_VALUE).build();
+    // [1, 1]
+    final ColumnValue oldStyleArrayValue = ColumnValue.newBuilder().addValue(NUMBER_VALUE)
+        .addValue(NUMBER_VALUE).build();
+
+    assertFalse(Frame.isNewStyleColumn(oldStyleScalarValue));
+    assertFalse(Frame.isNewStyleColumn(oldStyleArrayValue));
+
+    Object scalar = Frame.parseOldStyleColumn(oldStyleScalarValue);
+    assertEquals(1L, scalar);
+
+    Object array = Frame.parseOldStyleColumn(oldStyleArrayValue);
+    assertEquals(Arrays.asList(1L, 1L), array);
+  }
+
+  @Test public void testColumnValueParsing() {
+    // 1
+    final ColumnValue scalarValue = ColumnValue.newBuilder().setScalarValue(NUMBER_VALUE).build();
+    // [1, 1]
+    final ColumnValue arrayValue = ColumnValue.newBuilder().addArrayValue(NUMBER_VALUE)
+        .addArrayValue(NUMBER_VALUE).setHasArrayValue(true).build();
+
+    assertTrue(Frame.isNewStyleColumn(scalarValue));
+    assertTrue(Frame.isNewStyleColumn(arrayValue));
+
+    Object scalar = Frame.parseColumn(scalarValue);
+    assertEquals(1L, scalar);
+
+    Object array = Frame.parseColumn(arrayValue);
+    assertEquals(Arrays.asList(1L, 1L), array);
+  }
 }
 
 // End FrameTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/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 7d24598..a10c7dc 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
@@ -19,6 +19,7 @@ package org.apache.calcite.avatica.remote;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.Meta.Frame;
 import org.apache.calcite.avatica.proto.Common;
+import org.apache.calcite.avatica.proto.Common.ColumnValue;
 import org.apache.calcite.avatica.proto.Requests;
 import org.apache.calcite.avatica.proto.Responses;
 import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
@@ -113,16 +114,20 @@ public class ProtobufHandlerTest {
     Iterator<Common.ColumnValue> iter = columnValues.iterator();
     assertTrue(iter.hasNext());
     Common.ColumnValue column = iter.next();
-    assertEquals(1, column.getValueCount());
+    assertTrue("The Column should have contained a scalar: " + column,
+        ProtobufService.hasField(column, column.getDescriptorForType(),
+            ColumnValue.SCALAR_VALUE_FIELD_NUMBER));
 
-    Common.TypedValue value = column.getValue(0);
+    Common.TypedValue value = column.getScalarValue();
     assertEquals(Common.Rep.BOOLEAN, value.getType());
     assertEquals(true, value.getBoolValue());
 
     assertTrue(iter.hasNext());
     column = iter.next();
-    assertEquals(1, column.getValueCount());
-    value = column.getValue(0);
+    assertTrue("The Column should have contained a scalar: " + column,
+        ProtobufService.hasField(column, column.getDescriptorForType(),
+            ColumnValue.SCALAR_VALUE_FIELD_NUMBER));
+    value = column.getScalarValue();
     assertEquals(Common.Rep.STRING, value.getType());
     assertEquals("my_string", value.getStringValue());
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
index cfc92d9..c75bdb0 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufTranslationImplTest.java
@@ -19,7 +19,9 @@ package org.apache.calcite.avatica.remote;
 import org.apache.calcite.avatica.AvaticaParameter;
 import org.apache.calcite.avatica.AvaticaSeverity;
 import org.apache.calcite.avatica.ColumnMetaData;
+import org.apache.calcite.avatica.ColumnMetaData.ArrayType;
 import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.calcite.avatica.ColumnMetaData.ScalarType;
 import org.apache.calcite.avatica.ConnectionPropertiesImpl;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.Meta.Frame;
@@ -71,6 +73,7 @@ import org.junit.runners.Parameterized.Parameters;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.sql.DatabaseMetaData;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -252,6 +255,16 @@ public class ProtobufTranslationImplTest<T> {
     return requests;
   }
 
+  private static ColumnMetaData getArrayColumnMetaData(ScalarType componentType, int index,
+      String name) {
+    ArrayType arrayType = ColumnMetaData.array(componentType, "Array", Rep.ARRAY);
+    return new ColumnMetaData(
+        index, false, true, false, false, DatabaseMetaData.columnNullable,
+        true, -1, name, name, null,
+        0, 0, null, null, arrayType, true, false, false,
+        "ARRAY");
+  }
+
   /**
    * Generates a collection of Responses whose serialization will be tested.
    */
@@ -262,18 +275,22 @@ public class ProtobufTranslationImplTest<T> {
     // Nested classes (Signature, ColumnMetaData, CursorFactory, etc) are implicitly getting tested)
 
     // Stub out the metadata for a row
+    ScalarType arrayComponentType = ColumnMetaData.scalar(Types.INTEGER, "integer", Rep.INTEGER);
+    ColumnMetaData arrayColumnMetaData = getArrayColumnMetaData(arrayComponentType, 2, "counts");
     List<ColumnMetaData> columns =
         Arrays.asList(MetaImpl.columnMetaData("str", 0, String.class),
-            MetaImpl.columnMetaData("count", 1, Integer.class));
+            MetaImpl.columnMetaData("count", 1, Integer.class),
+            arrayColumnMetaData);
     List<AvaticaParameter> params =
         Arrays.asList(
             new AvaticaParameter(false, 10, 0, Types.VARCHAR, "VARCHAR",
                 String.class.getName(), "str"));
     Meta.CursorFactory cursorFactory = Meta.CursorFactory.create(Style.LIST, Object.class,
-        Arrays.asList("str", "count"));
+        Arrays.asList("str", "count", "counts"));
     // The row values
     List<Object> rows = new ArrayList<>();
-    rows.add(new Object[] {"str_value", 50});
+    rows.add(new Object[] {"str_value1", 50, Arrays.asList(1, 2, 3)});
+    rows.add(new Object[] {"str_value2", 100, Arrays.asList(1)});
 
     // Create the signature and frame using the metadata and values
     Signature signature = Signature.create(columns, "sql", params, cursorFactory,

http://git-wip-us.apache.org/repos/asf/calcite/blob/361096ba/site/_docs/avatica_protobuf_reference.md
----------------------------------------------------------------------
diff --git a/site/_docs/avatica_protobuf_reference.md b/site/_docs/avatica_protobuf_reference.md
index c6b662d..02a8ab1 100644
--- a/site/_docs/avatica_protobuf_reference.md
+++ b/site/_docs/avatica_protobuf_reference.md
@@ -28,12 +28,14 @@ miscellaneous:
   - { name: "AvaticaSeverity" }
   - { name: "AvaticaType" }
   - { name: "ColumnMetaData" }
+  - { name: "ColumnValue" }
   - { name: "ConnectionProperties" }
   - { name: "CursorFactory" }
   - { name: "DatabaseProperty" }
   - { name: "Frame" }
   - { name: "QueryState" }
   - { name: "Rep" }
+  - { name: "Row" }
   - { name: "RpcMetadata" }
   - { name: "Signature" }
   - { name: "StateType" }
@@ -947,11 +949,20 @@ message Row {
 
 {% highlight protobuf %}
 message ColumnValue {
-  repeated TypedValue value = 1;
+  repeated TypedValue value = 1; // Deprecated!
+  repeated ColumnValue array_value = 2;
+  boolean has_array_value = 3;
+  TypedValue scalar_value = 4;
 }
 {% endhighlight %}
 
-`value` A collection of <a href="#typedvalue">TypedValue</a>s.
+`value` The pre Calcite-1.6 means of serializing <a href="#typedvalue">TypedValue</a>s. Not used anymore.
+
+`array_value` The value of this column if it is an array (not a scalar).
+
+`has_array_value` Should be set to true if `array_value` is set.
+
+`scalar_value` The value of this column if it is a scalar (not an array).
 
 ### QueryState
 


[12/13] calcite git commit: [CALCITE-1057] Add RelMetadataProvider parameter to standard planner Programs

Posted by jh...@apache.org.
[CALCITE-1057] Add RelMetadataProvider parameter to standard planner Programs


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

Branch: refs/heads/branch-1.6
Commit: af77ec861989c50229c55be1889efcb0031cfd32
Parents: cecef9d
Author: maryannxue <we...@intel.com>
Authored: Thu Jan 14 14:17:18 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jan 14 14:17:18 2016 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/tools/Programs.java | 27 +++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/af77ec86/core/src/main/java/org/apache/calcite/tools/Programs.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java
index 472563e..a52387d 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -102,14 +102,11 @@ public class Programs {
 
   /** Program that converts filters and projects to {@link Calc}s. */
   public static final Program CALC_PROGRAM =
-      hep(CALC_RULES, true, new DefaultRelMetadataProvider());
+      calc(new DefaultRelMetadataProvider());
 
   /** Program that expands sub-queries. */
   public static final Program SUB_QUERY_PROGRAM =
-      hep(
-          ImmutableList.of((RelOptRule) SubQueryRemoveRule.FILTER,
-              SubQueryRemoveRule.PROJECT,
-              SubQueryRemoveRule.JOIN), true, new DefaultRelMetadataProvider());
+      subquery(new DefaultRelMetadataProvider());
 
   public static final ImmutableSet<RelOptRule> RULE_SET =
       ImmutableSet.of(
@@ -260,6 +257,17 @@ public class Programs {
     };
   }
 
+  public static Program calc(RelMetadataProvider metadataProvider) {
+    return hep(CALC_RULES, true, metadataProvider);
+  }
+
+  public static Program subquery(RelMetadataProvider metadataProvider) {
+    return hep(
+        ImmutableList.of((RelOptRule) SubQueryRemoveRule.FILTER,
+            SubQueryRemoveRule.PROJECT,
+            SubQueryRemoveRule.JOIN), true, metadataProvider);
+  }
+
   public static Program getProgram() {
     return new Program() {
       public RelNode run(RelOptPlanner planner, RelNode rel,
@@ -271,6 +279,11 @@ public class Programs {
 
   /** Returns the standard program used by Prepare. */
   public static Program standard() {
+    return standard(new DefaultRelMetadataProvider());
+  }
+
+  /** Returns the standard program with user metadata provider. */
+  public static Program standard(RelMetadataProvider metadataProvider) {
 
     final Program program1 =
         new Program() {
@@ -290,14 +303,14 @@ public class Programs {
           }
         };
 
-    return sequence(SUB_QUERY_PROGRAM,
+    return sequence(subquery(metadataProvider),
         new DecorrelateProgram(),
         new TrimFieldsProgram(),
         program1,
 
         // Second planner pass to do physical "tweaks". This the first time that
         // EnumerableCalcRel is introduced.
-        CALC_PROGRAM);
+        calc(metadataProvider));
   }
 
   /** Program backed by a {@link RuleSet}. */


[10/13] calcite git commit: [CALCITE-978] Enable customizing constant folding rule behavior when a Filter simplifies to false (Jason Altekruse)

Posted by jh...@apache.org.
[CALCITE-978] Enable customizing constant folding rule behavior when a Filter simplifies to false (Jason Altekruse)

For static schema systems, a Filter that is always false or null can be
replaced by a Values operator that produces no rows, as the schema
information can just be taken from the input Rel. In dynamic schema
environments, the filter might have an unknown input type, in these cases
they must define a system specific alternative to a Values operator, such
as inserting a Limit 0 instead of a Filter on top of the original input.

This change enables this behavior to be customized by a subclass of the
constant reduction rules.

Close apache/calcite#183


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

Branch: refs/heads/branch-1.6
Commit: 898fdfc2720770ec4752fb702ce0aae1521aa07d
Parents: ee283ca
Author: Jason Altekruse <al...@gmail.com>
Authored: Fri Apr 10 15:39:54 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Thu Jan 14 13:52:01 2016 -0800

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 51 ++++++++++++++++++--
 1 file changed, 48 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/898fdfc2/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 3fce8a6..1036ea4 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
@@ -55,6 +55,7 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlRowOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Stacks;
@@ -160,7 +161,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
             filter.getInput());
       } else if (newConditionExp instanceof RexLiteral
           || RexUtil.isNullLiteral(newConditionExp, true)) {
-        call.transformTo(call.builder().values(filter.getRowType()).build());
+        call.transformTo(createEmptyRelOrEquivalent(call, filter));
       } else if (reduced) {
         call.transformTo(call.builder().
             push(filter.getInput()).filter(expList.get(0)).build());
@@ -182,6 +183,28 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
       call.getPlanner().setImportance(filter, 0.0);
     }
 
+    /**
+     * For static schema systems, a filter that is always false or null can be
+     * replaced by a values operator that produces no rows, as the schema
+     * information can just be taken from the input Rel. In dynamic schema
+     * environments, the filter might have an unknown input type, in these cases
+     * they must define a system specific alternative to a Values operator, such
+     * as inserting a limit 0 instead of a filter on top of the original input.
+     *
+     * <p>The default implementation of this method is to call
+     * {@link RelBuilder#empty}, which for the static schema will be optimized
+     * to an empty
+     * {@link org.apache.calcite.rel.core.Values}.
+     *
+     * @param input rel to replace, assumes caller has already determined
+     *              equivalence to Values operation for 0 records or a
+     *              false filter.
+     * @return equivalent but less expensive replacement rel
+     */
+    protected RelNode createEmptyRelOrEquivalent(RelOptRuleCall call, Filter input) {
+      return call.builder().push(input).empty().build();
+    }
+
     private void reduceNotNullableFilter(
         RelOptRuleCall call,
         Filter filter,
@@ -212,7 +235,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
           if (alwaysTrue) {
             call.transformTo(filter.getInput());
           } else {
-            call.transformTo(call.builder().values(filter.getRowType()).build());
+            call.transformTo(createEmptyRelOrEquivalent(call, filter));
           }
         }
       }
@@ -343,7 +366,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
               || RexUtil.isNullLiteral(newConditionExp, true)) {
             // condition is always NULL or FALSE - replace calc
             // with empty
-            call.transformTo(call.builder().values(calc.getRowType()).build());
+            call.transformTo(createEmptyRelOrEquivalent(call, calc));
             return;
           } else {
             builder.addCondition(list.get(conditionIndex));
@@ -363,6 +386,28 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
         call.getPlanner().setImportance(calc, 0.0);
       }
     }
+
+    /**
+     * For static schema systems, a filter that is always false or null can be
+     * replaced by a values operator that produces no rows, as the schema
+     * information can just be taken from the input Rel. In dynamic schema
+     * environments, the filter might have an unknown input type, in these cases
+     * they must define a system specific alternative to a Values operator, such
+     * as inserting a limit 0 instead of a filter on top of the original input.
+     *
+     * <p>The default implementation of this method is to call
+     * {@link RelBuilder#empty}, which for the static schema will be optimized
+     * to an empty
+     * {@link org.apache.calcite.rel.core.Values}.
+     *
+     * @param input rel to replace, assumes caller has already determined
+     *              equivalence to Values operation for 0 records or a
+     *              false filter.
+     * @return equivalent but less expensive replacement rel
+     */
+    protected RelNode createEmptyRelOrEquivalent(RelOptRuleCall call, Calc input) {
+      return call.builder().push(input).empty().build();
+    }
   }
 
   //~ Constructors -----------------------------------------------------------


[08/13] calcite git commit: [CALCITE-1047] ChunkList.clear throws AssertionError

Posted by jh...@apache.org.
[CALCITE-1047] ChunkList.clear throws AssertionError

Re-work ChunkList with a more robust implementation of ListIterator and more thorough tests.


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

Branch: refs/heads/branch-1.6
Commit: 3cba7055061108ce0e079d8756bcfb020b8628c3
Parents: 2712d7d
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Jan 12 20:14:51 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed Jan 13 08:43:29 2016 -0800

----------------------------------------------------------------------
 .../java/org/apache/calcite/util/ChunkList.java | 243 ++++++++++++-------
 .../org/apache/calcite/util/ChunkListTest.java  | 217 ++++++++++++++---
 2 files changed, 340 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/3cba7055/core/src/main/java/org/apache/calcite/util/ChunkList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ChunkList.java b/core/src/main/java/org/apache/calcite/util/ChunkList.java
index 66644e9..8d7c9bf 100644
--- a/core/src/main/java/org/apache/calcite/util/ChunkList.java
+++ b/core/src/main/java/org/apache/calcite/util/ChunkList.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.util;
 
 import java.util.AbstractSequentialList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.ListIterator;
@@ -33,10 +34,6 @@ import java.util.NoSuchElementException;
  */
 public class ChunkList<E> extends AbstractSequentialList<E> {
   private static final int HEADER_SIZE = 3;
-  private int size;
-  private Object[] first;
-  private Object[] last;
-
   private static final int CHUNK_SIZE = 64;
   private static final Integer[] INTEGERS = new Integer[CHUNK_SIZE + 3];
 
@@ -46,6 +43,10 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
     }
   }
 
+  private int size;
+  private Object[] first;
+  private Object[] last;
+
   /**
    * Creates an empty ChunkList.
    */
@@ -105,6 +106,12 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
     return size;
   }
 
+  @Override public void clear() {
+    // base class method works, but let's optimize
+    size = 0;
+    first = last = null;
+  }
+
   @Override public boolean add(E element) {
     Object[] chunk = last;
     int occupied;
@@ -169,18 +176,20 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
   }
 
   private ChunkListIterator locate(int index) {
-    if (index == 0) {
-      return new ChunkListIterator();
+    if (index < 0 || index > size) {
+      throw new IndexOutOfBoundsException();
+    }
+    if (first == null) {
+      // Create an iterator positioned before the first element.
+      return new ChunkListIterator(null, 0, 0, -1, 0);
     }
     int n = 0;
     for (Object[] chunk = first;;) {
       final int occupied = occupied(chunk);
       final int nextN = n + occupied;
       final Object[] next = next(chunk);
-      if (nextN > index || next == null) {
-        return new ChunkListIterator(
-            chunk, n, index - n - 1 + HEADER_SIZE,
-            occupied + HEADER_SIZE);
+      if (nextN >= index || next == null) {
+        return new ChunkListIterator(chunk, n, index, -1, n + occupied);
       }
       n = nextN;
       chunk = next;
@@ -190,76 +199,87 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
   /** Iterator over a {@link ChunkList}. */
   private class ChunkListIterator implements ListIterator<E> {
     private Object[] chunk;
-    private int startIndex;
-    private int offset;
+    /** Offset in the list of the first element of this chunk. */
+    private int start;
+    /** Offset within current chunk of the next element to return. */
+    private int cursor;
+    /** Offset within the current chunk of the last element returned. -1 if
+     * {@link #next} or {@link #previous()} has not been called. */
+    private int lastRet;
+    /** Offset of the first unoccupied location in the current chunk. */
     private int end;
 
-    ChunkListIterator() {
-      this(null, 0, -1, 0);
-    }
-
-    ChunkListIterator(Object[] chunk, int startIndex, int offset, int end) {
+    ChunkListIterator(Object[] chunk, int start, int cursor, int lastRet,
+        int end) {
       this.chunk = chunk;
-      this.startIndex = startIndex;
-      this.offset = offset;
+      this.start = start;
+      this.cursor = cursor;
+      this.lastRet = lastRet;
       this.end = end;
     }
 
     public boolean hasNext() {
-      return offset + 1 < end
-          || (chunk == null
-          ? first != null
-          : ChunkList.next(chunk) != null);
+      return cursor < size;
     }
 
     public E next() {
-      ++offset;
-      assert offset <= end;
-      if (offset == end) {
+      if (cursor >= size) {
+        throw new NoSuchElementException();
+      }
+      if (cursor == end) {
         if (chunk == null) {
           chunk = first;
         } else {
           chunk = ChunkList.next(chunk);
-          startIndex += end - HEADER_SIZE;
         }
+        start = end;
         if (chunk == null) {
-          throw new NoSuchElementException();
+          end = start;
+        } else {
+          end = start + occupied(chunk);
         }
-        offset = HEADER_SIZE;
-        end = occupied(chunk) + HEADER_SIZE;
       }
-      return (E) element(chunk, offset);
+      @SuppressWarnings("unchecked")
+      final E element = (E) element(chunk,
+          HEADER_SIZE + (lastRet = cursor++) - start);
+      return element;
     }
 
     public boolean hasPrevious() {
-      return offset >= HEADER_SIZE || ChunkList.prev(chunk) != null;
+      return cursor > 0;
     }
 
     public E previous() {
-      --offset;
-      if (offset == HEADER_SIZE - 1) {
+      lastRet = cursor--;
+      if (cursor < start) {
         chunk = chunk == null ? last : ChunkList.prev(chunk);
         if (chunk == null) {
           throw new NoSuchElementException();
         }
-        end = occupied(chunk);
-        startIndex -= end;
-        offset = end - 1;
+        final int o = occupied(chunk);
+        end = start;
+        start -= o;
+        assert cursor == end - 1;
       }
-      return (E) element(chunk, offset);
+      //noinspection unchecked
+      return (E) element(chunk, cursor - start);
     }
 
     public int nextIndex() {
-      return startIndex + (offset - HEADER_SIZE) + 1;
+      return cursor;
     }
 
     public int previousIndex() {
-      return startIndex + (offset - HEADER_SIZE);
+      return cursor - 1;
     }
 
     public void remove() {
+      if (lastRet < 0) {
+        throw new IllegalStateException();
+      }
       --size;
-      if (end == HEADER_SIZE + 1) {
+      --cursor;
+      if (end == start + 1) {
         // Chunk is now empty.
         final Object[] prev = prev(chunk);
         final Object[] next = ChunkList.next(chunk);
@@ -272,80 +292,125 @@ public class ChunkList<E> extends AbstractSequentialList<E> {
           }
           chunk = null;
           end = HEADER_SIZE;
-          offset = end - 1;
         } else {
           if (prev == null) {
-            first = next;
+            chunk = first = next;
             setPrev(next, null);
+            end = occupied(chunk);
           } else {
             setNext(prev, next);
             setPrev(next, prev);
+            chunk = prev;
+            end = start;
+            start -= occupied(chunk);
           }
-          chunk = next;
-          offset = HEADER_SIZE;
-          end = HEADER_SIZE + occupied(next);
         }
+        lastRet = -1;
         return;
       }
-      // Move existing contents down one.
-      System.arraycopy(
-          chunk, offset + 1, chunk, offset, end - offset - 1);
-      --end;
-      setElement(chunk, end, null); // allow gc
-      setOccupied(chunk, end - HEADER_SIZE);
-      if (offset == end) {
-        final Object[] next = ChunkList.next(chunk);
-        if (next != null) {
-          startIndex += end - HEADER_SIZE;
-          chunk = next;
-          offset = HEADER_SIZE - 1;
-          end = HEADER_SIZE + occupied(next);
+      final int r = lastRet;
+      lastRet = -1;
+      if (r < start) {
+        // Element we wish to eliminate is the last element in the previous
+        // block.
+        Object[] c = chunk;
+        if (c == null) {
+          c = last;
         }
+        int o = occupied(c);
+        if (o == 1) {
+          // Block is now empty; remove it
+          final Object[] prev = prev(c);
+          if (prev == null) {
+            if (chunk == null) {
+              first = last = null;
+            } else {
+              first = chunk;
+              setPrev(chunk, null);
+            }
+          } else {
+            setNext(prev, chunk);
+            setPrev(chunk, prev);
+          }
+        } else {
+          --o;
+          setElement(c, HEADER_SIZE + o, null); // allow gc
+          setOccupied(c, o);
+        }
+      } else {
+        // Move existing contents down one.
+        System.arraycopy(chunk, HEADER_SIZE + r - start + 1,
+            chunk, HEADER_SIZE + r - start, end - r - 1);
+        --end;
+        final int o = end - start;
+        setElement(chunk, HEADER_SIZE + o, null); // allow gc
+        setOccupied(chunk, o);
       }
     }
 
     public void set(E e) {
-      setElement(chunk, offset, e);
+      if (lastRet < 0) {
+        throw new IllegalStateException();
+      }
+      Object[] c = chunk;
+      int p = lastRet;
+      int s = start;
+      if (p < start) {
+        // The element is at the end of the previous chunk
+        c = prev(c);
+        s -= occupied(c);
+      }
+      setElement(c, HEADER_SIZE + p - s, e);
     }
 
     public void add(E e) {
-      if (chunk == null || end == CHUNK_SIZE + HEADER_SIZE) {
+      if (chunk == null) {
+        Object[] newChunk = new Object[CHUNK_SIZE + HEADER_SIZE];
+        if (first != null) {
+          setNext(newChunk, first);
+          setPrev(first, newChunk);
+        }
+        first = newChunk;
+        if (last == null) {
+          last = newChunk;
+        }
+        chunk = newChunk;
+        end = start;
+      } else if (end == start + CHUNK_SIZE) {
         // FIXME We create a new chunk, but the next chunk might be
         // less than half full. We should consider using it.
         Object[] newChunk = new Object[CHUNK_SIZE + HEADER_SIZE];
-        if (chunk == null) {
-          if (first != null) {
-            setNext(newChunk, first);
-            setPrev(first, newChunk);
-          }
-          first = newChunk;
-          if (last == null) {
-            last = newChunk;
-          }
+        final Object[] next = ChunkList.next(chunk);
+        setPrev(newChunk, chunk);
+        setNext(chunk, newChunk);
+
+        if (next == null) {
+          last = newChunk;
         } else {
-          final Object[] next = ChunkList.next(chunk);
-          setPrev(newChunk, chunk);
-          setNext(chunk, newChunk);
+          setPrev(next, newChunk);
+          setNext(newChunk, next);
+        }
 
-          if (next == null) {
-            last = newChunk;
-          } else {
-            setPrev(next, newChunk);
-            setNext(newChunk, next);
-          }
-          startIndex += CHUNK_SIZE;
+        setOccupied(chunk, CHUNK_SIZE / 2);
+        setOccupied(newChunk, CHUNK_SIZE / 2);
+        System.arraycopy(chunk, HEADER_SIZE + CHUNK_SIZE / 2,
+            newChunk, HEADER_SIZE, CHUNK_SIZE / 2);
+        Arrays.fill(chunk, HEADER_SIZE + CHUNK_SIZE / 2,
+            HEADER_SIZE + CHUNK_SIZE, null);
+
+        if (cursor - start < CHUNK_SIZE / 2) {
+          end -= CHUNK_SIZE / 2;
+        } else {
+          start += CHUNK_SIZE / 2;
+          chunk = newChunk;
         }
-        chunk = newChunk;
-        end = offset = HEADER_SIZE;
-      } else {
-        // Move existing contents up one.
-        System.arraycopy(
-            chunk, offset, chunk, offset + 1, end - offset);
       }
-      setElement(chunk, offset, e);
-//            ++offset;
+      // Move existing contents up one.
+      System.arraycopy(chunk, HEADER_SIZE + cursor - start,
+          chunk, HEADER_SIZE + cursor - start + 1, end - cursor);
       ++end;
-      setOccupied(chunk, end - HEADER_SIZE);
+      setElement(chunk, HEADER_SIZE + cursor - start, e);
+      setOccupied(chunk, end - start);
       ++size;
     }
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/3cba7055/core/src/test/java/org/apache/calcite/util/ChunkListTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/util/ChunkListTest.java b/core/src/test/java/org/apache/calcite/util/ChunkListTest.java
index 0e2bb2d..efb1b09 100644
--- a/core/src/test/java/org/apache/calcite/util/ChunkListTest.java
+++ b/core/src/test/java/org/apache/calcite/util/ChunkListTest.java
@@ -19,6 +19,8 @@ package org.apache.calcite.util;
 import org.apache.calcite.linq4j.function.Function0;
 import org.apache.calcite.linq4j.function.Function1;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -30,9 +32,11 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.Random;
 
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -44,8 +48,13 @@ public class ChunkListTest {
    * Unit test for {@link ChunkList}.
    */
   @Test public void testChunkList() {
-    final ChunkList<Integer> list = new ChunkList<Integer>();
+    final ChunkList<Integer> list = new ChunkList<>();
+    final ChunkList<Integer> list0 = new ChunkList<>(list);
+    final ChunkList<Integer> list1 = new ChunkList<>(list);
+    list1.add(123);
     assertEquals(0, list.size());
+    assertEquals(0, list0.size());
+    assertEquals(1, list1.size());
     assertTrue(list.isEmpty());
     assertEquals("[]", list.toString());
 
@@ -56,6 +65,20 @@ public class ChunkListTest {
       // ok
     }
 
+    try {
+      list.get(-1);
+      fail("expected exception");
+    } catch (IndexOutOfBoundsException e) {
+      // ok
+    }
+
+    try {
+      list.get(0);
+      fail("expected exception");
+    } catch (IndexOutOfBoundsException e) {
+      // ok
+    }
+
     list.add(7);
     assertEquals(1, list.size());
     assertEquals(7, (int) list.get(0));
@@ -76,9 +99,10 @@ public class ChunkListTest {
     assertTrue(list.contains(9));
     assertFalse(list.contains(8));
 
-    list.addAll(Collections.nCopies(40, 1));
-    assertEquals(44, list.size());
+    list.addAll(Collections.nCopies(70, 1));
+    assertEquals(74, list.size());
     assertEquals(1, (int) list.get(40));
+    assertEquals(1, (int) list.get(70));
 
     int n = 0;
     for (Integer integer : list) {
@@ -96,44 +120,142 @@ public class ChunkListTest {
     i = list.indexOf(null);
     assertEquals(-1, i);
 
+    // sort an empty list
+    Collections.sort(list0);
+    assertThat(list0.isEmpty(), is(true));
+
+    // sort a list with 1 element
+    Collections.sort(list1);
+    assertThat(list1.size(), is(1));
+
     Collections.sort(list);
+    assertEquals(74, list.size());
 
     list.remove((Integer) 7);
     Collections.sort(list);
     assertEquals(1, (int) list.get(3));
 
     // remove all instances of a value that exists
-    boolean b = list.removeAll(Arrays.asList(9));
+    boolean b = list.removeAll(Collections.singletonList(9));
     assertTrue(b);
 
     // remove all instances of a non-existent value
-    b = list.removeAll(Arrays.asList(99));
+    b = list.removeAll(Collections.singletonList(99));
     assertFalse(b);
 
     // remove all instances of a value that occurs in the last chunk
     list.add(12345);
-    b = list.removeAll(Arrays.asList(12345));
+    b = list.removeAll(Collections.singletonList(12345));
     assertTrue(b);
 
     // remove all instances of a value that occurs in the last chunk but
     // not as the last value
     list.add(12345);
     list.add(123);
-    b = list.removeAll(Arrays.asList(12345));
+    b = list.removeAll(Collections.singletonList(12345));
     assertTrue(b);
 
-    assertEquals(
-        1000, new ChunkList<Integer>(Collections.nCopies(1000, 77)).size());
+    assertThat(new ChunkList<>(Collections.nCopies(1000, 77)).size(),
+        is(1000));
 
     // add to an empty list via iterator
     //noinspection MismatchedQueryAndUpdateOfCollection
-    final ChunkList<String> list2 = new ChunkList<String>();
+    final ChunkList<String> list2 = new ChunkList<>();
     list2.listIterator(0).add("x");
     assertEquals("[x]", list2.toString());
 
     // add at start
     list2.add(0, "y");
     assertEquals("[y, x]", list2.toString());
+
+    list2.remove(0);
+    assertEquals("[x]", list2.toString());
+
+    // clear a list of length 5, one element at a time, using an iterator
+    list2.clear();
+    list2.addAll(ImmutableList.of("a", "b", "c", "d", "e"));
+    assertThat(list2.size(), is(5));
+    final ListIterator<String> listIterator = list2.listIterator(0);
+    assertThat(listIterator.next(), is("a"));
+    listIterator.remove();
+    assertThat(listIterator.next(), is("b"));
+    listIterator.remove();
+    assertThat(listIterator.next(), is("c"));
+    listIterator.remove();
+    assertThat(listIterator.next(), is("d"));
+    listIterator.remove();
+    assertThat(list2.size(), is(1));
+    assertThat(listIterator.next(), is("e"));
+    listIterator.remove();
+    assertThat(list2.size(), is(0));
+  }
+
+  /** Clears lists of various sizes. */
+  @Test public void testClear() {
+    checkListClear(0);
+    checkListClear(1);
+    checkListClear(2);
+    checkListClear(32);
+    checkListClear(64);
+    checkListClear(65);
+    checkListClear(66);
+    checkListClear(100);
+    checkListClear(127);
+    checkListClear(128);
+    checkListClear(129);
+  }
+
+  private void checkListClear(int n) {
+    for (int i = 0; i < 4; i++) {
+      ChunkList<String> list = new ChunkList<>(Collections.nCopies(n, "z"));
+      assertThat(list.size(), is(n));
+      switch (i) {
+      case 0:
+        list.clear();
+        break;
+      case 1:
+        for (int j = 0; j < n; j++) {
+          list.remove(0);
+        }
+        break;
+      case 2:
+        for (int j = 0; j < n; j++) {
+          list.remove(list.size() - 1);
+        }
+        break;
+      case 3:
+        Random random = new Random();
+        for (int j = 0; j < n; j++) {
+          list.remove(random.nextInt(list.size()));
+        }
+        break;
+      }
+      assertThat(list.isEmpty(), is(true));
+    }
+  }
+
+  /**
+   * Removing via an iterator.
+   */
+  @Test public void testIterator() {
+    final ChunkList<String> list = new ChunkList<>();
+    list.add("a");
+    list.add("b");
+    final ListIterator<String> listIterator = list.listIterator(0);
+    try {
+      listIterator.remove();
+      fail("excepted exception");
+    } catch (IllegalStateException e) {
+      // ok
+    }
+    listIterator.next();
+    listIterator.remove();
+    assertThat(list.size(), is(1));
+    assertThat(listIterator.hasNext(), is(true));
+    listIterator.next();
+    listIterator.remove();
+    assertThat(list.size(), is(0));
+    assertThat(listIterator.hasNext(), is(false));
   }
 
   /**
@@ -142,41 +264,52 @@ public class ChunkListTest {
    */
   @Test public void testRandom() {
     final int iterationCount = 10000;
-    checkRandom(new Random(1), new ChunkList<Integer>(), iterationCount);
+    checkRandom(new Random(1), new ChunkList<Integer>(),
+        new ArrayList<Integer>(), iterationCount);
     final Random random = new Random(2);
     for (int j = 0; j < 10; j++) {
-      checkRandom(random, new ChunkList<Integer>(), iterationCount);
+      checkRandom(random, new ChunkList<Integer>(), new ArrayList<Integer>(),
+          iterationCount);
     }
-    checkRandom(
-        new Random(3), new ChunkList<Integer>(Collections.nCopies(1000, 5)),
-        iterationCount);
+    final ChunkList<Integer> chunkList =
+        new ChunkList<>(Collections.nCopies(1000, 5));
+    final List<Integer> referenceList = new ArrayList<>(chunkList);
+    checkRandom(new Random(3), chunkList, referenceList, iterationCount);
   }
 
   void checkRandom(
       Random random,
       ChunkList<Integer> list,
+      List<Integer> list2,
       int iterationCount) {
     int removeCount = 0;
     int addCount = 0;
+    int size;
+    int e;
     final int initialCount = list.size();
     for (int i = 0; i < iterationCount; i++) {
       assert list.isValid(true);
-      switch (random.nextInt(8)) {
+      switch (random.nextInt(10)) {
       case 0:
         // remove last
         if (!list.isEmpty()) {
+          assertThat(list2.isEmpty(), is(false));
           list.remove(list.size() - 1);
+          list2.remove(list2.size() - 1);
           ++removeCount;
         }
         break;
       case 1:
         // add to end
-        list.add(random.nextInt(1000));
+        e = random.nextInt(1000);
+        list.add(e);
+        list2.add(e);
         ++addCount;
         break;
       case 2:
         int n = 0;
-        final int size = list.size();
+        size = list.size();
+        assertThat(list.size(), is(list2.size()));
         for (Integer integer : list) {
           Util.discard(integer);
           assertTrue(n++ < size);
@@ -184,20 +317,26 @@ public class ChunkListTest {
         break;
       case 3:
         // remove all instances of a particular value
-        int sizeBefore = list.size();
-        boolean b = list.removeAll(
-            Collections.singletonList(random.nextInt(500)));
+        size = list.size();
+        final List<Integer> zz = Collections.singletonList(random.nextInt(500));
+        boolean b = list.removeAll(zz);
+        boolean b2 = list2.removeAll(zz);
+        assertThat(b, is(b2));
         if (b) {
-          assertTrue(list.size() < sizeBefore);
+          assertTrue(list.size() < size);
+          assertTrue(list2.size() < size);
         } else {
-          assertTrue(list.size() == sizeBefore);
+          assertTrue(list.size() == size);
+          assertTrue(list2.size() == size);
         }
-        removeCount += sizeBefore - list.size();
+        removeCount += size - list.size();
         break;
       case 4:
         // remove at random position
         if (!list.isEmpty()) {
-          list.remove(random.nextInt(list.size()));
+          e = random.nextInt(list.size());
+          list.remove(e);
+          list2.remove(e);
           ++removeCount;
         }
         break;
@@ -205,19 +344,35 @@ public class ChunkListTest {
         // add at random position
         int count = random.nextInt(list.size() + 1);
         ListIterator<Integer> it = list.listIterator();
+        ListIterator<Integer> it2 = list2.listIterator();
         for (int j = 0; j < count; j++) {
           it.next();
+          it2.next();
         }
-        it.add(list.size());
+        size = list.size();
+        it.add(size);
+        it2.add(size);
         ++addCount;
         break;
+      case 6:
+        // clear
+        if (random.nextInt(200) == 0) {
+          removeCount += list.size();
+          list.clear();
+          list2.clear();
+        }
+        break;
       default:
         // add at random position
-        list.add(random.nextInt(list.size() + 1), list.size());
+        int pos = random.nextInt(list.size() + 1);
+        e = list.size();
+        list.add(pos, e);
+        list2.add(pos, e);
         ++addCount;
         break;
       }
       assertEquals(list.size(), initialCount + addCount - removeCount);
+      assertEquals(list, list2);
     }
   }
 
@@ -231,22 +386,22 @@ public class ChunkListTest {
             Arrays.asList(
                 new Function0<List<Integer>>() {
                   public List<Integer> apply() {
-                    return new ArrayList<Integer>();
+                    return new ArrayList<>();
                   }
                 },
                 new Function0<List<Integer>>() {
                   public List<Integer> apply() {
-                    return new LinkedList<Integer>();
+                    return new LinkedList<>();
                   }
                 },
                 new Function0<List<Integer>>() {
                   public List<Integer> apply() {
-                    return new ChunkList<Integer>();
+                    return new ChunkList<>();
                   }
                 }),
             Arrays.asList("ArrayList", "LinkedList", "ChunkList-64"));
     final List<Pair<Function0<List<Integer>>, String>> factories1 =
-        new ArrayList<Pair<Function0<List<Integer>>, String>>();
+        new ArrayList<>();
     for (Pair<Function0<List<Integer>>, String> pair : factories0) {
       factories1.add(pair);
     }


[03/13] calcite git commit: [CALCITE-977] Make the constant expression Executor configurable in FrameworkConfig (Jason Altekruse)

Posted by jh...@apache.org.
[CALCITE-977] Make the constant expression Executor configurable in FrameworkConfig (Jason Altekruse)

Close apache/calcite#182


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

Branch: refs/heads/branch-1.6
Commit: 5323d8d48baa2d7bc8dea8b03bc0bda93563e0f9
Parents: e15f89e
Author: Jason Altekruse <al...@gmail.com>
Authored: Fri Apr 10 13:07:35 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Jan 12 13:47:17 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptPlanner.java   |  1 +
 .../org/apache/calcite/prepare/PlannerImpl.java  |  3 +++
 .../apache/calcite/tools/FrameworkConfig.java    |  6 ++++++
 .../org/apache/calcite/tools/Frameworks.java     | 19 +++++++++++++++++--
 4 files changed, 27 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/5323d8d4/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java
index 9b5e22a..bad9402 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java
@@ -318,6 +318,7 @@ public interface RelOptPlanner {
   /** Sets the object that can execute scalar expressions. */
   void setExecutor(Executor executor);
 
+  /** Returns the executor used to evaluate constant expressions. */
   Executor getExecutor();
 
   /** Called when a relational expression is copied to a similar expression. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/5323d8d4/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
index 18d9746..fa6ea30 100644
--- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java
@@ -72,6 +72,7 @@ public class PlannerImpl implements Planner {
   private SchemaPlus defaultSchema;
   private JavaTypeFactory typeFactory;
   private RelOptPlanner planner;
+  private RelOptPlanner.Executor executor;
 
   // set in STATE_4_VALIDATE
   private CalciteSqlValidator validator;
@@ -91,6 +92,7 @@ public class PlannerImpl implements Planner {
     this.state = State.STATE_0_CLOSED;
     this.traitDefs = config.getTraitDefs();
     this.convertletTable = config.getConvertletTable();
+    this.executor = config.getExecutor();
     reset();
   }
 
@@ -135,6 +137,7 @@ public class PlannerImpl implements Planner {
             Util.discard(rootSchema); // use our own defaultSchema
             typeFactory = (JavaTypeFactory) cluster.getTypeFactory();
             planner = cluster.getPlanner();
+            planner.setExecutor(executor);
             return null;
           }
         },

http://git-wip-us.apache.org/repos/asf/calcite/blob/5323d8d4/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
index 6301321..319c216 100644
--- a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
+++ b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java
@@ -18,6 +18,7 @@ package org.apache.calcite.tools;
 
 import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.RelOptCostFactory;
+import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.schema.SchemaPlus;
@@ -46,6 +47,11 @@ public interface FrameworkConfig {
   SchemaPlus getDefaultSchema();
 
   /**
+   * Returns the executor used to evaluate constant expressions.
+   */
+  RelOptPlanner.Executor getExecutor();
+
+  /**
    * Returns a list of one or more programs used during the course of query
    * evaluation.
    *

http://git-wip-us.apache.org/repos/asf/calcite/blob/5323d8d4/core/src/main/java/org/apache/calcite/tools/Frameworks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
index dffac61..a4e43fc 100644
--- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java
+++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java
@@ -21,6 +21,7 @@ import org.apache.calcite.jdbc.CalciteSchema;
 import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptCostFactory;
+import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.plan.RelTraitDef;
 import org.apache.calcite.prepare.CalcitePrepareImpl;
@@ -179,6 +180,7 @@ public class Frameworks {
     private SqlParser.Config parserConfig =
         SqlParser.Config.DEFAULT;
     private SchemaPlus defaultSchema;
+    private RelOptPlanner.Executor executor;
     private RelOptCostFactory costFactory;
     private RelDataTypeSystem typeSystem = RelDataTypeSystem.DEFAULT;
 
@@ -187,7 +189,7 @@ public class Frameworks {
     public FrameworkConfig build() {
       return new StdFrameworkConfig(context, convertletTable, operatorTable,
           programs, traitDefs, parserConfig, defaultSchema, costFactory,
-          typeSystem);
+          typeSystem, executor);
     }
 
     public ConfigBuilder context(Context c) {
@@ -195,6 +197,12 @@ public class Frameworks {
       return this;
     }
 
+    public ConfigBuilder executor(RelOptPlanner.Executor executor) {
+      Preconditions.checkNotNull(executor);
+      this.executor = executor;
+      return this;
+    }
+
     public ConfigBuilder convertletTable(
         SqlRexConvertletTable convertletTable) {
       this.convertletTable = Preconditions.checkNotNull(convertletTable);
@@ -273,6 +281,7 @@ public class Frameworks {
     private final SchemaPlus defaultSchema;
     private final RelOptCostFactory costFactory;
     private final RelDataTypeSystem typeSystem;
+    private final RelOptPlanner.Executor executor;
 
     public StdFrameworkConfig(Context context,
         SqlRexConvertletTable convertletTable,
@@ -282,7 +291,8 @@ public class Frameworks {
         SqlParser.Config parserConfig,
         SchemaPlus defaultSchema,
         RelOptCostFactory costFactory,
-        RelDataTypeSystem typeSystem) {
+        RelDataTypeSystem typeSystem,
+        RelOptPlanner.Executor executor) {
       this.context = context;
       this.convertletTable = convertletTable;
       this.operatorTable = operatorTable;
@@ -292,6 +302,7 @@ public class Frameworks {
       this.defaultSchema = defaultSchema;
       this.costFactory = costFactory;
       this.typeSystem = typeSystem;
+      this.executor = executor;
     }
 
     public SqlParser.Config getParserConfig() {
@@ -302,6 +313,10 @@ public class Frameworks {
       return defaultSchema;
     }
 
+    public RelOptPlanner.Executor getExecutor() {
+      return executor;
+    }
+
     public ImmutableList<Program> getPrograms() {
       return programs;
     }