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},