You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by sb...@apache.org on 2019/04/26 09:44:07 UTC

[arrow] branch master updated: ARROW-5117: [Go] fix panic when nil or empty slices are appended to builders

This is an automated email from the ASF dual-hosted git repository.

sbinet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new 0602142  ARROW-5117: [Go] fix panic when nil or empty slices are appended to builders
0602142 is described below

commit 06021422d10026b397e8d5e00ff6c61ebf88f376
Author: Sebastien Binet <bi...@cern.ch>
AuthorDate: Fri Apr 26 11:43:53 2019 +0200

    ARROW-5117: [Go] fix panic when nil or empty slices are appended to builders
    
    Author: Sebastien Binet <bi...@cern.ch>
    
    Closes #4131 from sbinet/issue-5117 and squashes the following commits:
    
    ed94f049 <Sebastien Binet> arrow/array: rename TestStringArray_Empty into TestStringBuilder_Empty
    bbd0a252 <Sebastien Binet> arrow/array: reorder Append nils in builder tests
    3dcfc56a <Sebastien Binet> array: add tests for binary, boolean, fixedsize and string arrays
    9599df01 <Sebastien Binet> array: generate numeric builder tests
    662d18eb <Sebastien Binet> arrow/array: consistently use defers for builders' Release
    9fc9bd99 <Sebastien Binet> ARROW-5117:  fix panic when nil or empty slices are appended to builders
---
 go/arrow/Makefile                              |    2 +-
 go/arrow/array/binarybuilder.go                |    8 +
 go/arrow/array/booleanbuilder.go               |    4 +
 go/arrow/array/booleanbuilder_test.go          |   45 +
 go/arrow/array/fixedsize_binarybuilder.go      |    4 +
 go/arrow/array/fixedsize_binarybuilder_test.go |   45 +
 go/arrow/array/numericbuilder.gen.go           |  120 +-
 go/arrow/array/numericbuilder.gen.go.tmpl      |    8 +-
 go/arrow/array/numericbuilder.gen_test.go      | 1885 ++++++++++++++++++++++++
 go/arrow/array/numericbuilder.gen_test.go.tmpl |  173 +++
 go/arrow/array/numericbuilder_test.go          |  584 --------
 go/arrow/array/string_test.go                  |   41 +
 12 files changed, 2286 insertions(+), 633 deletions(-)

diff --git a/go/arrow/Makefile b/go/arrow/Makefile
index a1fd225..bd77836 100644
--- a/go/arrow/Makefile
+++ b/go/arrow/Makefile
@@ -30,7 +30,7 @@ assembly:
 	@$(MAKE) -C math assembly
 
 generate: bin/tmpl
-	bin/tmpl -i -data=numeric.tmpldata type_traits_numeric.gen.go.tmpl array/numeric.gen.go.tmpl array/numericbuilder.gen.go.tmpl array/bufferbuilder_numeric.gen.go.tmpl
+	bin/tmpl -i -data=numeric.tmpldata type_traits_numeric.gen.go.tmpl array/numeric.gen.go.tmpl array/numericbuilder.gen_test.go.tmpl  array/numericbuilder.gen.go.tmpl array/bufferbuilder_numeric.gen.go.tmpl
 	bin/tmpl -i -data=datatype_numeric.gen.go.tmpldata datatype_numeric.gen.go.tmpl
 	@$(MAKE) -C math generate
 
diff --git a/go/arrow/array/binarybuilder.go b/go/arrow/array/binarybuilder.go
index c28f968..95945e1 100644
--- a/go/arrow/array/binarybuilder.go
+++ b/go/arrow/array/binarybuilder.go
@@ -95,6 +95,10 @@ func (b *BinaryBuilder) AppendValues(v [][]byte, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
+	if len(v) == 0 {
+		return
+	}
+
 	b.Reserve(len(v))
 	for _, vv := range v {
 		b.appendNextOffset()
@@ -112,6 +116,10 @@ func (b *BinaryBuilder) AppendStringValues(v []string, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
+	if len(v) == 0 {
+		return
+	}
+
 	b.Reserve(len(v))
 	for _, vv := range v {
 		b.appendNextOffset()
diff --git a/go/arrow/array/booleanbuilder.go b/go/arrow/array/booleanbuilder.go
index 28baa9b..943df1f 100644
--- a/go/arrow/array/booleanbuilder.go
+++ b/go/arrow/array/booleanbuilder.go
@@ -85,6 +85,10 @@ func (b *BooleanBuilder) AppendValues(v []bool, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
+	if len(v) == 0 {
+		return
+	}
+
 	b.Reserve(len(v))
 	for i, vv := range v {
 		bitutil.SetBitTo(b.rawData, b.length+i, vv)
diff --git a/go/arrow/array/booleanbuilder_test.go b/go/arrow/array/booleanbuilder_test.go
index 5540c9b..26de4c9 100644
--- a/go/arrow/array/booleanbuilder_test.go
+++ b/go/arrow/array/booleanbuilder_test.go
@@ -43,3 +43,48 @@ func TestBooleanBuilder_AppendValues(t *testing.T) {
 	assert.Equal(t, exp, got)
 	a.Release()
 }
+
+func TestBooleanBuilder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewBooleanBuilder(mem)
+	defer ab.Release()
+
+	want := tools.Bools(1, 1, 0, 1, 1, 0, 1, 0)
+
+	boolValues := func(a *array.Boolean) []bool {
+		vs := make([]bool, a.Len())
+		for i := range vs {
+			vs[i] = a.Value(i)
+		}
+		return vs
+	}
+
+	ab.AppendValues([]bool{}, nil)
+	a := ab.NewBooleanArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewBooleanArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(want, nil)
+	a = ab.NewBooleanArray()
+	assert.Equal(t, want, boolValues(a))
+	a.Release()
+
+	ab.AppendValues([]bool{}, nil)
+	ab.AppendValues(want, nil)
+	a = ab.NewBooleanArray()
+	assert.Equal(t, want, boolValues(a))
+	a.Release()
+
+	ab.AppendValues(want, nil)
+	ab.AppendValues([]bool{}, nil)
+	a = ab.NewBooleanArray()
+	assert.Equal(t, want, boolValues(a))
+	a.Release()
+}
diff --git a/go/arrow/array/fixedsize_binarybuilder.go b/go/arrow/array/fixedsize_binarybuilder.go
index 11a948f..053a192 100644
--- a/go/arrow/array/fixedsize_binarybuilder.go
+++ b/go/arrow/array/fixedsize_binarybuilder.go
@@ -91,6 +91,10 @@ func (b *FixedSizeBinaryBuilder) AppendValues(v [][]byte, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
+	if len(v) == 0 {
+		return
+	}
+
 	b.Reserve(len(v))
 	for _, vv := range v {
 		b.appendNextOffset()
diff --git a/go/arrow/array/fixedsize_binarybuilder_test.go b/go/arrow/array/fixedsize_binarybuilder_test.go
index ce86648..bd0bb5f 100644
--- a/go/arrow/array/fixedsize_binarybuilder_test.go
+++ b/go/arrow/array/fixedsize_binarybuilder_test.go
@@ -68,3 +68,48 @@ func TestFixedSizeBinaryBuilder(t *testing.T) {
 	b.Release()
 	a.Release()
 }
+
+func TestFixedSizeBinaryBuilder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := arrow.FixedSizeBinaryType{ByteWidth: 7}
+	ab := NewFixedSizeBinaryBuilder(mem, &dtype)
+	defer ab.Release()
+
+	want := [][]byte{
+		[]byte("1234567"),
+		[]byte("AZERTYU"),
+		[]byte("7654321"),
+	}
+
+	fixedSizeValues := func(a *FixedSizeBinary) [][]byte {
+		vs := make([][]byte, a.Len())
+		for i := range vs {
+			vs[i] = a.Value(i)
+		}
+		return vs
+	}
+
+	ab.AppendValues([][]byte{}, nil)
+	a := ab.NewFixedSizeBinaryArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewFixedSizeBinaryArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([][]byte{}, nil)
+	ab.AppendValues(want, nil)
+	a = ab.NewFixedSizeBinaryArray()
+	assert.Equal(t, want, fixedSizeValues(a))
+	a.Release()
+
+	ab.AppendValues(want, nil)
+	ab.AppendValues([][]byte{}, nil)
+	a = ab.NewFixedSizeBinaryArray()
+	assert.Equal(t, want, fixedSizeValues(a))
+	a.Release()
+}
diff --git a/go/arrow/array/numericbuilder.gen.go b/go/arrow/array/numericbuilder.gen.go
index 946c5ba..3c9421b 100644
--- a/go/arrow/array/numericbuilder.gen.go
+++ b/go/arrow/array/numericbuilder.gen.go
@@ -89,10 +89,12 @@ func (b *Int64Builder) AppendValues(v []int64, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Int64Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Int64Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -223,10 +225,12 @@ func (b *Uint64Builder) AppendValues(v []uint64, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Uint64Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Uint64Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -357,10 +361,12 @@ func (b *Float64Builder) AppendValues(v []float64, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Float64Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Float64Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -491,10 +497,12 @@ func (b *Int32Builder) AppendValues(v []int32, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Int32Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Int32Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -625,10 +633,12 @@ func (b *Uint32Builder) AppendValues(v []uint32, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Uint32Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Uint32Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -759,10 +769,12 @@ func (b *Float32Builder) AppendValues(v []float32, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Float32Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Float32Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -893,10 +905,12 @@ func (b *Int16Builder) AppendValues(v []int16, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Int16Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Int16Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1027,10 +1041,12 @@ func (b *Uint16Builder) AppendValues(v []uint16, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Uint16Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Uint16Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1161,10 +1177,12 @@ func (b *Int8Builder) AppendValues(v []int8, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Int8Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Int8Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1295,10 +1313,12 @@ func (b *Uint8Builder) AppendValues(v []uint8, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Uint8Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Uint8Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1430,10 +1450,12 @@ func (b *TimestampBuilder) AppendValues(v []arrow.Timestamp, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.TimestampTraits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.TimestampTraits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1565,10 +1587,12 @@ func (b *Time32Builder) AppendValues(v []arrow.Time32, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Time32Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Time32Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1700,10 +1724,12 @@ func (b *Time64Builder) AppendValues(v []arrow.Time64, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Time64Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Time64Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1834,10 +1860,12 @@ func (b *Date32Builder) AppendValues(v []arrow.Date32, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Date32Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Date32Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
@@ -1968,10 +1996,12 @@ func (b *Date64Builder) AppendValues(v []arrow.Date64, valid []bool) {
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.Date64Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.Date64Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
diff --git a/go/arrow/array/numericbuilder.gen.go.tmpl b/go/arrow/array/numericbuilder.gen.go.tmpl
index 5ae3737..e47e9b1 100644
--- a/go/arrow/array/numericbuilder.gen.go.tmpl
+++ b/go/arrow/array/numericbuilder.gen.go.tmpl
@@ -96,10 +96,12 @@ func (b *{{.Name}}Builder) AppendValues(v []{{or .QualifiedType .Type}}, valid [
 		panic("len(v) != len(valid) && len(valid) != 0")
 	}
 
-	b.Reserve(len(v))
-	if len(v) > 0 {
-		arrow.{{.Name}}Traits.Copy(b.rawData[b.length:], v)
+	if len(v) == 0 {
+		return
 	}
+
+	b.Reserve(len(v))
+	arrow.{{.Name}}Traits.Copy(b.rawData[b.length:], v)
 	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
 }
 
diff --git a/go/arrow/array/numericbuilder.gen_test.go b/go/arrow/array/numericbuilder.gen_test.go
new file mode 100644
index 0000000..099629e
--- /dev/null
+++ b/go/arrow/array/numericbuilder.gen_test.go
@@ -0,0 +1,1885 @@
+// Code generated by array/numericbuilder.gen_test.go.tmpl. DO NOT EDIT.
+
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package array_test
+
+import (
+	"testing"
+
+	"github.com/apache/arrow/go/arrow"
+	"github.com/apache/arrow/go/arrow/array"
+	"github.com/apache/arrow/go/arrow/memory"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewInt64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt64Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewInt64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewInt64Array()
+
+	// check state of builder after NewInt64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewInt64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewInt64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewInt64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []int64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Int64Values(), "unexpected Int64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Int64Values(), 10, "unexpected length of Int64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewInt64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []int64{7, 8}, a.Int64Values())
+	assert.Len(t, a.Int64Values(), 2)
+
+	a.Release()
+}
+
+func TestInt64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt64Builder(mem)
+	defer ab.Release()
+
+	exp := []int64{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewInt64Array()
+	assert.Equal(t, exp, a.Int64Values())
+
+	a.Release()
+}
+
+func TestInt64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt64Builder(mem)
+	defer ab.Release()
+
+	exp := []int64{0, 1, 2, 3}
+
+	ab.AppendValues([]int64{}, nil)
+	a := ab.NewInt64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewInt64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]int64{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewInt64Array()
+	assert.Equal(t, exp, a.Int64Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]int64{}, nil)
+	a = ab.NewInt64Array()
+	assert.Equal(t, exp, a.Int64Values())
+	a.Release()
+}
+
+func TestInt64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt64Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewUint64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint64Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewUint64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewUint64Array()
+
+	// check state of builder after NewUint64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewUint64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewUint64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewUint64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []uint64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Uint64Values(), "unexpected Uint64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Uint64Values(), 10, "unexpected length of Uint64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewUint64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []uint64{7, 8}, a.Uint64Values())
+	assert.Len(t, a.Uint64Values(), 2)
+
+	a.Release()
+}
+
+func TestUint64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint64Builder(mem)
+	defer ab.Release()
+
+	exp := []uint64{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewUint64Array()
+	assert.Equal(t, exp, a.Uint64Values())
+
+	a.Release()
+}
+
+func TestUint64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint64Builder(mem)
+	defer ab.Release()
+
+	exp := []uint64{0, 1, 2, 3}
+
+	ab.AppendValues([]uint64{}, nil)
+	a := ab.NewUint64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewUint64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]uint64{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewUint64Array()
+	assert.Equal(t, exp, a.Uint64Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]uint64{}, nil)
+	a = ab.NewUint64Array()
+	assert.Equal(t, exp, a.Uint64Values())
+	a.Release()
+}
+
+func TestUint64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint64Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewFloat64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat64Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewFloat64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewFloat64Array()
+
+	// check state of builder after NewFloat64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewFloat64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewFloat64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewFloat64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []float64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Float64Values(), "unexpected Float64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Float64Values(), 10, "unexpected length of Float64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewFloat64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []float64{7, 8}, a.Float64Values())
+	assert.Len(t, a.Float64Values(), 2)
+
+	a.Release()
+}
+
+func TestFloat64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat64Builder(mem)
+	defer ab.Release()
+
+	exp := []float64{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewFloat64Array()
+	assert.Equal(t, exp, a.Float64Values())
+
+	a.Release()
+}
+
+func TestFloat64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat64Builder(mem)
+	defer ab.Release()
+
+	exp := []float64{0, 1, 2, 3}
+
+	ab.AppendValues([]float64{}, nil)
+	a := ab.NewFloat64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewFloat64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]float64{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewFloat64Array()
+	assert.Equal(t, exp, a.Float64Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]float64{}, nil)
+	a = ab.NewFloat64Array()
+	assert.Equal(t, exp, a.Float64Values())
+	a.Release()
+}
+
+func TestFloat64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat64Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewInt32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt32Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewInt32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewInt32Array()
+
+	// check state of builder after NewInt32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewInt32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewInt32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewInt32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []int32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Int32Values(), "unexpected Int32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Int32Values(), 10, "unexpected length of Int32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewInt32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []int32{7, 8}, a.Int32Values())
+	assert.Len(t, a.Int32Values(), 2)
+
+	a.Release()
+}
+
+func TestInt32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt32Builder(mem)
+	defer ab.Release()
+
+	exp := []int32{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewInt32Array()
+	assert.Equal(t, exp, a.Int32Values())
+
+	a.Release()
+}
+
+func TestInt32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt32Builder(mem)
+	defer ab.Release()
+
+	exp := []int32{0, 1, 2, 3}
+
+	ab.AppendValues([]int32{}, nil)
+	a := ab.NewInt32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewInt32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]int32{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewInt32Array()
+	assert.Equal(t, exp, a.Int32Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]int32{}, nil)
+	a = ab.NewInt32Array()
+	assert.Equal(t, exp, a.Int32Values())
+	a.Release()
+}
+
+func TestInt32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt32Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewUint32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint32Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewUint32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewUint32Array()
+
+	// check state of builder after NewUint32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewUint32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewUint32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewUint32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []uint32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Uint32Values(), "unexpected Uint32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Uint32Values(), 10, "unexpected length of Uint32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewUint32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []uint32{7, 8}, a.Uint32Values())
+	assert.Len(t, a.Uint32Values(), 2)
+
+	a.Release()
+}
+
+func TestUint32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint32Builder(mem)
+	defer ab.Release()
+
+	exp := []uint32{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewUint32Array()
+	assert.Equal(t, exp, a.Uint32Values())
+
+	a.Release()
+}
+
+func TestUint32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint32Builder(mem)
+	defer ab.Release()
+
+	exp := []uint32{0, 1, 2, 3}
+
+	ab.AppendValues([]uint32{}, nil)
+	a := ab.NewUint32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewUint32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]uint32{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewUint32Array()
+	assert.Equal(t, exp, a.Uint32Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]uint32{}, nil)
+	a = ab.NewUint32Array()
+	assert.Equal(t, exp, a.Uint32Values())
+	a.Release()
+}
+
+func TestUint32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint32Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewFloat32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat32Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewFloat32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewFloat32Array()
+
+	// check state of builder after NewFloat32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewFloat32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewFloat32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewFloat32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []float32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Float32Values(), "unexpected Float32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Float32Values(), 10, "unexpected length of Float32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewFloat32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []float32{7, 8}, a.Float32Values())
+	assert.Len(t, a.Float32Values(), 2)
+
+	a.Release()
+}
+
+func TestFloat32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat32Builder(mem)
+	defer ab.Release()
+
+	exp := []float32{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewFloat32Array()
+	assert.Equal(t, exp, a.Float32Values())
+
+	a.Release()
+}
+
+func TestFloat32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat32Builder(mem)
+	defer ab.Release()
+
+	exp := []float32{0, 1, 2, 3}
+
+	ab.AppendValues([]float32{}, nil)
+	a := ab.NewFloat32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewFloat32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]float32{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewFloat32Array()
+	assert.Equal(t, exp, a.Float32Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]float32{}, nil)
+	a = ab.NewFloat32Array()
+	assert.Equal(t, exp, a.Float32Values())
+	a.Release()
+}
+
+func TestFloat32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewFloat32Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewInt16Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt16Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewInt16Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewInt16Array()
+
+	// check state of builder after NewInt16Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewInt16Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewInt16Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewInt16Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []int16{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Int16Values(), "unexpected Int16Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Int16Values(), 10, "unexpected length of Int16Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewInt16Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []int16{7, 8}, a.Int16Values())
+	assert.Len(t, a.Int16Values(), 2)
+
+	a.Release()
+}
+
+func TestInt16Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt16Builder(mem)
+	defer ab.Release()
+
+	exp := []int16{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewInt16Array()
+	assert.Equal(t, exp, a.Int16Values())
+
+	a.Release()
+}
+
+func TestInt16Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt16Builder(mem)
+	defer ab.Release()
+
+	exp := []int16{0, 1, 2, 3}
+
+	ab.AppendValues([]int16{}, nil)
+	a := ab.NewInt16Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewInt16Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]int16{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewInt16Array()
+	assert.Equal(t, exp, a.Int16Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]int16{}, nil)
+	a = ab.NewInt16Array()
+	assert.Equal(t, exp, a.Int16Values())
+	a.Release()
+}
+
+func TestInt16Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt16Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewUint16Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint16Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewUint16Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewUint16Array()
+
+	// check state of builder after NewUint16Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewUint16Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewUint16Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewUint16Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []uint16{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Uint16Values(), "unexpected Uint16Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Uint16Values(), 10, "unexpected length of Uint16Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewUint16Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []uint16{7, 8}, a.Uint16Values())
+	assert.Len(t, a.Uint16Values(), 2)
+
+	a.Release()
+}
+
+func TestUint16Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint16Builder(mem)
+	defer ab.Release()
+
+	exp := []uint16{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewUint16Array()
+	assert.Equal(t, exp, a.Uint16Values())
+
+	a.Release()
+}
+
+func TestUint16Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint16Builder(mem)
+	defer ab.Release()
+
+	exp := []uint16{0, 1, 2, 3}
+
+	ab.AppendValues([]uint16{}, nil)
+	a := ab.NewUint16Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewUint16Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]uint16{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewUint16Array()
+	assert.Equal(t, exp, a.Uint16Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]uint16{}, nil)
+	a = ab.NewUint16Array()
+	assert.Equal(t, exp, a.Uint16Values())
+	a.Release()
+}
+
+func TestUint16Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint16Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewInt8Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt8Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewInt8Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewInt8Array()
+
+	// check state of builder after NewInt8Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewInt8Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewInt8Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewInt8Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []int8{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Int8Values(), "unexpected Int8Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Int8Values(), 10, "unexpected length of Int8Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewInt8Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []int8{7, 8}, a.Int8Values())
+	assert.Len(t, a.Int8Values(), 2)
+
+	a.Release()
+}
+
+func TestInt8Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt8Builder(mem)
+	defer ab.Release()
+
+	exp := []int8{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewInt8Array()
+	assert.Equal(t, exp, a.Int8Values())
+
+	a.Release()
+}
+
+func TestInt8Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt8Builder(mem)
+	defer ab.Release()
+
+	exp := []int8{0, 1, 2, 3}
+
+	ab.AppendValues([]int8{}, nil)
+	a := ab.NewInt8Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewInt8Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]int8{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewInt8Array()
+	assert.Equal(t, exp, a.Int8Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]int8{}, nil)
+	a = ab.NewInt8Array()
+	assert.Equal(t, exp, a.Int8Values())
+	a.Release()
+}
+
+func TestInt8Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewInt8Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewUint8Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint8Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewUint8Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewUint8Array()
+
+	// check state of builder after NewUint8Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewUint8Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewUint8Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewUint8Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []uint8{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Uint8Values(), "unexpected Uint8Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Uint8Values(), 10, "unexpected length of Uint8Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewUint8Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []uint8{7, 8}, a.Uint8Values())
+	assert.Len(t, a.Uint8Values(), 2)
+
+	a.Release()
+}
+
+func TestUint8Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint8Builder(mem)
+	defer ab.Release()
+
+	exp := []uint8{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewUint8Array()
+	assert.Equal(t, exp, a.Uint8Values())
+
+	a.Release()
+}
+
+func TestUint8Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint8Builder(mem)
+	defer ab.Release()
+
+	exp := []uint8{0, 1, 2, 3}
+
+	ab.AppendValues([]uint8{}, nil)
+	a := ab.NewUint8Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewUint8Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]uint8{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewUint8Array()
+	assert.Equal(t, exp, a.Uint8Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]uint8{}, nil)
+	a = ab.NewUint8Array()
+	assert.Equal(t, exp, a.Uint8Values())
+	a.Release()
+}
+
+func TestUint8Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewUint8Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewTimestampBuilder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewTimestampArray
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewTimestampArray()
+
+	// check state of builder after NewTimestampArray
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTimestampArray did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTimestampArray did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTimestampArray did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Timestamp{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.TimestampValues(), "unexpected TimestampValues")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.TimestampValues(), 10, "unexpected length of TimestampValues")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewTimestampArray()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Timestamp{7, 8}, a.TimestampValues())
+	assert.Len(t, a.TimestampValues(), 2)
+
+	a.Release()
+}
+
+func TestTimestampBuilder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Timestamp{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+
+	a.Release()
+}
+
+func TestTimestampBuilder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Timestamp{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	a := ab.NewTimestampArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewTimestampArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	a = ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+	a.Release()
+}
+
+func TestTimestampBuilder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewTime32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time32Type{Unit: arrow.Second}
+	ab := array.NewTime32Builder(mem, dtype)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewTime32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewTime32Array()
+
+	// check state of builder after NewTime32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTime32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTime32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTime32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Time32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Time32Values(), "unexpected Time32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Time32Values(), 10, "unexpected length of Time32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewTime32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Time32{7, 8}, a.Time32Values())
+	assert.Len(t, a.Time32Values(), 2)
+
+	a.Release()
+}
+
+func TestTime32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time32Type{Unit: arrow.Second}
+	ab := array.NewTime32Builder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Time32{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewTime32Array()
+	assert.Equal(t, exp, a.Time32Values())
+
+	a.Release()
+}
+
+func TestTime32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time32Type{Unit: arrow.Second}
+	ab := array.NewTime32Builder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Time32{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Time32{}, nil)
+	a := ab.NewTime32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewTime32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Time32{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewTime32Array()
+	assert.Equal(t, exp, a.Time32Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Time32{}, nil)
+	a = ab.NewTime32Array()
+	assert.Equal(t, exp, a.Time32Values())
+	a.Release()
+}
+
+func TestTime32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time32Type{Unit: arrow.Second}
+	ab := array.NewTime32Builder(mem, dtype)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewTime64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time64Type{Unit: arrow.Second}
+	ab := array.NewTime64Builder(mem, dtype)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewTime64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewTime64Array()
+
+	// check state of builder after NewTime64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTime64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTime64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTime64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Time64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Time64Values(), "unexpected Time64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Time64Values(), 10, "unexpected length of Time64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewTime64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Time64{7, 8}, a.Time64Values())
+	assert.Len(t, a.Time64Values(), 2)
+
+	a.Release()
+}
+
+func TestTime64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time64Type{Unit: arrow.Second}
+	ab := array.NewTime64Builder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Time64{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewTime64Array()
+	assert.Equal(t, exp, a.Time64Values())
+
+	a.Release()
+}
+
+func TestTime64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time64Type{Unit: arrow.Second}
+	ab := array.NewTime64Builder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Time64{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Time64{}, nil)
+	a := ab.NewTime64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewTime64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Time64{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewTime64Array()
+	assert.Equal(t, exp, a.Time64Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Time64{}, nil)
+	a = ab.NewTime64Array()
+	assert.Equal(t, exp, a.Time64Values())
+	a.Release()
+}
+
+func TestTime64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.Time64Type{Unit: arrow.Second}
+	ab := array.NewTime64Builder(mem, dtype)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewDate32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewDate32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewDate32Array()
+
+	// check state of builder after NewDate32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Date32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date32Values(), "unexpected Date32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Date32Values(), 10, "unexpected length of Date32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewDate32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Date32{7, 8}, a.Date32Values())
+	assert.Len(t, a.Date32Values(), 2)
+
+	a.Release()
+}
+
+func TestDate32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+	defer ab.Release()
+
+	exp := []arrow.Date32{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate32Array()
+	assert.Equal(t, exp, a.Date32Values())
+
+	a.Release()
+}
+
+func TestDate32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+	defer ab.Release()
+
+	exp := []arrow.Date32{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Date32{}, nil)
+	a := ab.NewDate32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewDate32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Date32{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewDate32Array()
+	assert.Equal(t, exp, a.Date32Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Date32{}, nil)
+	a = ab.NewDate32Array()
+	assert.Equal(t, exp, a.Date32Values())
+	a.Release()
+}
+
+func TestDate32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+
+func TestNewDate64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewDate64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewDate64Array()
+
+	// check state of builder after NewDate64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Date64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date64Values(), "unexpected Date64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Date64Values(), 10, "unexpected length of Date64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewDate64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Date64{7, 8}, a.Date64Values())
+	assert.Len(t, a.Date64Values(), 2)
+
+	a.Release()
+}
+
+func TestDate64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+	defer ab.Release()
+
+	exp := []arrow.Date64{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate64Array()
+	assert.Equal(t, exp, a.Date64Values())
+
+	a.Release()
+}
+
+func TestDate64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+	defer ab.Release()
+
+	exp := []arrow.Date64{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Date64{}, nil)
+	a := ab.NewDate64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewDate64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Date64{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewDate64Array()
+	assert.Equal(t, exp, a.Date64Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Date64{}, nil)
+	a = ab.NewDate64Array()
+	assert.Equal(t, exp, a.Date64Values())
+	a.Release()
+}
+
+func TestDate64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
diff --git a/go/arrow/array/numericbuilder.gen_test.go.tmpl b/go/arrow/array/numericbuilder.gen_test.go.tmpl
new file mode 100644
index 0000000..ea74536
--- /dev/null
+++ b/go/arrow/array/numericbuilder.gen_test.go.tmpl
@@ -0,0 +1,173 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package array_test
+
+import (
+	"testing"
+
+	"github.com/apache/arrow/go/arrow"
+	"github.com/apache/arrow/go/arrow/array"
+	"github.com/apache/arrow/go/arrow/memory"
+	"github.com/stretchr/testify/assert"
+)
+
+{{range .In}}
+func TestNew{{.Name}}Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+{{if .Opt.Parametric -}}
+	dtype := &arrow.{{.Name}}Type{Unit: arrow.Second}
+	ab := array.New{{.Name}}Builder(mem, dtype)
+{{else}}
+	ab := array.New{{.Name}}Builder(mem)
+{{end -}}
+	defer ab.Release()
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before New{{.Name}}Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.New{{.Name}}Array()
+
+	// check state of builder after New{{.Name}}Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), New{{.Name}}Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), New{{.Name}}Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), New{{.Name}}Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []{{or .QualifiedType .Type}}{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.{{.Name}}Values(), "unexpected {{.Name}}Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.{{.Name}}Values(), 10, "unexpected length of {{.Name}}Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.New{{.Name}}Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []{{or .QualifiedType .Type}}{7, 8}, a.{{.Name}}Values())
+	assert.Len(t, a.{{.Name}}Values(), 2)
+
+	a.Release()
+}
+
+func Test{{.Name}}Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+{{if .Opt.Parametric -}}
+	dtype := &arrow.{{.Name}}Type{Unit: arrow.Second}
+	ab := array.New{{.Name}}Builder(mem, dtype)
+{{else}}
+	ab := array.New{{.Name}}Builder(mem)
+{{end -}}
+	defer ab.Release()
+
+	exp := []{{or .QualifiedType .Type}}{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.New{{.Name}}Array()
+	assert.Equal(t, exp, a.{{.Name}}Values())
+
+	a.Release()
+}
+
+func Test{{.Name}}Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+{{if .Opt.Parametric -}}
+	dtype := &arrow.{{.Name}}Type{Unit: arrow.Second}
+	ab := array.New{{.Name}}Builder(mem, dtype)
+{{else}}
+	ab := array.New{{.Name}}Builder(mem)
+{{end -}}
+	defer ab.Release()
+
+	exp := []{{or .QualifiedType .Type}}{0, 1, 2, 3}
+
+	ab.AppendValues([]{{or .QualifiedType .Type}}{}, nil)
+	a := ab.New{{.Name}}Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.New{{.Name}}Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]{{or .QualifiedType .Type}}{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.New{{.Name}}Array()
+	assert.Equal(t, exp, a.{{.Name}}Values())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]{{or .QualifiedType .Type}}{}, nil)
+	a = ab.New{{.Name}}Array()
+	assert.Equal(t, exp, a.{{.Name}}Values())
+	a.Release()
+}
+
+func Test{{.Name}}Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+{{if .Opt.Parametric -}}
+	dtype := &arrow.{{.Name}}Type{Unit: arrow.Second}
+	ab := array.New{{.Name}}Builder(mem, dtype)
+{{else}}
+	ab := array.New{{.Name}}Builder(mem)
+{{end -}}
+	defer ab.Release()
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+}
+{{end}}
+
+
diff --git a/go/arrow/array/numericbuilder_test.go b/go/arrow/array/numericbuilder_test.go
deleted file mode 100644
index 3bb49a3..0000000
--- a/go/arrow/array/numericbuilder_test.go
+++ /dev/null
@@ -1,584 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package array_test
-
-import (
-	"testing"
-
-	"github.com/apache/arrow/go/arrow"
-	"github.com/apache/arrow/go/arrow/array"
-	"github.com/apache/arrow/go/arrow/memory"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestNewFloat64Builder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewFloat64Builder(mem)
-
-	ab.Append(1)
-	ab.Append(2)
-	ab.Append(3)
-	ab.AppendNull()
-	ab.Append(5)
-	ab.Append(6)
-	ab.AppendNull()
-	ab.Append(8)
-	ab.Append(9)
-	ab.Append(10)
-
-	// check state of builder before NewFloat64Array
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewFloat64Array()
-
-	// check state of builder after NewFloat64Array
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewFloat64Array did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewFloat64Array did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewFloat64Array did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []float64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Float64Values(), "unexpected Float64Values")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.Float64Values(), 10, "unexpected length of Float64Values")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewFloat64Array()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []float64{7, 8}, a.Float64Values())
-	assert.Len(t, a.Float64Values(), 2)
-
-	a.Release()
-}
-
-func TestFloat64Builder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewFloat64Builder(mem)
-
-	exp := []float64{1.0, 1.1, 1.2, 1.3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewFloat64Array()
-	assert.Equal(t, exp, a.Float64Values())
-
-	a.Release()
-	ab.Release()
-}
-
-func TestFloat64Builder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewFloat64Builder(mem)
-
-	exp := []float64{1.0, 1.1, 1.2, 1.3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewFloat64Array()
-	assert.Equal(t, exp, a.Float64Values())
-	a.Release()
-
-	a = ab.NewFloat64Array()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.Release()
-}
-
-func TestFloat64Builder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewFloat64Builder(mem)
-
-	assert.Equal(t, 0, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	ab.Reserve(63)
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	for i := 0; i < 63; i++ {
-		ab.Append(0)
-	}
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 63, ab.Len())
-
-	ab.Resize(5)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Resize(32)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Release()
-}
-
-func TestNewTime32Builder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time32Type{Unit: arrow.Second}
-	ab := array.NewTime32Builder(mem, dtype)
-
-	ab.Append(1)
-	ab.Append(2)
-	ab.Append(3)
-	ab.AppendNull()
-	ab.Append(5)
-	ab.Append(6)
-	ab.AppendNull()
-	ab.Append(8)
-	ab.Append(9)
-	ab.Append(10)
-
-	// check state of builder before NewTime32Array
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewTime32Array()
-
-	// check state of builder after NewTime32Array
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTime32Array did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTime32Array did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTime32Array did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []arrow.Time32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Time32Values(), "unexpected Time32Values")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.Time32Values(), 10, "unexpected length of Time32Values")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewTime32Array()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []arrow.Time32{7, 8}, a.Time32Values())
-	assert.Len(t, a.Time32Values(), 2)
-
-	a.Release()
-}
-
-func TestTime32Builder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time32Type{Unit: arrow.Second}
-	ab := array.NewTime32Builder(mem, dtype)
-
-	exp := []arrow.Time32{0, 1, 2, 3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewTime32Array()
-	assert.Equal(t, exp, a.Time32Values())
-
-	a.Release()
-	ab.Release()
-}
-
-func TestTime32Builder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time32Type{Unit: arrow.Second}
-	ab := array.NewTime32Builder(mem, dtype)
-
-	exp := []arrow.Time32{0, 1, 2, 3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewTime32Array()
-	assert.Equal(t, exp, a.Time32Values())
-	a.Release()
-
-	a = ab.NewTime32Array()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.Release()
-}
-
-func TestTime32Builder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time32Type{Unit: arrow.Second}
-	ab := array.NewTime32Builder(mem, dtype)
-
-	assert.Equal(t, 0, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	ab.Reserve(63)
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	for i := 0; i < 63; i++ {
-		ab.Append(0)
-	}
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 63, ab.Len())
-
-	ab.Resize(5)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Resize(32)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Release()
-}
-
-func TestNewTime64Builder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time64Type{Unit: arrow.Second}
-	ab := array.NewTime64Builder(mem, dtype)
-
-	ab.Append(1)
-	ab.Append(2)
-	ab.Append(3)
-	ab.AppendNull()
-	ab.Append(5)
-	ab.Append(6)
-	ab.AppendNull()
-	ab.Append(8)
-	ab.Append(9)
-	ab.Append(10)
-
-	// check state of builder before NewTime64Array
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewTime64Array()
-
-	// check state of builder after NewTime64Array
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTime64Array did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTime64Array did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTime64Array did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []arrow.Time64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Time64Values(), "unexpected Time64Values")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.Time64Values(), 10, "unexpected length of Time64Values")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewTime64Array()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []arrow.Time64{7, 8}, a.Time64Values())
-	assert.Len(t, a.Time64Values(), 2)
-
-	a.Release()
-}
-
-func TestTime64Builder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time64Type{Unit: arrow.Second}
-	ab := array.NewTime64Builder(mem, dtype)
-
-	exp := []arrow.Time64{0, 1, 2, 3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewTime64Array()
-	assert.Equal(t, exp, a.Time64Values())
-
-	a.Release()
-	ab.Release()
-}
-
-func TestTime64Builder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time64Type{Unit: arrow.Second}
-	ab := array.NewTime64Builder(mem, dtype)
-
-	exp := []arrow.Time64{0, 1, 2, 3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewTime64Array()
-	assert.Equal(t, exp, a.Time64Values())
-	a.Release()
-
-	a = ab.NewTime64Array()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.Release()
-}
-
-func TestTime64Builder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.Time64Type{Unit: arrow.Second}
-	ab := array.NewTime64Builder(mem, dtype)
-
-	assert.Equal(t, 0, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	ab.Reserve(63)
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	for i := 0; i < 63; i++ {
-		ab.Append(0)
-	}
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 63, ab.Len())
-
-	ab.Resize(5)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Resize(32)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Release()
-}
-
-func TestNewDate32Builder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate32Builder(mem)
-
-	ab.Append(1)
-	ab.Append(2)
-	ab.Append(3)
-	ab.AppendNull()
-	ab.Append(5)
-	ab.Append(6)
-	ab.AppendNull()
-	ab.Append(8)
-	ab.Append(9)
-	ab.Append(10)
-
-	// check state of builder before NewDate32Array
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewDate32Array()
-
-	// check state of builder after NewDate32Array
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate32Array did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate32Array did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate32Array did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []arrow.Date32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date32Values(), "unexpected Date32Values")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.Date32Values(), 10, "unexpected length of Date32Values")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewDate32Array()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []arrow.Date32{7, 8}, a.Date32Values())
-	assert.Len(t, a.Date32Values(), 2)
-
-	a.Release()
-}
-
-func TestDate32Builder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate32Builder(mem)
-
-	exp := []arrow.Date32{1, 2, 3, 4}
-	ab.AppendValues(exp, nil)
-	a := ab.NewDate32Array()
-	assert.Equal(t, exp, a.Date32Values())
-
-	a.Release()
-	ab.Release()
-}
-
-func TestDate32Builder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate32Builder(mem)
-
-	exp := []arrow.Date32{1, 2, 3, 4}
-	ab.AppendValues(exp, nil)
-	a := ab.NewDate32Array()
-	assert.Equal(t, exp, a.Date32Values())
-	a.Release()
-
-	a = ab.NewDate32Array()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.Release()
-}
-
-func TestDate32Builder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate32Builder(mem)
-
-	assert.Equal(t, 0, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	ab.Reserve(63)
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	for i := 0; i < 63; i++ {
-		ab.Append(0)
-	}
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 63, ab.Len())
-
-	ab.Resize(5)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Resize(32)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Release()
-}
-
-func TestNewDate64Builder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate64Builder(mem)
-
-	ab.Append(1)
-	ab.Append(2)
-	ab.Append(3)
-	ab.AppendNull()
-	ab.Append(5)
-	ab.Append(6)
-	ab.AppendNull()
-	ab.Append(8)
-	ab.Append(9)
-	ab.Append(10)
-
-	// check state of builder before NewDate64Array
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewDate64Array()
-
-	// check state of builder after NewDate64Array
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate64Array did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate64Array did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate64Array did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []arrow.Date64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date64Values(), "unexpected Date64Values")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.Date64Values(), 10, "unexpected length of Date64Values")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewDate64Array()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []arrow.Date64{7, 8}, a.Date64Values())
-	assert.Len(t, a.Date64Values(), 2)
-
-	a.Release()
-}
-
-func TestDate64Builder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate64Builder(mem)
-
-	exp := []arrow.Date64{1, 2, 3, 4}
-	ab.AppendValues(exp, nil)
-	a := ab.NewDate64Array()
-	assert.Equal(t, exp, a.Date64Values())
-
-	a.Release()
-	ab.Release()
-}
-
-func TestDate64Builder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate64Builder(mem)
-
-	exp := []arrow.Date64{1, 2, 3, 4}
-	ab.AppendValues(exp, nil)
-	a := ab.NewDate64Array()
-	assert.Equal(t, exp, a.Date64Values())
-	a.Release()
-
-	a = ab.NewDate64Array()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.Release()
-}
-
-func TestDate64Builder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	ab := array.NewDate64Builder(mem)
-
-	assert.Equal(t, 0, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	ab.Reserve(63)
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 0, ab.Len())
-
-	for i := 0; i < 63; i++ {
-		ab.Append(0)
-	}
-	assert.Equal(t, 64, ab.Cap())
-	assert.Equal(t, 63, ab.Len())
-
-	ab.Resize(5)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Resize(32)
-	assert.Equal(t, 5, ab.Len())
-
-	ab.Release()
-}
diff --git a/go/arrow/array/string_test.go b/go/arrow/array/string_test.go
index 799277c..016fc74 100644
--- a/go/arrow/array/string_test.go
+++ b/go/arrow/array/string_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/apache/arrow/go/arrow"
 	"github.com/apache/arrow/go/arrow/array"
 	"github.com/apache/arrow/go/arrow/memory"
+	"github.com/stretchr/testify/assert"
 )
 
 func TestStringArray(t *testing.T) {
@@ -95,3 +96,43 @@ func TestStringArray(t *testing.T) {
 		t.Fatalf("got=%q, want=%q", got, want)
 	}
 }
+
+func TestStringBuilder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	want := []string{"hello", "世界", "", "bye"}
+
+	ab := array.NewStringBuilder(mem)
+	defer ab.Release()
+
+	stringValues := func(a *array.String) []string {
+		vs := make([]string, a.Len())
+		for i := range vs {
+			vs[i] = a.Value(i)
+		}
+		return vs
+	}
+
+	ab.AppendValues([]string{}, nil)
+	a := ab.NewStringArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewStringArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]string{}, nil)
+	ab.AppendValues(want, nil)
+	a = ab.NewStringArray()
+	assert.Equal(t, want, stringValues(a))
+	a.Release()
+
+	ab.AppendValues(want, nil)
+	ab.AppendValues([]string{}, nil)
+	a = ab.NewStringArray()
+	assert.Equal(t, want, stringValues(a))
+	a.Release()
+}