[calcite-avatica] branch master updated: [CALCITE-4181] Avatica throws exception when select field is a List (Kent Nguyen)

Mon, 11 Jan 2021 00:03:14 -0800

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

rubenql 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 ed44494  [CALCITE-4181] Avatica throws exception when select field is 
a List<Object> (Kent Nguyen)
ed44494 is described below

commit ed444948659a55309860952e1bbb41ee77ff4699
Author: Kent Nguyen <kngu...@fontis.vn>
AuthorDate: Thu Aug 20 13:29:15 2020 +0700

    [CALCITE-4181] Avatica throws exception when select field is a List<Object> 
(Kent Nguyen)
---
 .../calcite/avatica/util/AbstractCursor.java       |   1 +
 .../apache/calcite/avatica/util/ArrayImplTest.java | 214 +++++++++++++++++++++
 2 files changed, 215 insertions(+)

diff --git 
a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java 
b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
index 5559f60..ce81049 100644
--- a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
+++ b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -1341,6 +1341,7 @@ public abstract class AbstractCursor implements Cursor {
       case Types.TIMESTAMP:
       case Types.STRUCT:
       case Types.JAVA_OBJECT:
+      case Types.OTHER:
         return componentAccessor.getObject();
       default:
         throw new IllegalStateException("Unhandled ARRAY component type: " + 
componentType.rep
diff --git 
a/core/src/test/java/org/apache/calcite/avatica/util/ArrayImplTest.java 
b/core/src/test/java/org/apache/calcite/avatica/util/ArrayImplTest.java
index 2ebd13b..9133270 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/ArrayImplTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/ArrayImplTest.java
@@ -33,6 +33,7 @@ import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -164,6 +165,219 @@ public class ArrayImplTest {
     }
   }
 
+  /**
+   * The same test as arrayOfStructs(), except we use List instead of 
ArrayImpl.
+   */
+  @Test public void listOfStructs() throws Exception {
+    ColumnMetaData intMetaData = MetaImpl.columnMetaData("MY_INT", 1, 
int.class, false);
+    ColumnMetaData stringMetaData = MetaImpl.columnMetaData("MY_STRING", 2, 
String.class, true);
+    StructType structType = ColumnMetaData.struct(Arrays.asList(intMetaData, 
stringMetaData));
+    Struct struct1 = new StructImpl(Arrays.asList(1, "one"));
+    Struct struct2 = new StructImpl(Arrays.asList(2, "two"));
+    Struct struct3 = new StructImpl(Arrays.asList(3));
+    Struct struct4 = new StructImpl(Arrays.asList(4, "four"));
+    ArrayType arrayType = ColumnMetaData.array(structType, "OBJECT", 
Rep.STRUCT);
+    ColumnMetaData arrayMetaData = MetaImpl.columnMetaData("MY_ARRAY", 1, 
arrayType, false);
+    ArrayImpl.Factory factory = new 
ArrayFactoryImpl(Unsafe.localCalendar().getTimeZone());
+
+    List<Object> list1 = Arrays.asList(struct1, struct2);
+    List<Object> list2 = Arrays.asList(struct3, struct4);
+    List<List<Object>> rows = Arrays.asList(Arrays.asList(list1), 
Arrays.asList(list2));
+
+    try (Cursor cursor = new ListIteratorCursor(rows.iterator())) {
+      List<Accessor> accessors = 
cursor.createAccessors(Arrays.asList(arrayMetaData),
+          Unsafe.localCalendar(), factory);
+      assertEquals(1, accessors.size());
+      Accessor accessor = accessors.get(0);
+
+      assertTrue(cursor.next());
+      Array actualArray = accessor.getArray();
+
+      Object[] arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      Struct actualStruct = (Struct) arrayData[0];
+      Object[] o = actualStruct.getAttributes();
+      assertEquals(2, o.length);
+      assertEquals(1, o[0]);
+      assertEquals("one", o[1]);
+
+      actualStruct = (Struct) arrayData[1];
+      o = actualStruct.getAttributes();
+      assertEquals(2, o.length);
+      assertEquals(2, o[0]);
+      assertEquals("two", o[1]);
+
+      assertTrue(cursor.next());
+      actualArray = accessor.getArray();
+      arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      actualStruct = (Struct) arrayData[0];
+      o = actualStruct.getAttributes();
+      assertEquals(1, o.length);
+      assertEquals(3, o[0]);
+
+      actualStruct = (Struct) arrayData[1];
+      o = actualStruct.getAttributes();
+      assertEquals(2, o.length);
+      assertEquals(4, o[0]);
+      assertEquals("four", o[1]);
+    }
+  }
+
+  /**
+   * Plain Java object class for the two tests that follow.
+   */
+  static class PlainJavaObject {
+    public int intProperty;
+    public String stringProperty;
+
+    PlainJavaObject(int intProp, String stringProp) {
+      intProperty = intProp;
+      stringProperty = stringProp;
+    }
+
+    @Override public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+
+      if (o == null) {
+        return false;
+      }
+
+      if (getClass() != o.getClass()) {
+        return false;
+      }
+
+      PlainJavaObject pjo = (PlainJavaObject) o;
+
+      return Objects.equals(stringProperty, pjo.stringProperty)
+          && Objects.equals(intProperty, pjo.intProperty);
+    }
+
+    @Override public int hashCode() {
+      return Objects.hash(stringProperty, intProperty);
+    }
+  }
+
+  /**
+   * Test case for when a column is an array of plain Java objects.
+   * This is a common use case when data come from a dynamic schema source.
+   */
+  @Test public void arraysOfJavaObjects() throws Exception {
+    final ColumnMetaData.Rep rep = 
ColumnMetaData.Rep.of(PlainJavaObject.class);
+    ColumnMetaData.AvaticaType objectAvaticaType = ColumnMetaData.scalar(
+        Types.OTHER,
+        "OTHER",
+        rep
+    );
+
+    String arrayTypeName = "JavaType(" + PlainJavaObject.class.toString() + ") 
ARRAY";
+    ArrayType arrayType = ColumnMetaData.array(objectAvaticaType, 
arrayTypeName, rep);
+
+    ColumnMetaData javaObjectArrayMetaData = MetaImpl.columnMetaData(
+        "PLAIN_JAVA_OBJECT_ARRAY",
+        1,
+        arrayType,
+        true
+    );
+
+    PlainJavaObject pjo1 = new PlainJavaObject(1, "one");
+    PlainJavaObject pjo2 = new PlainJavaObject(2, "two");
+    PlainJavaObject pjo3 = new PlainJavaObject(3, "three");
+    PlainJavaObject pjo4 = new PlainJavaObject(4, "four");
+
+    ArrayImpl.Factory factory = new 
ArrayFactoryImpl(Unsafe.localCalendar().getTimeZone());
+
+    Array array1 = factory.createArray(objectAvaticaType, Arrays.asList(pjo1, 
pjo2));
+    Array array2 = factory.createArray(objectAvaticaType, Arrays.asList(pjo3, 
pjo4));
+    List<List<Object>> rows = Arrays.asList(Arrays.asList(array1), 
Arrays.asList(array2));
+
+    try (Cursor cursor = new ListIteratorCursor(rows.iterator())) {
+      List<Accessor> accessors = cursor.createAccessors(
+          Arrays.asList(javaObjectArrayMetaData),
+          Unsafe.localCalendar(),
+          factory
+      );
+      assertEquals(1, accessors.size());
+      Accessor accessor = accessors.get(0);
+
+      assertTrue(cursor.next());
+      Array actualArray = accessor.getArray();
+
+      Object[] arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      assertEquals(pjo1, arrayData[0]);
+      assertEquals(pjo2, arrayData[1]);
+
+      assertTrue(cursor.next());
+      actualArray = accessor.getArray();
+      arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      assertEquals(pjo3, arrayData[0]);
+      assertEquals(pjo4, arrayData[1]);
+    }
+  }
+
+  /**
+   * Test case for when a column is a list of plain Java objects.
+   */
+  @Test public void listOfJavaObjects() throws Exception {
+    final ColumnMetaData.Rep rep = 
ColumnMetaData.Rep.of(PlainJavaObject.class);
+    final ColumnMetaData.Rep rep2 = 
ColumnMetaData.Rep.of(PlainJavaObject.class);
+    ColumnMetaData.AvaticaType objectAvaticaType = ColumnMetaData.scalar(
+        Types.OTHER,
+        "OTHER",
+        rep
+    );
+
+    String arrayTypeName = "JavaType(" + PlainJavaObject.class.toString() + ") 
ARRAY";
+    ArrayType arrayType = ColumnMetaData.array(objectAvaticaType, 
arrayTypeName, rep2);
+
+    ColumnMetaData javaObjectArrayMetaData = MetaImpl.columnMetaData(
+        "PLAIN_JAVA_OBJECT_ARRAY",
+        1,
+        arrayType,
+        true
+    );
+
+    PlainJavaObject pjo1 = new PlainJavaObject(1, "one");
+    PlainJavaObject pjo2 = new PlainJavaObject(2, "two");
+    PlainJavaObject pjo3 = new PlainJavaObject(3, "three");
+    PlainJavaObject pjo4 = new PlainJavaObject(4, "four");
+
+    ArrayImpl.Factory factory = new 
ArrayFactoryImpl(Unsafe.localCalendar().getTimeZone());
+
+    List<Object> list1 = Arrays.asList(pjo1, pjo2);
+    List<Object> list2 = Arrays.asList(pjo3, pjo4);
+    List<List<Object>> rows = Arrays.asList(Arrays.asList(list1), 
Arrays.asList(list2));
+
+    try (Cursor cursor = new ListIteratorCursor(rows.iterator())) {
+      List<Accessor> accessors = cursor.createAccessors(
+          Arrays.asList(javaObjectArrayMetaData),
+          Unsafe.localCalendar(),
+          factory
+      );
+      assertEquals(1, accessors.size());
+      Accessor accessor = accessors.get(0);
+
+      assertTrue(cursor.next());
+      Array actualArray = accessor.getArray();
+
+      Object[] arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      assertEquals(pjo1, arrayData[0]);
+      assertEquals(pjo2, arrayData[1]);
+
+      assertTrue(cursor.next());
+      actualArray = accessor.getArray();
+      arrayData = (Object[]) actualArray.getArray();
+      assertEquals(2, arrayData.length);
+      assertEquals(pjo3, arrayData[0]);
+      assertEquals(pjo4, arrayData[1]);
+    }
+  }
+
   @Test public void testArrayWithOffsets() throws Exception {
     // Define the struct type we're creating
     ScalarType intType = ColumnMetaData.scalar(Types.INTEGER, "INTEGER", 
Rep.INTEGER);

Reply via email to