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 bdb7d5f53f..d9a705f644 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 @@ -908,15 +908,15 @@ private DateFromNumberAccessor(Getter getter, Calendar localCalendar) { } @Override public Date getDate(Calendar calendar) throws SQLException { - final Number v = getNumber(); + final Number v = getDate(); if (v == null) { return null; } - return longToDate(v.longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar); + return longToDate(((Number) v).longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar); } @Override public Timestamp getTimestamp(Calendar calendar) throws SQLException { - final Number v = getNumber(); + final Number v = getDate(); if (v == null) { return null; } @@ -925,12 +925,23 @@ private DateFromNumberAccessor(Getter getter, Calendar localCalendar) { } @Override public String getString() throws SQLException { - final Number v = getNumber(); + final Number v = getDate(); if (v == null) { return null; } return dateAsString(v.intValue(), null); } + + protected Number getDate() throws SQLException { + final Object value = super.getObject(); + if (value == null) { + return null; + } + if (value instanceof Date) { + return ((Date) value).toLocalDate().toEpochDay(); + } + return (Number) value; + } } /** @@ -973,6 +984,17 @@ private TimeFromNumberAccessor(Getter getter, Calendar localCalendar) { } return timeAsString(v.intValue(), null); } + + protected Number getNumber() throws SQLException { + final Object v = super.getObject(); + if (v == null) { + return null; + } + if (v instanceof Time) { + return ((Time) v).getTime(); + } + return (Number) v; + } } /** @@ -1001,7 +1023,7 @@ private TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) { } @Override public Date getDate(Calendar calendar) throws SQLException { - final Timestamp timestamp = getTimestamp(calendar); + final Timestamp timestamp = getTimestamp(calendar); if (timestamp == null) { return null; } @@ -1009,7 +1031,7 @@ private TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) { } @Override public Time getTime(Calendar calendar) throws SQLException { - final Timestamp timestamp = getTimestamp(calendar); + final Timestamp timestamp = getTimestamp(calendar); if (timestamp == null) { return null; } @@ -1025,6 +1047,17 @@ private TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) { } return timestampAsString(v.longValue(), null); } + + protected Number getNumber() throws SQLException { + final Object v = super.getObject(); + if (v == null) { + return null; + } + if (v instanceof Timestamp) { + return ((Timestamp) v).getTime(); + } + return (Number) v; + } } /** diff --git a/core/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java b/core/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java index 3cdc70a2f3..e868d36dc9 100644 --- a/core/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java +++ b/core/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java @@ -227,11 +227,21 @@ Object getArrayData(Object o, AbstractCursor.ArrayAccessor componentAccessor) * Elements are compared using {@link Object#equals(Object)}, and null * values are equal to each other. */ public static boolean equalContents(Array left, Array right) throws SQLException { + if (left.getBaseType() != right.getBaseType()) { + return false; + } ResultSet leftResultSet = left.getResultSet(); ResultSet rightResultSet = right.getResultSet(); + int leftColumnCount = leftResultSet.getMetaData().getColumnCount(); + int rightColumnCount = rightResultSet.getMetaData().getColumnCount(); + if (leftColumnCount != rightColumnCount) { + return false; + } while (leftResultSet.next() && rightResultSet.next()) { - if (!Objects.equals(leftResultSet.getObject(1), rightResultSet.getObject(1))) { - return false; + for (int i = 1; i <= leftColumnCount; i++) { + if (!Objects.equals(leftResultSet.getObject(i), rightResultSet.getObject(i))) { + return false; + } } } return !leftResultSet.next() && !rightResultSet.next(); diff --git a/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java b/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java index d07b5f396d..bdaaa6d72d 100644 --- a/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java +++ b/core/src/test/java/org/apache/calcite/avatica/AvaticaResultSetConversionsTest.java @@ -57,6 +57,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.TimeZone; import static org.hamcrest.CoreMatchers.isA; import static org.junit.Assert.assertEquals; @@ -172,6 +173,27 @@ public TestMetaImpl(AvaticaConnection connection) { ColumnMetaData.scalar(Types.BOOLEAN, "BOOLEAN", ColumnMetaData.Rep.PRIMITIVE_BOOLEAN), DatabaseMetaData.columnNoNulls))), + DatabaseMetaData.columnNoNulls), + columnMetaData("date_array", 13, + ColumnMetaData.array( + ColumnMetaData.scalar(Types.DATE, "DATE", + ColumnMetaData.Rep.PRIMITIVE_INT), + "ARRAY", + ColumnMetaData.Rep.ARRAY), + DatabaseMetaData.columnNoNulls), + columnMetaData("timestamp_array", 14, + ColumnMetaData.array( + ColumnMetaData.scalar(Types.TIMESTAMP, "TIMESTAMP", + ColumnMetaData.Rep.PRIMITIVE_LONG), + "ARRAY", + ColumnMetaData.Rep.ARRAY), + DatabaseMetaData.columnNoNulls), + columnMetaData("time_array", 15, + ColumnMetaData.array( + ColumnMetaData.scalar(Types.TIME, "TIME", + ColumnMetaData.Rep.NUMBER), + "ARRAY", + ColumnMetaData.Rep.ARRAY), DatabaseMetaData.columnNoNulls)); List row = Collections.singletonList( @@ -180,7 +202,10 @@ public TestMetaImpl(AvaticaConnection connection) { new Date(1476130718123L), new Time(1476130718123L), new Timestamp(1476130718123L), Arrays.asList(1, 2, 3), - new StructImpl(Arrays.asList(42, false)) + new StructImpl(Arrays.asList(42, false)), + Arrays.asList(123, 18234), + Arrays.asList(1476130718123L, 1479123123242L), + Arrays.asList(1476123L, 147912242L) }); CursorFactory factory = CursorFactory.deduce(columns, null); @@ -560,6 +585,60 @@ private ArrayAccessorTestHelper(Getter g) { } } + /** + * Accessor test helper for date array column. + */ + private static final class DateArrayAccessorTestHelper extends AccessorTestHelper { + private DateArrayAccessorTestHelper(Getter g) { + super(g); + } + + @Override public void testGetArray(ResultSet resultSet) throws SQLException { + ColumnMetaData.ScalarType intType = + ColumnMetaData.scalar(Types.DATE, "DATE", ColumnMetaData.Rep.PRIMITIVE_INT); + Array expectedArray = + new ArrayFactoryImpl(TimeZone.getTimeZone("UTC")).createArray( + intType, Arrays.asList(123, 18234)); + assertTrue(ArrayImpl.equalContents(expectedArray, g.getArray(resultSet))); + } + } + + /** + * Accessor test helper for time array column. + */ + private static final class TimeArrayAccessorTestHelper extends AccessorTestHelper { + private TimeArrayAccessorTestHelper(Getter g) { + super(g); + } + + @Override public void testGetArray(ResultSet resultSet) throws SQLException { + ColumnMetaData.ScalarType intType = + ColumnMetaData.scalar(Types.TIME, "TIME", ColumnMetaData.Rep.NUMBER); + Array expectedArray = + new ArrayFactoryImpl(TimeZone.getTimeZone("UTC")).createArray( + intType, Arrays.asList(1476123L, 147912242L)); + assertTrue(ArrayImpl.equalContents(expectedArray, g.getArray(resultSet))); + } + } + + /** + * Accessor test helper for timestamp array column. + */ + private static final class TimestampArrayAccessorTestHelper extends AccessorTestHelper { + private TimestampArrayAccessorTestHelper(Getter g) { + super(g); + } + + @Override public void testGetArray(ResultSet resultSet) throws SQLException { + ColumnMetaData.ScalarType intType = + ColumnMetaData.scalar(Types.TIMESTAMP, "TIMESTAMP", ColumnMetaData.Rep.PRIMITIVE_LONG); + Array expectedArray = + new ArrayFactoryImpl(TimeZone.getTimeZone("UTC")).createArray( + intType, Arrays.asList(1476130718123L, 1479123123242L)); + assertTrue(ArrayImpl.equalContents(expectedArray, g.getArray(resultSet))); + } + } + /** * Accessor test helper for row column. */ @@ -1033,7 +1112,13 @@ public static Collection data() { new ArrayAccessorTestHelper(new OrdinalGetter(12)), new ArrayAccessorTestHelper(new LabelGetter("array")), new StructAccessorTestHelper(new OrdinalGetter(13)), - new StructAccessorTestHelper(new LabelGetter("struct"))); + new StructAccessorTestHelper(new LabelGetter("struct")), + new DateArrayAccessorTestHelper(new OrdinalGetter(14)), + new DateArrayAccessorTestHelper(new LabelGetter("date_array")), + new TimestampArrayAccessorTestHelper(new OrdinalGetter(15)), + new TimestampArrayAccessorTestHelper(new LabelGetter("timestamp_array")), + new TimeArrayAccessorTestHelper(new OrdinalGetter(16)), + new TimeArrayAccessorTestHelper(new LabelGetter("time_array"))); } private final AccessorTestHelper testHelper;