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.git
The following commit(s) were added to refs/heads/main by this push:
new 05a57dece1 GH-35421: [Go] Ensure interface contract between
`array.X.ValueStr` & `array.XBuilder.AppendValueFromString` (#35457)
05a57dece1 is described below
commit 05a57dece1d093281fb04e4a0f9a1289ad4ed325
Author: Alex Shcherbakov <[email protected]>
AuthorDate: Mon May 8 23:21:20 2023 +0300
GH-35421: [Go] Ensure interface contract between `array.X.ValueStr` &
`array.XBuilder.AppendValueFromString` (#35457)
### Rationale for this change
I noticed that some values produced by `array.X.ValueStr` can't be parsed
back by `array.XBuilder.AppendValueFromString` while debugging
https://github.com/cloudquery/cloudquery/pull/10284.
Additionally, some arrays didn't implement the corresponding functions at
all.
### What changes are included in this PR?
* Ensure interface contract
* Use `array.NullValueStr` constant
* Fix bugs found along the way
* Synced `internal/types/UUID` with CQ implementation to account for
`valid` param
### Are these changes tested?
This code was developed in TDD mode. The changes workflow was:
1. Introduce `XStringRoundTrip` tests to test that the resulting array will
be equal in the Arrow sense (using
[`array.Equal`](https://pkg.go.dev/github.com/apache/arrow/go/v12/arrow/array#Equal))
2. Fix any discrepancies
### Are there any user-facing changes?
Some fixes to the accepted values & parse logic to correspond to the
interface contract.
* Closes: #35421
Authored-by: candiduslynx <[email protected]>
Signed-off-by: Matt Topol <[email protected]>
---
.gitignore | 2 +-
go/arrow/array/array.go | 4 +
go/arrow/array/binary.go | 8 +-
go/arrow/array/binary_test.go | 42 +-
go/arrow/array/binarybuilder.go | 19 +-
go/arrow/array/binarybuilder_test.go | 1 -
go/arrow/array/boolean.go | 2 +-
go/arrow/array/boolean_test.go | 32 +-
go/arrow/array/booleanbuilder_test.go | 4 +-
go/arrow/array/decimal128.go | 6 +-
go/arrow/array/decimal128_test.go | 44 +-
go/arrow/array/decimal256.go | 6 +-
go/arrow/array/decimal256_test.go | 44 +-
go/arrow/array/dictionary.go | 26 +-
go/arrow/array/dictionary_test.go | 68 ++-
go/arrow/array/encoded.go | 62 ++-
go/arrow/array/encoded_test.go | 45 ++
go/arrow/array/fixed_size_list.go | 9 +-
go/arrow/array/fixed_size_list_test.go | 41 +-
go/arrow/array/fixedsize_binary.go | 2 +-
go/arrow/array/fixedsize_binary_test.go | 35 ++
go/arrow/array/float16.go | 9 +-
go/arrow/array/float16_builder_test.go | 38 +-
go/arrow/array/interval.go | 25 +-
go/arrow/array/interval_test.go | 107 +++++
go/arrow/array/list.go | 13 +-
go/arrow/array/list_test.go | 84 ++++
go/arrow/array/map.go | 4 +-
go/arrow/array/map_test.go | 45 ++
go/arrow/array/null.go | 9 +-
go/arrow/array/null_test.go | 29 ++
go/arrow/array/numeric.gen.go | 32 +-
go/arrow/array/numeric.gen.go.tmpl | 2 +-
go/arrow/array/numericbuilder.gen.go | 7 +-
go/arrow/array/numericbuilder.gen.go.tmpl | 11 +-
go/arrow/array/numericbuilder.gen_test.go | 594 ++++++++++++++++++++++++-
go/arrow/array/numericbuilder.gen_test.go.tmpl | 65 ++-
go/arrow/array/string.go | 22 +-
go/arrow/array/string_test.go | 64 +++
go/arrow/array/struct.go | 21 +-
go/arrow/array/struct_test.go | 42 +-
go/arrow/array/union.go | 66 ++-
go/arrow/array/union_test.go | 88 +++-
go/arrow/csv/reader_test.go | 4 +-
go/arrow/example_test.go | 6 +-
go/arrow/math/float64_arm64.go | 5 +-
go/arrow/math/float64_neon_arm64.go | 3 +-
go/arrow/math/float64_noasm.go | 1 +
go/arrow/math/float64_ppc64le.go | 3 +-
go/arrow/math/float64_s390x.go | 1 +
go/arrow/math/int64_arm64.go | 5 +-
go/arrow/math/int64_neon_arm64.go | 3 +-
go/arrow/math/int64_noasm.go | 1 +
go/arrow/math/int64_ppc64le.go | 3 +-
go/arrow/math/int64_s390x.go | 1 +
go/arrow/math/uint64_arm64.go | 5 +-
go/arrow/math/uint64_neon_arm64.go | 3 +-
go/arrow/math/uint64_noasm.go | 1 +
go/arrow/math/uint64_ppc64le.go | 3 +-
go/arrow/math/uint64_s390x.go | 1 +
go/internal/types/extension_types.go | 184 ++++----
go/internal/types/extension_types_test.go | 33 ++
62 files changed, 1899 insertions(+), 246 deletions(-)
diff --git a/.gitignore b/.gitignore
index 7db35b0ca3..5ab2313829 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,4 +94,4 @@ dev/archery/build
swift/Arrow/.build
# Go dependencies
-go/vendor
\ No newline at end of file
+go/vendor
diff --git a/go/arrow/array/array.go b/go/arrow/array/array.go
index 1cca0d2633..83273211f6 100644
--- a/go/arrow/array/array.go
+++ b/go/arrow/array/array.go
@@ -27,6 +27,10 @@ import (
const (
// UnknownNullCount specifies the NullN should be calculated from the
null bitmap buffer.
UnknownNullCount = -1
+
+ // NullValueStr represents a null value in arrow.Array.ValueStr and in
Builder.AppendValueFromString.
+ // It should be returned from the arrow.Array.ValueStr implementations.
+ // Using it as the value in Builder.AppendValueFromString should be
equivalent to Builder.AppendNull.
NullValueStr = "(null)"
)
diff --git a/go/arrow/array/binary.go b/go/arrow/array/binary.go
index 8db30bf52a..787059f071 100644
--- a/go/arrow/array/binary.go
+++ b/go/arrow/array/binary.go
@@ -57,7 +57,7 @@ func (a *Binary) Value(i int) []byte {
return a.valueBytes[a.valueOffsets[idx]:a.valueOffsets[idx+1]]
}
-// ValueString returns the string at index i
+// ValueStr returns a copy of the base64-encoded string value or NullValueStr
func (a *Binary) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
@@ -65,7 +65,7 @@ func (a *Binary) ValueStr(i int) string {
return base64.StdEncoding.EncodeToString(a.Value(i))
}
-// ValueStr returns the string at index i without performing additional
allocations.
+// ValueString returns the string at index i without performing additional
allocations.
// The string is only valid for the lifetime of the Binary array.
func (a *Binary) ValueString(i int) string {
b := a.Value(i)
@@ -112,7 +112,7 @@ func (a *Binary) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%q", a.ValueString(i))
}
@@ -251,7 +251,7 @@ func (a *LargeBinary) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(&o, "%q", a.ValueString(i))
}
diff --git a/go/arrow/array/binary_test.go b/go/arrow/array/binary_test.go
index 863013fa7b..b1dd5a5358 100644
--- a/go/arrow/array/binary_test.go
+++ b/go/arrow/array/binary_test.go
@@ -20,11 +20,10 @@ import (
"reflect"
"testing"
- "github.com/stretchr/testify/assert"
-
"github.com/apache/arrow/go/v13/arrow"
"github.com/apache/arrow/go/v13/arrow/bitutil"
"github.com/apache/arrow/go/v13/arrow/memory"
+ "github.com/stretchr/testify/assert"
)
func TestBinary(t *testing.T) {
@@ -51,7 +50,7 @@ func TestBinary(t *testing.T) {
assert.Equal(t, []byte{}, a.Value(1))
assert.Equal(t, []byte("BBBB"), a.Value(2))
assert.Equal(t, "QUFB", a.ValueStr(0))
- assert.Equal(t, "(null)", a.ValueStr(1))
+ assert.Equal(t, NullValueStr, a.ValueStr(1))
a.Release()
// Test builder reset and NewArray API.
@@ -63,7 +62,7 @@ func TestBinary(t *testing.T) {
assert.Equal(t, []byte{}, a.Value(1))
assert.Equal(t, []byte("BBBB"), a.Value(2))
assert.Equal(t, "QUFB", a.ValueStr(0))
- assert.Equal(t, "(null)", a.ValueStr(1))
+ assert.Equal(t, NullValueStr, a.ValueStr(1))
a.Release()
b.Release()
@@ -97,7 +96,7 @@ func TestLargeBinary(t *testing.T) {
assert.Equal(t, []byte{}, a.Value(1))
assert.Equal(t, []byte("BBBB"), a.Value(2))
assert.Equal(t, "QUFB", a.ValueStr(0))
- assert.Equal(t, "(null)", a.ValueStr(1))
+ assert.Equal(t, NullValueStr, a.ValueStr(1))
a.Release()
// Test builder reset and NewArray API.
@@ -109,7 +108,7 @@ func TestLargeBinary(t *testing.T) {
assert.Equal(t, []byte{}, a.Value(1))
assert.Equal(t, []byte("BBBB"), a.Value(2))
assert.Equal(t, "QUFB", a.ValueStr(0))
- assert.Equal(t, "(null)", a.ValueStr(1))
+ assert.Equal(t, NullValueStr, a.ValueStr(1))
a.Release()
b.Release()
@@ -670,3 +669,34 @@ func TestBinaryInvalidOffsets(t *testing.T) {
NewBinaryData(NewData(arrow.BinaryTypes.Binary, 1, buffers,
nil, 0, 2))
}, "data has offset and value offset is overflowing")
}
+
+func TestBinaryStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ values := []string{"a", "bc", "", "", "hijk", "lm", "", "opq", "", "tu"}
+ valid := []bool{true, true, false, false, true, true, true, true,
false, true}
+
+ b := NewBinaryBuilder(mem, arrow.BinaryTypes.Binary)
+ defer b.Release()
+
+ b.AppendStringValues(values, valid)
+
+ arr := b.NewArray().(*Binary)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+
+ b1 := NewBinaryBuilder(mem, arrow.BinaryTypes.Binary)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*Binary)
+ defer arr1.Release()
+
+ assert.True(t, Equal(arr, arr1))
+}
diff --git a/go/arrow/array/binarybuilder.go b/go/arrow/array/binarybuilder.go
index 955f0d0744..f86dae8504 100644
--- a/go/arrow/array/binarybuilder.go
+++ b/go/arrow/array/binarybuilder.go
@@ -294,18 +294,17 @@ func (b *BinaryBuilder) AppendValueFromString(s string)
error {
b.AppendNull()
return nil
}
- switch b.dtype.ID() {
- case arrow.BINARY, arrow.LARGE_BINARY:
- decodedVal, err := base64.StdEncoding.DecodeString(s)
- if err != nil {
- return fmt.Errorf("could not decode base64 string: %w",
err)
- }
- b.Append(decodedVal)
- case arrow.STRING, arrow.LARGE_STRING:
+
+ if b.dtype.IsUtf8() {
b.Append([]byte(s))
- default:
- return fmt.Errorf("cannot append string to type %s", b.dtype)
+ return nil
+ }
+
+ decodedVal, err := base64.StdEncoding.DecodeString(s)
+ if err != nil {
+ return fmt.Errorf("could not decode base64 string: %w", err)
}
+ b.Append(decodedVal)
return nil
}
diff --git a/go/arrow/array/binarybuilder_test.go
b/go/arrow/array/binarybuilder_test.go
index b22b4f9a0f..48dce6aca4 100644
--- a/go/arrow/array/binarybuilder_test.go
+++ b/go/arrow/array/binarybuilder_test.go
@@ -38,7 +38,6 @@ func TestBinaryBuilder(t *testing.T) {
ab.AppendNull()
} else {
ab.Append(v)
-
}
}
diff --git a/go/arrow/array/boolean.go b/go/arrow/array/boolean.go
index b7bfaf5e77..0ad9c9b067 100644
--- a/go/arrow/array/boolean.go
+++ b/go/arrow/array/boolean.go
@@ -73,7 +73,7 @@ func (a *Boolean) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", a.Value(i))
}
diff --git a/go/arrow/array/boolean_test.go b/go/arrow/array/boolean_test.go
index 5cc1cc775c..48b127ae9f 100644
--- a/go/arrow/array/boolean_test.go
+++ b/go/arrow/array/boolean_test.go
@@ -288,5 +288,35 @@ func TestBooleanStringer(t *testing.T) {
}
assert.Equal(t, "true", arr.ValueStr(0))
assert.Equal(t, "false", arr.ValueStr(1))
- assert.Equal(t, "(null)", arr.ValueStr(2))
+ assert.Equal(t, array.NullValueStr, arr.ValueStr(2))
+}
+
+func TestBooleanStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ values := []bool{true, false, true, true, true, true, true, false,
true, false}
+ valid := []bool{true, false, false, true, false, true, true, false,
true, false}
+
+ b := array.NewBooleanBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.Boolean)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewBooleanBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Boolean)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
}
diff --git a/go/arrow/array/booleanbuilder_test.go
b/go/arrow/array/booleanbuilder_test.go
index 1fa75c7812..ef7064163e 100644
--- a/go/arrow/array/booleanbuilder_test.go
+++ b/go/arrow/array/booleanbuilder_test.go
@@ -32,7 +32,7 @@ func TestBooleanBuilder_AppendValues(t *testing.T) {
b := array.NewBooleanBuilder(mem)
exp := tools.Bools(1, 1, 0, 1, 1, 0)
- got := make([]bool, len(exp) + 2)
+ got := make([]bool, len(exp)+2)
b.AppendValues(exp, nil)
assert.NoError(t, b.AppendValueFromString("true"))
@@ -44,7 +44,7 @@ func TestBooleanBuilder_AppendValues(t *testing.T) {
got[i] = a.Value(i)
}
assert.Equal(t, exp, got)
-
+
a.Release()
}
diff --git a/go/arrow/array/decimal128.go b/go/arrow/array/decimal128.go
index 13b5fe5c41..f943e0c3da 100644
--- a/go/arrow/array/decimal128.go
+++ b/go/arrow/array/decimal128.go
@@ -48,12 +48,12 @@ func NewDecimal128Data(data arrow.ArrayData) *Decimal128 {
}
func (a *Decimal128) Value(i int) decimal128.Num { return a.values[i] }
+
func (a *Decimal128) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
- } else {
- return a.GetOneForMarshal(i).(string)
}
+ return a.GetOneForMarshal(i).(string)
}
func (a *Decimal128) Values() []decimal128.Num { return a.values }
@@ -67,7 +67,7 @@ func (a *Decimal128) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", a.Value(i))
}
diff --git a/go/arrow/array/decimal128_test.go
b/go/arrow/array/decimal128_test.go
index bca928c991..da2c57e93c 100644
--- a/go/arrow/array/decimal128_test.go
+++ b/go/arrow/array/decimal128_test.go
@@ -171,7 +171,7 @@ func TestDecimal128Slice(t *testing.T) {
if got, want := v.String(), `[(null) {4 -4}]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
- assert.Equal(t, "(null)", v.ValueStr(0))
+ assert.Equal(t, array.NullValueStr, v.ValueStr(0))
assert.Equal(t, "-7.378697629e+18", v.ValueStr(1))
if got, want := v.NullN(), 1; got != want {
@@ -182,3 +182,45 @@ func TestDecimal128Slice(t *testing.T) {
t.Fatalf("invalid offset: got=%d, want=%d", got, want)
}
}
+
+func TestDecimal128StringRoundTrip(t *testing.T) {
+ dt := &arrow.Decimal128Type{Precision: 20, Scale: 5}
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewDecimal128Builder(mem, dt)
+ defer b.Release()
+
+ values := []decimal128.Num{
+ decimal128.New(1, 1),
+ decimal128.New(1, 2),
+ decimal128.New(1, 3),
+ {},
+ decimal128.FromI64(-5),
+ decimal128.FromI64(-6),
+ {},
+ decimal128.FromI64(8),
+ decimal128.FromI64(9),
+ decimal128.FromI64(10),
+ }
+ valid := []bool{true, true, true, false, true, true, false, true, true,
true}
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.Decimal128)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDecimal128Builder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Decimal128)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/decimal256.go b/go/arrow/array/decimal256.go
index 8273cb0825..8cd4476030 100644
--- a/go/arrow/array/decimal256.go
+++ b/go/arrow/array/decimal256.go
@@ -48,12 +48,12 @@ func NewDecimal256Data(data arrow.ArrayData) *Decimal256 {
}
func (a *Decimal256) Value(i int) decimal256.Num { return a.values[i] }
+
func (a *Decimal256) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
- } else {
- return a.GetOneForMarshal(i).(string)
}
+ return a.GetOneForMarshal(i).(string)
}
func (a *Decimal256) Values() []decimal256.Num { return a.values }
@@ -67,7 +67,7 @@ func (a *Decimal256) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", a.Value(i))
}
diff --git a/go/arrow/array/decimal256_test.go
b/go/arrow/array/decimal256_test.go
index 3441c9eba2..6fa2858d59 100644
--- a/go/arrow/array/decimal256_test.go
+++ b/go/arrow/array/decimal256_test.go
@@ -172,7 +172,7 @@ func TestDecimal256Slice(t *testing.T) {
if got, want := v.String(), `[(null) {[4 4 4 4]}]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
- assert.Equal(t, "(null)", v.ValueStr(0))
+ assert.Equal(t, array.NullValueStr, v.ValueStr(0))
assert.Equal(t, "2.510840694e+57", v.ValueStr(1))
if got, want := v.NullN(), 1; got != want {
@@ -183,3 +183,45 @@ func TestDecimal256Slice(t *testing.T) {
t.Fatalf("invalid offset: got=%d, want=%d", got, want)
}
}
+
+func TestDecimal256StringRoundTrip(t *testing.T) {
+ dt := &arrow.Decimal256Type{Precision: 70, Scale: 10}
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewDecimal256Builder(mem, dt)
+ defer b.Release()
+
+ values := []decimal256.Num{
+ decimal256.New(1, 1, 1, 1),
+ decimal256.New(2, 2, 2, 2),
+ decimal256.New(3, 3, 3, 3),
+ {},
+ decimal256.FromI64(-5),
+ decimal256.FromI64(-6),
+ {},
+ decimal256.FromI64(8),
+ decimal256.FromI64(9),
+ decimal256.FromI64(10),
+ }
+ valid := []bool{true, true, true, false, true, true, false, true, true,
true}
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.Decimal256)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDecimal256Builder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Decimal256)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/dictionary.go b/go/arrow/array/dictionary.go
index 6cf3fb2e5c..1b0de34b8e 100644
--- a/go/arrow/array/dictionary.go
+++ b/go/arrow/array/dictionary.go
@@ -254,6 +254,9 @@ func (d *Dictionary) CanCompareIndices(other *Dictionary)
bool {
}
func (d *Dictionary) ValueStr(i int) string {
+ if d.IsNull(i) {
+ return NullValueStr
+ }
return d.Dictionary().ValueStr(d.GetValueIndex(i))
}
@@ -713,7 +716,6 @@ func (b *dictionaryBuilder) ResetFull() {
func (b *dictionaryBuilder) Cap() int { return b.idxBuilder.Cap() }
-// UnmarshalJSON is not yet implemented for dictionary builders and will
always error.
func (b *dictionaryBuilder) UnmarshalJSON(data []byte) error {
dec := json.NewDecoder(bytes.NewReader(data))
t, err := dec.Token()
@@ -742,11 +744,29 @@ func (b *dictionaryBuilder) Unmarshal(dec *json.Decoder)
error {
}
func (b *dictionaryBuilder) AppendValueFromString(s string) error {
- return fmt.Errorf("%w: AppendValueFromString to dictionary not yet
implemented", arrow.ErrNotImplemented)
+ bldr := NewBuilder(b.mem, b.dt.ValueType)
+ defer bldr.Release()
+
+ if err := bldr.AppendValueFromString(s); err != nil {
+ return err
+ }
+
+ arr := bldr.NewArray()
+ defer arr.Release()
+ return b.AppendArray(arr)
}
func (b *dictionaryBuilder) UnmarshalOne(dec *json.Decoder) error {
- return errors.New("unmarshal json to dictionary not yet implemented")
+ bldr := NewBuilder(b.mem, b.dt.ValueType)
+ defer bldr.Release()
+
+ if err := bldr.UnmarshalOne(dec); err != nil {
+ return err
+ }
+
+ arr := bldr.NewArray()
+ defer arr.Release()
+ return b.AppendArray(arr)
}
func (b *dictionaryBuilder) NewArray() arrow.Array {
diff --git a/go/arrow/array/dictionary_test.go
b/go/arrow/array/dictionary_test.go
index 47e5fa7528..7758c82c45 100644
--- a/go/arrow/array/dictionary_test.go
+++ b/go/arrow/array/dictionary_test.go
@@ -385,6 +385,39 @@ func (p *PrimitiveDictionaryTestSuite) TestResetFull() {
p.True(array.ArrayEqual(exdict, result.Dictionary()))
}
+func (p *PrimitiveDictionaryTestSuite) TestStringRoundTrip() {
+ dt := &arrow.DictionaryType{IndexType: &arrow.Int8Type{}, ValueType:
p.typ}
+ b := array.NewDictionaryBuilder(p.mem, dt)
+ defer b.Release()
+
+ builder := reflect.ValueOf(b)
+ fn := builder.MethodByName("Append")
+
p.Nil(fn.Call([]reflect.Value{reflect.ValueOf(1).Convert(p.reftyp)})[0].Interface())
+
p.Nil(fn.Call([]reflect.Value{reflect.ValueOf(2).Convert(p.reftyp)})[0].Interface())
+
p.Nil(fn.Call([]reflect.Value{reflect.ValueOf(1).Convert(p.reftyp)})[0].Interface())
+ b.AppendNull()
+
+ p.EqualValues(4, b.Len())
+ p.EqualValues(1, b.NullN())
+
+ arr := b.NewArray().(*array.Dictionary)
+ defer arr.Release()
+ p.True(arrow.TypeEqual(dt, arr.DataType()))
+
+ b1 := array.NewDictionaryBuilder(p.mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ p.NoError(b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Dictionary)
+ defer arr1.Release()
+
+ p.Equal(arr.Len(), arr1.Len())
+ p.True(array.Equal(arr, arr1))
+}
+
func TestBasicStringDictionaryBuilder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
defer mem.AssertSize(t, 0)
@@ -808,6 +841,39 @@ func TestFixedSizeBinaryDictionaryBuilderDeltaDictionary(t
*testing.T) {
assert.True(t, array.ArrayEqual(fsbArr2, delta2))
}
+func TestFixedSizeBinaryDictionaryStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
+ defer mem.AssertSize(t, 0)
+
+ dictType := &arrow.DictionaryType{IndexType: &arrow.Int8Type{},
ValueType: &arrow.FixedSizeBinaryType{ByteWidth: 4}}
+ b := array.NewDictionaryBuilder(mem, dictType)
+ defer b.Release()
+
+ builder := b.(*array.FixedSizeBinaryDictionaryBuilder)
+ test := []byte{12, 12, 11, 12}
+ test2 := []byte{12, 12, 11, 11}
+ assert.NoError(t, builder.Append(test))
+ assert.NoError(t, builder.Append(test2))
+ assert.NoError(t, builder.Append(test))
+
+ arr := builder.NewDictionaryArray()
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDictionaryBuilder(mem, dictType)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Dictionary)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestDecimalDictionaryBuilderBasic(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
defer mem.AssertSize(t, 0)
@@ -1624,7 +1690,7 @@ func TestDictionaryUnifierChunkedArrayNestedDict(t
*testing.T) {
assert.EqualError(t, err, "unimplemented dictionary value type,
list<item: dictionary<values=utf8, indices=uint32, ordered=false>, nullable>")
}
-func TestDictioanryUnifierTableZeroColumns(t *testing.T) {
+func TestDictionaryUnifierTableZeroColumns(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
defer mem.AssertSize(t, 0)
diff --git a/go/arrow/array/encoded.go b/go/arrow/array/encoded.go
index d9cbc0980a..5e9fa65259 100644
--- a/go/arrow/array/encoded.go
+++ b/go/arrow/array/encoded.go
@@ -21,7 +21,6 @@ import (
"fmt"
"math"
"reflect"
- "strings"
"sync/atomic"
"github.com/apache/arrow/go/v13/arrow"
@@ -193,15 +192,19 @@ func (r *RunEndEncoded) GetPhysicalLength() int {
return encoded.GetPhysicalLength(r.data)
}
+// GetPhysicalIndex can be used to get the run-encoded value instead of costly
LogicalValuesArray
+// in the following way:
+//
+// r.Values().(valuetype).Value(r.GetPhysicalIndex(i))
+func (r *RunEndEncoded) GetPhysicalIndex(i int) int {
+ return encoded.FindPhysicalIndex(r.data, i+r.data.offset)
+}
+
+// ValueStr will return the str representation of the value at the logical
offset i.
func (r *RunEndEncoded) ValueStr(i int) string {
- value := r.values.GetOneForMarshal(i)
- if byts, ok := value.(json.RawMessage); ok {
- value = string(byts)
- }
- return fmt.Sprintf("{%d -> %v}",
- r.ends.GetOneForMarshal(i),
- value)
+ return r.values.ValueStr(r.GetPhysicalIndex(i))
}
+
func (r *RunEndEncoded) String() string {
var buf bytes.Buffer
buf.WriteByte('[')
@@ -214,9 +217,7 @@ func (r *RunEndEncoded) String() string {
if byts, ok := value.(json.RawMessage); ok {
value = string(byts)
}
- fmt.Fprintf(&buf, "{%d -> %v}",
- r.ends.GetOneForMarshal(i),
- value)
+ fmt.Fprintf(&buf, "{%d -> %v}", r.ends.GetOneForMarshal(i),
value)
}
buf.WriteByte(']')
@@ -224,8 +225,7 @@ func (r *RunEndEncoded) String() string {
}
func (r *RunEndEncoded) GetOneForMarshal(i int) interface{} {
- physIndex := encoded.FindPhysicalIndex(r.data, i+r.data.offset)
- return r.values.GetOneForMarshal(physIndex)
+ return r.values.GetOneForMarshal(r.GetPhysicalIndex(i))
}
func (r *RunEndEncoded) MarshalJSON() ([]byte, error) {
@@ -280,7 +280,10 @@ type RunEndEncodedBuilder struct {
values Builder
maxRunEnd uint64
+ // currently, mixing AppendValueFromString & UnmarshalOne is unsupported
lastUnmarshalled interface{}
+ unmarshalled bool // tracks if Unmarshal was called (in case
lastUnmarshalled is nil)
+ lastStr *string
}
func NewRunEndEncodedBuilder(mem memory.Allocator, runEnds, encoded
arrow.DataType) *RunEndEncodedBuilder {
@@ -331,6 +334,8 @@ func (b *RunEndEncodedBuilder) addLength(n uint64) {
func (b *RunEndEncodedBuilder) finishRun() {
b.lastUnmarshalled = nil
+ b.lastStr = nil
+ b.unmarshalled = false
if b.length == 0 {
return
}
@@ -407,12 +412,36 @@ func (b *RunEndEncodedBuilder) newData() (data *Data) {
return
}
+// AppendValueFromString can't be used in conjunction with UnmarshalOne
func (b *RunEndEncodedBuilder) AppendValueFromString(s string) error {
- dec := json.NewDecoder(strings.NewReader(s))
- return b.UnmarshalOne(dec)
+ // we don't support mixing AppendValueFromString & UnmarshalOne
+ if b.unmarshalled {
+ return fmt.Errorf("%w: mixing AppendValueFromString &
UnmarshalOne not yet implemented", arrow.ErrNotImplemented)
+ }
+
+ if s == NullValueStr {
+ b.AppendNull()
+ return nil
+ }
+
+ if b.lastStr != nil && s == *b.lastStr {
+ b.ContinueRun(1)
+ return nil
+ }
+
+ b.Append(1)
+ lastStr := s
+ b.lastStr = &lastStr
+ return b.ValueBuilder().AppendValueFromString(s)
}
+// UnmarshalOne can't be used in conjunction with AppendValueFromString
func (b *RunEndEncodedBuilder) UnmarshalOne(dec *json.Decoder) error {
+ // we don't support mixing AppendValueFromString & UnmarshalOne
+ if b.lastStr != nil {
+ return fmt.Errorf("%w: mixing AppendValueFromString &
UnmarshalOne not yet implemented", arrow.ErrNotImplemented)
+ }
+
var value interface{}
if err := dec.Decode(&value); err != nil {
return err
@@ -437,9 +466,11 @@ func (b *RunEndEncodedBuilder) UnmarshalOne(dec
*json.Decoder) error {
b.Append(1)
b.lastUnmarshalled = value
+ b.unmarshalled = true
return
b.ValueBuilder().UnmarshalOne(json.NewDecoder(bytes.NewReader(data)))
}
+// Unmarshal can't be used in conjunction with AppendValueFromString (as it
calls UnmarshalOne)
func (b *RunEndEncodedBuilder) Unmarshal(dec *json.Decoder) error {
b.finishRun()
for dec.More() {
@@ -450,6 +481,7 @@ func (b *RunEndEncodedBuilder) Unmarshal(dec *json.Decoder)
error {
return nil
}
+// UnmarshalJSON can't be used in conjunction with AppendValueFromString (as
it calls UnmarshalOne)
func (b *RunEndEncodedBuilder) UnmarshalJSON(data []byte) error {
dec := json.NewDecoder(bytes.NewReader(data))
t, err := dec.Token()
diff --git a/go/arrow/array/encoded_test.go b/go/arrow/array/encoded_test.go
index c24b71cc5f..c8be6d193a 100644
--- a/go/arrow/array/encoded_test.go
+++ b/go/arrow/array/encoded_test.go
@@ -253,6 +253,51 @@ func TestRunEndEncodedBuilder(t *testing.T) {
assert.Equal(t, "Hello", strValues.ValueStr(0))
}
+func TestRunEndEncodedStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewRunEndEncodedBuilder(mem, arrow.PrimitiveTypes.Int16,
arrow.BinaryTypes.String)
+ defer b.Release()
+
+ valBldr := b.ValueBuilder().(*array.StringBuilder)
+
+ b.Append(100)
+ valBldr.Append("Hello")
+ b.Append(100)
+ valBldr.Append("beautiful")
+ b.Append(50)
+ valBldr.Append("world")
+ b.ContinueRun(50)
+ b.Append(100)
+ valBldr.Append("of")
+ b.Append(100)
+ valBldr.Append("RLE")
+ b.AppendNull()
+
+ arr := b.NewArray().(*array.RunEndEncoded)
+ defer arr.Release()
+ logical := arr.LogicalValuesArray()
+ defer logical.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewRunEndEncodedBuilder(mem, arrow.PrimitiveTypes.Int16,
arrow.BinaryTypes.String)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.RunEndEncoded)
+ defer arr1.Release()
+ logical1 := arr1.LogicalValuesArray()
+ defer logical1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+ assert.True(t, array.Equal(logical, logical1))
+}
+
func TestREEBuilderOverflow(t *testing.T) {
for _, typ := range []arrow.DataType{arrow.PrimitiveTypes.Int16,
arrow.PrimitiveTypes.Int32, arrow.PrimitiveTypes.Int64} {
t.Run("run_ends="+typ.String(), func(t *testing.T) {
diff --git a/go/arrow/array/fixed_size_list.go
b/go/arrow/array/fixed_size_list.go
index 1afbf10332..cadcfeb603 100644
--- a/go/arrow/array/fixed_size_list.go
+++ b/go/arrow/array/fixed_size_list.go
@@ -49,7 +49,7 @@ func NewFixedSizeListData(data arrow.ArrayData)
*FixedSizeList {
func (a *FixedSizeList) ListValues() arrow.Array { return a.values }
func (a *FixedSizeList) ValueStr(i int) string {
- if !a.IsValid(i) {
+ if a.IsNull(i) {
return NullValueStr
}
return string(a.GetOneForMarshal(i).(json.RawMessage))
@@ -62,7 +62,7 @@ func (a *FixedSizeList) String() string {
o.WriteString(" ")
}
if !a.IsValid(i) {
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
continue
}
sub := a.newListValue(i)
@@ -208,6 +208,7 @@ func (b *FixedSizeListBuilder) Append(v bool) {
func (b *FixedSizeListBuilder) AppendNull() {
b.Reserve(1)
b.unsafeAppendBoolToBitmap(false)
+ // require to append this due to value indexes
for i := int32(0); i < b.n; i++ {
b.values.AppendNull()
}
@@ -294,6 +295,10 @@ func (b *FixedSizeListBuilder) newData() (data *Data) {
}
func (b *FixedSizeListBuilder) AppendValueFromString(s string) error {
+ if s == NullValueStr {
+ b.AppendNull()
+ return nil
+ }
dec := json.NewDecoder(strings.NewReader(s))
return b.UnmarshalOne(dec)
}
diff --git a/go/arrow/array/fixed_size_list_test.go
b/go/arrow/array/fixed_size_list_test.go
index fef8054701..10e1f78f02 100644
--- a/go/arrow/array/fixed_size_list_test.go
+++ b/go/arrow/array/fixed_size_list_test.go
@@ -173,7 +173,7 @@ func TestFixedSizeListArrayStringer(t *testing.T) {
t.Fatalf("got=%q, want=%q", got, want)
}
assert.Equal(t, "[0,1,2]", arr.ValueStr(0))
- assert.Equal(t, "(null)", arr.ValueStr(1))
+ assert.Equal(t, array.NullValueStr, arr.ValueStr(1))
}
func TestFixedSizeListArraySlice(t *testing.T) {
@@ -216,3 +216,42 @@ func TestFixedSizeListArraySlice(t *testing.T) {
t.Fatalf("got=%q, want=%q", got, want)
}
}
+
+func TestFixedSizeListStringRoundTrip(t *testing.T) {
+ // 1. create array
+ pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer pool.AssertSize(t, 0)
+
+ const N = 3
+ var (
+ values = [][N]int32{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, -9,
-8}}
+ valid = []bool{true, false, true, true}
+ )
+
+ b := array.NewFixedSizeListBuilder(pool, N, arrow.PrimitiveTypes.Int32)
+ defer b.Release()
+
+ vb := b.ValueBuilder().(*array.Int32Builder)
+ vb.Reserve(len(values))
+
+ for i, v := range values {
+ b.Append(valid[i])
+ vb.AppendValues(v[:], nil)
+ }
+
+ arr := b.NewArray().(*array.FixedSizeList)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewFixedSizeListBuilder(pool, N, arrow.PrimitiveTypes.Int32)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.FixedSizeList)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/fixedsize_binary.go
b/go/arrow/array/fixedsize_binary.go
index 64d7a8a057..c7f0b6f479 100644
--- a/go/arrow/array/fixedsize_binary.go
+++ b/go/arrow/array/fixedsize_binary.go
@@ -68,7 +68,7 @@ func (a *FixedSizeBinary) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%q", a.Value(i))
}
diff --git a/go/arrow/array/fixedsize_binary_test.go
b/go/arrow/array/fixedsize_binary_test.go
index b9db71fe2b..c320605e11 100644
--- a/go/arrow/array/fixedsize_binary_test.go
+++ b/go/arrow/array/fixedsize_binary_test.go
@@ -152,3 +152,38 @@ func TestFixedSizeBinary_MarshalUnmarshalJSON(t
*testing.T) {
t.Fatalf("got=%q, want=%q", gotString, wantString)
}
}
+
+func TestFixedSizeBinaryStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := &arrow.FixedSizeBinaryType{ByteWidth: 7}
+ b := array.NewFixedSizeBinaryBuilder(mem, dt)
+
+ values := [][]byte{
+ []byte("7654321"),
+ nil,
+ []byte("AZERTYU"),
+ }
+ valid := []bool{true, false, true}
+ b.AppendValues(values, valid)
+ // encoded abcdefg base64
+ assert.NoError(t, b.AppendValueFromString("YWJjZGVmZw=="))
+
+ arr := b.NewArray().(*array.FixedSizeBinary)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewFixedSizeBinaryBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.FixedSizeBinary)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/float16.go b/go/arrow/array/float16.go
index 98b2e79743..9ccecd3dcd 100644
--- a/go/arrow/array/float16.go
+++ b/go/arrow/array/float16.go
@@ -39,7 +39,12 @@ func NewFloat16Data(data arrow.ArrayData) *Float16 {
}
func (a *Float16) Value(i int) float16.Num { return a.values[i] }
-func (a *Float16) ValueStr(i int) string { return a.Value(i).String()}
+func (a *Float16) ValueStr(i int) string {
+ if a.IsNull(i) {
+ return NullValueStr
+ }
+ return a.Value(i).String()
+}
func (a *Float16) Values() []float16.Num { return a.values }
@@ -52,7 +57,7 @@ func (a *Float16) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", a.values[i].Float32())
}
diff --git a/go/arrow/array/float16_builder_test.go
b/go/arrow/array/float16_builder_test.go
index 2d3867ebd4..a1ad3f7444 100644
--- a/go/arrow/array/float16_builder_test.go
+++ b/go/arrow/array/float16_builder_test.go
@@ -50,7 +50,7 @@ func TestNewFloat16Builder(t *testing.T) {
ab.Append(float16.New(9))
ab.Append(float16.New(10))
assert.NoError(t, ab.AppendValueFromString("11.0"))
-
+
// check state of builder before NewFloat16Array
assert.Equal(t, 11, ab.Len(), "unexpected Len()")
assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
@@ -118,3 +118,39 @@ func TestFloat16Builder_Empty(t *testing.T) {
assert.Equal(t, want, a.Values())
a.Release()
}
+
+func TestFloat16StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewFloat16Builder(mem)
+ defer b.Release()
+
+ b.Append(float16.New(1))
+ b.Append(float16.New(2))
+ b.Append(float16.New(3))
+ b.AppendNull()
+ b.Append(float16.New(5))
+ b.Append(float16.New(6))
+ b.AppendNull()
+ b.Append(float16.New(8))
+ b.Append(float16.New(9))
+ b.Append(float16.New(10))
+
+ arr := b.NewArray().(*array.Float16)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewFloat16Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Float16)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/interval.go b/go/arrow/array/interval.go
index 48f7bf9dda..c105e04f8c 100644
--- a/go/arrow/array/interval.go
+++ b/go/arrow/array/interval.go
@@ -56,7 +56,7 @@ func NewMonthIntervalData(data arrow.ArrayData)
*MonthInterval {
return a
}
-func (a *MonthInterval) Value(i int) arrow.MonthInterval { return
a.values[i] }
+func (a *MonthInterval) Value(i int) arrow.MonthInterval { return a.values[i] }
func (a *MonthInterval) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
@@ -74,7 +74,7 @@ func (a *MonthInterval) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -287,7 +287,7 @@ func (b *MonthIntervalBuilder) AppendValueFromString(s
string) error {
b.Append(arrow.MonthInterval(v))
return nil
}
-
+
func (b *MonthIntervalBuilder) UnmarshalOne(dec *json.Decoder) error {
var v *arrow.MonthInterval
if err := dec.Decode(&v); err != nil {
@@ -341,13 +341,18 @@ func NewDayTimeIntervalData(data arrow.ArrayData)
*DayTimeInterval {
return a
}
-func (a *DayTimeInterval) Value(i int) arrow.DayTimeInterval {
return a.values[i] }
+func (a *DayTimeInterval) Value(i int) arrow.DayTimeInterval { return
a.values[i] }
func (a *DayTimeInterval) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
}
- return fmt.Sprintf("%q", a.Value(i))
+ data, err := json.Marshal(a.GetOneForMarshal(i))
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
}
+
func (a *DayTimeInterval) DayTimeIntervalValues() []arrow.DayTimeInterval {
return a.values }
func (a *DayTimeInterval) String() string {
@@ -359,7 +364,7 @@ func (a *DayTimeInterval) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -628,7 +633,11 @@ func (a *MonthDayNanoInterval) ValueStr(i int) string {
if a.IsNull(i) {
return NullValueStr
}
- return fmt.Sprintf("%q", a.Value(i))
+ data, err := json.Marshal(a.GetOneForMarshal(i))
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
}
func (a *MonthDayNanoInterval) MonthDayNanoIntervalValues()
[]arrow.MonthDayNanoInterval {
@@ -644,7 +653,7 @@ func (a *MonthDayNanoInterval) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
diff --git a/go/arrow/array/interval_test.go b/go/arrow/array/interval_test.go
index c425082d27..cc5b5d8c75 100644
--- a/go/arrow/array/interval_test.go
+++ b/go/arrow/array/interval_test.go
@@ -151,6 +151,38 @@ func TestMonthIntervalBuilder_Empty(t *testing.T) {
arr.Release()
}
+func TestMonthIntervalStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ values = []arrow.MonthInterval{1, 2, 3, 4}
+ valid = []bool{true, true, false, true}
+ )
+
+ b := array.NewMonthIntervalBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.MonthInterval)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewMonthIntervalBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.MonthInterval)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestDayTimeArray(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -280,6 +312,43 @@ func TestDayTimeIntervalBuilder_Empty(t *testing.T) {
arr.Release()
}
+func TestDayTimeIntervalStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ values = []arrow.DayTimeInterval{
+ {Days: 1, Milliseconds: 1},
+ {Days: 2, Milliseconds: 2},
+ {Days: 3, Milliseconds: 3},
+ {Days: 4, Milliseconds: 4},
+ }
+ valid = []bool{true, true, false, true}
+ )
+
+ b := array.NewDayTimeIntervalBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.DayTimeInterval)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDayTimeIntervalBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.DayTimeInterval)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestMonthDayNanoArray(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -415,3 +484,41 @@ func TestMonthDayNanoIntervalBuilder_Empty(t *testing.T) {
assert.Equal(t, want, dtValues(arr))
arr.Release()
}
+
+func TestMonthDayNanoIntervalStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ values = []arrow.MonthDayNanoInterval{
+ {Months: 1, Days: 1, Nanoseconds: 1000}, {Months: 2,
Days: 2, Nanoseconds: 2000},
+ {Months: 3, Days: 3, Nanoseconds: 3000}, {Months: 4,
Days: 4, Nanoseconds: 4000},
+ {Months: 0, Days: 0, Nanoseconds: 0}, {Months: -1,
Days: -2, Nanoseconds: -300},
+ {Months: math.MaxInt32, Days: math.MinInt32,
Nanoseconds: math.MaxInt64},
+ {Months: math.MinInt32, Days: math.MaxInt32,
Nanoseconds: math.MinInt64},
+ }
+ valid = []bool{true, true, false, true, true, true, false, true}
+ )
+
+ b := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.MonthDayNanoInterval)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.MonthDayNanoInterval)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/list.go b/go/arrow/array/list.go
index 9cf1fc86b0..d61d980aac 100644
--- a/go/arrow/array/list.go
+++ b/go/arrow/array/list.go
@@ -69,7 +69,7 @@ func (a *List) String() string {
o.WriteString(" ")
}
if !a.IsValid(i) {
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
continue
}
sub := a.newListValue(i)
@@ -191,6 +191,7 @@ func (a *LargeList) ValueStr(i int) string {
}
return string(a.GetOneForMarshal(i).(json.RawMessage))
}
+
func (a *LargeList) String() string {
o := new(strings.Builder)
o.WriteString("[")
@@ -199,7 +200,7 @@ func (a *LargeList) String() string {
o.WriteString(" ")
}
if !a.IsValid(i) {
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
continue
}
sub := a.newListValue(i)
@@ -547,8 +548,12 @@ func (b *baseListBuilder) newData() (data *Data) {
}
func (b *baseListBuilder) AppendValueFromString(s string) error {
- dec := json.NewDecoder(strings.NewReader(s))
- return b.UnmarshalOne(dec)
+ if s == NullValueStr {
+ b.AppendNull()
+ return nil
+ }
+
+ return b.UnmarshalOne(json.NewDecoder(strings.NewReader(s)))
}
func (b *baseListBuilder) UnmarshalOne(dec *json.Decoder) error {
diff --git a/go/arrow/array/list_test.go b/go/arrow/array/list_test.go
index 977c7f3e85..138548532f 100644
--- a/go/arrow/array/list_test.go
+++ b/go/arrow/array/list_test.go
@@ -301,3 +301,87 @@ func TestListArraySlice(t *testing.T) {
})
}
}
+
+func TestListStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewListBuilder(mem, arrow.PrimitiveTypes.Int32)
+ defer b.Release()
+ vb := b.ValueBuilder().(*array.Int32Builder)
+
+ var values = [][]int32{
+ {0, 1, 2, 3, 4, 5, 6},
+ {1, 2, 3, 4, 5, 6, 7},
+ {2, 3, 4, 5, 6, 7, 8},
+ {3, 4, 5, 6, 7, 8, 9},
+ }
+ for _, value := range values {
+ b.AppendNull()
+ b.Append(true)
+ for _, el := range value {
+ vb.Append(el)
+ vb.AppendNull()
+ }
+ b.Append(false)
+ }
+
+ arr := b.NewArray().(*array.List)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewListBuilder(mem, arrow.PrimitiveTypes.Int32)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.List)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
+func TestLargeListStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewLargeListBuilder(mem, arrow.PrimitiveTypes.Int32)
+ defer b.Release()
+ vb := b.ValueBuilder().(*array.Int32Builder)
+
+ var values = [][]int32{
+ {0, 1, 2, 3, 4, 5, 6},
+ {1, 2, 3, 4, 5, 6, 7},
+ {2, 3, 4, 5, 6, 7, 8},
+ {3, 4, 5, 6, 7, 8, 9},
+ }
+ for _, value := range values {
+ b.AppendNull()
+ b.Append(true)
+ for _, el := range value {
+ vb.Append(el)
+ vb.AppendNull()
+ }
+ b.Append(false)
+ }
+
+ arr := b.NewArray().(*array.LargeList)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewLargeListBuilder(mem, arrow.PrimitiveTypes.Int32)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.LargeList)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/map.go b/go/arrow/array/map.go
index 5c3c54713b..815465c1e5 100644
--- a/go/arrow/array/map.go
+++ b/go/arrow/array/map.go
@@ -128,7 +128,7 @@ type MapBuilder struct {
// building using keys in sorted order for each value. The KeysSorted value
will just be
// used when creating the DataType for the map.
//
-// Example
+// # Example
//
// Simple example provided of converting a []map[string]int32 to an array.Map
// by using a MapBuilder:
@@ -303,7 +303,7 @@ func (b *MapBuilder) ValueBuilder() Builder {
}
func (b *MapBuilder) AppendValueFromString(s string) error {
- return arrow.ErrNotImplemented
+ return b.listBuilder.AppendValueFromString(s)
}
func (b *MapBuilder) UnmarshalOne(dec *json.Decoder) error {
diff --git a/go/arrow/array/map_test.go b/go/arrow/array/map_test.go
index b876d01810..c9b87b045a 100644
--- a/go/arrow/array/map_test.go
+++ b/go/arrow/array/map_test.go
@@ -17,6 +17,7 @@
package array_test
import (
+ "strconv"
"testing"
"github.com/apache/arrow/go/v13/arrow"
@@ -172,3 +173,47 @@ func TestMapArrayBuildIntToInt(t *testing.T) {
assert.Equal(t, "[{[0 1 2 3 4 5] [1 1 2 3 5 8]} (null) {[0 1 2 3 4 5]
[(null) (null) 0 1 (null) 2]} {[] []}]", arr.String())
}
+
+func TestMapStringRoundTrip(t *testing.T) {
+ // 1. create array
+ dt := arrow.MapOf(arrow.BinaryTypes.String, arrow.PrimitiveTypes.Int32)
+
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewMapBuilderWithType(mem, dt)
+ defer b.Release()
+
+ kb := b.KeyBuilder().(*array.StringBuilder)
+ ib := b.ItemBuilder().(*array.Int32Builder)
+
+ for n := 0; n < 10; n++ {
+ b.AppendNull()
+ b.Append(true)
+
+ for r := 'a'; r <= 'z'; r++ {
+ kb.Append(string(r) + strconv.Itoa(n))
+ if (n+int(r))%2 == 0 {
+ ib.AppendNull()
+ } else {
+ ib.Append(int32(n + int(r)))
+ }
+ }
+ }
+
+ arr := b.NewArray().(*array.Map)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewMapBuilderWithType(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Map)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/null.go b/go/arrow/array/null.go
index d65ba67d94..80cef00777 100644
--- a/go/arrow/array/null.go
+++ b/go/arrow/array/null.go
@@ -58,9 +58,9 @@ func NewNullData(data arrow.ArrayData) *Null {
return a
}
-func (a *Null) ValueStr(i int) string {
- return NullValueStr
-}
+func (a *Null) ValueStr(int) string { return NullValueStr }
+
+func (a *Null) Value(int) interface{} { return nil }
func (a *Null) String() string {
o := new(strings.Builder)
@@ -69,7 +69,7 @@ func (a *Null) String() string {
if i > 0 {
o.WriteString(" ")
}
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
}
o.WriteString("]")
return o.String()
@@ -125,6 +125,7 @@ func (b *NullBuilder) AppendValueFromString(s string) error
{
}
return fmt.Errorf("cannot convert %q to null", s)
}
+
func (b *NullBuilder) AppendEmptyValue() { b.AppendNull() }
func (*NullBuilder) Reserve(size int) {}
diff --git a/go/arrow/array/null_test.go b/go/arrow/array/null_test.go
index c4620ef0b5..ea622dff31 100644
--- a/go/arrow/array/null_test.go
+++ b/go/arrow/array/null_test.go
@@ -22,6 +22,7 @@ import (
"github.com/apache/arrow/go/v13/arrow"
"github.com/apache/arrow/go/v13/arrow/array"
"github.com/apache/arrow/go/v13/arrow/memory"
+ "github.com/stretchr/testify/assert"
)
func TestNullArray(t *testing.T) {
@@ -75,3 +76,31 @@ func TestNullArray(t *testing.T) {
}
}
+
+func TestNullStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewNullBuilder(mem)
+ defer b.Release()
+
+ b.AppendNull()
+ b.AppendNull()
+
+ arr := b.NewArray().(*array.Null)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewNullBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Null)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/numeric.gen.go b/go/arrow/array/numeric.gen.go
index 1fc26d3c14..1849d6531b 100644
--- a/go/arrow/array/numeric.gen.go
+++ b/go/arrow/array/numeric.gen.go
@@ -62,7 +62,7 @@ func (a *Int64) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -157,7 +157,7 @@ func (a *Uint64) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -252,7 +252,7 @@ func (a *Float64) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -347,7 +347,7 @@ func (a *Int32) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -442,7 +442,7 @@ func (a *Uint32) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -537,7 +537,7 @@ func (a *Float32) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -632,7 +632,7 @@ func (a *Int16) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -727,7 +727,7 @@ func (a *Uint16) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -822,7 +822,7 @@ func (a *Int8) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -917,7 +917,7 @@ func (a *Uint8) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1012,7 +1012,7 @@ func (a *Timestamp) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1102,7 +1102,7 @@ func (a *Time32) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1192,7 +1192,7 @@ func (a *Time64) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1282,7 +1282,7 @@ func (a *Date32) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1372,7 +1372,7 @@ func (a *Date64) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
@@ -1462,7 +1462,7 @@ func (a *Duration) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
diff --git a/go/arrow/array/numeric.gen.go.tmpl
b/go/arrow/array/numeric.gen.go.tmpl
index 4b71199289..adece058b8 100644
--- a/go/arrow/array/numeric.gen.go.tmpl
+++ b/go/arrow/array/numeric.gen.go.tmpl
@@ -62,7 +62,7 @@ func (a *{{.Name}}) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%v", v)
}
diff --git a/go/arrow/array/numericbuilder.gen.go
b/go/arrow/array/numericbuilder.gen.go
index a9d00197cc..17fee6688a 100644
--- a/go/arrow/array/numericbuilder.gen.go
+++ b/go/arrow/array/numericbuilder.gen.go
@@ -3534,7 +3534,12 @@ func (b *DurationBuilder) AppendValueFromString(s
string) error {
b.AppendNull()
return nil
}
- return fmt.Errorf("%w: AppendValueFromString not implemented for
Duration", arrow.ErrNotImplemented)
+ dur, err := time.ParseDuration(s)
+ if err != nil {
+ return err
+ }
+
+ b.Append(arrow.Duration(dur / b.dtype.Unit.Multiplier()))
return nil
}
diff --git a/go/arrow/array/numericbuilder.gen.go.tmpl
b/go/arrow/array/numericbuilder.gen.go.tmpl
index 5e615ddc85..d18829b2f0 100644
--- a/go/arrow/array/numericbuilder.gen.go.tmpl
+++ b/go/arrow/array/numericbuilder.gen.go.tmpl
@@ -224,8 +224,13 @@ func (b *{{.Name}}Builder) AppendValueFromString(s string)
error {
return err
}
b.Append(v)
- {{else if (eq .Name "Duration") -}}
- return fmt.Errorf("%w: AppendValueFromString not implemented for
Duration", arrow.ErrNotImplemented)
+ {{else if (eq .Name "Duration") -}}
+ dur, err := time.ParseDuration(s)
+ if err != nil {
+ return err
+ }
+
+ b.Append(arrow.Duration(dur / b.dtype.Unit.Multiplier()))
{{else if or (eq .Name "Int8") (eq .Name "Int16") (eq .Name "Int32") (eq
.Name "Int64") -}}
v, err := strconv.ParseInt(s, 10, {{.Size}} * 8)
if err != nil {
@@ -247,8 +252,6 @@ func (b *{{.Name}}Builder) AppendValueFromString(s string)
error {
return err
}
b.Append({{.name}}(v))
- {{else}}
- return fmt.Errorf("%w: AppendValueFromString not implemented for
{{.Name}}", ErrNotImplemented)
{{end -}}
return nil
}
diff --git a/go/arrow/array/numericbuilder.gen_test.go
b/go/arrow/array/numericbuilder.gen_test.go
index 3a63cdd6ec..90c5a7f452 100644
--- a/go/arrow/array/numericbuilder.gen_test.go
+++ b/go/arrow/array/numericbuilder.gen_test.go
@@ -27,6 +27,42 @@ import (
"github.com/stretchr/testify/assert"
)
+func TestInt64StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewInt64Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Int64)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewInt64Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Int64)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewInt64Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -47,10 +83,9 @@ func TestNewInt64Builder(t *testing.T) {
ab.Append(8)
ab.Append(9)
ab.Append(10)
- assert.NoError(t, ab.AppendValueFromString("11"))
// check state of builder before NewInt64Array
- assert.Equal(t, 11, ab.Len(), "unexpected Len()")
+ assert.Equal(t, 10, ab.Len(), "unexpected Len()")
assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
a := ab.NewInt64Array()
@@ -62,9 +97,9 @@ func TestNewInt64Builder(t *testing.T) {
// 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, 11},
a.Int64Values(), "unexpected Int64Values")
+ 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(), 11, "unexpected length of Int64Values")
+ assert.Len(t, a.Int64Values(), 10, "unexpected length of Int64Values")
a.Release()
@@ -194,6 +229,42 @@ func TestInt64Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestUint64StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewUint64Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Uint64)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewUint64Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Uint64)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewUint64Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -360,6 +431,42 @@ func TestUint64Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestFloat64StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewFloat64Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Float64)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewFloat64Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Float64)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewFloat64Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -526,6 +633,42 @@ func TestFloat64Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestInt32StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewInt32Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Int32)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewInt32Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Int32)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewInt32Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -692,6 +835,42 @@ func TestInt32Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestUint32StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewUint32Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Uint32)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewUint32Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Uint32)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewUint32Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -858,6 +1037,42 @@ func TestUint32Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestFloat32StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewFloat32Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Float32)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewFloat32Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Float32)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewFloat32Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1024,6 +1239,42 @@ func TestFloat32Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestInt16StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewInt16Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Int16)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewInt16Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Int16)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewInt16Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1190,6 +1441,42 @@ func TestInt16Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestUint16StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewUint16Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Uint16)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewUint16Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Uint16)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewUint16Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1356,6 +1643,42 @@ func TestUint16Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestInt8StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewInt8Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Int8)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewInt8Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Int8)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewInt8Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1522,6 +1845,42 @@ func TestInt8Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestUint8StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewUint8Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Uint8)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewUint8Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Uint8)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewUint8Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1688,6 +2047,43 @@ func TestUint8Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestTimestampStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := &arrow.TimestampType{Unit: arrow.Second}
+ b := array.NewTimestampBuilder(mem, dt)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Timestamp)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewTimestampBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Timestamp)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewTimestampBuilder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -1858,6 +2254,43 @@ func TestTimestampBuilder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestTime32StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := &arrow.Time32Type{Unit: arrow.Second}
+ b := array.NewTime32Builder(mem, dt)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Time32)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewTime32Builder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Time32)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewTime32Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -2028,6 +2461,43 @@ func TestTime32Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestTime64StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := &arrow.Time64Type{Unit: arrow.Microsecond}
+ b := array.NewTime64Builder(mem, dt)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Time64)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewTime64Builder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Time64)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewTime64Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -2198,6 +2668,42 @@ func TestTime64Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestDate32StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewDate32Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Date32)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDate32Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Date32)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewDate32Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -2364,6 +2870,49 @@ func TestDate32Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestDate64StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ b := array.NewDate64Builder(mem)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Date64)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDate64Builder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Date64)
+ defer arr1.Release()
+
+ assert.Exactly(t, arr.Len(), arr1.Len())
+ for i := 0; i < arr.Len(); i++ {
+ assert.Exactly(t, arr.IsValid(i), arr1.IsValid(i))
+ assert.Exactly(t, arr.ValueStr(i), arr1.ValueStr(i))
+ if arr.IsValid(i) {
+ assert.Exactly(t, arr.Value(i).ToTime(),
arr1.Value(i).ToTime())
+ }
+ }
+}
+
func TestNewDate64Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -2530,6 +3079,43 @@ func TestDate64Builder_Resize(t *testing.T) {
assert.Equal(t, 5, ab.Len())
}
+func TestDurationStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := &arrow.DurationType{Unit: arrow.Second}
+ b := array.NewDurationBuilder(mem, dt)
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.Duration)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDurationBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Duration)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestNewDurationBuilder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
diff --git a/go/arrow/array/numericbuilder.gen_test.go.tmpl
b/go/arrow/array/numericbuilder.gen_test.go.tmpl
index 63245ef382..6b01684ac6 100644
--- a/go/arrow/array/numericbuilder.gen_test.go.tmpl
+++ b/go/arrow/array/numericbuilder.gen_test.go.tmpl
@@ -26,6 +26,66 @@ import (
)
{{range .In}}
+func Test{{.Name}}StringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+{{if .Opt.Parametric -}}
+{{ if or (eq .Name "Time64") -}}
+ dt := &arrow.{{.Name}}Type{Unit: arrow.Microsecond}
+{{else -}}
+ dt := &arrow.{{.Name}}Type{Unit: arrow.Second}
+{{end -}}
+ b := array.New{{.Name}}Builder(mem, dt)
+{{else -}}
+ b := array.New{{.Name}}Builder(mem)
+{{end -}}
+ defer b.Release()
+
+ b.Append(1)
+ b.Append(2)
+ b.Append(3)
+ b.AppendNull()
+ b.Append(5)
+ b.Append(6)
+ b.AppendNull()
+ b.Append(8)
+ b.Append(9)
+ b.Append(10)
+
+ arr := b.NewArray().(*array.{{.Name}})
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+{{if .Opt.Parametric -}}
+ b1 := array.New{{.Name}}Builder(mem, dt)
+{{else -}}
+ b1 := array.New{{.Name}}Builder(mem)
+{{end -}}
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.{{.Name}})
+ defer arr1.Release()
+
+{{ if or (eq .Name "Date64") -}}
+ assert.Exactly(t, arr.Len(), arr1.Len())
+ for i := 0; i < arr.Len(); i++ {
+ assert.Exactly(t, arr.IsValid(i), arr1.IsValid(i))
+ assert.Exactly(t, arr.ValueStr(i), arr1.ValueStr(i))
+ if arr.IsValid(i) {
+ assert.Exactly(t, arr.Value(i).ToTime(),
arr1.Value(i).ToTime())
+ }
+ }
+{{else -}}
+ assert.True(t, array.Equal(arr, arr1))
+{{end -}}
+}
+
func TestNew{{.Name}}Builder(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -51,10 +111,9 @@ func TestNew{{.Name}}Builder(t *testing.T) {
ab.Append(8)
ab.Append(9)
ab.Append(10)
- ab.AppendValueFromString(11)
// check state of builder before New{{.Name}}Array
- assert.Equal(t, 11, ab.Len(), "unexpected Len()")
+ assert.Equal(t, 10, ab.Len(), "unexpected Len()")
assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
a := ab.New{{.Name}}Array()
@@ -66,7 +125,7 @@ func TestNew{{.Name}}Builder(t *testing.T) {
// 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, 11}, a.{{.Name}}Values(), "unexpected {{.Name}}Values")
+ 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")
diff --git a/go/arrow/array/string.go b/go/arrow/array/string.go
index 48fe032541..dacf66572e 100644
--- a/go/arrow/array/string.go
+++ b/go/arrow/array/string.go
@@ -53,12 +53,12 @@ func (a *String) Value(i int) string {
i = i + a.array.data.offset
return a.values[a.offsets[i]:a.offsets[i+1]]
}
+
func (a *String) ValueStr(i int) string {
if a.IsNull(i) {
- return "(null)"
- } else {
- return a.Value(i)
+ return NullValueStr
}
+ return a.Value(i)
}
// ValueOffset returns the offset of the value at index i.
@@ -100,7 +100,7 @@ func (a *String) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%q", a.Value(i))
}
@@ -195,7 +195,13 @@ func (a *LargeString) Value(i int) string {
i = i + a.array.data.offset
return a.values[a.offsets[i]:a.offsets[i+1]]
}
-func (a *LargeString) ValueStr(i int) string { return a.Value(i) }
+
+func (a *LargeString) ValueStr(i int) string {
+ if a.IsNull(i) {
+ return NullValueStr
+ }
+ return a.Value(i)
+}
// ValueOffset returns the offset of the value at index i.
func (a *LargeString) ValueOffset(i int) int64 {
@@ -236,7 +242,7 @@ func (a *LargeString) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(NullValueStr)
default:
fmt.Fprintf(o, "%q", a.Value(i))
}
@@ -315,7 +321,9 @@ func NewStringBuilder(mem memory.Allocator) *StringBuilder {
return b
}
-func (b *StringBuilder) Type() arrow.DataType { return
arrow.BinaryTypes.String }
+func (b *StringBuilder) Type() arrow.DataType {
+ return arrow.BinaryTypes.String
+}
// Append appends a string to the builder.
func (b *StringBuilder) Append(v string) {
diff --git a/go/arrow/array/string_test.go b/go/arrow/array/string_test.go
index bfbe035807..9f27ceaa86 100644
--- a/go/arrow/array/string_test.go
+++ b/go/arrow/array/string_test.go
@@ -281,6 +281,38 @@ func TestStringInvalidOffsets(t *testing.T) {
}, "data has offset and value offset is overflowing")
}
+func TestStringStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ values = []string{"hello", "世界", "", "bye"}
+ valid = []bool{true, true, false, true}
+ )
+
+ b := array.NewStringBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.String)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewStringBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.String)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestLargeStringArray(t *testing.T) {
mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer mem.AssertSize(t, 0)
@@ -530,3 +562,35 @@ func TestLargeStringInvalidOffsets(t *testing.T) {
array.NewLargeStringData(array.NewData(arrow.BinaryTypes.LargeString, 1,
buffers, nil, 0, 2))
}, "data has offset and value offset is overflowing")
}
+
+func TestLargeStringStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ values = []string{"hello", "世界", "", "bye"}
+ valid = []bool{true, true, false, true}
+ )
+
+ b := array.NewLargeStringBuilder(mem)
+ defer b.Release()
+
+ b.AppendValues(values, valid)
+
+ arr := b.NewArray().(*array.LargeString)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewLargeStringBuilder(mem)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.LargeString)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
diff --git a/go/arrow/array/struct.go b/go/arrow/array/struct.go
index a37b67f4c8..cb4fb5ec5e 100644
--- a/go/arrow/array/struct.go
+++ b/go/arrow/array/struct.go
@@ -83,12 +83,15 @@ func (a *Struct) Field(i int) arrow.Array { return
a.fields[i] }
// ValueStr returns the string representation (as json) of the value at index
i.
func (a *Struct) ValueStr(i int) string {
- var buf bytes.Buffer
- enc := json.NewEncoder(&buf)
- if err := enc.Encode(a.GetOneForMarshal(i)); err != nil {
+ if a.IsNull(i) {
+ return NullValueStr
+ }
+
+ data, err := json.Marshal(a.GetOneForMarshal(i))
+ if err != nil {
panic(err)
}
- return buf.String()
+ return string(data)
}
func (a *Struct) String() string {
@@ -118,7 +121,8 @@ func (a *Struct) String() string {
// newStructFieldWithParentValidityMask returns the Interface at fieldIndex
// with a nullBitmapBytes adjusted according on the parent struct
nullBitmapBytes.
// From the docs:
-// "When reading the struct array the parent validity bitmap takes priority."
+//
+// "When reading the struct array the parent validity bitmap takes
priority."
func (a *Struct) newStructFieldWithParentValidityMask(fieldIndex int)
arrow.Array {
field := a.Field(fieldIndex)
nullBitmapBytes := field.NullBitmapBytes()
@@ -362,8 +366,13 @@ func (b *StructBuilder) newData() (data *Data) {
}
func (b *StructBuilder) AppendValueFromString(s string) error {
+ if s == NullValueStr {
+ b.AppendNull()
+ return nil
+ }
+
if !strings.HasPrefix(s, "{") && !strings.HasSuffix(s, "}") {
- return fmt.Errorf("%w: invalid string for struct should be be
of form: {*}", arrow.ErrInvalid,)
+ return fmt.Errorf("%w: invalid string for struct should be be
of form: {*}", arrow.ErrInvalid)
}
dec := json.NewDecoder(strings.NewReader(s))
return b.UnmarshalOne(dec)
diff --git a/go/arrow/array/struct_test.go b/go/arrow/array/struct_test.go
index 9c12373170..30f5673f40 100644
--- a/go/arrow/array/struct_test.go
+++ b/go/arrow/array/struct_test.go
@@ -134,6 +134,46 @@ func TestStructArray(t *testing.T) {
}
}
+func TestStructStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ dt := arrow.StructOf(
+ arrow.Field{Name: "nullable_bool", Type:
new(arrow.BooleanType), Nullable: true},
+ arrow.Field{Name: "non_nullable_bool", Type:
new(arrow.BooleanType)},
+ )
+
+ builder := array.NewStructBuilder(memory.DefaultAllocator, dt)
+ nullableBld := builder.FieldBuilder(0).(*array.BooleanBuilder)
+ nonNullableBld := builder.FieldBuilder(1).(*array.BooleanBuilder)
+
+ builder.Append(true)
+ nullableBld.Append(true)
+ nonNullableBld.Append(true)
+
+ builder.Append(true)
+ nullableBld.AppendNull()
+ nonNullableBld.Append(true)
+
+ builder.AppendNull()
+
+ arr := builder.NewArray().(*array.Struct)
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewStructBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.Struct)
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}
+
func TestStructArrayEmpty(t *testing.T) {
pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
defer pool.AssertSize(t, 0)
@@ -295,7 +335,7 @@ func TestStructArrayStringer(t *testing.T) {
arr := sb.NewArray().(*array.Struct)
defer arr.Release()
- assert.Equal(t, "{\"f1\":1.1,\"f2\":1}\n", arr.ValueStr(4))
+ assert.Equal(t, `{"f1":1.1,"f2":1}`, arr.ValueStr(4))
want := "{[1.1 (null) 1.3 1.4 1.1] [1 2 (null) 4 1]}"
got := arr.String()
if got != want {
diff --git a/go/arrow/array/union.go b/go/arrow/array/union.go
index 3181ccc6ba..c868ca2599 100644
--- a/go/arrow/array/union.go
+++ b/go/arrow/array/union.go
@@ -344,13 +344,23 @@ func (a *SparseUnion) MarshalJSON() ([]byte, error) {
}
func (a *SparseUnion) ValueStr(i int) string {
- var buf bytes.Buffer
- enc := json.NewEncoder(&buf)
- if err := enc.Encode(a.GetOneForMarshal(i)); err != nil {
+ if a.IsNull(i) {
+ return NullValueStr
+ }
+
+ val := a.GetOneForMarshal(i)
+ if val == nil {
+ // child is nil
+ return NullValueStr
+ }
+
+ data, err := json.Marshal(val)
+ if err != nil {
panic(err)
}
- return buf.String()
+ return string(data)
}
+
func (a *SparseUnion) String() string {
var b strings.Builder
b.WriteByte('[')
@@ -584,12 +594,12 @@ func (a *DenseUnion) GetOneForMarshal(i int) interface{} {
childID := a.ChildID(i)
data := a.Field(childID)
- offsets := a.RawValueOffsets()
- if data.IsNull(int(offsets[i])) {
+ offset := int(a.RawValueOffsets()[i])
+ if data.IsNull(offset) {
return nil
}
- return []interface{}{typeID, data.GetOneForMarshal(int(offsets[i]))}
+ return []interface{}{typeID, data.GetOneForMarshal(offset)}
}
func (a *DenseUnion) MarshalJSON() ([]byte, error) {
@@ -610,12 +620,21 @@ func (a *DenseUnion) MarshalJSON() ([]byte, error) {
}
func (a *DenseUnion) ValueStr(i int) string {
- var buf bytes.Buffer
- enc := json.NewEncoder(&buf)
- if err := enc.Encode(a.GetOneForMarshal(i)); err != nil {
+ if a.IsNull(i) {
+ return NullValueStr
+ }
+
+ val := a.GetOneForMarshal(i)
+ if val == nil {
+ // child in nil
+ return NullValueStr
+ }
+
+ data, err := json.Marshal(val)
+ if err != nil {
panic(err)
}
- return buf.String()
+ return string(data)
}
func (a *DenseUnion) String() string {
@@ -730,8 +749,8 @@ func newUnionBuilder(mem memory.Allocator, children
[]Builder, typ arrow.UnionTy
mode: typ.Mode(),
codes: typ.TypeCodes(),
children: children,
- typeIDtoChildID: make([]int, typ.MaxTypeCode()+1),
- typeIDtoBuilder: make([]Builder, typ.MaxTypeCode()+1),
+ typeIDtoChildID: make([]int, int(typ.MaxTypeCode())+1), //
convert to int as int8(127) +1 panics
+ typeIDtoBuilder: make([]Builder, int(typ.MaxTypeCode())+1), //
convert to int as int8(127) +1 panics
childFields: make([]arrow.Field, len(children)),
typesBuilder: newInt8BufferBuilder(mem),
}
@@ -1005,6 +1024,10 @@ func (b *SparseUnionBuilder) Unmarshal(dec
*json.Decoder) error {
}
func (b *SparseUnionBuilder) AppendValueFromString(s string) error {
+ if s == NullValueStr {
+ b.AppendNull()
+ return nil
+ }
dec := json.NewDecoder(strings.NewReader(s))
return b.UnmarshalOne(dec)
}
@@ -1110,10 +1133,15 @@ func NewEmptyDenseUnionBuilder(mem memory.Allocator)
*DenseUnionBuilder {
// children and type codes. Builders will be constructed for each child
// using the fields in typ
func NewDenseUnionBuilder(mem memory.Allocator, typ *arrow.DenseUnionType)
*DenseUnionBuilder {
- children := make([]Builder, len(typ.Fields()))
- for i, f := range typ.Fields() {
- children[i] = NewBuilder(mem, f.Type)
- defer children[i].Release()
+ children := make([]Builder, 0, len(typ.Fields()))
+ defer func() {
+ for _, child := range children {
+ child.Release()
+ }
+ }()
+
+ for _, f := range typ.Fields() {
+ children = append(children, NewBuilder(mem, f.Type))
}
return NewDenseUnionBuilderWithBuilders(mem, typ, children)
}
@@ -1255,6 +1283,10 @@ func (b *DenseUnionBuilder) Unmarshal(dec *json.Decoder)
error {
}
func (d *DenseUnionBuilder) AppendValueFromString(s string) error {
+ if s == NullValueStr {
+ d.AppendNull()
+ return nil
+ }
dec := json.NewDecoder(strings.NewReader(s))
return d.UnmarshalOne(dec)
}
diff --git a/go/arrow/array/union_test.go b/go/arrow/array/union_test.go
index 78129b8f05..5ce1f97ebe 100644
--- a/go/arrow/array/union_test.go
+++ b/go/arrow/array/union_test.go
@@ -373,12 +373,13 @@ func (s *UnionFactorySuite) TestMakeDenseUnions() {
children := make([]arrow.Array, 4)
children[0], _, _ = array.FromJSON(s.mem, arrow.BinaryTypes.String,
strings.NewReader(`["abc", "def", "xyz"]`))
+ defer children[0].Release()
children[1], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Uint8,
strings.NewReader(`[10, 20, 30]`))
+ defer children[1].Release()
children[2], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Float64,
strings.NewReader(`[1.618, 2.718, 3.142]`))
+ defer children[2].Release()
children[3], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Int8,
strings.NewReader(`[-12]`))
- for _, c := range children {
- defer c.Release()
- }
+ defer children[3].Release()
fieldNames := []string{"str", "int1", "real", "int2"}
@@ -458,6 +459,46 @@ func (s *UnionFactorySuite) TestMakeDenseUnions() {
})
}
+func (s *UnionFactorySuite) TestDenseUnionStringRoundTrip() {
+ // typeIDs: {0, 1, 2, 0, 1, 3, 2, 0, 2, 1}
+ offsets := s.offsetsFromSlice(0, 0, 0, 1, 1, 0, 1, 2, 1, 2)
+ defer offsets.Release()
+
+ children := make([]arrow.Array, 4)
+ children[0], _, _ = array.FromJSON(s.mem, arrow.BinaryTypes.String,
strings.NewReader(`["abc", "def", "xyz"]`))
+ defer children[0].Release()
+ children[1], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Uint8,
strings.NewReader(`[10, 20, 30]`))
+ defer children[1].Release()
+ children[2], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Float64,
strings.NewReader(`[1.618, 2.718, 3.142]`))
+ defer children[2].Release()
+ children[3], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Int8,
strings.NewReader(`[-12]`))
+ defer children[3].Release()
+
+ fields := []string{"str", "int1", "real", "int2"}
+
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(s.T(), 0)
+
+ dt := arrow.DenseUnionFromArrays(children, fields, s.codes)
+ arr, err :=
array.NewDenseUnionFromArraysWithFieldCodes(s.logicalTypeIDs, offsets,
children, fields, s.codes)
+ s.NoError(err)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewDenseUnionBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ s.NoError(b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.DenseUnion)
+ defer arr1.Release()
+
+ s.True(array.Equal(arr, arr1))
+}
+
func (s *UnionFactorySuite) TestMakeSparse() {
children := make([]arrow.Array, 4)
children[0], _, _ = array.FromJSON(s.mem, arrow.BinaryTypes.String,
@@ -533,6 +574,47 @@ func (s *UnionFactorySuite) TestMakeSparse() {
})
}
+func (s *UnionFactorySuite) TestSparseUnionStringRoundTrip() {
+ children := make([]arrow.Array, 4)
+ children[0], _, _ = array.FromJSON(s.mem, arrow.BinaryTypes.String,
+ strings.NewReader(`["abc", "", "", "def", "", "", "", "xyz",
"", ""]`))
+ defer children[0].Release()
+ children[1], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Uint8,
+ strings.NewReader(`[0, 10, 0, 0, 20, 0, 0, 0, 0, 30]`))
+ defer children[1].Release()
+ children[2], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Float64,
+ strings.NewReader(`[0.0, 0.0, 1.618, 0.0, 0.0, 0.0, 2.718, 0.0,
3.142, 0.0]`))
+ defer children[2].Release()
+ children[3], _, _ = array.FromJSON(s.mem, arrow.PrimitiveTypes.Int8,
+ strings.NewReader(`[0, 0, 0, 0, 0, -12, 0, 0, 0, 0]`))
+ defer children[3].Release()
+
+ fields := []string{"str", "int1", "real", "int2"}
+
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(s.T(), 0)
+
+ dt := arrow.SparseUnionFromArrays(children, fields, s.codes)
+
+ arr, err :=
array.NewSparseUnionFromArraysWithFieldCodes(s.logicalTypeIDs, children,
fields, s.codes)
+ s.NoError(err)
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ b1 := array.NewSparseUnionBuilder(mem, dt)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ s.NoError(b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray().(*array.SparseUnion)
+ defer arr1.Release()
+
+ s.True(array.Equal(arr, arr1))
+}
+
type UnionBuilderSuite struct {
suite.Suite
diff --git a/go/arrow/csv/reader_test.go b/go/arrow/csv/reader_test.go
index 08e9f260db..4382ef6296 100644
--- a/go/arrow/csv/reader_test.go
+++ b/go/arrow/csv/reader_test.go
@@ -388,8 +388,8 @@ func testCSVReader(t *testing.T, filepath string,
withHeader bool, stringsCanBeN
str1Value := `""`
str2Value := `"null"`
if stringsCanBeNull {
- str1Value = "(null)"
- str2Value = "(null)"
+ str1Value = array.NullValueStr
+ str2Value = array.NullValueStr
}
want := fmt.Sprintf(`rec[0]["bool"]: [true]
diff --git a/go/arrow/example_test.go b/go/arrow/example_test.go
index 276aa510ff..ee23231319 100644
--- a/go/arrow/example_test.go
+++ b/go/arrow/example_test.go
@@ -53,7 +53,7 @@ func Example_minimal() {
for i, v := range ints.Int64Values() {
fmt.Printf("ints[%d] = ", i)
if ints.IsNull(i) {
- fmt.Println("(null)")
+ fmt.Println(array.NullValueStr)
} else {
fmt.Println(v)
}
@@ -97,7 +97,7 @@ func Example_fromMemory() {
for i := 0; i < n; i++ {
fmt.Printf("bools[%d] = ", i)
if bools.IsNull(i) {
- fmt.Println("(null)")
+ fmt.Println(array.NullValueStr)
} else {
fmt.Printf("%t\n", bools.Value(i))
}
@@ -640,7 +640,7 @@ func Example_mapArray() {
if itemArr.IsValid(int(j)) {
fmt.Printf("%v", itemArr.Value(int(j)))
} else {
- fmt.Printf("(null)")
+ fmt.Printf(array.NullValueStr)
}
}
fmt.Printf("}\n")
diff --git a/go/arrow/math/float64_arm64.go b/go/arrow/math/float64_arm64.go
index 759d967474..31ed189d5a 100644
--- a/go/arrow/math/float64_arm64.go
+++ b/go/arrow/math/float64_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,12 +16,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
func initFloat64NEON() {
- Float64.sum = sum_float64_neon
+ Float64.sum = sum_float64_neon
}
func initFloat64Go() {
diff --git a/go/arrow/math/float64_neon_arm64.go
b/go/arrow/math/float64_neon_arm64.go
index e31494ef94..5c09f28624 100755
--- a/go/arrow/math/float64_neon_arm64.go
+++ b/go/arrow/math/float64_neon_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_simd_amd64.go.tmpl. DO NOT EDIT.
+// Code generated by type_simd_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/float64_noasm.go b/go/arrow/math/float64_noasm.go
index b480ad34f3..bfa3e6e589 100644
--- a/go/arrow/math/float64_noasm.go
+++ b/go/arrow/math/float64_noasm.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build noasm
// +build noasm
package math
diff --git a/go/arrow/math/float64_ppc64le.go b/go/arrow/math/float64_ppc64le.go
index f60be90721..3d962005ce 100644
--- a/go/arrow/math/float64_ppc64le.go
+++ b/go/arrow/math/float64_ppc64le.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_ppc64le.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/float64_s390x.go b/go/arrow/math/float64_s390x.go
index f60be90721..cf091f53d1 100644
--- a/go/arrow/math/float64_s390x.go
+++ b/go/arrow/math/float64_s390x.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/int64_arm64.go b/go/arrow/math/int64_arm64.go
index 917902be0b..7bd200746e 100644
--- a/go/arrow/math/int64_arm64.go
+++ b/go/arrow/math/int64_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,12 +16,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
func initInt64NEON() {
- Int64.sum = sum_int64_neon
+ Int64.sum = sum_int64_neon
}
func initInt64Go() {
diff --git a/go/arrow/math/int64_neon_arm64.go
b/go/arrow/math/int64_neon_arm64.go
index 6639bf46f5..fab545aa1e 100755
--- a/go/arrow/math/int64_neon_arm64.go
+++ b/go/arrow/math/int64_neon_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_simd_amd64.go.tmpl. DO NOT EDIT.
+// Code generated by type_simd_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/int64_noasm.go b/go/arrow/math/int64_noasm.go
index 5a5efc31bb..09e945da75 100644
--- a/go/arrow/math/int64_noasm.go
+++ b/go/arrow/math/int64_noasm.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build noasm
// +build noasm
package math
diff --git a/go/arrow/math/int64_ppc64le.go b/go/arrow/math/int64_ppc64le.go
index 1a615a9b27..ff40824cc1 100644
--- a/go/arrow/math/int64_ppc64le.go
+++ b/go/arrow/math/int64_ppc64le.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_ppc64le.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/int64_s390x.go b/go/arrow/math/int64_s390x.go
index 1a615a9b27..d32d860ca0 100644
--- a/go/arrow/math/int64_s390x.go
+++ b/go/arrow/math/int64_s390x.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/uint64_arm64.go b/go/arrow/math/uint64_arm64.go
index df87289dff..54981c2278 100644
--- a/go/arrow/math/uint64_arm64.go
+++ b/go/arrow/math/uint64_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,12 +16,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
func initUint64NEON() {
- Uint64.sum = sum_uint64_neon
+ Uint64.sum = sum_uint64_neon
}
func initUint64Go() {
diff --git a/go/arrow/math/uint64_neon_arm64.go
b/go/arrow/math/uint64_neon_arm64.go
index 867ef74522..7bfa0aba0b 100755
--- a/go/arrow/math/uint64_neon_arm64.go
+++ b/go/arrow/math/uint64_neon_arm64.go
@@ -1,4 +1,4 @@
-// Code generated by type_simd_amd64.go.tmpl. DO NOT EDIT.
+// Code generated by type_simd_arm64.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/uint64_noasm.go b/go/arrow/math/uint64_noasm.go
index b7174b3d74..c40ecc4678 100644
--- a/go/arrow/math/uint64_noasm.go
+++ b/go/arrow/math/uint64_noasm.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build noasm
// +build noasm
package math
diff --git a/go/arrow/math/uint64_ppc64le.go b/go/arrow/math/uint64_ppc64le.go
index 8f7419fd48..b6b1c536af 100644
--- a/go/arrow/math/uint64_ppc64le.go
+++ b/go/arrow/math/uint64_ppc64le.go
@@ -1,4 +1,4 @@
-// Code generated by type_s390x.go.tmpl. DO NOT EDIT.
+// Code generated by type_ppc64le.go.tmpl. DO NOT EDIT.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/arrow/math/uint64_s390x.go b/go/arrow/math/uint64_s390x.go
index 8f7419fd48..d6e7da7cf3 100644
--- a/go/arrow/math/uint64_s390x.go
+++ b/go/arrow/math/uint64_s390x.go
@@ -16,6 +16,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build !noasm
// +build !noasm
package math
diff --git a/go/internal/types/extension_types.go
b/go/internal/types/extension_types.go
index 53de27b8f6..ee3b2ddd9f 100644
--- a/go/internal/types/extension_types.go
+++ b/go/internal/types/extension_types.go
@@ -32,26 +32,50 @@ import (
"golang.org/x/xerrors"
)
+var UUID = NewUUIDType()
+
type UUIDBuilder struct {
*array.ExtensionBuilder
}
-func NewUUIDBuilder(bldr *array.ExtensionBuilder) *UUIDBuilder {
- b := &UUIDBuilder{
- ExtensionBuilder: bldr,
- }
- return b
+func NewUUIDBuilder(builder *array.ExtensionBuilder) *UUIDBuilder {
+ return &UUIDBuilder{ExtensionBuilder: builder}
}
func (b *UUIDBuilder) Append(v uuid.UUID) {
b.ExtensionBuilder.Builder.(*array.FixedSizeBinaryBuilder).Append(v[:])
}
+func (b *UUIDBuilder) UnsafeAppend(v uuid.UUID) {
+
b.ExtensionBuilder.Builder.(*array.FixedSizeBinaryBuilder).UnsafeAppend(v[:])
+}
+
+func (b *UUIDBuilder) AppendValueFromString(s string) error {
+ if s == array.NullValueStr {
+ b.AppendNull()
+ return nil
+ }
+
+ uid, err := uuid.Parse(s)
+ if err != nil {
+ return err
+ }
+
+ b.Append(uid)
+ return nil
+}
+
func (b *UUIDBuilder) AppendValues(v []uuid.UUID, valid []bool) {
+ if len(v) != len(valid) && len(valid) != 0 {
+ panic("len(v) != len(valid) && len(valid) != 0")
+ }
+
data := make([][]byte, len(v))
- for i, u := range v {
- data[i] = make([]byte, 16)
- copy(data[i][:], u[:])
+ for i := range v {
+ if len(valid) > 0 && !valid[i] {
+ continue
+ }
+ data[i] = v[i][:]
}
b.ExtensionBuilder.Builder.(*array.FixedSizeBinaryBuilder).AppendValues(data,
valid)
}
@@ -65,11 +89,15 @@ func (b *UUIDBuilder) UnmarshalOne(dec *json.Decoder) error
{
var val uuid.UUID
switch v := t.(type) {
case string:
- data, err := uuid.Parse(v)
+ val, err = uuid.Parse(v)
+ if err != nil {
+ return err
+ }
+ case []byte:
+ val, err = uuid.ParseBytes(v)
if err != nil {
return err
}
- val = data
case nil:
b.AppendNull()
return nil
@@ -82,14 +110,6 @@ func (b *UUIDBuilder) UnmarshalOne(dec *json.Decoder) error
{
}
}
- if len(val) != 16 {
- return &json.UnmarshalTypeError{
- Value: fmt.Sprint(val),
- Type: reflect.TypeOf([]byte{}),
- Offset: dec.InputOffset(),
- Struct: fmt.Sprintf("FixedSizeBinary[%d]", 16),
- }
- }
b.Append(val)
return nil
}
@@ -111,43 +131,18 @@ func (b *UUIDBuilder) UnmarshalJSON(data []byte) error {
}
if delim, ok := t.(json.Delim); !ok || delim != '[' {
- return fmt.Errorf("fixed size binary builder must unpack from
json array, found %s", delim)
+ return fmt.Errorf("uuid builder must unpack from json array,
found %s", delim)
}
return b.Unmarshal(dec)
}
-func (b *UUIDBuilder) AppendValueFromString(s string) error {
- if s == array.NullValueStr {
- b.AppendNull()
- return nil
- }
- u, err := uuid.Parse(s)
- if err != nil {
- return fmt.Errorf("%w: invalid uuid: %v", arrow.ErrInvalid, err)
- }
- b.Append(u)
- return nil
-}
-
// UUIDArray is a simple array which is a FixedSizeBinary(16)
type UUIDArray struct {
array.ExtensionArrayBase
}
-func (a UUIDArray) ValueStr(i int) string {
- if a.IsNull(i) {
- return "(null)"
- }
- arr := a.Storage().(*array.FixedSizeBinary)
- uuidStr, err := uuid.FromBytes(arr.Value(i))
- if err != nil {
- panic(fmt.Errorf("invalid uuid: %w", err))
- }
- return uuidStr.String()
-}
-
-func (a UUIDArray) String() string {
+func (a *UUIDArray) String() string {
arr := a.Storage().(*array.FixedSizeBinary)
o := new(strings.Builder)
o.WriteString("[")
@@ -157,46 +152,47 @@ func (a UUIDArray) String() string {
}
switch {
case a.IsNull(i):
- o.WriteString("(null)")
+ o.WriteString(array.NullValueStr)
default:
- uuidStr, err := uuid.FromBytes(arr.Value(i))
- if err != nil {
- panic(fmt.Errorf("invalid uuid: %w", err))
- }
- fmt.Fprintf(o, "%q", uuidStr)
+ fmt.Fprintf(o, "%q", a.Value(i))
}
}
o.WriteString("]")
return o.String()
}
+func (a *UUIDArray) Value(i int) uuid.UUID {
+ if a.IsNull(i) {
+ return uuid.Nil
+ }
+ return
uuid.Must(uuid.FromBytes(a.Storage().(*array.FixedSizeBinary).Value(i)))
+}
+
+func (a *UUIDArray) ValueStr(i int) string {
+ switch {
+ case a.IsNull(i):
+ return array.NullValueStr
+ default:
+ return a.Value(i).String()
+ }
+}
+
func (a *UUIDArray) MarshalJSON() ([]byte, error) {
arr := a.Storage().(*array.FixedSizeBinary)
- vals := make([]interface{}, a.Len())
+ values := make([]interface{}, a.Len())
for i := 0; i < a.Len(); i++ {
if a.IsValid(i) {
- uuidStr, err := uuid.FromBytes(arr.Value(i))
- if err != nil {
- panic(fmt.Errorf("invalid uuid: %w", err))
- }
- vals[i] = uuidStr
- } else {
- vals[i] = nil
+ values[i] =
uuid.Must(uuid.FromBytes(arr.Value(i))).String()
}
}
- return json.Marshal(vals)
+ return json.Marshal(values)
}
func (a *UUIDArray) GetOneForMarshal(i int) interface{} {
- arr := a.Storage().(*array.FixedSizeBinary)
- if a.IsValid(i) {
- uuidObj, err := uuid.FromBytes(arr.Value(i))
- if err != nil {
- panic(fmt.Errorf("invalid uuid: %w", err))
- }
- return uuidObj
+ if a.IsNull(i) {
+ return nil
}
- return nil
+ return a.Value(i)
}
// UUIDType is a simple extension type that represents a FixedSizeBinary(16)
@@ -205,27 +201,39 @@ type UUIDType struct {
arrow.ExtensionBase
}
-// NewUUIDType is a convenience function to create an instance of UuidType
+// NewUUIDType is a convenience function to create an instance of UUIDType
// with the correct storage type
func NewUUIDType() *UUIDType {
- return &UUIDType{
- ExtensionBase: arrow.ExtensionBase{
- Storage: &arrow.FixedSizeBinaryType{ByteWidth: 16}}}
+ return &UUIDType{ExtensionBase: arrow.ExtensionBase{Storage:
&arrow.FixedSizeBinaryType{ByteWidth: 16}}}
}
-// ArrayType returns TypeOf(UuidArray) for constructing uuid arrays
-func (UUIDType) ArrayType() reflect.Type { return reflect.TypeOf(UUIDArray{}) }
+// ArrayType returns TypeOf(UUIDArray{}) for constructing UUID arrays
+func (*UUIDType) ArrayType() reflect.Type {
+ return reflect.TypeOf(UUIDArray{})
+}
+
+func (*UUIDType) ExtensionName() string {
+ return "uuid"
+}
+
+func (e *UUIDType) String() string {
+ return fmt.Sprintf("extension_type<storage=%s>", e.Storage)
+}
-func (UUIDType) ExtensionName() string { return "uuid" }
+func (e *UUIDType) MarshalJSON() ([]byte, error) {
+ return []byte(fmt.Sprintf(`{"name":"%s","metadata":%s}`,
e.ExtensionName(), e.Serialize())), nil
+}
// Serialize returns "uuid-serialized" for testing proper metadata passing
-func (UUIDType) Serialize() string { return "uuid-serialized" }
+func (*UUIDType) Serialize() string {
+ return "uuid-serialized"
+}
// Deserialize expects storageType to be FixedSizeBinaryType{ByteWidth: 16}
and the data to be
// "uuid-serialized" in order to correctly create a UUIDType for testing
deserialize.
-func (UUIDType) Deserialize(storageType arrow.DataType, data string)
(arrow.ExtensionType, error) {
- if string(data) != "uuid-serialized" {
- return nil, fmt.Errorf("type identifier did not match: '%s'",
string(data))
+func (*UUIDType) Deserialize(storageType arrow.DataType, data string)
(arrow.ExtensionType, error) {
+ if data != "uuid-serialized" {
+ return nil, fmt.Errorf("type identifier did not match: '%s'",
data)
}
if !arrow.TypeEqual(storageType, &arrow.FixedSizeBinaryType{ByteWidth:
16}) {
return nil, fmt.Errorf("invalid storage type for UUIDType: %s",
storageType.Name())
@@ -233,12 +241,12 @@ func (UUIDType) Deserialize(storageType arrow.DataType,
data string) (arrow.Exte
return NewUUIDType(), nil
}
-// UuidTypes are equal if both are named "uuid"
-func (u UUIDType) ExtensionEquals(other arrow.ExtensionType) bool {
- return u.ExtensionName() == other.ExtensionName()
+// ExtensionEquals returns true if both extensions have the same name
+func (e *UUIDType) ExtensionEquals(other arrow.ExtensionType) bool {
+ return e.ExtensionName() == other.ExtensionName()
}
-func (u UUIDType) NewBuilder(bldr *array.ExtensionBuilder) array.Builder {
+func (*UUIDType) NewBuilder(bldr *array.ExtensionBuilder) array.Builder {
return NewUUIDBuilder(bldr)
}
@@ -251,7 +259,7 @@ type Parametric1Array struct {
func (a Parametric1Array) ValueStr(i int) string {
arr := a.Storage().(*array.Int32)
if a.IsNull(i) {
- return "(null)"
+ return array.NullValueStr
}
return fmt.Sprintf("%d", arr.Value(i))
}
@@ -266,7 +274,7 @@ type Parametric2Array struct {
func (a Parametric2Array) ValueStr(i int) string {
arr := a.Storage().(*array.Int32)
if a.IsNull(i) {
- return "(null)"
+ return array.NullValueStr
}
return fmt.Sprintf("%d", arr.Value(i))
}
@@ -384,7 +392,7 @@ type ExtStructArray struct {
func (a ExtStructArray) ValueStr(i int) string {
arr := a.Storage().(*array.Struct)
if a.IsNull(i) {
- return "(null)"
+ return array.NullValueStr
}
b, err := arr.MarshalJSON()
if err != nil {
@@ -441,7 +449,7 @@ type DictExtensionArray struct {
func (a DictExtensionArray) ValueStr(i int) string {
arr := a.Storage().(*array.Dictionary)
if a.IsNull(i) {
- return "(null)"
+ return array.NullValueStr
}
b, err := arr.MarshalJSON()
if err != nil {
@@ -491,7 +499,7 @@ type SmallintArray struct {
func (a SmallintArray) ValueStr(i int) string {
if a.IsNull(i) {
- return "(null)"
+ return array.NullValueStr
}
arr := a.Storage().(*array.Int16)
return fmt.Sprintf("%d", arr.Value(i))
diff --git a/go/internal/types/extension_types_test.go
b/go/internal/types/extension_types_test.go
index 0ece6eb49e..51764b0e8f 100644
--- a/go/internal/types/extension_types_test.go
+++ b/go/internal/types/extension_types_test.go
@@ -66,3 +66,36 @@ func TestExtensionRecordBuilder(t *testing.T) {
require.NoError(t, err)
require.Equal(t, record, record1)
}
+
+func TestUUIDStringRoundTrip(t *testing.T) {
+ // 1. create array
+ mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
+ defer mem.AssertSize(t, 0)
+
+ extBuilder := array.NewExtensionBuilder(mem, types.NewUUIDType())
+ defer extBuilder.Release()
+ b := types.NewUUIDBuilder(extBuilder)
+ b.Append(uuid.Nil)
+ b.AppendNull()
+ b.Append(uuid.NameSpaceURL)
+ b.AppendNull()
+ b.Append(testUUID)
+
+ arr := b.NewArray()
+ defer arr.Release()
+
+ // 2. create array via AppendValueFromString
+ extBuilder1 := array.NewExtensionBuilder(mem, types.NewUUIDType())
+ defer extBuilder1.Release()
+ b1 := types.NewUUIDBuilder(extBuilder1)
+ defer b1.Release()
+
+ for i := 0; i < arr.Len(); i++ {
+ assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+ }
+
+ arr1 := b1.NewArray()
+ defer arr1.Release()
+
+ assert.True(t, array.Equal(arr, arr1))
+}