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 <[email protected]>
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);