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 5327234c fix(arrow/array): support zero-column tables (#988)
5327234c is described below

commit 5327234c4d0949b9e08da7f47fe3cb5f96e63f47
Author: Minh Vu <[email protected]>
AuthorDate: Thu Jul 23 22:10:30 2026 +0200

    fix(arrow/array): support zero-column tables (#988)
    
    ### Rationale for this change
    
    Arrow schemas and record batches may have zero fields while still
    carrying a logical row count. `NewTableFromSlice` indexed the first
    column unconditionally and panicked for an empty schema.
    `NewTableFromRecords` inferred rows from columns, so zero-column record
    batches lost their row counts.
    
    ### What changes are included in this PR?
    
    Handle the empty column slice without indexing `cols[0]`. When the
    schema has no fields, sum `RecordBatch.NumRows` to preserve the logical
    row count. Tables with columns keep the existing column-based row
    inference. Regression tests cover both constructors.
    
    ### Are these changes tested?
    
    Yes:
    
    - `go test ./arrow/array`
    - `go test -race -count=1 ./arrow/array`
    
    ### Are there any user-facing changes?
    
    Zero-column table construction no longer panics, and zero-column record
    batches retain their logical row counts. Existing behavior for tables
    with columns is unchanged.
---
 arrow/array/table.go      | 16 ++++++++++++++--
 arrow/array/table_test.go | 30 ++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/arrow/array/table.go b/arrow/array/table.go
index 540124b1..6bd44045 100644
--- a/arrow/array/table.go
+++ b/arrow/array/table.go
@@ -149,10 +149,15 @@ func NewTableFromSlice(schema *arrow.Schema, data 
[][]arrow.Array) arrow.Table {
                chunked.Release()
        }
 
+       var rows int64
+       if len(cols) > 0 {
+               rows = int64(cols[0].Len())
+       }
+
        tbl := simpleTable{
                schema: schema,
                cols:   cols,
-               rows:   int64(cols[0].Len()),
+               rows:   rows,
        }
        tbl.refCount.Add(1)
 
@@ -178,6 +183,13 @@ func NewTableFromSlice(schema *arrow.Schema, data 
[][]arrow.Array) arrow.Table {
 func NewTableFromRecords(schema *arrow.Schema, recs []arrow.RecordBatch) 
arrow.Table {
        arrs := make([]arrow.Array, len(recs))
        cols := make([]arrow.Column, schema.NumFields())
+       rows := int64(-1)
+       if len(cols) == 0 {
+               rows = 0
+               for _, rec := range recs {
+                       rows += rec.NumRows()
+               }
+       }
 
        defer func(cols []arrow.Column) {
                for i := range cols {
@@ -195,7 +207,7 @@ func NewTableFromRecords(schema *arrow.Schema, recs 
[]arrow.RecordBatch) arrow.T
                chunk.Release()
        }
 
-       return NewTable(schema, cols, -1)
+       return NewTable(schema, cols, rows)
 }
 
 func (tbl *simpleTable) Schema() *arrow.Schema { return tbl.schema }
diff --git a/arrow/array/table_test.go b/arrow/array/table_test.go
index bbf4a4e6..110b1c7c 100644
--- a/arrow/array/table_test.go
+++ b/arrow/array/table_test.go
@@ -113,6 +113,36 @@ func TestChunked(t *testing.T) {
        }
 }
 
+func TestTableFromSliceWithoutColumns(t *testing.T) {
+       schema := arrow.NewSchema(nil, nil)
+       tbl := array.NewTableFromSlice(schema, nil)
+       defer tbl.Release()
+
+       if got, want := tbl.NumRows(), int64(0); got != want {
+               t.Fatalf("NumRows = %d, want %d", got, want)
+       }
+}
+
+func TestTableFromRecordsWithoutColumns(t *testing.T) {
+       schema := arrow.NewSchema(nil, nil)
+       records := []arrow.RecordBatch{
+               array.NewRecordBatch(schema, nil, 2),
+               array.NewRecordBatch(schema, nil, 3),
+       }
+       defer func() {
+               for _, rec := range records {
+                       rec.Release()
+               }
+       }()
+
+       tbl := array.NewTableFromRecords(schema, records)
+       defer tbl.Release()
+
+       if got, want := tbl.NumRows(), int64(5); got != want {
+               t.Fatalf("NumRows = %d, want %d", got, want)
+       }
+}
+
 func TestChunkedEqualDataType(t *testing.T) {
        mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
        defer mem.AssertSize(t, 0)

Reply via email to