Skip to content

Commit 7c77c0c

Browse files
committed
GH-1300: Use Locale.ROOT when building C Data Interface format strings
Format.asString built the FixedSizeList, FixedSizeBinary and Decimal format strings with String.format and no explicit Locale, so JVMs whose default locale uses digits outside ASCII exported strings such as "+w:٨" that other Arrow implementations cannot parse. Closes #1300.
1 parent d035fc8 commit 7c77c0c

2 files changed

Lines changed: 21 additions & 4 deletions

File tree

‎c/src/main/java/org/apache/arrow/c/Format.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@ static String asString(ArrowType arrowType) {
6363
{
6464
ArrowType.Decimal type = (ArrowType.Decimal) arrowType;
6565
if (type.getBitWidth() == 128) {
66-
return String.format("d:%d,%d", type.getPrecision(), type.getScale());
66+
return String.format(Locale.ROOT, "d:%d,%d", type.getPrecision(), type.getScale());
6767
}
6868
return String.format(
69-
"d:%d,%d,%d", type.getPrecision(), type.getScale(), type.getBitWidth());
69+
Locale.ROOT, "d:%d,%d,%d", type.getPrecision(), type.getScale(), type.getBitWidth());
7070
}
7171
case Duration:
7272
{
@@ -88,12 +88,12 @@ static String asString(ArrowType arrowType) {
8888
case FixedSizeBinary:
8989
{
9090
ArrowType.FixedSizeBinary type = (ArrowType.FixedSizeBinary) arrowType;
91-
return String.format("w:%d", type.getByteWidth());
91+
return String.format(Locale.ROOT, "w:%d", type.getByteWidth());
9292
}
9393
case FixedSizeList:
9494
{
9595
ArrowType.FixedSizeList type = (ArrowType.FixedSizeList) arrowType;
96-
return String.format("+w:%d", type.getListSize());
96+
return String.format(Locale.ROOT, "+w:%d", type.getListSize());
9797
}
9898
case FloatingPoint:
9999
{

‎c/src/test/java/org/apache/arrow/c/FormatTest.java‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.junit.jupiter.api.Assertions.assertThrows;
2121
import static org.junit.jupiter.api.Assertions.assertTrue;
2222

23+
import java.util.Locale;
2324
import org.apache.arrow.vector.types.DateUnit;
2425
import org.apache.arrow.vector.types.FloatingPointPrecision;
2526
import org.apache.arrow.vector.types.IntervalUnit;
@@ -156,4 +157,20 @@ public void testAsType()
156157
assertThrows(UnsupportedOperationException.class, () -> Format.asType(":", 0L));
157158
assertThrows(NumberFormatException.class, () -> Format.asType("w:1,2,3", 0L));
158159
}
160+
161+
@Test
162+
public void testAsStringIgnoresDefaultLocale() {
163+
// Locales that use digits other than 0-9 (Arabic-Indic, Bengali, Devanagari, ...)
164+
// must not leak into the format string, which other implementations parse as ASCII.
165+
Locale saved = Locale.getDefault();
166+
try {
167+
Locale.setDefault(Locale.forLanguageTag("ar-EG"));
168+
assertEquals("d:10,2", Format.asString(new ArrowType.Decimal(10, 2, 128)));
169+
assertEquals("d:10,2,256", Format.asString(new ArrowType.Decimal(10, 2, 256)));
170+
assertEquals("w:16", Format.asString(new ArrowType.FixedSizeBinary(16)));
171+
assertEquals("+w:8", Format.asString(new ArrowType.FixedSizeList(8)));
172+
} finally {
173+
Locale.setDefault(saved);
174+
}
175+
}
159176
}

0 commit comments

Comments
 (0)