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 9d23a674 fix(array): support dense union slice offsets (#877)
9d23a674 is described below

commit 9d23a674a30f766b93e4ba878ede62a30040588f
Author: Minh Vu <[email protected]>
AuthorDate: Thu Jul 2 19:01:09 2026 +0200

    fix(array): support dense union slice offsets (#877)
    
    Normalize the type-id and offset value buffers to each input array's 
logical window before constructing dense union data, so a dense union can be 
built from type-id and offset arrays that were sliced at different offsets. The 
union is built at offset 0 with zero-copy buffer sharing.
---
 arrow/array/union.go      | 20 ++++++++++++++++++--
 arrow/array/union_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/arrow/array/union.go b/arrow/array/union.go
index d9d18267..f3159242 100644
--- a/arrow/array/union.go
+++ b/arrow/array/union.go
@@ -558,14 +558,30 @@ func NewDenseUnionFromArraysWithFieldCodes(typeIDs, 
offsets arrow.Array, childre
        }
 
        ty := arrow.DenseUnionFromArrays(children, fields, codes)
-       buffers := []*memory.Buffer{nil, typeIDs.Data().Buffers()[1], 
offsets.Data().Buffers()[1]}
+       typeIDBuffer := typeIDs.Data().Buffers()[1]
+       if typeIDBuffer != nil {
+               typeIDBuffer = memory.SliceBuffer(typeIDBuffer,
+                       arrow.Int8Traits.BytesRequired(typeIDs.Data().Offset()),
+                       arrow.Int8Traits.BytesRequired(typeIDs.Len()))
+               defer typeIDBuffer.Release()
+       }
+
+       offsetBuffer := offsets.Data().Buffers()[1]
+       if offsetBuffer != nil {
+               offsetBuffer = memory.SliceBuffer(offsetBuffer,
+                       
arrow.Int32Traits.BytesRequired(offsets.Data().Offset()),
+                       arrow.Int32Traits.BytesRequired(offsets.Len()))
+               defer offsetBuffer.Release()
+       }
+
+       buffers := []*memory.Buffer{nil, typeIDBuffer, offsetBuffer}
 
        childData := make([]arrow.ArrayData, len(children))
        for i, c := range children {
                childData[i] = c.Data()
        }
 
-       data := NewData(ty, typeIDs.Len(), buffers, childData, 0, 
typeIDs.Data().Offset())
+       data := NewData(ty, typeIDs.Len(), buffers, childData, 0, 0)
        defer data.Release()
        return NewDenseUnionData(data), nil
 }
diff --git a/arrow/array/union_test.go b/arrow/array/union_test.go
index 5d975d57..7421b1bc 100644
--- a/arrow/array/union_test.go
+++ b/arrow/array/union_test.go
@@ -471,6 +471,50 @@ func (s *UnionFactorySuite) TestMakeDenseUnions() {
                s.Nil(result)
                s.EqualError(err, "arrow/array: union typeIDs and offsets must 
have the same length")
        })
+
+       s.Run("mismatched type id and offset data offsets", func() {
+               expected, err := array.NewDenseUnionFromArrays(s.typeIDs, 
offsets, children)
+               s.NoError(err)
+               defer expected.Release()
+
+               baseTypeIDs := s.typeidsFromSlice(3, 0, 1, 2, 0, 1, 3, 2, 0, 2, 
1)
+               defer baseTypeIDs.Release()
+               slicedTypeIDs := array.NewSlice(baseTypeIDs, 1, 
int64(baseTypeIDs.Len()))
+               defer slicedTypeIDs.Release()
+
+               result, err := array.NewDenseUnionFromArrays(slicedTypeIDs, 
offsets, children)
+               s.NoError(err)
+               defer result.Release()
+               s.Zero(result.Data().Offset())
+               s.NoError(result.ValidateFull())
+               s.True(array.Equal(expected, result))
+
+               baseOffsets := s.offsetsFromSlice(99, 0, 0, 0, 1, 1, 0, 1, 2, 
1, 2)
+               defer baseOffsets.Release()
+               slicedOffsets := array.NewSlice(baseOffsets, 1, 
int64(baseOffsets.Len()))
+               defer slicedOffsets.Release()
+
+               result, err = array.NewDenseUnionFromArrays(s.typeIDs, 
slicedOffsets, children)
+               s.NoError(err)
+               defer result.Release()
+               s.Zero(result.Data().Offset())
+               s.NoError(result.ValidateFull())
+               s.True(array.Equal(expected, result))
+
+               baseOffsets = s.offsetsFromSlice(-1, -1, 0, 0, 0, 1, 1, 0, 1, 
2, 1, 2)
+               defer baseOffsets.Release()
+               slicedOffsets = array.NewSlice(baseOffsets, 2, 
int64(baseOffsets.Len()))
+               defer slicedOffsets.Release()
+               s.Equal(1, slicedTypeIDs.Data().Offset())
+               s.Equal(2, slicedOffsets.Data().Offset())
+
+               result, err = array.NewDenseUnionFromArrays(slicedTypeIDs, 
slicedOffsets, children)
+               s.NoError(err)
+               defer result.Release()
+               s.Zero(result.Data().Offset())
+               s.NoError(result.ValidateFull())
+               s.True(array.Equal(expected, result))
+       })
 }
 
 func (s *UnionFactorySuite) TestDenseUnionStringRoundTrip() {

Reply via email to