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 38d768e7 fix(arrow/array): avoid panics cleaning partial tables (#1103)
38d768e7 is described below

commit 38d768e71ad996c7edd77a7950d6ec05d818e3ee
Author: Minh Vu <[email protected]>
AuthorDate: Fri Aug 7 19:45:48 2026 +0200

    fix(arrow/array): avoid panics cleaning partial tables (#1103)
    
    ### Rationale for this change
    
    NewTableFromRecords releases every entry in its column slice when
    construction fails. Entries that have not been initialized contain nil
    data, so cleanup can panic and hide the original construction error.
    
    ### What changes are included in this PR?
    
    Skip uninitialized columns while unwinding and add a checked-allocator
    regression test.
    
    ### Are these changes tested?
    
    - `go test ./arrow/array`
    
    ### Are there any user-facing changes?
    
    No API changes. This corrects the reported behavior while preserving the
    existing ownership and compatibility contracts.
---
 arrow/array/table.go      |  3 +++
 arrow/array/table_test.go | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/arrow/array/table.go b/arrow/array/table.go
index c8cd7ed9..e1f1bb08 100644
--- a/arrow/array/table.go
+++ b/arrow/array/table.go
@@ -195,6 +195,9 @@ func NewTableFromRecords(schema *arrow.Schema, recs 
[]arrow.RecordBatch) arrow.T
 
        defer func(cols []arrow.Column) {
                for i := range cols {
+                       if cols[i].Data() == nil {
+                               continue
+                       }
                        cols[i].Release()
                }
        }(cols)
diff --git a/arrow/array/table_test.go b/arrow/array/table_test.go
index 94c308b7..f39b2426 100644
--- a/arrow/array/table_test.go
+++ b/arrow/array/table_test.go
@@ -179,6 +179,47 @@ func TestTableFromRecordsWithoutColumns(t *testing.T) {
        }
 }
 
+func TestTableFromRecordsReleasesPartialColumnsOnPanic(t *testing.T) {
+       mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+       defer mem.AssertSize(t, 0)
+
+       firstBuilder := array.NewInt32Builder(mem)
+       firstBuilder.Append(1)
+       first := firstBuilder.NewArray()
+       firstBuilder.Release()
+
+       secondBuilder := array.NewInt64Builder(mem)
+       secondBuilder.Append(2)
+       second := secondBuilder.NewArray()
+       secondBuilder.Release()
+
+       recordSchema := arrow.NewSchema([]arrow.Field{
+               {Name: "first", Type: arrow.PrimitiveTypes.Int32},
+               {Name: "second", Type: arrow.PrimitiveTypes.Int64},
+       }, nil)
+       rec := array.NewRecordBatch(recordSchema, []arrow.Array{first, second}, 
-1)
+       first.Release()
+       second.Release()
+       defer rec.Release()
+
+       tableSchema := arrow.NewSchema([]arrow.Field{
+               {Name: "first", Type: arrow.PrimitiveTypes.Int32},
+               {Name: "second", Type: arrow.PrimitiveTypes.Int32},
+       }, nil)
+
+       defer func() {
+               r := recover()
+               if r == nil {
+                       t.Fatal("expected NewTableFromRecords to panic")
+               }
+               err, ok := r.(error)
+               if !ok || !errors.Is(err, arrow.ErrInvalid) {
+                       t.Fatalf("expected ErrInvalid, got %v", r)
+               }
+       }()
+       array.NewTableFromRecords(tableSchema, []arrow.RecordBatch{rec})
+}
+
 func TestChunkedEqualDataType(t *testing.T) {
        mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
        defer mem.AssertSize(t, 0)

Reply via email to