From c1b6e616b979399db1782690b321b20815e89368 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Sun, 7 Sep 2025 10:23:17 +1000 Subject: [PATCH 1/9] Fix support for ResultSet.getObject for TIMESTAMP_WITH_TIMEZONE Turns out AvaticaSite.get does not account for TIMESTAMP_WITH_TIMEZONE types so we add support on an override function. --- ...owFlightJdbcVectorSchemaRootResultSet.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java index 0dc2b07c9..5b527109b 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java @@ -19,6 +19,7 @@ import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Types; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -28,14 +29,17 @@ import org.apache.arrow.util.AutoCloseables; import org.apache.arrow.vector.VectorSchemaRoot; import org.apache.arrow.vector.types.pojo.Schema; +import org.apache.calcite.avatica.AvaticaConnection; import org.apache.calcite.avatica.AvaticaResultSet; import org.apache.calcite.avatica.AvaticaResultSetMetaData; +import org.apache.calcite.avatica.AvaticaSite; import org.apache.calcite.avatica.AvaticaStatement; import org.apache.calcite.avatica.ColumnMetaData; import org.apache.calcite.avatica.Meta; import org.apache.calcite.avatica.Meta.Frame; import org.apache.calcite.avatica.Meta.Signature; import org.apache.calcite.avatica.QueryState; +import org.apache.calcite.avatica.util.Cursor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,6 +106,33 @@ void populateData(final VectorSchemaRoot vectorSchemaRoot, final Schema schema) execute2(new ArrowFlightJdbcCursor(vectorSchemaRoot), this.signature.columns); } + /** + * The default method in AvaticaResultSet does not properly handle TIMESTASMP_WITH_TIMEZONE, so we + * override here to add support. + * + * @param columnIndex the first column is 1, the second is 2, ... + * @return + * @throws SQLException + */ + @Override + public Object getObject(int columnIndex) throws SQLException { + this.checkOpen(); + + Cursor.Accessor accessor; + try { + accessor = accessorList.get(columnIndex - 1); + } catch (IndexOutOfBoundsException var3) { + throw AvaticaConnection.HELPER.createException("invalid column ordinal: " + columnIndex); + } + + ColumnMetaData metaData = columnMetaDataList.get(columnIndex - 1); + if (metaData.type.id == Types.TIMESTAMP_WITH_TIMEZONE) { + return accessor.getTimestamp(localCalendar); + } else { + return AvaticaSite.get(accessor, metaData.type.id, localCalendar); + } + } + @Override protected void cancel() { signature.columns.clear(); From 258ba4c982f44b6858f647f5838a4b721fbdc657 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Sun, 7 Sep 2025 15:48:48 -0600 Subject: [PATCH 2/9] Add test --- .../jdbc/FlightServerTestExtension.java | 6 + .../driver/jdbc/TimestampResultSetTest.java | 175 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java index db0438059..f71114e1b 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java @@ -130,6 +130,12 @@ public Connection getConnection(boolean useEncryption) throws SQLException { return this.createDataSource().getConnection(); } + public Connection getConnection(String timezone) throws SQLException { + setUseEncryption(false); + properties.put("timezone", timezone); + return this.createDataSource().getConnection(); + } + private void setUseEncryption(boolean useEncryption) { properties.put("useEncryption", useEncryption); } diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java new file mode 100644 index 000000000..ace114f3e --- /dev/null +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.arrow.driver.jdbc; + +import com.google.common.collect.ImmutableList; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Collections; +import java.util.TimeZone; +import org.apache.arrow.driver.jdbc.utils.MockFlightSqlProducer; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.vector.TimeStampMilliTZVector; +import org.apache.arrow.vector.TimeStampMilliVector; +import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.types.TimeUnit; +import org.apache.arrow.vector.types.pojo.ArrowType; +import org.apache.arrow.vector.types.pojo.Field; +import org.apache.arrow.vector.types.pojo.Schema; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** + * Timestamps have a lot of nuances in JDBC. This class is here to test that timestamp behavior is + * correct for different types of Timestamp vectors as well as different methods of retrieving the + * timestamps in JDBC. + */ +public class TimestampResultSetTest { + private static final MockFlightSqlProducer FLIGHT_SQL_PRODUCER = new MockFlightSqlProducer(); + + @RegisterExtension public static FlightServerTestExtension FLIGHT_SERVER_TEST_EXTENSION; + + static { + FLIGHT_SERVER_TEST_EXTENSION = + FlightServerTestExtension.createStandardTestExtension(FLIGHT_SQL_PRODUCER); + } + + private static final String QUERY_STRING = "SELECT * FROM TIMESTAMPS"; + private static final Schema QUERY_SCHEMA = + new Schema( + ImmutableList.of( + Field.nullable("no_tz", new ArrowType.Timestamp(TimeUnit.MILLISECOND, null)), + Field.nullable("utc", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "UTC")), + Field.nullable("utc+1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT+1:00")), + Field.nullable("utc-1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT-1:00")))); + + @BeforeAll + public static void setup() throws SQLException { + Instant firstDay2025 = OffsetDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); + + FLIGHT_SQL_PRODUCER.addSelectQuery( + QUERY_STRING, + QUERY_SCHEMA, + Collections.singletonList( + listener -> { + try (final BufferAllocator allocator = new RootAllocator(Long.MAX_VALUE); + final VectorSchemaRoot root = VectorSchemaRoot.create(QUERY_SCHEMA, allocator)) { + listener.start(root); + root.getFieldVectors() + .forEach( + v -> { + if (v instanceof TimeStampMilliVector) { + ((TimeStampMilliVector) v).setSafe(0, firstDay2025.toEpochMilli()); + } else if (v instanceof TimeStampMilliTZVector) { + String vecTz = + ((ArrowType.Timestamp) v.getField().getType()).getTimezone(); + long millis = firstDay2025.toEpochMilli(); + ((TimeStampMilliTZVector) v).setSafe(0, millis); + } + }); + root.setRowCount(1); + listener.putNext(); + } catch (final Throwable throwable) { + listener.error(throwable); + } finally { + listener.completed(); + } + })); + } + + /** + * This test doesn't yet test anything other than ensuring all ResultSet methods to retrieve a + * timestamp succeed. + * + *

This is a good starting point to add more tests to ensure the values are correct when we + * change the "local calendar" either through changing the JVM default or through the connection + * property. + */ + @Test + public void test() { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + try (Connection connection = FLIGHT_SERVER_TEST_EXTENSION.getConnection("UTC")) { + try (PreparedStatement s = connection.prepareStatement(QUERY_STRING)) { + try (ResultSet rs = s.executeQuery()) { + int numCols = rs.getMetaData().getColumnCount(); + try { + rs.next(); + for (int i = 1; i <= numCols; i++) { + int type = rs.getMetaData().getColumnType(i); + String name = rs.getMetaData().getColumnName(i); + System.out.println(name); + System.out.print("- getDate:\t\t\t\t\t\t\t"); + System.out.print(rs.getDate(i)); + System.out.println(); + System.out.print("- getTimestamp:\t\t\t\t\t\t"); + System.out.print(rs.getTimestamp(i)); + System.out.println(); + System.out.print("- getString:\t\t\t\t\t\t"); + System.out.print(rs.getString(i)); + System.out.println(); + System.out.print("- getObject:\t\t\t\t\t\t"); + System.out.print(rs.getObject(i)); + System.out.println(); + System.out.print("- getObject(Timestamp.class):\t\t"); + System.out.print(rs.getObject(i, Timestamp.class)); + System.out.println(); + System.out.print("- getTimestamp(default Calendar):\t"); + System.out.print(rs.getTimestamp(i, Calendar.getInstance())); + System.out.println(); + System.out.print("- getTimestamp(UTC Calendar):\t\t"); + System.out.print( + rs.getTimestamp(i, Calendar.getInstance(TimeZone.getTimeZone("UTC")))); + System.out.println(); + System.out.print("- getObject(LocalDateTime.class):\t"); + System.out.print(rs.getObject(i, LocalDateTime.class)); + System.out.println(); + if (type == Types.TIMESTAMP_WITH_TIMEZONE) { + System.out.print("- getObject(Instant.class):\t\t\t"); + System.out.print(rs.getObject(i, Instant.class)); + System.out.println(); + System.out.print("- getObject(OffsetDateTime.class):\t"); + System.out.print(rs.getObject(i, OffsetDateTime.class)); + System.out.println(); + System.out.print("- getObject(ZonedDateTime.class):\t"); + System.out.print(rs.getObject(i, ZonedDateTime.class)); + System.out.println(); + } + System.out.println(); + } + System.out.println(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} From adfac1fd5fbb7795e1da17caae8464f62c664118 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Sun, 7 Sep 2025 16:30:52 -0600 Subject: [PATCH 3/9] Minor cleanup --- .../org/apache/arrow/driver/jdbc/TimestampResultSetTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java index ace114f3e..c3c7f1a08 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java @@ -87,10 +87,7 @@ public static void setup() throws SQLException { if (v instanceof TimeStampMilliVector) { ((TimeStampMilliVector) v).setSafe(0, firstDay2025.toEpochMilli()); } else if (v instanceof TimeStampMilliTZVector) { - String vecTz = - ((ArrowType.Timestamp) v.getField().getType()).getTimezone(); - long millis = firstDay2025.toEpochMilli(); - ((TimeStampMilliTZVector) v).setSafe(0, millis); + ((TimeStampMilliTZVector) v).setSafe(0, firstDay2025.toEpochMilli()); } }); root.setRowCount(1); From c44d298b7a40a97e7ad36641a89fc72a6527cc1f Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Sun, 7 Sep 2025 16:33:01 -0600 Subject: [PATCH 4/9] more cleanup --- .../arrow/driver/jdbc/TimestampResultSetTest.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java index c3c7f1a08..fb793d8c6 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java @@ -34,8 +34,7 @@ import org.apache.arrow.driver.jdbc.utils.MockFlightSqlProducer; import org.apache.arrow.memory.BufferAllocator; import org.apache.arrow.memory.RootAllocator; -import org.apache.arrow.vector.TimeStampMilliTZVector; -import org.apache.arrow.vector.TimeStampMilliVector; +import org.apache.arrow.vector.TimeStampVector; import org.apache.arrow.vector.VectorSchemaRoot; import org.apache.arrow.vector.types.TimeUnit; import org.apache.arrow.vector.types.pojo.ArrowType; @@ -82,14 +81,7 @@ public static void setup() throws SQLException { final VectorSchemaRoot root = VectorSchemaRoot.create(QUERY_SCHEMA, allocator)) { listener.start(root); root.getFieldVectors() - .forEach( - v -> { - if (v instanceof TimeStampMilliVector) { - ((TimeStampMilliVector) v).setSafe(0, firstDay2025.toEpochMilli()); - } else if (v instanceof TimeStampMilliTZVector) { - ((TimeStampMilliTZVector) v).setSafe(0, firstDay2025.toEpochMilli()); - } - }); + .forEach(v -> ((TimeStampVector) v).setSafe(0, firstDay2025.toEpochMilli())); root.setRowCount(1); listener.putNext(); } catch (final Throwable throwable) { From e847fd4a621ff5cc1c4f54d360ebff55b3d89404 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Thu, 11 Sep 2025 17:03:30 -0600 Subject: [PATCH 5/9] Update tzs to standard format --- .../org/apache/arrow/driver/jdbc/TimestampResultSetTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java index fb793d8c6..0921ae2d3 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java @@ -65,8 +65,8 @@ public class TimestampResultSetTest { ImmutableList.of( Field.nullable("no_tz", new ArrowType.Timestamp(TimeUnit.MILLISECOND, null)), Field.nullable("utc", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "UTC")), - Field.nullable("utc+1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT+1:00")), - Field.nullable("utc-1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT-1:00")))); + Field.nullable("utc+1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT+1")), + Field.nullable("utc-1", new ArrowType.Timestamp(TimeUnit.MILLISECOND, "GMT-1")))); @BeforeAll public static void setup() throws SQLException { From 0702685a63d9e7073881fc018f201b18dbfd9e29 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Sat, 27 Sep 2025 09:10:31 -0600 Subject: [PATCH 6/9] Change exception name --- .../driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java index 5b527109b..30a165cfe 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java @@ -121,7 +121,7 @@ public Object getObject(int columnIndex) throws SQLException { Cursor.Accessor accessor; try { accessor = accessorList.get(columnIndex - 1); - } catch (IndexOutOfBoundsException var3) { + } catch (IndexOutOfBoundsException e) { throw AvaticaConnection.HELPER.createException("invalid column ordinal: " + columnIndex); } From 81af50ac7f93c992378eebd4a43694b5f5c9721b Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Mon, 6 Oct 2025 11:48:36 -0600 Subject: [PATCH 7/9] Fix checkstyle --- .../driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java index 30a165cfe..622e5fe7f 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java @@ -111,8 +111,8 @@ void populateData(final VectorSchemaRoot vectorSchemaRoot, final Schema schema) * override here to add support. * * @param columnIndex the first column is 1, the second is 2, ... - * @return - * @throws SQLException + * @return Object + * @throws SQLException if there is an underlying exception */ @Override public Object getObject(int columnIndex) throws SQLException { From 96e3bdbb0520f11820e0f685decdfa1b4b0def19 Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Tue, 7 Oct 2025 16:14:52 -0600 Subject: [PATCH 8/9] Ensure local timezone is always respected --- .../driver/jdbc/ArrowFlightJdbcArray.java | 19 +++-- .../driver/jdbc/ArrowFlightJdbcCursor.java | 7 +- ...owFlightJdbcVectorSchemaRootResultSet.java | 5 +- .../ArrowFlightJdbcAccessorFactory.java | 20 +++-- ...rrowFlightJdbcTimeStampVectorAccessor.java | 13 ++-- ...ractArrowFlightJdbcListVectorAccessor.java | 9 ++- ...actArrowFlightJdbcUnionVectorAccessor.java | 6 +- ...rowFlightJdbcDenseUnionVectorAccessor.java | 11 ++- ...FlightJdbcFixedSizeListVectorAccessor.java | 6 +- ...rrowFlightJdbcLargeListVectorAccessor.java | 6 +- .../ArrowFlightJdbcListVectorAccessor.java | 6 +- .../ArrowFlightJdbcMapVectorAccessor.java | 6 +- .../ArrowFlightJdbcUnionVectorAccessor.java | 8 +- .../driver/jdbc/ArrowFlightJdbcArrayTest.java | 25 ++++--- .../ArrowFlightJdbcAccessorFactoryTest.java | 73 ++++++++++--------- ...FlightJdbcTimeStampVectorAccessorTest.java | 5 +- ...stractArrowFlightJdbcListAccessorTest.java | 13 +++- ...rrowFlightJdbcUnionVectorAccessorTest.java | 2 +- ...lightJdbcDenseUnionVectorAccessorTest.java | 4 +- .../ArrowFlightJdbcMapVectorAccessorTest.java | 11 ++- ...rrowFlightJdbcUnionVectorAccessorTest.java | 6 +- ...owFlightJdbcVarCharVectorAccessorTest.java | 2 +- 22 files changed, 163 insertions(+), 100 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArray.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArray.java index 9b9eba51e..b2c7014f1 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArray.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArray.java @@ -21,6 +21,7 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Arrays; +import java.util.Calendar; import java.util.Map; import org.apache.arrow.driver.jdbc.accessor.impl.complex.AbstractArrowFlightJdbcListVectorAccessor; import org.apache.arrow.driver.jdbc.utils.SqlTypes; @@ -42,6 +43,7 @@ public class ArrowFlightJdbcArray implements Array { private final FieldVector dataVector; private final long startOffset; private final long valuesCount; + private final Calendar localCalendar; /** * Instantiate an {@link Array} backed up by given {@link FieldVector}, limited by a start offset @@ -51,10 +53,12 @@ public class ArrowFlightJdbcArray implements Array { * @param startOffset offset from FieldVector pointing to this Array's first value. * @param valuesCount how many items this Array contains. */ - public ArrowFlightJdbcArray(FieldVector dataVector, long startOffset, long valuesCount) { + public ArrowFlightJdbcArray( + FieldVector dataVector, long startOffset, long valuesCount, Calendar localCalendar) { this.dataVector = dataVector; this.startOffset = startOffset; this.valuesCount = valuesCount; + this.localCalendar = localCalendar; } @Override @@ -125,7 +129,8 @@ public ResultSet getResultSet(Map> map) throws SQLException { throw new SQLFeatureNotSupportedException(); } - return getResultSetNoBoundariesCheck(this.dataVector, this.startOffset, this.valuesCount); + return getResultSetNoBoundariesCheck( + this.dataVector, this.startOffset, this.valuesCount, this.localCalendar); } @Override @@ -134,14 +139,15 @@ public ResultSet getResultSet(long index, int count) throws SQLException { } private static ResultSet getResultSetNoBoundariesCheck( - ValueVector dataVector, long start, long count) throws SQLException { + ValueVector dataVector, long start, long count, Calendar localCalendar) throws SQLException { TransferPair transferPair = dataVector.getTransferPair(dataVector.getAllocator()); transferPair.splitAndTransfer( LargeMemoryUtil.checkedCastToInt(start), LargeMemoryUtil.checkedCastToInt(count)); FieldVector vectorSlice = (FieldVector) transferPair.getTo(); VectorSchemaRoot vectorSchemaRoot = VectorSchemaRoot.of(vectorSlice); - return ArrowFlightJdbcVectorSchemaRootResultSet.fromVectorSchemaRoot(vectorSchemaRoot); + return ArrowFlightJdbcVectorSchemaRootResultSet.fromVectorSchemaRoot( + vectorSchemaRoot, localCalendar); } @Override @@ -153,7 +159,10 @@ public ResultSet getResultSet(long index, int count, Map> map) checkBoundaries(index, count); return getResultSetNoBoundariesCheck( - this.dataVector, LargeMemoryUtil.checkedCastToInt(this.startOffset + index), count); + this.dataVector, + LargeMemoryUtil.checkedCastToInt(this.startOffset + index), + count, + this.localCalendar); } @Override diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcCursor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcCursor.java index fbf0b308c..48a67c872 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcCursor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcCursor.java @@ -55,18 +55,19 @@ public List createAccessors( return IntStream.range(0, fieldVectors.size()) .mapToObj(root::getVector) - .map(this::createAccessor) + .map(v -> this.createAccessor(v, localCalendar)) .collect(Collectors.toCollection(() -> new ArrayList<>(fieldVectors.size()))); } - private Accessor createAccessor(FieldVector vector) { + private Accessor createAccessor(FieldVector vector, Calendar localCalendar) { return ArrowFlightJdbcAccessorFactory.createAccessor( vector, this::getCurrentRow, (boolean wasNull) -> { // AbstractCursor creates a boolean array of length 1 to hold the wasNull value this.wasNull[0] = wasNull; - }); + }, + localCalendar); } /** diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java index 622e5fe7f..668c38e62 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcVectorSchemaRootResultSet.java @@ -20,6 +20,7 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Types; +import java.util.Calendar; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -68,10 +69,10 @@ public class ArrowFlightJdbcVectorSchemaRootResultSet extends AvaticaResultSet { * @return a ResultSet which accesses the given VectorSchemaRoot */ public static ArrowFlightJdbcVectorSchemaRootResultSet fromVectorSchemaRoot( - final VectorSchemaRoot vectorSchemaRoot) throws SQLException { + final VectorSchemaRoot vectorSchemaRoot, Calendar localCalendar) throws SQLException { // Similar to how org.apache.calcite.avatica.util.ArrayFactoryImpl does - final TimeZone timeZone = TimeZone.getDefault(); + final TimeZone timeZone = localCalendar.getTimeZone(); final QueryState state = new QueryState(); final Meta.Signature signature = ArrowFlightMetaImpl.newSignature(null, null, null); diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactory.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactory.java index dad1fa5f7..d02f1ac56 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactory.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactory.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor; +import java.util.Calendar; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.impl.ArrowFlightJdbcNullVectorAccessor; import org.apache.arrow.driver.jdbc.accessor.impl.binary.ArrowFlightJdbcBinaryVectorAccessor; @@ -87,7 +88,10 @@ public class ArrowFlightJdbcAccessorFactory { * @return an instance of one of the accessors. */ public static ArrowFlightJdbcAccessor createAccessor( - ValueVector vector, IntSupplier getCurrentRow, WasNullConsumer setCursorWasNull) { + ValueVector vector, + IntSupplier getCurrentRow, + WasNullConsumer setCursorWasNull, + Calendar localCalendar) { if (vector instanceof UInt1Vector) { return new ArrowFlightJdbcBaseIntVectorAccessor( (UInt1Vector) vector, getCurrentRow, setCursorWasNull); @@ -138,7 +142,7 @@ public static ArrowFlightJdbcAccessor createAccessor( (FixedSizeBinaryVector) vector, getCurrentRow, setCursorWasNull); } else if (vector instanceof TimeStampVector) { return new ArrowFlightJdbcTimeStampVectorAccessor( - (TimeStampVector) vector, getCurrentRow, setCursorWasNull); + (TimeStampVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof TimeNanoVector) { return new ArrowFlightJdbcTimeVectorAccessor( (TimeNanoVector) vector, getCurrentRow, setCursorWasNull); @@ -180,22 +184,22 @@ public static ArrowFlightJdbcAccessor createAccessor( (StructVector) vector, getCurrentRow, setCursorWasNull); } else if (vector instanceof MapVector) { return new ArrowFlightJdbcMapVectorAccessor( - (MapVector) vector, getCurrentRow, setCursorWasNull); + (MapVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof ListVector) { return new ArrowFlightJdbcListVectorAccessor( - (ListVector) vector, getCurrentRow, setCursorWasNull); + (ListVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof LargeListVector) { return new ArrowFlightJdbcLargeListVectorAccessor( - (LargeListVector) vector, getCurrentRow, setCursorWasNull); + (LargeListVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof FixedSizeListVector) { return new ArrowFlightJdbcFixedSizeListVectorAccessor( - (FixedSizeListVector) vector, getCurrentRow, setCursorWasNull); + (FixedSizeListVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof UnionVector) { return new ArrowFlightJdbcUnionVectorAccessor( - (UnionVector) vector, getCurrentRow, setCursorWasNull); + (UnionVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof DenseUnionVector) { return new ArrowFlightJdbcDenseUnionVectorAccessor( - (DenseUnionVector) vector, getCurrentRow, setCursorWasNull); + (DenseUnionVector) vector, getCurrentRow, setCursorWasNull, localCalendar); } else if (vector instanceof NullVector || vector == null) { return new ArrowFlightJdbcNullVectorAccessor(setCursorWasNull); } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java index 813fbc7cf..d5518c934 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessor.java @@ -51,6 +51,7 @@ public class ArrowFlightJdbcTimeStampVectorAccessor extends ArrowFlightJdbcAcces private final LongToLocalDateTime longToLocalDateTime; private final Holder holder; private final boolean isZoned; + private final Calendar localCalendar; /** Functional interface used to convert a number (in any time resolution) to LocalDateTime. */ interface LongToLocalDateTime { @@ -61,9 +62,11 @@ interface LongToLocalDateTime { public ArrowFlightJdbcTimeStampVectorAccessor( TimeStampVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { super(currentRowSupplier, setCursorWasNull); this.holder = new Holder(); + this.localCalendar = localCalendar; this.getter = createGetter(vector); // whether the vector included TZ info @@ -89,7 +92,7 @@ public T getObject(final Class type) throws SQLException { } else if (type == OffsetDateTime.class) { value = getOffsetDateTime(); } else if (type == LocalDateTime.class) { - value = getLocalDateTime(null); + value = getLocalDateTime(localCalendar); } else if (type == ZonedDateTime.class) { value = getZonedDateTime(); } else if (type == Instant.class) { @@ -105,7 +108,7 @@ public T getObject(final Class type) throws SQLException { @Override public Object getObject() { - return this.getTimestamp(null); + return this.getTimestamp(localCalendar); } private ZonedDateTime getZonedDateTime() { @@ -154,7 +157,7 @@ private LocalDateTime getLocalDateTime(Calendar calendar) { long millis = this.timeUnit.toMillis(value); localDateTime = localDateTime.minus( - timeZone.getOffset(millis) - this.timeZone.getOffset(millis), ChronoUnit.MILLIS); + this.timeZone.getOffset(millis) - timeZone.getOffset(millis), ChronoUnit.MILLIS); } return localDateTime; } @@ -202,7 +205,7 @@ private Timestamp getTimestampWithOffset(Calendar calendar, LocalDateTime localD long millis = Timestamp.valueOf(localDateTime).getTime(); localDateTime = localDateTime.minus( - timeZone.getOffset(millis) - this.timeZone.getOffset(millis), ChronoUnit.MILLIS); + this.timeZone.getOffset(millis) - timeZone.getOffset(millis), ChronoUnit.MILLIS); } return Timestamp.valueOf(localDateTime); } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListVectorAccessor.java index cbd07b7d4..c35c6e2df 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListVectorAccessor.java @@ -17,6 +17,7 @@ package org.apache.arrow.driver.jdbc.accessor.impl.complex; import java.sql.Array; +import java.util.Calendar; import java.util.List; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.ArrowFlightJdbcArray; @@ -33,10 +34,14 @@ */ public abstract class AbstractArrowFlightJdbcListVectorAccessor extends ArrowFlightJdbcAccessor { + private final Calendar localCalendar; + protected AbstractArrowFlightJdbcListVectorAccessor( IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { super(currentRowSupplier, setCursorWasNull); + this.localCalendar = localCalendar; } @Override @@ -67,6 +72,6 @@ public final Array getArray() { long endOffset = getEndOffset(index); long valuesCount = endOffset - startOffset; - return new ArrowFlightJdbcArray(dataVector, startOffset, valuesCount); + return new ArrowFlightJdbcArray(dataVector, startOffset, valuesCount, localCalendar); } } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessor.java index 99364be2a..7bdc7455d 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessor.java @@ -50,13 +50,17 @@ public abstract class AbstractArrowFlightJdbcUnionVectorAccessor extends ArrowFl */ private final ArrowFlightJdbcAccessor[] accessors = new ArrowFlightJdbcAccessor[128]; + protected final Calendar localCalendar; + private final ArrowFlightJdbcNullVectorAccessor nullAccessor = new ArrowFlightJdbcNullVectorAccessor((boolean wasNull) -> {}); protected AbstractArrowFlightJdbcUnionVectorAccessor( IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { super(currentRowSupplier, setCursorWasNull); + this.localCalendar = localCalendar; } protected abstract ArrowFlightJdbcAccessor createAccessorForVector(ValueVector vector); diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessor.java index b847cc74f..0384ed867 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessor; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -38,15 +39,19 @@ public class ArrowFlightJdbcDenseUnionVectorAccessor public ArrowFlightJdbcDenseUnionVectorAccessor( DenseUnionVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } @Override protected ArrowFlightJdbcAccessor createAccessorForVector(ValueVector vector) { return ArrowFlightJdbcAccessorFactory.createAccessor( - vector, () -> this.vector.getOffset(this.getCurrentRow()), (boolean wasNull) -> {}); + vector, + () -> this.vector.getOffset(this.getCurrentRow()), + (boolean wasNull) -> {}, + localCalendar); } @Override diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcFixedSizeListVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcFixedSizeListVectorAccessor.java index 970418475..dcc9d5a42 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcFixedSizeListVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcFixedSizeListVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.List; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -31,8 +32,9 @@ public class ArrowFlightJdbcFixedSizeListVectorAccessor public ArrowFlightJdbcFixedSizeListVectorAccessor( FixedSizeListVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcLargeListVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcLargeListVectorAccessor.java index 33e1a8589..aed147355 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcLargeListVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcLargeListVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.List; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -31,8 +32,9 @@ public class ArrowFlightJdbcLargeListVectorAccessor public ArrowFlightJdbcLargeListVectorAccessor( LargeListVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcListVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcListVectorAccessor.java index 8827fdf6a..a45f9037f 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcListVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcListVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.List; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -31,8 +32,9 @@ public class ArrowFlightJdbcListVectorAccessor extends AbstractArrowFlightJdbcLi public ArrowFlightJdbcListVectorAccessor( ListVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessor.java index 32336f31e..b834164e6 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.Map; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -33,8 +34,9 @@ public class ArrowFlightJdbcMapVectorAccessor extends AbstractArrowFlightJdbcLis public ArrowFlightJdbcMapVectorAccessor( MapVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessor.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessor.java index 5b4d7dce3..b7890a7ee 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessor.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessor.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.accessor.impl.complex; +import java.util.Calendar; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessor; import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory; @@ -37,15 +38,16 @@ public class ArrowFlightJdbcUnionVectorAccessor extends AbstractArrowFlightJdbcU public ArrowFlightJdbcUnionVectorAccessor( UnionVector vector, IntSupplier currentRowSupplier, - ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull) { - super(currentRowSupplier, setCursorWasNull); + ArrowFlightJdbcAccessorFactory.WasNullConsumer setCursorWasNull, + Calendar localCalendar) { + super(currentRowSupplier, setCursorWasNull, localCalendar); this.vector = vector; } @Override protected ArrowFlightJdbcAccessor createAccessorForVector(ValueVector vector) { return ArrowFlightJdbcAccessorFactory.createAccessor( - vector, this::getCurrentRow, (boolean wasNull) -> {}); + vector, this::getCurrentRow, (boolean wasNull) -> {}, localCalendar); } @Override diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArrayTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArrayTest.java index 06d101724..b01f7b38c 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArrayTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightJdbcArrayTest.java @@ -25,6 +25,7 @@ import java.sql.SQLFeatureNotSupportedException; import java.sql.Types; import java.util.Arrays; +import java.util.Calendar; import java.util.HashMap; import org.apache.arrow.driver.jdbc.utils.RootAllocatorTestExtension; import org.apache.arrow.vector.IntVector; @@ -58,21 +59,21 @@ public void tearDown() { @Test public void testShouldGetBaseTypeNameReturnCorrectTypeName() { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); assertEquals("INTEGER", arrowFlightJdbcArray.getBaseTypeName()); } @Test public void testShouldGetBaseTypeReturnCorrectType() { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); assertEquals(Types.INTEGER, arrowFlightJdbcArray.getBaseType()); } @Test public void testShouldGetArrayReturnValidArray() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); Object[] array = (Object[]) arrowFlightJdbcArray.getArray(); Object[] expected = new Object[dataVector.getValueCount()]; @@ -85,7 +86,7 @@ public void testShouldGetArrayReturnValidArray() throws SQLException { @Test public void testShouldGetArrayReturnValidArrayWithOffsets() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); Object[] array = (Object[]) arrowFlightJdbcArray.getArray(1, 5); Object[] expected = new Object[5]; @@ -99,7 +100,7 @@ public void testShouldGetArrayReturnValidArrayWithOffsets() throws SQLException public void testShouldGetArrayWithOffsetsThrowArrayIndexOutOfBoundsException() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); assertThrows( ArrayIndexOutOfBoundsException.class, () -> arrowFlightJdbcArray.getArray(0, dataVector.getValueCount() + 1)); @@ -108,7 +109,7 @@ public void testShouldGetArrayWithOffsetsThrowArrayIndexOutOfBoundsException() @Test public void testShouldGetArrayWithMapNotBeSupported() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); HashMap> map = new HashMap<>(); assertThrows(SQLFeatureNotSupportedException.class, () -> arrowFlightJdbcArray.getArray(map)); } @@ -116,7 +117,7 @@ public void testShouldGetArrayWithMapNotBeSupported() throws SQLException { @Test public void testShouldGetArrayWithOffsetsAndMapNotBeSupported() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); HashMap> map = new HashMap<>(); assertThrows( SQLFeatureNotSupportedException.class, () -> arrowFlightJdbcArray.getArray(0, 5, map)); @@ -125,7 +126,7 @@ public void testShouldGetArrayWithOffsetsAndMapNotBeSupported() throws SQLExcept @Test public void testShouldGetResultSetReturnValidResultSet() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); try (ResultSet resultSet = arrowFlightJdbcArray.getResultSet()) { int count = 0; while (resultSet.next()) { @@ -138,7 +139,7 @@ public void testShouldGetResultSetReturnValidResultSet() throws SQLException { @Test public void testShouldGetResultSetReturnValidResultSetWithOffsets() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); try (ResultSet resultSet = arrowFlightJdbcArray.getResultSet(3, 5)) { int count = 0; while (resultSet.next()) { @@ -152,7 +153,7 @@ public void testShouldGetResultSetReturnValidResultSetWithOffsets() throws SQLEx @Test public void testToString() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); JsonStringArrayList array = new JsonStringArrayList<>(); array.addAll(Arrays.asList((Object[]) arrowFlightJdbcArray.getArray())); @@ -163,7 +164,7 @@ public void testToString() throws SQLException { @Test public void testShouldGetResultSetWithMapNotBeSupported() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); HashMap> map = new HashMap<>(); assertThrows( SQLFeatureNotSupportedException.class, () -> arrowFlightJdbcArray.getResultSet(map)); @@ -172,7 +173,7 @@ public void testShouldGetResultSetWithMapNotBeSupported() throws SQLException { @Test public void testShouldGetResultSetWithOffsetsAndMapNotBeSupported() throws SQLException { ArrowFlightJdbcArray arrowFlightJdbcArray = - new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount()); + new ArrowFlightJdbcArray(dataVector, 0, dataVector.getValueCount(), Calendar.getInstance()); HashMap> map = new HashMap<>(); assertThrows( SQLFeatureNotSupportedException.class, () -> arrowFlightJdbcArray.getResultSet(0, 5, map)); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactoryTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactoryTest.java index b56bf3c63..b0ca240f6 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactoryTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/ArrowFlightJdbcAccessorFactoryTest.java @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Calendar; import java.util.function.IntSupplier; import org.apache.arrow.driver.jdbc.accessor.impl.binary.ArrowFlightJdbcBinaryVectorAccessor; import org.apache.arrow.driver.jdbc.accessor.impl.calendar.ArrowFlightJdbcDateVectorAccessor; @@ -68,7 +69,7 @@ public void createAccessorForUInt1Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createUInt1Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -79,7 +80,7 @@ public void createAccessorForUInt2Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createUInt2Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -90,7 +91,7 @@ public void createAccessorForUInt4Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createUInt4Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -101,7 +102,7 @@ public void createAccessorForUInt8Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createUInt8Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -112,7 +113,7 @@ public void createAccessorForTinyIntVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTinyIntVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -123,7 +124,7 @@ public void createAccessorForSmallIntVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createSmallIntVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -134,7 +135,7 @@ public void createAccessorForIntVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createIntVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -145,7 +146,7 @@ public void createAccessorForBigIntVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createBigIntVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBaseIntVectorAccessor); } @@ -156,7 +157,7 @@ public void createAccessorForFloat4Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createFloat4Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcFloat4VectorAccessor); } @@ -167,7 +168,7 @@ public void createAccessorForFloat8Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createFloat8Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcFloat8VectorAccessor); } @@ -178,7 +179,7 @@ public void createAccessorForBitVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createBitVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBitVectorAccessor); } @@ -189,7 +190,7 @@ public void createAccessorForDecimalVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createDecimalVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDecimalVectorAccessor); } @@ -200,7 +201,7 @@ public void createAccessorForDecimal256Vector() { try (ValueVector valueVector = rootAllocatorTestExtension.createDecimal256Vector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDecimalVectorAccessor); } @@ -211,7 +212,7 @@ public void createAccessorForVarBinaryVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createVarBinaryVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBinaryVectorAccessor); } @@ -222,7 +223,7 @@ public void createAccessorForLargeVarBinaryVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createLargeVarBinaryVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBinaryVectorAccessor); } @@ -233,7 +234,7 @@ public void createAccessorForFixedSizeBinaryVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createFixedSizeBinaryVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcBinaryVectorAccessor); } @@ -244,7 +245,7 @@ public void createAccessorForTimeStampVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTimeStampMilliVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcTimeStampVectorAccessor); } @@ -255,7 +256,7 @@ public void createAccessorForTimeNanoVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTimeNanoVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcTimeVectorAccessor); } @@ -266,7 +267,7 @@ public void createAccessorForTimeMicroVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTimeMicroVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcTimeVectorAccessor); } @@ -277,7 +278,7 @@ public void createAccessorForTimeMilliVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTimeMilliVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcTimeVectorAccessor); } @@ -288,7 +289,7 @@ public void createAccessorForTimeSecVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createTimeSecVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcTimeVectorAccessor); } @@ -299,7 +300,7 @@ public void createAccessorForDateDayVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createDateDayVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDateVectorAccessor); } @@ -310,7 +311,7 @@ public void createAccessorForDateMilliVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createDateMilliVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDateVectorAccessor); } @@ -322,7 +323,7 @@ public void createAccessorForVarCharVector() { new VarCharVector("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcVarCharVectorAccessor); } @@ -334,7 +335,7 @@ public void createAccessorForLargeVarCharVector() { new LargeVarCharVector("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcVarCharVectorAccessor); } @@ -349,7 +350,7 @@ public void createAccessorForDurationVector() { rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDurationVectorAccessor); } @@ -361,7 +362,7 @@ public void createAccessorForIntervalDayVector() { new IntervalDayVector("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcIntervalVectorAccessor); } @@ -373,7 +374,7 @@ public void createAccessorForIntervalYearVector() { new IntervalYearVector("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcIntervalVectorAccessor); } @@ -385,7 +386,7 @@ public void createAccessorForIntervalMonthDayNanoVector() { new IntervalMonthDayNanoVector("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcIntervalVectorAccessor); } @@ -397,7 +398,7 @@ public void createAccessorForUnionVector() { new UnionVector("", rootAllocatorTestExtension.getRootAllocator(), null, null)) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcUnionVectorAccessor); } @@ -409,7 +410,7 @@ public void createAccessorForDenseUnionVector() { new DenseUnionVector("", rootAllocatorTestExtension.getRootAllocator(), null, null)) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcDenseUnionVectorAccessor); } @@ -421,7 +422,7 @@ public void createAccessorForStructVector() { StructVector.empty("", rootAllocatorTestExtension.getRootAllocator())) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcStructVectorAccessor); } @@ -432,7 +433,7 @@ public void createAccessorForListVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createListVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcListVectorAccessor); } @@ -443,7 +444,7 @@ public void createAccessorForLargeListVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createLargeListVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcLargeListVectorAccessor); } @@ -454,7 +455,7 @@ public void createAccessorForFixedSizeListVector() { try (ValueVector valueVector = rootAllocatorTestExtension.createFixedSizeListVector()) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcFixedSizeListVectorAccessor); } @@ -466,7 +467,7 @@ public void createAccessorForMapVector() { MapVector.empty("", rootAllocatorTestExtension.getRootAllocator(), true)) { ArrowFlightJdbcAccessor accessor = ArrowFlightJdbcAccessorFactory.createAccessor( - valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}); + valueVector, GET_CURRENT_ROW, (boolean wasNull) -> {}, Calendar.getInstance()); assertTrue(accessor instanceof ArrowFlightJdbcMapVectorAccessor); } diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessorTest.java index e4863bd80..262f1a734 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcTimeStampVectorAccessorTest.java @@ -71,7 +71,10 @@ public class ArrowFlightJdbcTimeStampVectorAccessorTest { accessorSupplier = (vector, getCurrentRow) -> new ArrowFlightJdbcTimeStampVectorAccessor( - (TimeStampVector) vector, getCurrentRow, (boolean wasNull) -> {}); + (TimeStampVector) vector, + getCurrentRow, + (boolean wasNull) -> {}, + Calendar.getInstance()); private final AccessorTestUtils.AccessorIterator accessorIterator = new AccessorTestUtils.AccessorIterator<>(accessorSupplier); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListAccessorTest.java index ad689837e..ec368d036 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcListAccessorTest.java @@ -22,6 +22,7 @@ import java.sql.Array; import java.sql.ResultSet; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import java.util.function.Supplier; import java.util.stream.Stream; @@ -54,13 +55,19 @@ public class AbstractArrowFlightJdbcListAccessorTest { (boolean wasNull) -> {}; if (vector instanceof ListVector) { return new ArrowFlightJdbcListVectorAccessor( - (ListVector) vector, getCurrentRow, noOpWasNullConsumer); + (ListVector) vector, getCurrentRow, noOpWasNullConsumer, Calendar.getInstance()); } else if (vector instanceof LargeListVector) { return new ArrowFlightJdbcLargeListVectorAccessor( - (LargeListVector) vector, getCurrentRow, noOpWasNullConsumer); + (LargeListVector) vector, + getCurrentRow, + noOpWasNullConsumer, + Calendar.getInstance()); } else if (vector instanceof FixedSizeListVector) { return new ArrowFlightJdbcFixedSizeListVectorAccessor( - (FixedSizeListVector) vector, getCurrentRow, noOpWasNullConsumer); + (FixedSizeListVector) vector, + getCurrentRow, + noOpWasNullConsumer, + Calendar.getInstance()); } return null; }; diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessorTest.java index 6a143d2ee..9ce8cea8c 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/AbstractArrowFlightJdbcUnionVectorAccessorTest.java @@ -238,7 +238,7 @@ public void testGetBigDecimalWithScaleUsesSpecificAccessor() throws SQLException private static class AbstractArrowFlightJdbcUnionVectorAccessorMock extends AbstractArrowFlightJdbcUnionVectorAccessor { protected AbstractArrowFlightJdbcUnionVectorAccessorMock() { - super(() -> 0, (boolean wasNull) -> {}); + super(() -> 0, (boolean wasNull) -> {}, Calendar.getInstance()); } @Override diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessorTest.java index 6832ac085..860ba505a 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcDenseUnionVectorAccessorTest.java @@ -22,6 +22,7 @@ import java.sql.Timestamp; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import org.apache.arrow.driver.jdbc.utils.AccessorTestUtils; import org.apache.arrow.driver.jdbc.utils.RootAllocatorTestExtension; @@ -52,7 +53,8 @@ public class ArrowFlightJdbcDenseUnionVectorAccessorTest { getCurrentRow, (boolean wasNull) -> { // No Operation - }); + }, + Calendar.getInstance()); private final AccessorTestUtils.AccessorIterator accessorIterator = new AccessorTestUtils.AccessorIterator<>(accessorSupplier); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessorTest.java index 696e5afb7..a36871f60 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcMapVectorAccessorTest.java @@ -25,6 +25,7 @@ import java.sql.Array; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Calendar; import java.util.Map; import org.apache.arrow.driver.jdbc.utils.AccessorTestUtils; import org.apache.arrow.driver.jdbc.utils.RootAllocatorTestExtension; @@ -105,7 +106,7 @@ public void testShouldGetObjectReturnValidMap() { AccessorTestUtils.Cursor cursor = new AccessorTestUtils.Cursor(vector.getValueCount()); ArrowFlightJdbcMapVectorAccessor accessor = new ArrowFlightJdbcMapVectorAccessor( - vector, cursor::getCurrentRow, (boolean wasNull) -> {}); + vector, cursor::getCurrentRow, (boolean wasNull) -> {}, Calendar.getInstance()); Map expected = new JsonStringHashMap<>(); expected.put(1, 11); @@ -134,7 +135,8 @@ public void testShouldGetObjectReturnValidMap() { public void testShouldGetObjectReturnNull() { vector.setNull(0); ArrowFlightJdbcMapVectorAccessor accessor = - new ArrowFlightJdbcMapVectorAccessor(vector, () -> 0, (boolean wasNull) -> {}); + new ArrowFlightJdbcMapVectorAccessor( + vector, () -> 0, (boolean wasNull) -> {}, Calendar.getInstance()); assertNull(accessor.getObject()); assertTrue(accessor.wasNull()); @@ -145,7 +147,7 @@ public void testShouldGetArrayReturnValidArray() throws SQLException { AccessorTestUtils.Cursor cursor = new AccessorTestUtils.Cursor(vector.getValueCount()); ArrowFlightJdbcMapVectorAccessor accessor = new ArrowFlightJdbcMapVectorAccessor( - vector, cursor::getCurrentRow, (boolean wasNull) -> {}); + vector, cursor::getCurrentRow, (boolean wasNull) -> {}, Calendar.getInstance()); Array array = accessor.getArray(); assertNotNull(array); @@ -210,7 +212,8 @@ public void testShouldGetArrayReturnNull() { ((StructVector) vector.getDataVector()).setNull(0); ArrowFlightJdbcMapVectorAccessor accessor = - new ArrowFlightJdbcMapVectorAccessor(vector, () -> 0, (boolean wasNull) -> {}); + new ArrowFlightJdbcMapVectorAccessor( + vector, () -> 0, (boolean wasNull) -> {}, Calendar.getInstance()); assertNull(accessor.getArray()); assertTrue(accessor.wasNull()); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessorTest.java index 82cd88239..52b2fc2ab 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/complex/ArrowFlightJdbcUnionVectorAccessorTest.java @@ -22,6 +22,7 @@ import java.sql.Timestamp; import java.util.Arrays; +import java.util.Calendar; import java.util.List; import org.apache.arrow.driver.jdbc.utils.AccessorTestUtils; import org.apache.arrow.driver.jdbc.utils.RootAllocatorTestExtension; @@ -47,7 +48,10 @@ public class ArrowFlightJdbcUnionVectorAccessorTest { accessorSupplier = (vector, getCurrentRow) -> new ArrowFlightJdbcUnionVectorAccessor( - (UnionVector) vector, getCurrentRow, (boolean wasNull) -> {}); + (UnionVector) vector, + getCurrentRow, + (boolean wasNull) -> {}, + Calendar.getInstance()); private final AccessorTestUtils.AccessorIterator accessorIterator = new AccessorTestUtils.AccessorIterator<>(accessorSupplier); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/text/ArrowFlightJdbcVarCharVectorAccessorTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/text/ArrowFlightJdbcVarCharVectorAccessorTest.java index a2f6fd586..6b996f547 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/text/ArrowFlightJdbcVarCharVectorAccessorTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/text/ArrowFlightJdbcVarCharVectorAccessorTest.java @@ -652,7 +652,7 @@ public void testShouldGetTimeStampBeConsistentWithTimeStampAccessor() throws Exc rootAllocatorTestExtension.createTimeStampMilliVector()) { ArrowFlightJdbcTimeStampVectorAccessor timeStampVectorAccessor = new ArrowFlightJdbcTimeStampVectorAccessor( - timeStampVector, () -> 0, (boolean wasNull) -> {}); + timeStampVector, () -> 0, (boolean wasNull) -> {}, Calendar.getInstance()); Text value = new Text(timeStampVectorAccessor.getString()); when(getter.get(0)).thenReturn(value.copyBytes()); From fda7067ebde328caa6a20166e8effa3d25204a8d Mon Sep 17 00:00:00 2001 From: Diego Fernandez Date: Tue, 7 Oct 2025 16:15:11 -0600 Subject: [PATCH 9/9] Add tests --- .../driver/jdbc/TimestampResultSetTest.java | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java index 0921ae2d3..3ac9daba0 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/TimestampResultSetTest.java @@ -16,8 +16,11 @@ */ package org.apache.arrow.driver.jdbc; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.google.common.collect.ImmutableList; import java.sql.Connection; +import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,6 +29,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Calendar; @@ -51,6 +55,8 @@ */ public class TimestampResultSetTest { private static final MockFlightSqlProducer FLIGHT_SQL_PRODUCER = new MockFlightSqlProducer(); + private static Instant firstDay2025 = + OffsetDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); @RegisterExtension public static FlightServerTestExtension FLIGHT_SERVER_TEST_EXTENSION; @@ -70,8 +76,6 @@ public class TimestampResultSetTest { @BeforeAll public static void setup() throws SQLException { - Instant firstDay2025 = OffsetDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant(); - FLIGHT_SQL_PRODUCER.addSelectQuery( QUERY_STRING, QUERY_SCHEMA, @@ -161,4 +165,56 @@ public void test() { throw new RuntimeException(e); } } + + @Test + public void testTzConnectionOptionIsRespected() { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + try (Connection connection = FLIGHT_SERVER_TEST_EXTENSION.getConnection("GTM+1")) { + try (PreparedStatement s = connection.prepareStatement(QUERY_STRING)) { + try (ResultSet rs = s.executeQuery()) { + int numCols = rs.getMetaData().getColumnCount(); + try { + rs.next(); + for (int i = 1; i <= numCols; i++) { + int type = rs.getMetaData().getColumnType(i); + String name = rs.getMetaData().getColumnName(i); + Date date = rs.getDate(i); + Timestamp timestamp = rs.getTimestamp(i); + String string = rs.getString(i); + Timestamp object = (Timestamp) rs.getObject(i); + Timestamp objectWithClass = rs.getObject(i, Timestamp.class); + Timestamp timestampWithDefaultCalendar = rs.getTimestamp(i, Calendar.getInstance()); + Timestamp timestampWithUTCCalendar = + rs.getTimestamp(i, Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + LocalDateTime objectLocalDateTime = rs.getObject(i, LocalDateTime.class); + + assertEquals(timestamp, object, "Mismatch for column " + name); + assertEquals(timestamp, objectWithClass, "Mismatch for column " + name); + assertEquals(timestamp.toString(), string, "Mismatch for column " + name); + assertEquals(timestamp.toString(), object.toString(), "Mismatch for column " + name); + assertEquals( + objectLocalDateTime, + LocalDateTime.ofInstant(firstDay2025, ZoneId.of("UTC")), + "Mismatch for column " + name); + + if (type == Types.TIMESTAMP_WITH_TIMEZONE) { + Instant instant = rs.getObject(i, Instant.class); + OffsetDateTime offsetDateTime = rs.getObject(i, OffsetDateTime.class); + ZonedDateTime zonedDateTime = rs.getObject(i, ZonedDateTime.class); + assertEquals(firstDay2025, instant, "Mismatch for column " + name); + assertEquals( + firstDay2025, offsetDateTime.toInstant(), "Mismatch for column " + name); + assertEquals( + firstDay2025, zonedDateTime.toInstant(), "Mismatch for column " + name); + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } }