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 0d21f8e4 fix(arrow/scalar): release partial children after failed
struct extraction (#1118)
0d21f8e4 is described below
commit 0d21f8e4ef2a21b0963356f935ed2b16e35bfbe4
Author: Minh Vu <[email protected]>
AuthorDate: Mon Aug 10 19:02:28 2026 +0200
fix(arrow/scalar): release partial children after failed struct extraction
(#1118)
### Rationale for this change
GetScalar can create children before a later Struct child fails
conversion. Returning immediately leaves the children already created on
the error path unreleased.
### What changes are included in this PR?
Release partial children when extraction fails while preserving
ownership for a successfully built struct scalar. The regression test
uses a list child followed by an unsupported view child.
### Are these changes tested?
- `go test ./arrow/scalar`
### Are there any user-facing changes?
No API changes. This corrects the reported behavior while preserving the
existing ownership and compatibility contracts.
---
arrow/scalar/scalar.go | 5 +++++
arrow/scalar/scalar_test.go | 24 ++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/arrow/scalar/scalar.go b/arrow/scalar/scalar.go
index 535eb367..194b11b3 100644
--- a/arrow/scalar/scalar.go
+++ b/arrow/scalar/scalar.go
@@ -677,6 +677,11 @@ func GetScalar(arr arrow.Array, idx int) (Scalar, error) {
for i := range children {
child, err := GetScalar(arr.Field(i), idx)
if err != nil {
+ for _, child := range children[:i] {
+ if releasable, ok :=
child.(Releasable); ok {
+ releasable.Release()
+ }
+ }
return nil, err
}
children[i] = child
diff --git a/arrow/scalar/scalar_test.go b/arrow/scalar/scalar_test.go
index 36557f2f..24cb7ba0 100644
--- a/arrow/scalar/scalar_test.go
+++ b/arrow/scalar/scalar_test.go
@@ -1635,6 +1635,30 @@ func TestGetScalarIndexOutOfRange(t *testing.T) {
assert.ErrorIs(t, err, arrow.ErrIndex)
}
+func TestGetScalarReleasesPartialStructChildrenOnError(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := arrow.StructOf(
+ arrow.Field{Name: "values", Type:
arrow.ListOf(arrow.PrimitiveTypes.Int32)},
+ arrow.Field{Name: "view", Type: arrow.BinaryTypes.StringView},
+ )
+ builder := array.NewStructBuilder(mem, dt)
+ defer builder.Release()
+
+ builder.Append(true)
+ listBuilder := builder.FieldBuilder(0).(*array.ListBuilder)
+ listBuilder.Append(true)
+ listBuilder.ValueBuilder().(*array.Int32Builder).Append(1)
+ builder.FieldBuilder(1).(*array.StringViewBuilder).Append("unsupported")
+
+ arr := builder.NewStructArray()
+ defer arr.Release()
+
+ _, err := scalar.GetScalar(arr, 0)
+ require.Error(t, err)
+}
+
func TestDictionaryScalarValidateErrors(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
defer mem.AssertSize(t, 0)