This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new f80d348b7b [format] Compare array wrapper-group names
case-insensitively in ParquetReaderUtil (#9568)
f80d348b7b is described below
commit f80d348b7bc449a7e9c47a642adcc0cde2248ef1
Author: YangJie <[email protected]>
AuthorDate: Thu Sep 3 04:26:17 2026 -0400
[format] Compare array wrapper-group names case-insensitively in
ParquetReaderUtil (#9568)
---
.../format/parquet/reader/ParquetReaderUtil.java | 5 +-
.../parquet/ParquetCaseInsensitiveReadTest.java | 61 ++++++++++++++++++++++
2 files changed, 64 insertions(+), 2 deletions(-)
diff --git
a/paimon-format/src/main/java/org/apache/paimon/format/parquet/reader/ParquetReaderUtil.java
b/paimon-format/src/main/java/org/apache/paimon/format/parquet/reader/ParquetReaderUtil.java
index 60c29f55a9..48f98b785b 100644
---
a/paimon-format/src/main/java/org/apache/paimon/format/parquet/reader/ParquetReaderUtil.java
+++
b/paimon-format/src/main/java/org/apache/paimon/format/parquet/reader/ParquetReaderUtil.java
@@ -44,7 +44,6 @@ import org.apache.parquet.schema.Type;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.stream.Collectors;
import static
org.apache.paimon.format.parquet.ParquetSchemaConverter.convertToPaimonField;
@@ -168,7 +167,9 @@ public class ParquetReaderUtil {
if (columnIO instanceof GroupColumnIO) {
GroupColumnIO groupColumnIO = (GroupColumnIO) columnIO;
if (!StringUtils.isNullOrWhitespaceOnly(fieldName)) {
- while (!Objects.equals(groupColumnIO.getName(),
fieldName)) {
+ // Column lookup is case-insensitive; the wrapper-group
names can
+ // therefore differ in case from the requested field name.
+ while
(!groupColumnIO.getName().equalsIgnoreCase(fieldName)) {
groupColumnIO = (GroupColumnIO)
groupColumnIO.getChild(0);
}
elementTypeColumnIO = groupColumnIO;
diff --git
a/paimon-format/src/test/java/org/apache/paimon/format/parquet/ParquetCaseInsensitiveReadTest.java
b/paimon-format/src/test/java/org/apache/paimon/format/parquet/ParquetCaseInsensitiveReadTest.java
index 33a6559a44..5517f1914e 100644
---
a/paimon-format/src/test/java/org/apache/paimon/format/parquet/ParquetCaseInsensitiveReadTest.java
+++
b/paimon-format/src/test/java/org/apache/paimon/format/parquet/ParquetCaseInsensitiveReadTest.java
@@ -18,7 +18,10 @@
package org.apache.paimon.format.parquet;
+import org.apache.paimon.data.BinaryString;
+import org.apache.paimon.data.GenericArray;
import org.apache.paimon.data.GenericRow;
+import org.apache.paimon.data.InternalArray;
import org.apache.paimon.data.InternalRow;
import org.apache.paimon.format.FormatReaderContext;
import org.apache.paimon.fs.Path;
@@ -118,6 +121,29 @@ class ParquetCaseInsensitiveReadTest {
assertThat(nested.getLong(1)).isEqualTo(20L);
}
+ @Test
+ void testArrayCaseInsensitiveColumnMatching() throws Exception {
+ Path path = writeArrayMixedCaseParquet();
+
+ // Lowercase name for a column the file spells "Tags" +
caseSensitive=false.
+ RowType readType =
+ RowType.builder().field("tags",
DataTypes.ARRAY(DataTypes.STRING())).build();
+
+ List<InternalRow> rows = read(path, readType, false);
+
+ assertThat(rows).hasSize(2);
+ InternalArray first = rows.get(0).getArray(0);
+ assertThat(first.size()).isEqualTo(2);
+ assertThat(first.getString(0).toString()).isEqualTo("a");
+ assertThat(first.getString(1).toString()).isEqualTo("b");
+ // A second row of a different length, so a wrong offset and a wrong
length differ.
+ InternalArray second = rows.get(1).getArray(0);
+ assertThat(second.size()).isEqualTo(3);
+ assertThat(second.getString(0).toString()).isEqualTo("c");
+ assertThat(second.getString(1).toString()).isEqualTo("d");
+ assertThat(second.getString(2).toString()).isEqualTo("e");
+ }
+
@Test
void testAmbiguousCaseInsensitiveMatchFails() throws Exception {
Path path = writeDuplicateCaseParquet();
@@ -164,6 +190,14 @@ class ParquetCaseInsensitiveReadTest {
RowType child = (RowType) rowType.getTypeAt(i);
values[i] = copy(row.getRow(i, child.getFieldCount()),
child);
break;
+ case ARRAY:
+ InternalArray array = row.getArray(i);
+ BinaryString[] strings = new BinaryString[array.size()];
+ for (int j = 0; j < array.size(); j++) {
+ strings[j] = array.isNullAt(j) ? null :
array.getString(j).copy();
+ }
+ values[i] = new GenericArray(strings);
+ break;
default:
throw new UnsupportedOperationException(
"Unhandled type in test: " + rowType.getTypeAt(i));
@@ -242,6 +276,33 @@ class ParquetCaseInsensitiveReadTest {
factory.newGroup().append("col",
"a").append("COL", "b")));
}
+ private Path writeArrayMixedCaseParquet() throws Exception {
+ MessageType schema =
+ MessageTypeParser.parseMessageType(
+ "message root {\n"
+ + " optional group Tags (LIST) {\n"
+ + " repeated group list {\n"
+ + " optional binary element (UTF8);\n"
+ + " }\n"
+ + " }\n"
+ + "}");
+
+ return write(
+ schema,
+ factory -> {
+ List<Group> groups = new ArrayList<>();
+ for (String[] pair : new String[][] {{"a", "b"}, {"c",
"d", "e"}}) {
+ Group g = factory.newGroup();
+ Group tags = g.addGroup("Tags");
+ for (String v : pair) {
+ tags.addGroup("list").append("element", v);
+ }
+ groups.add(g);
+ }
+ return groups;
+ });
+ }
+
private interface GroupSupplier {
List<Group> get(SimpleGroupFactory factory);
}