This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-java.git
The following commit(s) were added to refs/heads/main by this push:
new 2afc1d30d GH-1311: Use Locale.ROOT when formatting JDBC interval
strings (#1312)
2afc1d30d is described below
commit 2afc1d30d892467bded7dac8cdfaca009a83ad1e
Author: Abdul Rawoof Khan <[email protected]>
AuthorDate: Sat Oct 3 08:04:45 2026 +0530
GH-1311: Use Locale.ROOT when formatting JDBC interval strings (#1312)
## What's Changed
`formatIntervalYear` and `formatIntervalDay` build the Oracle-style
interval strings the JDBC interval accessor returns from
`getString()`/`getObject()` with `String.format` and no explicit locale,
so `java.util.Formatter` renders the `%d` digits using the JVM default
locale. On a JVM whose default locale uses non-ASCII digits (`ar-EG`,
`bn-BD`, `mr-IN`, ...) an interval comes back as `+٠٢١-٠٢` instead of
`+021-02`, which corrupts the value handed to JDBC clients and breaks
anything parsing it as ASCII. Pass `Locale.ROOT` to both calls, the same
fix GH-1300 applied to the C Data Interface format strings.
Closes #1311.
---
.../arrow/driver/jdbc/utils/IntervalStringUtils.java | 12 ++++++++++--
.../ArrowFlightJdbcIntervalVectorAccessorTest.java | 16 ++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git
a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/IntervalStringUtils.java
b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/IntervalStringUtils.java
index 1aed6cd2c..20a606971 100644
---
a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/IntervalStringUtils.java
+++
b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/IntervalStringUtils.java
@@ -18,6 +18,7 @@ package org.apache.arrow.driver.jdbc.utils;
import java.time.Duration;
import java.time.Period;
+import java.util.Locale;
import org.apache.arrow.vector.util.DateUtility;
/**
@@ -43,7 +44,7 @@ public final class IntervalStringUtils {
final int years = (int) (months / DateUtility.yearsToMonths);
months = months % DateUtility.yearsToMonths;
- return String.format("%c%03d-%02d", neg ? '-' : '+', years, months);
+ return String.format(Locale.ROOT, "%c%03d-%02d", neg ? '-' : '+', years,
months);
}
/**
@@ -73,6 +74,13 @@ public final class IntervalStringUtils {
millis = millis % DateUtility.secondsToMillis;
return String.format(
- "%c%03d %02d:%02d:%02d.%03d", neg ? '-' : '+', days, hours, minutes,
seconds, millis);
+ Locale.ROOT,
+ "%c%03d %02d:%02d:%02d.%03d",
+ neg ? '-' : '+',
+ days,
+ hours,
+ minutes,
+ seconds,
+ millis);
}
}
diff --git
a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcIntervalVectorAccessorTest.java
b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcIntervalVectorAccessorTest.java
index 521debc32..457558a04 100644
---
a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcIntervalVectorAccessorTest.java
+++
b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/accessor/impl/calendar/ArrowFlightJdbcIntervalVectorAccessorTest.java
@@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Duration;
import java.time.Period;
import java.time.format.DateTimeParseException;
+import java.util.Locale;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.arrow.driver.jdbc.accessor.ArrowFlightJdbcAccessorFactory;
@@ -36,6 +37,7 @@ import org.apache.arrow.vector.IntervalYearVector;
import org.apache.arrow.vector.PeriodDuration;
import org.apache.arrow.vector.ValueVector;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -254,6 +256,20 @@ public class ArrowFlightJdbcIntervalVectorAccessorTest {
assertEquals("-1567 00:00:00.000",
formatIntervalDay(Duration.ofDays(-1567)));
}
+ @Test
+ public void testFormatIntervalIgnoresDefaultLocale() {
+ // Locales such as Arabic-Indic render %d with non-ASCII digits; the
interval strings handed
+ // back through getString() must stay ASCII regardless of the JVM default
locale.
+ Locale saved = Locale.getDefault();
+ try {
+ Locale.setDefault(Locale.forLanguageTag("ar-EG"));
+ assertEquals("+021-02", formatIntervalYear(Period.of(21, 2, 0)));
+ assertEquals("+001 18:25:16.766",
formatIntervalDay(Duration.parse("PT42H25M16.766S")));
+ } finally {
+ Locale.setDefault(saved);
+ }
+ }
+
@ParameterizedTest
@MethodSource("data")
public void testShouldGetStringReturnCorrectString(Supplier<ValueVector>
vectorSupplier)