diff --git a/arrow/datatype_nested.go b/arrow/datatype_nested.go index ae3b7f8d..2f2f8b81 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 fc4c672c..1bc1d3bc 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},