You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@orc.apache.org by do...@apache.org on 2026/06/16 17:06:56 UTC

(orc) branch branch-2.1 updated: ORC-2177: Fix array conversion with empty first batch

This is an automated email from the ASF dual-hosted git repository.

dongjoon-hyun pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/orc.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 4cc79423f ORC-2177: Fix array conversion with empty first batch
4cc79423f is described below

commit 4cc79423f79c97ed3e0f0512b2e4a274a4f92aec
Author: sychen <sy...@ctrip.com>
AuthorDate: Tue Jun 16 10:00:49 2026 -0700

    ORC-2177: Fix array conversion with empty first batch
    
    ### What changes were proposed in this pull request?
    Add a `batchSize > 0` guard in `ConvertTreeReader.convertVector()` before accessing index 0.
    
    ### Why are the changes needed?
    When reading an ORC file with schema evolution converting `array<int>` to `array<string>`, an `ArrayIndexOutOfBoundsException` is thrown if the first batch processed by the element reader has `childCount=0` (i.e., all rows in the batch contain empty arrays).
    
    ```java
    java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
            at org.apache.orc.impl.ConvertTreeReaderFactory$StringGroupFromAnyIntegerTreeReader.setConvertVectorElement(ConvertTreeReaderFactory.java:1094)
            at org.apache.orc.impl.ConvertTreeReaderFactory$ConvertTreeReader.convertVector(ConvertTreeReaderFactory.java:305)
            at org.apache.orc.impl.ConvertTreeReaderFactory$StringGroupFromAnyIntegerTreeReader.nextVector(ConvertTreeReaderFactory.java:1115)
            at org.apache.orc.impl.TreeReaderFactory$ListTreeReader.nextVector(TreeReaderFactory.java:2892)
            at org.apache.orc.impl.reader.tree.StructBatchReader.readBatchColumn(StructBatchReader.java:66)
            at org.apache.orc.impl.reader.tree.StructBatchReader.nextBatchForLevel(StructBatchReader.java:101)
            at org.apache.orc.impl.reader.tree.StructBatchReader.nextBatch(StructBatchReader.java:78)
            at org.apache.orc.impl.RecordReaderImpl.nextBatch(RecordReaderImpl.java:1444)
    ```
    
    ### How was this patch tested?
    Added `testIntArrayToStringArrayFirstBatchAllEmpty` in `TestConvertTreeReaderFactory`
    
    ### Was this patch authored or co-authored using generative AI tooling?
    Generated-by: Claude
    
    Closes #2638 from cxzl25/ORC-2177.
    
    Authored-by: sychen <sy...@ctrip.com>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
    (cherry picked from commit 6d125348a6aca67919de4e12c2a3b8c07a3cdefb)
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 .../apache/orc/impl/ConvertTreeReaderFactory.java  | 12 ++++----
 .../orc/impl/TestConvertTreeReaderFactory.java     | 34 ++++++++++++++++++++++
 2 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/java/core/src/java/org/apache/orc/impl/ConvertTreeReaderFactory.java b/java/core/src/java/org/apache/orc/impl/ConvertTreeReaderFactory.java
index 6886b551e..aed0a44ac 100644
--- a/java/core/src/java/org/apache/orc/impl/ConvertTreeReaderFactory.java
+++ b/java/core/src/java/org/apache/orc/impl/ConvertTreeReaderFactory.java
@@ -299,11 +299,13 @@ public class ConvertTreeReaderFactory extends TreeReaderFactory {
       resultColVector.reset();
       if (fromColVector.isRepeating) {
         resultColVector.isRepeating = true;
-        if (fromColVector.noNulls || !fromColVector.isNull[0]) {
-          setConvertVectorElement(0);
-        } else {
-          resultColVector.noNulls = false;
-          resultColVector.isNull[0] = true;
+        if (batchSize > 0) {
+          if (fromColVector.noNulls || !fromColVector.isNull[0]) {
+            setConvertVectorElement(0);
+          } else {
+            resultColVector.noNulls = false;
+            resultColVector.isNull[0] = true;
+          }
         }
       } else if (fromColVector.noNulls) {
         for (int i = 0; i < batchSize; i++) {
diff --git a/java/core/src/test/org/apache/orc/impl/TestConvertTreeReaderFactory.java b/java/core/src/test/org/apache/orc/impl/TestConvertTreeReaderFactory.java
index 53f94cbf7..c1bbcfe4c 100644
--- a/java/core/src/test/org/apache/orc/impl/TestConvertTreeReaderFactory.java
+++ b/java/core/src/test/org/apache/orc/impl/TestConvertTreeReaderFactory.java
@@ -745,4 +745,38 @@ public class TestConvertTreeReaderFactory implements TestConf {
     readDecimalInNullStripe("decimal(18,2)", DecimalColumnVector.class,
             new String[]{"null", "1024", "1"});
   }
+
+  @Test
+  public void testIntArrayToStringArrayFirstBatchAllEmpty() throws Exception {
+    TypeDescription fileSchema = TypeDescription.fromString("struct<col1:array<int>>");
+    TypeDescription readerSchema = TypeDescription.fromString("struct<col1:array<string>>");
+
+    try (Writer w = OrcFile.createWriter(testFilePath,
+        OrcFile.writerOptions(conf).setSchema(fileSchema))) {
+      VectorizedRowBatch b = fileSchema.createRowBatch(3);
+      ListColumnVector lc = (ListColumnVector) b.cols[0];
+      for (int i = 0; i < 3; i++) {
+        lc.offsets[i] = 0;
+        lc.lengths[i] = 0;
+      }
+      lc.childCount = 0;
+      b.size = 3;
+      w.addRowBatch(b);
+    }
+
+    try (Reader reader = OrcFile.createReader(testFilePath, OrcFile.readerOptions(conf));
+         RecordReader rows = reader.rows(reader.options().schema(readerSchema))) {
+      VectorizedRowBatch rb = readerSchema.createRowBatch(3);
+      assertTrue(rows.nextBatch(rb));
+      ListColumnVector r = (ListColumnVector) rb.cols[0];
+      // Cast verifies schema evolution took effect (would be LongColumnVector without evolution)
+      BytesColumnVector child = (BytesColumnVector) r.child;
+      assertEquals(0, r.childCount);
+      for (int i = 0; i < 3; i++) {
+        assertEquals(0, r.lengths[i], "row " + i + " should be empty array");
+      }
+    } finally {
+      fs.delete(testFilePath, false);
+    }
+  }
 }