This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git
The following commit(s) were added to refs/heads/main by this push:
new d8b61707 fix(internal/utils): keep byteReader position after failed
seeks (#1005)
d8b61707 is described below
commit d8b617079e80b195800da271536590077d4e3546
Author: Minh Vu <[email protected]>
AuthorDate: Mon Jul 27 22:01:44 2026 +0200
fix(internal/utils): keep byteReader position after failed seeks (#1005)
`byteReader` updated its cached position even when the underlying seek
failed, which could make `Peek` and `Read` disagree about where the
reader was. `Discard` also returned `io.EOF` when it consumed exactly
the remaining bytes.
This only updates the cached position after a successful seek and treats
exact exhaustion as a successful discard. Added focused regressions for
both behaviors.
Tests: `go test ./internal/utils`
---
internal/utils/buf_reader.go | 6 ++++--
internal/utils/buf_reader_test.go | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/internal/utils/buf_reader.go b/internal/utils/buf_reader.go
index 40a7af8d..2d0b5cc9 100644
--- a/internal/utils/buf_reader.go
+++ b/internal/utils/buf_reader.go
@@ -55,7 +55,9 @@ func (r *byteReader) Read(buf []byte) (n int, err error) {
func (r *byteReader) Seek(offset int64, whence int) (pos int64, err error) {
pos, err = r.r.Seek(offset, whence)
- r.pos = int(pos)
+ if err == nil {
+ r.pos = int(pos)
+ }
return
}
@@ -86,7 +88,7 @@ func (r *byteReader) Discard(n int) (int, error) {
newPos = r.pos + n
)
- if newPos >= len(r.buf) {
+ if newPos > len(r.buf) {
newPos = len(r.buf)
n = newPos - r.pos
err = io.EOF
diff --git a/internal/utils/buf_reader_test.go
b/internal/utils/buf_reader_test.go
index e22b80dc..620c6c5b 100644
--- a/internal/utils/buf_reader_test.go
+++ b/internal/utils/buf_reader_test.go
@@ -66,3 +66,25 @@ func TestBufferedReaderPeekReturnsAvailableBytesOnError(t
*testing.T) {
t.Fatalf("Peek = %q, want %q", got, "a")
}
}
+
+func TestByteReaderSeekErrorPreservesPosition(t *testing.T) {
+ r := NewByteReader([]byte("abc"))
+ buf := make([]byte, 1)
+ if n, err := r.Read(buf); n != 1 || err != nil {
+ t.Fatalf("Read = (%d, %v), want (1, nil)", n, err)
+ }
+
+ if _, err := r.Seek(0, -1); err == nil {
+ t.Fatal("Seek with invalid whence returned nil error")
+ }
+ if got, err := r.Peek(1); err != nil || string(got) != "b" {
+ t.Fatalf("Peek after failed seek = (%q, %v), want (%q, nil)",
got, err, "b")
+ }
+}
+
+func TestByteReaderDiscardExactRemainingBytes(t *testing.T) {
+ r := NewByteReader([]byte("abc"))
+ if n, err := r.Discard(3); n != 3 || err != nil {
+ t.Fatalf("Discard = (%d, %v), want (3, nil)", n, err)
+ }
+}