Repository: calcite
Updated Branches:
  refs/heads/master 052c7447f -> 942693e67


[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/942693e6
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/942693e6
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/942693e6

Branch: refs/heads/master
Commit: 942693e67d1916264c98e0e803040e7f1f4311e3
Parents: 052c744
Author: Josh Elser <[email protected]>
Authored: Mon Jan 11 23:08:48 2016 -0500
Committer: Josh Elser <[email protected]>
Committed: Tue Jan 12 14:23:55 2016 -0500

----------------------------------------------------------------------
 .../java/org/apache/calcite/avatica/Meta.java   |  98 ++-
 .../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, 993 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/942693e6/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..3e75cec 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
@@ -967,17 +970,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 +988,81 @@ public interface Meta {
       return new Frame(proto.getOffset(), proto.getDone(), parsedRows);
     }
 
+    /**
+     * Determine if this message contains the new attributes in the message. 
We can't directly test
+     * for the negative because our 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));
+      }
+    }
+
+    /**
+     * Parse 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());
+      }
+    }
+
+    /**
+     * Verify 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/942693e6/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/942693e6/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/942693e6/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/942693e6/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/942693e6/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/942693e6/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
 

Reply via email to