From 22dce0b3f4cea2dcdc5ecad0fd1c787f1fa3954c Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Sun, 16 Aug 2026 17:42:10 -0700 Subject: [PATCH] fix(java): handle logical stream end seek Treat a stream's exact logical end as a valid seek target even when the shared disk range list contains data for later streams. This prevents an EOF seek from selecting an unrelated range or failing as out of bounds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../core/src/java/org/apache/orc/impl/InStream.java | 8 ++++++-- .../src/test/org/apache/orc/impl/TestInStream.java | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/java/core/src/java/org/apache/orc/impl/InStream.java b/java/core/src/java/org/apache/orc/impl/InStream.java index bf23a95087..9ea85b7f57 100644 --- a/java/core/src/java/org/apache/orc/impl/InStream.java +++ b/java/core/src/java/org/apache/orc/impl/InStream.java @@ -233,9 +233,13 @@ public void seek(long desired) throws IOException { } else { for (DiskRangeList curRange = bytes; curRange != null; curRange = curRange.next) { + // Accept this stream's logical end when later ranges belong to other streams. + boolean isLogicalEnd = + desired == length && positionFile == curRange.getEnd(); if (curRange.getOffset() <= positionFile && - (curRange.next == null ? positionFile <= curRange.getEnd() : - positionFile < curRange.getEnd())) { + (isLogicalEnd || + (curRange.next == null ? positionFile <= curRange.getEnd() : + positionFile < curRange.getEnd()))) { position = desired; setCurrent(curRange, true); return; diff --git a/java/core/src/test/org/apache/orc/impl/TestInStream.java b/java/core/src/test/org/apache/orc/impl/TestInStream.java index 596afcf304..ad483c7ec8 100644 --- a/java/core/src/test/org/apache/orc/impl/TestInStream.java +++ b/java/core/src/test/org/apache/orc/impl/TestInStream.java @@ -790,6 +790,19 @@ public long getNext() { } } + @Test + public void testSeekToLogicalEndWithLaterDiskRange() throws IOException { + BufferChunk streamRange = new BufferChunk(ByteBuffer.allocate(10), 100); + streamRange.insertAfter(new BufferChunk(ByteBuffer.allocate(10), 120)); + try (InStream.UncompressedStream stream = + new InStream.UncompressedStream("test", streamRange, 100, 10)) { + stream.seek(10); + assertSame(streamRange, stream.currentRange); + assertEquals(0, stream.available()); + assertEquals(-1, stream.read()); + } + } + private static byte[] input(int... data) { byte[] result = new byte[data.length]; for(int i = 0; i < data.length; ++i) {