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 4e37ccc4 fix(arrow): isolate schemas created by AddField (#1079)
4e37ccc4 is described below

commit 4e37ccc478da98c1a8256d3a484f6381cbf09e12
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 20:21:09 2026 +0200

    fix(arrow): isolate schemas created by AddField (#1079)
    
    ### Rationale for this change
    
    Schema.AddField used append directly on the parent field slice when 
inserting at the end. If the parent had spare capacity, two schemas derived 
from it shared the same appended slot. Creating the second sibling then 
silently replaced the first sibling's field while its name index still 
described the original field.
    
    For example, a derived schema created with field "first" can later report 
field "second" after another AddField call on the same parent.
    
    ### What changes are included in this PR?
    
    Always allocate the result field slice before inserting the new field. 
Parent and sibling schemas no longer share writable backing storage. Field 
ordering, metadata, endianness, and index validation are unchanged.
    
    ### Are these changes tested?
    
    Yes. The regression test builds a parent with spare field capacity, derives 
two sibling schemas, and verifies that creating the second sibling does not 
mutate the first.
    
    - go test ./arrow
    - go test -race ./arrow -run 
'^TestSchemaAddFieldDoesNotAliasParentStorage$' -count=1
    
    ### Are there any user-facing changes?
    
    No API changes. Schemas returned by AddField now remain immutable when 
their parent is reused.
---
 arrow/schema.go      | 13 ++++---------
 arrow/schema_test.go | 23 +++++++++++++++++++++++
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/arrow/schema.go b/arrow/schema.go
index cb99adb5..78eac9cd 100644
--- a/arrow/schema.go
+++ b/arrow/schema.go
@@ -268,15 +268,10 @@ func (s *Schema) AddField(i int, field Field) (*Schema, 
error) {
                return nil, fmt.Errorf("arrow: invalid field index %d", i)
        }
 
-       var fields []Field
-       if i == len(s.fields) {
-               fields = append(s.fields, field)
-       } else {
-               fields = make([]Field, len(s.fields)+1)
-               copy(fields[:i], s.fields[:i])
-               fields[i] = field
-               copy(fields[i+1:], s.fields[i:])
-       }
+       fields := make([]Field, len(s.fields)+1)
+       copy(fields[:i], s.fields[:i])
+       fields[i] = field
+       copy(fields[i+1:], s.fields[i:])
 
        return newSchema(fields, &s.meta, s.endianness), nil
 }
diff --git a/arrow/schema_test.go b/arrow/schema_test.go
index 0069e69d..b1e213b9 100644
--- a/arrow/schema_test.go
+++ b/arrow/schema_test.go
@@ -373,6 +373,29 @@ func TestSchemaAddField(t *testing.T) {
        }
 }
 
+func TestSchemaAddFieldDoesNotAliasParentStorage(t *testing.T) {
+       field := func(name string) Field {
+               return Field{Name: name, Type: PrimitiveTypes.Int32}
+       }
+
+       parent := NewSchema([]Field{field("f1")}, nil)
+       fields := make([]Field, len(parent.fields), len(parent.fields)+1)
+       copy(fields, parent.fields)
+       parent.fields = fields
+
+       first, err := parent.AddField(parent.NumFields(), field("first"))
+       if err != nil {
+               t.Fatalf("unexpected error: %v", err)
+       }
+       if _, err := parent.AddField(parent.NumFields(), field("second")); err 
!= nil {
+               t.Fatalf("unexpected error: %v", err)
+       }
+
+       if got, want := first.Field(1).Name, "first"; got != want {
+               t.Fatalf("derived schema field changed: got=%q, want=%q", got, 
want)
+       }
+}
+
 func TestSchemaEqual(t *testing.T) {
        fields := []Field{
                {Name: "f1", Type: PrimitiveTypes.Int32},

Reply via email to