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 6b039a76 fix(arrow): return owned field index slices (#1159)
6b039a76 is described below

commit 6b039a763f912e7cd18e23731e592022020ee280
Author: Minh Vu <[email protected]>
AuthorDate: Fri Aug 28 00:05:22 2026 +0200

    fix(arrow): return owned field index slices (#1159)
    
    ### Rationale for this change
    
    Schema.FieldIndices and StructType.FieldIndices return slices backed by
    internal index maps. Mutating a returned slice can corrupt later field
    lookups.
    
    ### What changes are included in this PR?
    
    Return cloned index slices from both methods. Schema.HasField reads the
    internal map directly so the ownership fix does not add an allocation
    there.
    
    ### Are these changes tested?
    
    Yes. Regression tests mutate returned slices and verify that Schema and
    StructType keep their original indices. The full arrow package suite
    passes.
    
    ### Are there any user-facing changes?
    
    Callers now receive slices they can safely modify.
    
    Co-authored-by: Matt Topol <[email protected]>
---
 arrow/datatype_nested.go      |  5 +++--
 arrow/datatype_nested_test.go | 11 +++++++++++
 arrow/schema.go               |  6 +++---
 arrow/schema_test.go          | 13 +++++++++++++
 4 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/arrow/datatype_nested.go b/arrow/datatype_nested.go
index 6e92a1a9..cf8ca377 100644
--- a/arrow/datatype_nested.go
+++ b/arrow/datatype_nested.go
@@ -19,6 +19,7 @@ package arrow
 import (
        "errors"
        "fmt"
+       "slices"
        "strconv"
        "strings"
 
@@ -501,9 +502,9 @@ func (t *StructType) FieldsByName(n string) ([]Field, bool) 
{
        return fields, ok
 }
 
-// FieldIndices returns indices of all fields with the given name, or nil.
+// FieldIndices returns a copy of the indices of all fields with the given 
name, or nil.
 func (t *StructType) FieldIndices(name string) []int {
-       return t.index[name]
+       return slices.Clone(t.index[name])
 }
 
 func (t *StructType) Fingerprint() string {
diff --git a/arrow/datatype_nested_test.go b/arrow/datatype_nested_test.go
index b0d42b08..1845d171 100644
--- a/arrow/datatype_nested_test.go
+++ b/arrow/datatype_nested_test.go
@@ -336,6 +336,17 @@ func TestStructField(t *testing.T) {
        assert.Equal(t, ty.FieldIndices("f3"), []int(nil))
 }
 
+func TestStructTypeFieldIndicesReturnsCopy(t *testing.T) {
+       typeWithDuplicates := StructOf(
+               Field{Name: "id", Type: PrimitiveTypes.Int32},
+               Field{Name: "id", Type: PrimitiveTypes.Int64},
+       )
+       indices := typeWithDuplicates.FieldIndices("id")
+       indices[0] = 99
+
+       assert.Equal(t, []int{0, 1}, typeWithDuplicates.FieldIndices("id"))
+}
+
 func TestFieldEqual(t *testing.T) {
        for _, tc := range []struct {
                a, b Field
diff --git a/arrow/schema.go b/arrow/schema.go
index 78eac9cd..d3f52584 100644
--- a/arrow/schema.go
+++ b/arrow/schema.go
@@ -232,12 +232,12 @@ func (sc *Schema) FieldsByName(n string) ([]Field, bool) {
        return nil, false
 }
 
-// FieldIndices returns the indices of the named field or nil.
+// FieldIndices returns a copy of the indices of the named field or nil.
 func (sc *Schema) FieldIndices(n string) []int {
-       return sc.index[n]
+       return slices.Clone(sc.index[n])
 }
 
-func (sc *Schema) HasField(n string) bool { return len(sc.FieldIndices(n)) > 0 
}
+func (sc *Schema) HasField(n string) bool { return len(sc.index[n]) > 0 }
 func (sc *Schema) HasMetadata() bool      { return len(sc.meta.keys) > 0 }
 
 // Equal returns whether two schema are equal.
diff --git a/arrow/schema_test.go b/arrow/schema_test.go
index b1e213b9..2f9043bb 100644
--- a/arrow/schema_test.go
+++ b/arrow/schema_test.go
@@ -349,6 +349,19 @@ func TestSchemaFieldsByNameReturnsCopy(t *testing.T) {
        }
 }
 
+func TestSchemaFieldIndicesReturnsCopy(t *testing.T) {
+       schema := NewSchema([]Field{
+               {Name: "id", Type: PrimitiveTypes.Int32},
+               {Name: "id", Type: PrimitiveTypes.Int64},
+       }, nil)
+       indices := schema.FieldIndices("id")
+       indices[0] = 99
+
+       if got, want := schema.FieldIndices("id"), []int{0, 1}; 
!reflect.DeepEqual(got, want) {
+               t.Fatalf("schema indices mutated through returned slice: got 
%v, want %v", got, want)
+       }
+}
+
 func TestSchemaAddField(t *testing.T) {
        s := NewSchema([]Field{
                {Name: "f1", Type: PrimitiveTypes.Int32},

Reply via email to