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 d6af7dbc fix(array): struct stringer required child mask (#873)
d6af7dbc is described below

commit d6af7dbc15bb14eefca0d7207ad65f4d575a39a7
Author: Minh Vu <[email protected]>
AuthorDate: Wed Jul 1 17:23:48 2026 +0200

    fix(array): struct stringer required child mask (#873)
    
    ### What changed
    
    Struct.String now handles child fields that do not have their own
    validity bitmap when applying the parent struct validity mask. It
    creates an all-valid bitmap for the child first, clears parent-null
    positions, and only releases an existing child bitmap when one is
    present.
    
    ### Why
    
    When a nullable struct had a required child with no child null bitmap,
    the masking path could clear bits in a zero-length slice and then
    release a nil buffer. Calling String on that shape could panic instead
    of rendering parent-null slots as null.
    
    ### Validation
    
    - go test ./arrow/array -run
    TestStructArrayStringerMasksRequiredChildWithoutNullBitmap -count=1
    - go test ./arrow/array -count=1
    -
    PARQUET_TEST_DATA=/Users/hoangvu/Code/OSS/arrow-go/parquet-testing/data
    ARROW_TEST_DATA=/Users/hoangvu/Code/OSS/arrow-go/arrow-testing/data go
    test ./... -count=1
---
 arrow/array/struct.go      | 14 +++++++++++---
 arrow/array/struct_test.go | 27 +++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/arrow/array/struct.go b/arrow/array/struct.go
index 7df6d8d4..07505de1 100644
--- a/arrow/array/struct.go
+++ b/arrow/array/struct.go
@@ -169,8 +169,14 @@ func (a *Struct) String() string {
 func (a *Struct) newStructFieldWithParentValidityMask(fieldIndex int) 
arrow.Array {
        field := a.Field(fieldIndex)
        nullBitmapBytes := field.NullBitmapBytes()
-       maskedNullBitmapBytes := make([]byte, len(nullBitmapBytes))
-       copy(maskedNullBitmapBytes, nullBitmapBytes)
+       var maskedNullBitmapBytes []byte
+       if len(nullBitmapBytes) == 0 {
+               maskedNullBitmapBytes = make([]byte, 
int(bitutil.BytesForBits(int64(field.Len()))))
+               bitutil.SetBitsTo(maskedNullBitmapBytes, 0, int64(field.Len()), 
true)
+       } else {
+               maskedNullBitmapBytes = make([]byte, len(nullBitmapBytes))
+               copy(maskedNullBitmapBytes, nullBitmapBytes)
+       }
        for i := 0; i < field.Len(); i++ {
                if a.IsNull(i) {
                        bitutil.ClearBit(maskedNullBitmapBytes, i)
@@ -180,7 +186,9 @@ func (a *Struct) 
newStructFieldWithParentValidityMask(fieldIndex int) arrow.Arra
        defer data.Release()
        bufs := make([]*memory.Buffer, len(data.Buffers()))
        copy(bufs, data.buffers)
-       bufs[0].Release()
+       if bufs[0] != nil {
+               bufs[0].Release()
+       }
        bufs[0] = memory.NewBufferBytes(maskedNullBitmapBytes)
        data.buffers = bufs
        maskedField := MakeFromData(data)
diff --git a/arrow/array/struct_test.go b/arrow/array/struct_test.go
index 24f522ed..216b353a 100644
--- a/arrow/array/struct_test.go
+++ b/arrow/array/struct_test.go
@@ -448,6 +448,33 @@ func TestStructArrayNullBitmap(t *testing.T) {
        }
 }
 
+func TestStructArrayStringerMasksRequiredChildWithoutNullBitmap(t *testing.T) {
+       pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+       defer pool.AssertSize(t, 0)
+
+       childData := array.NewData(arrow.PrimitiveTypes.Int32, 3, 
[]*memory.Buffer{
+               nil,
+               memory.NewBufferBytes(arrow.Int32Traits.CastToBytes([]int32{1, 
2, 3})),
+       }, nil, 0, 0)
+       defer childData.Release()
+       child := array.MakeFromData(childData)
+       defer child.Release()
+       require.Empty(t, child.NullBitmapBytes())
+
+       fields := []arrow.Field{
+               {Name: "f1", Type: arrow.PrimitiveTypes.Int32, Nullable: false},
+       }
+       nullBitmap := memory.NewBufferBytes([]byte{0x05})
+
+       arr, err := 
array.NewStructArrayWithFieldsAndNulls([]arrow.Array{child}, fields, 
nullBitmap, 1, 0)
+       require.NoError(t, err)
+       defer arr.Release()
+
+       assert.NotPanics(t, func() {
+               assert.Equal(t, "{[1 (null) 3]}", arr.String())
+       })
+}
+
 func TestStructArrayUnmarshalJSONMissingFields(t *testing.T) {
        pool := memory.NewGoAllocator()
 

Reply via email to