You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2020/11/13 21:41:38 UTC

[calcite-avatica] branch master updated: [CALCITE-4379] Meta.Frame created with java float values in rows hits a ClassCastException in toProto()

This is an automated email from the ASF dual-hosted git repository.

elserj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite-avatica.git


The following commit(s) were added to refs/heads/master by this push:
     new 9dfc5ca  [CALCITE-4379] Meta.Frame created with java float values in rows hits a ClassCastException in toProto()
9dfc5ca is described below

commit 9dfc5cad3efe72e9b14513b15a988ba86ab5a4ea
Author: Dmitri Bourlatchkov <dm...@datastax.com>
AuthorDate: Thu Nov 5 12:38:46 2020 -0500

    [CALCITE-4379] Meta.Frame created with java float values in rows hits a ClassCastException in toProto()
    
    * Remove unnecessary conversion of Float values to long in
      TypedValue.toProto(...). The subsequently invoked writeToProtoWithType(...)
      method actually expects float values in this case.
    
    * Make a similar fix for Character values.
    
    * Add Frame serialization round-trip unit tests to cover this failure mode.
    
    * Note: a similar problem appears to still exist for Timestamp and Date/Time
      values in this context, but I did not attempt to fix it in this commit because
      there is apparently no use case for putting Timestamp/Date/Time objects into
      Frames. Those values are normally returned as plain numbers in result rows.
    
    Closes #130
    
    Signed-off-by: Josh Elser <el...@apache.org>
---
 .../apache/calcite/avatica/remote/TypedValue.java  |  4 +-
 .../java/org/apache/calcite/avatica/FrameTest.java | 79 ++++++++++++++++++++++
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java b/core/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java
index 9b98d2a..29b7487 100644
--- a/core/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java
+++ b/core/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java
@@ -802,7 +802,7 @@ public class TypedValue {
       writeToProtoWithType(builder, o, Common.Rep.DOUBLE);
       return Common.Rep.DOUBLE;
     } else if (o instanceof Float) {
-      writeToProtoWithType(builder, ((Float) o).longValue(), Common.Rep.FLOAT);
+      writeToProtoWithType(builder, o, Common.Rep.FLOAT);
       return Common.Rep.FLOAT;
     } else if (o instanceof BigDecimal) {
       writeToProtoWithType(builder, o, Common.Rep.BIG_DECIMAL);
@@ -812,7 +812,7 @@ public class TypedValue {
       writeToProtoWithType(builder, o, Common.Rep.STRING);
       return Common.Rep.STRING;
     } else if (o instanceof Character) {
-      writeToProtoWithType(builder, o.toString(), Common.Rep.CHARACTER);
+      writeToProtoWithType(builder, o, Common.Rep.CHARACTER);
       return Common.Rep.CHARACTER;
     // Bytes
     } else if (o instanceof byte[]) {
diff --git a/core/src/test/java/org/apache/calcite/avatica/FrameTest.java b/core/src/test/java/org/apache/calcite/avatica/FrameTest.java
index 4f34a3c..88345ef 100644
--- a/core/src/test/java/org/apache/calcite/avatica/FrameTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/FrameTest.java
@@ -23,6 +23,7 @@ import org.apache.calcite.avatica.proto.Common.TypedValue;
 
 import org.junit.Test;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -105,6 +106,84 @@ public class FrameTest {
     serializeAndTestEquality(singleRow);
   }
 
+  protected void testValueRoundTrip(Object value) {
+    List<Object> rows = Collections.singletonList(new Object[]{value});
+    serializeAndTestEquality(new Frame(0, true, rows));
+  }
+
+  @Test
+  public void testInteger() {
+    testValueRoundTrip(Integer.MIN_VALUE);
+    testValueRoundTrip(Integer.MAX_VALUE);
+  }
+
+  @Test
+  public void testLong() {
+    testValueRoundTrip(1L);
+    testValueRoundTrip(0L);
+    testValueRoundTrip(Long.MIN_VALUE);
+    testValueRoundTrip(Long.MAX_VALUE);
+  }
+
+  @Test
+  public void testFloat() {
+    testValueRoundTrip(Float.MIN_VALUE);
+    testValueRoundTrip(Float.MAX_VALUE);
+    testValueRoundTrip(Float.MIN_NORMAL);
+  }
+
+  @Test
+  public void testDouble() {
+    testValueRoundTrip(Double.MIN_VALUE);
+    testValueRoundTrip(Double.MAX_VALUE);
+    testValueRoundTrip(Double.MIN_NORMAL);
+  }
+
+  @Test
+  public void testString() {
+    testValueRoundTrip("example-value");
+    testValueRoundTrip("");
+  }
+
+  @Test
+  public void testChar() {
+    testValueRoundTrip('a');
+    testValueRoundTrip('\0');
+  }
+
+  @Test
+  public void testByte() {
+    testValueRoundTrip(Byte.MAX_VALUE);
+    testValueRoundTrip(Byte.MIN_VALUE);
+  }
+
+  @Test
+  public void testByteArray() {
+    testValueRoundTrip(new byte[] {1, 0});
+  }
+
+  @Test
+  public void testBoolean() {
+    testValueRoundTrip(true);
+    testValueRoundTrip(false);
+  }
+
+  @Test
+  public void testShort() {
+    testValueRoundTrip(Short.MAX_VALUE);
+    testValueRoundTrip(Short.MIN_VALUE);
+  }
+
+  @Test
+  public void testBigDecimal() {
+    testValueRoundTrip(BigDecimal.valueOf(0));
+    testValueRoundTrip(BigDecimal.valueOf(1));
+    testValueRoundTrip(BigDecimal // make a non-integer value larger than Long.MAX_VALUE
+        .valueOf(Long.MAX_VALUE)
+        .multiply(BigDecimal.TEN)
+        .add(BigDecimal.valueOf(0.12345d)));
+  }
+
   @Test public void testMalformedColumnValue() {
     // Invalid ColumnValue: has an array and scalar
     final ColumnValue bothAttributesColumnValue = ColumnValue.newBuilder().setHasArrayValue(true)