From 63c2f9c003340c66ae39adbd3602f94aa73a2242 Mon Sep 17 00:00:00 2001 From: yujin5701 Date: Wed, 8 Jul 2026 12:23:51 +0900 Subject: [PATCH] GH-477: Fix Flight JDBC DATE(MILLISECOND) parameter binding --- .../impl/DateAvaticaParameterConverter.java | 3 +- .../ArrowFlightPreparedStatementTest.java | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/converter/impl/DateAvaticaParameterConverter.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/converter/impl/DateAvaticaParameterConverter.java index 8795213530..ebbfae6fb8 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/converter/impl/DateAvaticaParameterConverter.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/converter/impl/DateAvaticaParameterConverter.java @@ -16,6 +16,7 @@ */ package org.apache.arrow.driver.jdbc.converter.impl; +import java.util.concurrent.TimeUnit; import org.apache.arrow.vector.DateDayVector; import org.apache.arrow.vector.DateMilliVector; import org.apache.arrow.vector.FieldVector; @@ -33,7 +34,7 @@ public DateAvaticaParameterConverter(ArrowType.Date type) {} public boolean bindParameter(FieldVector vector, TypedValue typedValue, int index) { int value = (int) typedValue.toLocal(); if (vector instanceof DateMilliVector) { - ((DateMilliVector) vector).setSafe(index, value); + ((DateMilliVector) vector).setSafe(index, TimeUnit.DAYS.toMillis(value)); return true; } else if (vector instanceof DateDayVector) { ((DateDayVector) vector).setSafe(index, value); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java index 078837adf3..73ece46403 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowFlightPreparedStatementTest.java @@ -25,9 +25,11 @@ import java.nio.charset.StandardCharsets; import java.sql.Connection; +import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.time.LocalDate; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -38,6 +40,7 @@ import org.apache.arrow.memory.RootAllocator; import org.apache.arrow.vector.IntVector; import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.types.DateUnit; import org.apache.arrow.vector.types.Types; import org.apache.arrow.vector.types.pojo.ArrowType; import org.apache.arrow.vector.types.pojo.Field; @@ -180,6 +183,49 @@ public void testQueryWithParameterBinding() throws SQLException { } } + @Test + public void testQueryWithDateMillisecondParameterBinding() throws SQLException { + final String query = "Fake query with date millisecond parameter"; + final Schema schema = + new Schema(Collections.singletonList(Field.nullable("", Types.MinorType.INT.getType()))); + final Schema parameterSchema = + new Schema( + Collections.singletonList( + Field.nullable("", new ArrowType.Date(DateUnit.MILLISECOND)))); + final LocalDate date = LocalDate.of(2000, 1, 1); + final List> expected = + Collections.singletonList(Collections.singletonList(date.atStartOfDay())); + + PRODUCER.addSelectQuery( + query, + schema, + Collections.singletonList( + listener -> { + try (final BufferAllocator allocator = new RootAllocator(Long.MAX_VALUE); + final VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) { + ((IntVector) root.getVector(0)).setSafe(0, 10); + root.setRowCount(1); + listener.start(root); + listener.putNext(); + } catch (final Throwable throwable) { + listener.error(throwable); + } finally { + listener.completed(); + } + })); + + PRODUCER.addExpectedParameters(query, parameterSchema, expected); + + try (final PreparedStatement preparedStatement = connection.prepareStatement(query)) { + preparedStatement.setDate(1, Date.valueOf(date)); + + try (final ResultSet resultSet = preparedStatement.executeQuery()) { + resultSet.next(); + assert true; + } + } + } + @Test @Disabled("https://github.com/apache/arrow/issues/34741: flaky test") public void testPreparedStatementExecutionOnce() throws SQLException {