This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new 12aaf2c ARROW-13804: [Go] Add Interval type Month, Day, Nano
12aaf2c is described below
commit 12aaf2ce15600d1a8d8cbdaf71ca7a922f520a82
Author: Matthew Topol <[email protected]>
AuthorDate: Wed Oct 13 16:58:24 2021 -0400
ARROW-13804: [Go] Add Interval type Month, Day, Nano
#10177 Added the interval type Month, Day, Nano to the flatbuffer and
C++/Java, this updates the flatbuffer generated files and adds support for the
type to Go.
Closes #11310 from zeroshade/arrow-13804-month-day-nano
Authored-by: Matthew Topol <[email protected]>
Signed-off-by: Matthew Topol <[email protected]>
---
.github/workflows/archery.yml | 2 +
dev/archery/archery/integration/datagen.py | 2 -
go/arrow/array/array.go | 4 +-
go/arrow/array/array_test.go | 3 +-
go/arrow/array/builder.go | 3 +
go/arrow/array/compare.go | 6 +
go/arrow/array/interval.go | 199 +++++++++++++++++++++
go/arrow/array/interval_test.go | 131 ++++++++++++++
go/arrow/cdata/cdata.go | 1 +
go/arrow/cdata/cdata_exports.go | 2 +
go/arrow/cdata/cdata_test.go | 1 +
go/arrow/datatype_fixedwidth.go | 98 ++++++----
go/arrow/internal/arrdata/arrdata.go | 19 +-
go/arrow/internal/arrjson/arrjson.go | 48 +++++
go/arrow/internal/arrjson/arrjson_test.go | 174 ++++++++++++++++--
.../cmd/arrow-flight-integration-server/main.go | 1 -
go/arrow/internal/flight_integration/scenario.go | 20 ++-
go/arrow/ipc/file_reader.go | 2 +-
go/arrow/ipc/metadata.go | 8 +
go/arrow/scalar/parse.go | 2 +
go/arrow/scalar/scalar.go | 14 +-
go/arrow/scalar/scalar_test.go | 27 +++
go/arrow/scalar/temporal.go | 42 +++++
go/arrow/type_traits_interval.go | 62 ++++++-
go/arrow/type_traits_test.go | 34 ++++
.../java/org/apache/arrow/flight/FlightStream.java | 10 +-
26 files changed, 836 insertions(+), 79 deletions(-)
diff --git a/.github/workflows/archery.yml b/.github/workflows/archery.yml
index 66cd04a..fa84f4dc 100644
--- a/.github/workflows/archery.yml
+++ b/.github/workflows/archery.yml
@@ -56,6 +56,8 @@ jobs:
uses: actions/setup-python@v1
with:
python-version: '3.6'
+ - name: Install pygit2 binary wheel
+ run: pip install pygit2 --only-binary pygit2
- name: Install Archery, Crossbow- and Test Dependencies
run: pip install pytest responses -e dev/archery[all]
- name: Archery Unittests
diff --git a/dev/archery/archery/integration/datagen.py
b/dev/archery/archery/integration/datagen.py
index 7e23047..8a9f4de 100644
--- a/dev/archery/archery/integration/datagen.py
+++ b/dev/archery/archery/integration/datagen.py
@@ -1564,7 +1564,6 @@ def get_generated_json_files(tempdir=None):
generate_null_case([10, 0])
.skip_category('C#')
.skip_category('Go') # TODO(ARROW-7901)
- .skip_category('Go') # TODO(ARROW-7901)
.skip_category('JS'), # TODO(ARROW-7900)
generate_null_trivial_case([0, 0])
@@ -1590,7 +1589,6 @@ def get_generated_json_files(tempdir=None):
generate_month_day_nano_interval_case()
.skip_category('C#')
- .skip_category('Go')
.skip_category('JS')
.skip_category('Rust'),
diff --git a/go/arrow/array/array.go b/go/arrow/array/array.go
index 8679773..5779717 100644
--- a/go/arrow/array/array.go
+++ b/go/arrow/array/array.go
@@ -207,10 +207,10 @@ func init() {
arrow.LARGE_STRING: unsupportedArrayType,
arrow.LARGE_BINARY: unsupportedArrayType,
arrow.LARGE_LIST: unsupportedArrayType,
- arrow.INTERVAL_MONTH_DAY_NANO: unsupportedArrayType,
arrow.INTERVAL: func(data *Data) Interface {
return NewIntervalData(data) },
+ arrow.INTERVAL_MONTH_DAY_NANO: func(data *Data) Interface {
return NewMonthDayNanoIntervalData(data) },
- // invalid data types to fill out array size 2⁵-1
+ // invalid data types to fill out array to size 2^6 - 1
63: invalidDataType,
}
}
diff --git a/go/arrow/array/array_test.go b/go/arrow/array/array_test.go
index 5d93245..b986332 100644
--- a/go/arrow/array/array_test.go
+++ b/go/arrow/array/array_test.go
@@ -68,7 +68,8 @@ func TestMakeFromData(t *testing.T) {
{name: "time64", d: &testDataType{arrow.TIME64}},
{name: "month_interval", d:
arrow.FixedWidthTypes.MonthInterval},
{name: "day_time_interval", d:
arrow.FixedWidthTypes.DayTimeInterval},
- {name: "decimal", d: &testDataType{arrow.DECIMAL128}},
+ {name: "decimal128", d: &testDataType{arrow.DECIMAL128}},
+ {name: "month_day_nano_interval", d:
arrow.FixedWidthTypes.MonthDayNanoInterval},
{name: "list", d: &testDataType{arrow.LIST}, child:
[]*array.Data{
array.NewData(&testDataType{arrow.INT64}, 0 /* length
*/, make([]*memory.Buffer, 2 /*null bitmap, values*/), nil /* childData */, 0
/* nulls */, 0 /* offset */),
diff --git a/go/arrow/array/builder.go b/go/arrow/array/builder.go
index 5342c5f..77d0d42 100644
--- a/go/arrow/array/builder.go
+++ b/go/arrow/array/builder.go
@@ -266,12 +266,15 @@ func NewBuilder(mem memory.Allocator, dtype
arrow.DataType) Builder {
return NewDayTimeIntervalBuilder(mem)
case *arrow.MonthIntervalType:
return NewMonthIntervalBuilder(mem)
+ case *arrow.MonthDayNanoIntervalType:
+ return NewMonthDayNanoIntervalBuilder(mem)
}
case arrow.INTERVAL_MONTHS:
return NewMonthIntervalBuilder(mem)
case arrow.INTERVAL_DAY_TIME:
return NewDayTimeIntervalBuilder(mem)
case arrow.INTERVAL_MONTH_DAY_NANO:
+ return NewMonthDayNanoIntervalBuilder(mem)
case arrow.DECIMAL128:
if typ, ok := dtype.(*arrow.Decimal128Type); ok {
return NewDecimal128Builder(mem, typ)
diff --git a/go/arrow/array/compare.go b/go/arrow/array/compare.go
index f0ff5ed..c4ee046 100644
--- a/go/arrow/array/compare.go
+++ b/go/arrow/array/compare.go
@@ -161,6 +161,9 @@ func ArrayEqual(left, right Interface) bool {
case *DayTimeInterval:
r := right.(*DayTimeInterval)
return arrayEqualDayTimeInterval(l, r)
+ case *MonthDayNanoInterval:
+ r := right.(*MonthDayNanoInterval)
+ return arrayEqualMonthDayNanoInterval(l, r)
case *Duration:
r := right.(*Duration)
return arrayEqualDuration(l, r)
@@ -355,6 +358,9 @@ func arrayApproxEqual(left, right Interface, opt
equalOption) bool {
case *DayTimeInterval:
r := right.(*DayTimeInterval)
return arrayEqualDayTimeInterval(l, r)
+ case *MonthDayNanoInterval:
+ r := right.(*MonthDayNanoInterval)
+ return arrayEqualMonthDayNanoInterval(l, r)
case *Duration:
r := right.(*Duration)
return arrayEqualDuration(l, r)
diff --git a/go/arrow/array/interval.go b/go/arrow/array/interval.go
index d313558..c9191eb 100644
--- a/go/arrow/array/interval.go
+++ b/go/arrow/array/interval.go
@@ -34,6 +34,8 @@ func NewIntervalData(data *Data) Interface {
return NewMonthIntervalData(data)
case *arrow.DayTimeIntervalType:
return NewDayTimeIntervalData(data)
+ case *arrow.MonthDayNanoIntervalType:
+ return NewMonthDayNanoIntervalData(data)
default:
panic(xerrors.Errorf("arrow/array: unknown interval data type
%T", data.dtype))
}
@@ -425,10 +427,207 @@ func (b *DayTimeIntervalBuilder) newData() (data *Data) {
return
}
+// A type which represents an immutable sequence of arrow.DayTimeInterval
values.
+type MonthDayNanoInterval struct {
+ array
+ values []arrow.MonthDayNanoInterval
+}
+
+func NewMonthDayNanoIntervalData(data *Data) *MonthDayNanoInterval {
+ a := &MonthDayNanoInterval{}
+ a.refCount = 1
+ a.setData(data)
+ return a
+}
+
+func (a *MonthDayNanoInterval) Value(i int) arrow.MonthDayNanoInterval {
return a.values[i] }
+func (a *MonthDayNanoInterval) MonthDayNanoIntervalValues()
[]arrow.MonthDayNanoInterval {
+ return a.values
+}
+
+func (a *MonthDayNanoInterval) String() string {
+ o := new(strings.Builder)
+ o.WriteString("[")
+ for i, v := range a.values {
+ if i > 0 {
+ fmt.Fprintf(o, " ")
+ }
+ switch {
+ case a.IsNull(i):
+ o.WriteString("(null)")
+ default:
+ fmt.Fprintf(o, "%v", v)
+ }
+ }
+ o.WriteString("]")
+ return o.String()
+}
+
+func (a *MonthDayNanoInterval) setData(data *Data) {
+ a.array.setData(data)
+ vals := data.buffers[1]
+ if vals != nil {
+ a.values =
arrow.MonthDayNanoIntervalTraits.CastFromBytes(vals.Bytes())
+ beg := a.array.data.offset
+ end := beg + a.array.data.length
+ a.values = a.values[beg:end]
+ }
+}
+
+func arrayEqualMonthDayNanoInterval(left, right *MonthDayNanoInterval) bool {
+ for i := 0; i < left.Len(); i++ {
+ if left.IsNull(i) {
+ continue
+ }
+ if left.Value(i) != right.Value(i) {
+ return false
+ }
+ }
+ return true
+}
+
+type MonthDayNanoIntervalBuilder struct {
+ builder
+
+ data *memory.Buffer
+ rawData []arrow.MonthDayNanoInterval
+}
+
+func NewMonthDayNanoIntervalBuilder(mem memory.Allocator)
*MonthDayNanoIntervalBuilder {
+ return &MonthDayNanoIntervalBuilder{builder: builder{refCount: 1, mem:
mem}}
+}
+
+// Release decreases the reference count by 1.
+// When the reference count goes to zero, the memory is freed.
+func (b *MonthDayNanoIntervalBuilder) Release() {
+ debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
+
+ if atomic.AddInt64(&b.refCount, -1) == 0 {
+ if b.nullBitmap != nil {
+ b.nullBitmap.Release()
+ b.nullBitmap = nil
+ }
+ if b.data != nil {
+ b.data.Release()
+ b.data = nil
+ b.rawData = nil
+ }
+ }
+}
+
+func (b *MonthDayNanoIntervalBuilder) Append(v arrow.MonthDayNanoInterval) {
+ b.Reserve(1)
+ b.UnsafeAppend(v)
+}
+
+func (b *MonthDayNanoIntervalBuilder) AppendNull() {
+ b.Reserve(1)
+ b.UnsafeAppendBoolToBitmap(false)
+}
+
+func (b *MonthDayNanoIntervalBuilder) UnsafeAppend(v
arrow.MonthDayNanoInterval) {
+ bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+ b.rawData[b.length] = v
+ b.length++
+}
+
+func (b *MonthDayNanoIntervalBuilder) UnsafeAppendBoolToBitmap(isValid bool) {
+ if isValid {
+ bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+ } else {
+ b.nulls++
+ }
+ b.length++
+}
+
+// AppendValues will append the values in the v slice. The valid slice
determines which values
+// in v are valid (not null). The valid slice must either be empty or be equal
in length to v. If empty,
+// all values in v are appended and considered valid.
+func (b *MonthDayNanoIntervalBuilder) AppendValues(v
[]arrow.MonthDayNanoInterval, valid []bool) {
+ if len(v) != len(valid) && len(valid) != 0 {
+ panic("len(v) != len(valid) && len(valid) != 0")
+ }
+
+ if len(v) == 0 {
+ return
+ }
+
+ b.Reserve(len(v))
+ arrow.MonthDayNanoIntervalTraits.Copy(b.rawData[b.length:], v)
+ b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
+}
+
+func (b *MonthDayNanoIntervalBuilder) init(capacity int) {
+ b.builder.init(capacity)
+
+ b.data = memory.NewResizableBuffer(b.mem)
+ bytesN := arrow.MonthDayNanoIntervalTraits.BytesRequired(capacity)
+ b.data.Resize(bytesN)
+ b.rawData =
arrow.MonthDayNanoIntervalTraits.CastFromBytes(b.data.Bytes())
+}
+
+// Reserve ensures there is enough space for appending n elements
+// by checking the capacity and calling Resize if necessary.
+func (b *MonthDayNanoIntervalBuilder) Reserve(n int) {
+ b.builder.reserve(n, b.Resize)
+}
+
+// Resize adjusts the space allocated by b to n elements. If n is greater than
b.Cap(),
+// additional memory will be allocated. If n is smaller, the allocated memory
may reduced.
+func (b *MonthDayNanoIntervalBuilder) Resize(n int) {
+ nBuilder := n
+ if n < minBuilderCapacity {
+ n = minBuilderCapacity
+ }
+
+ if b.capacity == 0 {
+ b.init(n)
+ } else {
+ b.builder.resize(nBuilder, b.init)
+ b.data.Resize(arrow.MonthDayNanoIntervalTraits.BytesRequired(n))
+ b.rawData =
arrow.MonthDayNanoIntervalTraits.CastFromBytes(b.data.Bytes())
+ }
+}
+
+// NewArray creates a MonthDayNanoInterval array from the memory buffers used
by the builder and resets the MonthDayNanoIntervalBuilder
+// so it can be used to build a new array.
+func (b *MonthDayNanoIntervalBuilder) NewArray() Interface {
+ return b.NewMonthDayNanoIntervalArray()
+}
+
+// NewMonthDayNanoIntervalArray creates a MonthDayNanoInterval array from the
memory buffers used by the builder and resets the MonthDayNanoIntervalBuilder
+// so it can be used to build a new array.
+func (b *MonthDayNanoIntervalBuilder) NewMonthDayNanoIntervalArray() (a
*MonthDayNanoInterval) {
+ data := b.newData()
+ a = NewMonthDayNanoIntervalData(data)
+ data.Release()
+ return
+}
+
+func (b *MonthDayNanoIntervalBuilder) newData() (data *Data) {
+ bytesRequired :=
arrow.MonthDayNanoIntervalTraits.BytesRequired(b.length)
+ if bytesRequired > 0 && bytesRequired < b.data.Len() {
+ // trim buffers
+ b.data.Resize(bytesRequired)
+ }
+ data = NewData(arrow.FixedWidthTypes.MonthDayNanoInterval, b.length,
[]*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
+ b.reset()
+
+ if b.data != nil {
+ b.data.Release()
+ b.data = nil
+ b.rawData = nil
+ }
+
+ return
+}
+
var (
_ Interface = (*MonthInterval)(nil)
_ Interface = (*DayTimeInterval)(nil)
+ _ Interface = (*MonthDayNanoInterval)(nil)
_ Builder = (*MonthIntervalBuilder)(nil)
_ Builder = (*DayTimeIntervalBuilder)(nil)
+ _ Builder = (*MonthDayNanoIntervalBuilder)(nil)
)
diff --git a/go/arrow/array/interval_test.go b/go/arrow/array/interval_test.go
index 3e47881..0e983fd 100644
--- a/go/arrow/array/interval_test.go
+++ b/go/arrow/array/interval_test.go
@@ -17,6 +17,7 @@
package array_test
import (
+ "math"
"testing"
"github.com/apache/arrow/go/arrow"
@@ -274,3 +275,133 @@ func TestDayTimeIntervalBuilder_Empty(t *testing.T) {
assert.Equal(t, want, dtValues(arr))
arr.Release()
}
+
+func TestMonthDayNanoArray(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ var (
+ want = []arrow.MonthDayNanoInterval{
+ {1, 1, 1000}, {2, 2, 2000}, {3, 3, 3000}, {4, 4, 4000},
+ {0, 0, 0}, {-1, -2, -300}, {math.MaxInt32,
math.MinInt32, math.MaxInt64},
+ {math.MinInt32, math.MaxInt32, math.MinInt64},
+ }
+ valids = []bool{true, true, false, true, true, true, false,
true}
+ )
+
+ b := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer b.Release()
+
+ b.Retain()
+ b.Release()
+
+ b.AppendValues(want[:2], nil)
+ b.AppendNull()
+ b.Append(want[3])
+ b.AppendValues(want[4:], valids[4:])
+
+ if got, want := b.Len(), len(want); got != want {
+ t.Fatalf("invalid len: got=%d, want=%d", got, want)
+ }
+
+ if got, want := b.NullN(), 2; got != want {
+ t.Fatalf("invalid nulls: got=%d, want=%d", got, want)
+ }
+
+ arr := b.NewMonthDayNanoIntervalArray()
+ defer arr.Release()
+
+ arr.Retain()
+ arr.Release()
+
+ if got, want := arr.Len(), len(want); got != want {
+ t.Fatalf("invalid len: got=%d, want=%d", got, want)
+ }
+
+ if got, want := arr.NullN(), 2; got != want {
+ t.Fatalf("invalid nulls: got=%d, want=%d", got, want)
+ }
+
+ for i := range want {
+ if arr.IsNull(i) != !valids[i] {
+ t.Fatalf("arr[%d]-validity: got=%v want=%v", i,
!arr.IsNull(i), valids[i])
+ }
+ switch {
+ case arr.IsNull(i):
+ default:
+ got := arr.Value(i)
+ if got != want[i] {
+ t.Fatalf("arr[%d]: got=%q, want=%q", i, got,
want[i])
+ }
+ }
+ }
+
+ sub := array.MakeFromData(arr.Data())
+ defer sub.Release()
+
+ if sub.DataType().ID() != arrow.INTERVAL_MONTH_DAY_NANO {
+ t.Fatalf("invalid type: got=%q, want=interval",
sub.DataType().Name())
+ }
+
+ if _, ok := sub.(*array.MonthDayNanoInterval); !ok {
+ t.Fatalf("could not type-assert to array.MonthDayNanoInterval")
+ }
+
+ if got, want := arr.String(), `[{1 1 1000} {2 2 2000} (null) {4 4 4000}
{0 0 0} {-1 -2 -300} (null) {-2147483648 2147483647 -9223372036854775808}]`;
got != want {
+ t.Fatalf("got=%q, want=%q", got, want)
+ }
+ slice := array.NewSliceData(arr.Data(), 2, 4)
+ defer slice.Release()
+
+ sub1 := array.MakeFromData(slice)
+ defer sub1.Release()
+
+ v, ok := sub1.(*array.MonthDayNanoInterval)
+ if !ok {
+ t.Fatalf("could not type-assert to array.MonthDayNanoInterval")
+ }
+
+ if got, want := v.String(), `[(null) {4 4 4000}]`; got != want {
+ t.Fatalf("got=%q, want=%q", got, want)
+ }
+}
+
+func TestMonthDayNanoIntervalBuilder_Empty(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+ defer mem.AssertSize(t, 0)
+
+ want := []arrow.MonthDayNanoInterval{{1, 1, 1000}, {2, 2, 2000}, {3, 3,
3000}, {4, 4, 4000}}
+
+ b := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer b.Release()
+
+ dtValues := func(a *array.MonthDayNanoInterval)
[]arrow.MonthDayNanoInterval {
+ vs := make([]arrow.MonthDayNanoInterval, a.Len())
+ for i := range vs {
+ vs[i] = a.Value(i)
+ }
+ return vs
+ }
+
+ b.AppendValues([]arrow.MonthDayNanoInterval{}, nil)
+ arr := b.NewMonthDayNanoIntervalArray()
+ assert.Zero(t, arr.Len())
+ arr.Release()
+
+ b.AppendValues(nil, nil)
+ arr = b.NewMonthDayNanoIntervalArray()
+ assert.Zero(t, arr.Len())
+ arr.Release()
+
+ b.AppendValues([]arrow.MonthDayNanoInterval{}, nil)
+ b.AppendValues(want, nil)
+ arr = b.NewMonthDayNanoIntervalArray()
+ assert.Equal(t, want, dtValues(arr))
+ arr.Release()
+
+ b.AppendValues(want, nil)
+ b.AppendValues([]arrow.MonthDayNanoInterval{}, nil)
+ arr = b.NewMonthDayNanoIntervalArray()
+ assert.Equal(t, want, dtValues(arr))
+ arr.Release()
+}
diff --git a/go/arrow/cdata/cdata.go b/go/arrow/cdata/cdata.go
index a8d1a5d..c3b50cd 100644
--- a/go/arrow/cdata/cdata.go
+++ b/go/arrow/cdata/cdata.go
@@ -87,6 +87,7 @@ var formatToSimpleType = map[string]arrow.DataType{
"tDn": arrow.FixedWidthTypes.Duration_ns,
"tiM": arrow.FixedWidthTypes.MonthInterval,
"tiD": arrow.FixedWidthTypes.DayTimeInterval,
+ "tin": arrow.FixedWidthTypes.MonthDayNanoInterval,
}
// decode metadata from C which is encoded as
diff --git a/go/arrow/cdata/cdata_exports.go b/go/arrow/cdata/cdata_exports.go
index 8565952..926a1cc 100644
--- a/go/arrow/cdata/cdata_exports.go
+++ b/go/arrow/cdata/cdata_exports.go
@@ -208,6 +208,8 @@ func (exp *schemaExporter) exportFormat(dt arrow.DataType)
string {
return "tiM"
case *arrow.DayTimeIntervalType:
return "tiD"
+ case *arrow.MonthDayNanoIntervalType:
+ return "tin"
case *arrow.ListType:
return "+l"
case *arrow.FixedSizeListType:
diff --git a/go/arrow/cdata/cdata_test.go b/go/arrow/cdata/cdata_test.go
index 47cd334..cf6aba3 100644
--- a/go/arrow/cdata/cdata_test.go
+++ b/go/arrow/cdata/cdata_test.go
@@ -149,6 +149,7 @@ func TestImportTemporalSchema(t *testing.T) {
{arrow.FixedWidthTypes.Duration_ns, "tDn"},
{arrow.FixedWidthTypes.MonthInterval, "tiM"},
{arrow.FixedWidthTypes.DayTimeInterval, "tiD"},
+ {arrow.FixedWidthTypes.MonthDayNanoInterval, "tin"},
{arrow.FixedWidthTypes.Timestamp_s, "tss:"},
{&arrow.TimestampType{Unit: arrow.Second, TimeZone:
"Europe/Paris"}, "tss:Europe/Paris"},
{arrow.FixedWidthTypes.Timestamp_ms, "tsm:"},
diff --git a/go/arrow/datatype_fixedwidth.go b/go/arrow/datatype_fixedwidth.go
index b30ee63..541f091 100644
--- a/go/arrow/datatype_fixedwidth.go
+++ b/go/arrow/datatype_fixedwidth.go
@@ -150,7 +150,7 @@ type Decimal128Type struct {
Scale int32
}
-func (*Decimal128Type) ID() Type { return DECIMAL }
+func (*Decimal128Type) ID() Type { return DECIMAL128 }
func (*Decimal128Type) Name() string { return "decimal" }
func (*Decimal128Type) BitWidth() int { return 128 }
func (t *Decimal128Type) String() string {
@@ -193,45 +193,69 @@ func (*DayTimeIntervalType) Fingerprint() string { return
typeIDFingerprint(INTE
// BitWidth returns the number of bits required to store a single element of
this data type in memory.
func (t *DayTimeIntervalType) BitWidth() int { return 64 }
+// MonthDayNanoInterval represents a number of months, days and nanoseconds
(fraction of day).
+type MonthDayNanoInterval struct {
+ Months int32 `json:"months"`
+ Days int32 `json:"days"`
+ Nanoseconds int64 `json:"nanoseconds"`
+}
+
+// MonthDayNanoIntervalType is encoded as two signed 32-bit integers
representing
+// a number of months and a number of days, followed by a 64-bit integer
representing
+// the number of nanoseconds since midnight for fractions of a day.
+type MonthDayNanoIntervalType struct{}
+
+func (*MonthDayNanoIntervalType) ID() Type { return
INTERVAL_MONTH_DAY_NANO }
+func (*MonthDayNanoIntervalType) Name() string { return
"month_day_nano_interval" }
+func (*MonthDayNanoIntervalType) String() string { return
"month_day_nano_interval" }
+func (*MonthDayNanoIntervalType) Fingerprint() string {
+ return typeIDFingerprint(INTERVAL_MONTH_DAY_NANO) + "N"
+}
+
+// BitWidth returns the number of bits required to store a single element of
this data type in memory.
+func (*MonthDayNanoIntervalType) BitWidth() int { return 128 }
+
var (
FixedWidthTypes = struct {
- Boolean FixedWidthDataType
- Date32 FixedWidthDataType
- Date64 FixedWidthDataType
- DayTimeInterval FixedWidthDataType
- Duration_s FixedWidthDataType
- Duration_ms FixedWidthDataType
- Duration_us FixedWidthDataType
- Duration_ns FixedWidthDataType
- Float16 FixedWidthDataType
- MonthInterval FixedWidthDataType
- Time32s FixedWidthDataType
- Time32ms FixedWidthDataType
- Time64us FixedWidthDataType
- Time64ns FixedWidthDataType
- Timestamp_s FixedWidthDataType
- Timestamp_ms FixedWidthDataType
- Timestamp_us FixedWidthDataType
- Timestamp_ns FixedWidthDataType
+ Boolean FixedWidthDataType
+ Date32 FixedWidthDataType
+ Date64 FixedWidthDataType
+ DayTimeInterval FixedWidthDataType
+ Duration_s FixedWidthDataType
+ Duration_ms FixedWidthDataType
+ Duration_us FixedWidthDataType
+ Duration_ns FixedWidthDataType
+ Float16 FixedWidthDataType
+ MonthInterval FixedWidthDataType
+ Time32s FixedWidthDataType
+ Time32ms FixedWidthDataType
+ Time64us FixedWidthDataType
+ Time64ns FixedWidthDataType
+ Timestamp_s FixedWidthDataType
+ Timestamp_ms FixedWidthDataType
+ Timestamp_us FixedWidthDataType
+ Timestamp_ns FixedWidthDataType
+ MonthDayNanoInterval FixedWidthDataType
}{
- Boolean: &BooleanType{},
- Date32: &Date32Type{},
- Date64: &Date64Type{},
- DayTimeInterval: &DayTimeIntervalType{},
- Duration_s: &DurationType{Unit: Second},
- Duration_ms: &DurationType{Unit: Millisecond},
- Duration_us: &DurationType{Unit: Microsecond},
- Duration_ns: &DurationType{Unit: Nanosecond},
- Float16: &Float16Type{},
- MonthInterval: &MonthIntervalType{},
- Time32s: &Time32Type{Unit: Second},
- Time32ms: &Time32Type{Unit: Millisecond},
- Time64us: &Time64Type{Unit: Microsecond},
- Time64ns: &Time64Type{Unit: Nanosecond},
- Timestamp_s: &TimestampType{Unit: Second, TimeZone: "UTC"},
- Timestamp_ms: &TimestampType{Unit: Millisecond, TimeZone:
"UTC"},
- Timestamp_us: &TimestampType{Unit: Microsecond, TimeZone:
"UTC"},
- Timestamp_ns: &TimestampType{Unit: Nanosecond, TimeZone:
"UTC"},
+ Boolean: &BooleanType{},
+ Date32: &Date32Type{},
+ Date64: &Date64Type{},
+ DayTimeInterval: &DayTimeIntervalType{},
+ Duration_s: &DurationType{Unit: Second},
+ Duration_ms: &DurationType{Unit: Millisecond},
+ Duration_us: &DurationType{Unit: Microsecond},
+ Duration_ns: &DurationType{Unit: Nanosecond},
+ Float16: &Float16Type{},
+ MonthInterval: &MonthIntervalType{},
+ Time32s: &Time32Type{Unit: Second},
+ Time32ms: &Time32Type{Unit: Millisecond},
+ Time64us: &Time64Type{Unit: Microsecond},
+ Time64ns: &Time64Type{Unit: Nanosecond},
+ Timestamp_s: &TimestampType{Unit: Second, TimeZone:
"UTC"},
+ Timestamp_ms: &TimestampType{Unit: Millisecond,
TimeZone: "UTC"},
+ Timestamp_us: &TimestampType{Unit: Microsecond,
TimeZone: "UTC"},
+ Timestamp_ns: &TimestampType{Unit: Nanosecond,
TimeZone: "UTC"},
+ MonthDayNanoInterval: &MonthDayNanoIntervalType{},
}
_ FixedWidthDataType = (*FixedSizeBinaryType)(nil)
diff --git a/go/arrow/internal/arrdata/arrdata.go
b/go/arrow/internal/arrdata/arrdata.go
index 69dc8a1..77f3d35 100644
--- a/go/arrow/internal/arrdata/arrdata.go
+++ b/go/arrow/internal/arrdata/arrdata.go
@@ -553,6 +553,7 @@ func makeIntervalsRecords() []array.Record {
[]arrow.Field{
arrow.Field{Name: "months", Type:
arrow.FixedWidthTypes.MonthInterval, Nullable: true},
arrow.Field{Name: "days", Type:
arrow.FixedWidthTypes.DayTimeInterval, Nullable: true},
+ arrow.Field{Name: "nanos", Type:
arrow.FixedWidthTypes.MonthDayNanoInterval, Nullable: true},
}, nil,
)
@@ -561,14 +562,17 @@ func makeIntervalsRecords() []array.Record {
[]array.Interface{
arrayOf(mem, []arrow.MonthInterval{1, 2, 3, 4, 5},
mask),
arrayOf(mem, []arrow.DayTimeInterval{{1, 1}, {2, 2},
{3, 3}, {4, 4}, {5, 5}}, mask),
+ arrayOf(mem, []arrow.MonthDayNanoInterval{{1, 1, 1000},
{2, 2, 2000}, {3, 3, 3000}, {4, 4, 4000}, {5, 5, 5000}}, mask),
},
[]array.Interface{
- arrayOf(mem, []arrow.MonthInterval{11, 12, 13, 14, 15},
mask),
- arrayOf(mem, []arrow.DayTimeInterval{{11, 11}, {12,
12}, {13, 13}, {14, 14}, {15, 15}}, mask),
+ arrayOf(mem, []arrow.MonthInterval{-11, -12, -13, -14,
-15}, mask),
+ arrayOf(mem, []arrow.DayTimeInterval{{-11, -11}, {-12,
-12}, {-13, -13}, {-14, -14}, {-15, -15}}, mask),
+ arrayOf(mem, []arrow.MonthDayNanoInterval{{-11, -11,
-11000}, {-12, -12, -12000}, {-13, -13, -13000}, {-14, -14, -14000}, {-15, -15,
-15000}}, mask),
},
[]array.Interface{
- arrayOf(mem, []arrow.MonthInterval{21, 22, 23, 24, 25},
mask),
- arrayOf(mem, []arrow.DayTimeInterval{{21, 21}, {22,
22}, {23, 23}, {24, 24}, {25, 25}}, mask),
+ arrayOf(mem, []arrow.MonthInterval{21, 22, 23, 24, 25,
0}, append(mask, true)),
+ arrayOf(mem, []arrow.DayTimeInterval{{21, 21}, {22,
22}, {23, 23}, {24, 24}, {25, 25}, {0, 0}}, append(mask, true)),
+ arrayOf(mem, []arrow.MonthDayNanoInterval{{21, 21,
21000}, {22, 22, 22000}, {23, 23, 23000}, {24, 24, 24000}, {25, 25, 25000}, {0,
0, 0}}, append(mask, true)),
},
}
@@ -1153,6 +1157,13 @@ func arrayOf(mem memory.Allocator, a interface{}, valids
[]bool) array.Interface
bldr.AppendValues(a, valids)
return bldr.NewArray()
+ case []arrow.MonthDayNanoInterval:
+ bldr := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer bldr.Release()
+
+ bldr.AppendValues(a, valids)
+ return bldr.NewArray()
+
case []duration_s:
bldr := array.NewDurationBuilder(mem, &arrow.DurationType{Unit:
arrow.Second})
defer bldr.Release()
diff --git a/go/arrow/internal/arrjson/arrjson.go
b/go/arrow/internal/arrjson/arrjson.go
index a8209ea..c792229 100644
--- a/go/arrow/internal/arrjson/arrjson.go
+++ b/go/arrow/internal/arrjson/arrjson.go
@@ -169,6 +169,8 @@ func (f FieldWrapper) MarshalJSON() ([]byte, error) {
typ = unitZoneJSON{Name: "interval", Unit: "YEAR_MONTH"}
case *arrow.DayTimeIntervalType:
typ = unitZoneJSON{Name: "interval", Unit: "DAY_TIME"}
+ case *arrow.MonthDayNanoIntervalType:
+ typ = unitZoneJSON{Name: "interval", Unit: "MONTH_DAY_NANO"}
case *arrow.DurationType:
switch dt.Unit {
case arrow.Second:
@@ -388,6 +390,8 @@ func (f *FieldWrapper) UnmarshalJSON(data []byte) error {
f.arrowType = arrow.FixedWidthTypes.MonthInterval
case "DAY_TIME":
f.arrowType = arrow.FixedWidthTypes.DayTimeInterval
+ case "MONTH_DAY_NANO":
+ f.arrowType = arrow.FixedWidthTypes.MonthDayNanoInterval
}
case "duration":
t := unitZoneJSON{}
@@ -889,6 +893,14 @@ func arrayFromJSON(mem memory.Allocator, dt
arrow.DataType, arr Array) array.Int
bldr.AppendValues(data, valids)
return bldr.NewArray()
+ case *arrow.MonthDayNanoIntervalType:
+ bldr := array.NewMonthDayNanoIntervalBuilder(mem)
+ defer bldr.Release()
+ data := monthDayNanointervalFromJSON(arr.Data)
+ valids := validsFromJSON(arr.Valids)
+ bldr.AppendValues(data, valids)
+ return bldr.NewArray()
+
case *arrow.DurationType:
bldr := array.NewDurationBuilder(mem, dt)
defer bldr.Release()
@@ -1155,6 +1167,13 @@ func arrayToJSON(field arrow.Field, arr array.Interface)
Array {
Data: daytimeintervalToJSON(arr),
Valids: validsToJSON(arr),
}
+ case *array.MonthDayNanoInterval:
+ return Array{
+ Name: field.Name,
+ Count: arr.Len(),
+ Data: monthDayNanointervalToJSON(arr),
+ Valids: validsToJSON(arr),
+ }
case *array.Duration:
return Array{
Name: field.Name,
@@ -1672,6 +1691,35 @@ func daytimeintervalToJSON(arr *array.DayTimeInterval)
[]interface{} {
return o
}
+func monthDayNanointervalFromJSON(vs []interface{})
[]arrow.MonthDayNanoInterval {
+ o := make([]arrow.MonthDayNanoInterval, len(vs))
+ for i, vv := range vs {
+ v := vv.(map[string]interface{})
+ months, err := v["months"].(json.Number).Int64()
+ if err != nil {
+ panic(err)
+ }
+ days, err := v["days"].(json.Number).Int64()
+ if err != nil {
+ panic(err)
+ }
+ ns, err := v["nanoseconds"].(json.Number).Int64()
+ if err != nil {
+ panic(err)
+ }
+ o[i] = arrow.MonthDayNanoInterval{Months: int32(months), Days:
int32(days), Nanoseconds: ns}
+ }
+ return o
+}
+
+func monthDayNanointervalToJSON(arr *array.MonthDayNanoInterval) []interface{}
{
+ o := make([]interface{}, arr.Len())
+ for i := range o {
+ o[i] = arr.Value(i)
+ }
+ return o
+}
+
func durationFromJSON(vs []interface{}) []arrow.Duration {
o := make([]arrow.Duration, len(vs))
for i, v := range vs {
diff --git a/go/arrow/internal/arrjson/arrjson_test.go
b/go/arrow/internal/arrjson/arrjson_test.go
index 6ffbfa9..c16145b 100644
--- a/go/arrow/internal/arrjson/arrjson_test.go
+++ b/go/arrow/internal/arrjson/arrjson_test.go
@@ -2673,6 +2673,15 @@ func makeIntervalsWantJSONs() string {
},
"nullable": true,
"children": []
+ },
+ {
+ "name": "nanos",
+ "type": {
+ "name": "interval",
+ "unit": "MONTH_DAY_NANO"
+ },
+ "nullable": true,
+ "children": []
}
]
},
@@ -2730,6 +2739,44 @@ func makeIntervalsWantJSONs() string {
"milliseconds": 5
}
]
+ },
+ {
+ "name": "nanos",
+ "count": 5,
+ "VALIDITY": [
+ 1,
+ 0,
+ 0,
+ 1,
+ 1
+ ],
+ "DATA": [
+ {
+ "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": 5,
+ "days": 5,
+ "nanoseconds": 5000
+ }
+ ]
}
]
},
@@ -2747,11 +2794,11 @@ func makeIntervalsWantJSONs() string {
1
],
"DATA": [
- 11,
- 12,
- 13,
- 14,
- 15
+ -11,
+ -12,
+ -13,
+ -14,
+ -15
]
},
{
@@ -2766,40 +2813,79 @@ func makeIntervalsWantJSONs() string {
],
"DATA": [
{
- "days": 11,
- "milliseconds": 11
+ "days": -11,
+ "milliseconds": -11
},
{
- "days": 12,
- "milliseconds": 12
+ "days": -12,
+ "milliseconds": -12
},
{
- "days": 13,
- "milliseconds": 13
+ "days": -13,
+ "milliseconds": -13
},
{
- "days": 14,
- "milliseconds": 14
+ "days": -14,
+ "milliseconds": -14
},
{
- "days": 15,
- "milliseconds": 15
+ "days": -15,
+ "milliseconds": -15
+ }
+ ]
+ },
+ {
+ "name": "nanos",
+ "count": 5,
+ "VALIDITY": [
+ 1,
+ 0,
+ 0,
+ 1,
+ 1
+ ],
+ "DATA": [
+ {
+ "months": -11,
+ "days": -11,
+ "nanoseconds": -11000
+ },
+ {
+ "months": -12,
+ "days": -12,
+ "nanoseconds": -12000
+ },
+ {
+ "months": -13,
+ "days": -13,
+ "nanoseconds": -13000
+ },
+ {
+ "months": -14,
+ "days": -14,
+ "nanoseconds": -14000
+ },
+ {
+ "months": -15,
+ "days": -15,
+ "nanoseconds": -15000
}
]
}
]
},
{
- "count": 5,
+ "count": 6,
"columns": [
{
"name": "months",
- "count": 5,
+ "count": 6,
"VALIDITY": [
1,
0,
0,
1,
+ 1,
1
],
"DATA": [
@@ -2807,17 +2893,19 @@ func makeIntervalsWantJSONs() string {
22,
23,
24,
- 25
+ 25,
+ 0
]
},
{
"name": "days",
- "count": 5,
+ "count": 6,
"VALIDITY": [
1,
0,
0,
1,
+ 1,
1
],
"DATA": [
@@ -2840,6 +2928,54 @@ func makeIntervalsWantJSONs() string {
{
"days": 25,
"milliseconds": 25
+ },
+ {
+ "days": 0,
+ "milliseconds": 0
+ }
+ ]
+ },
+ {
+ "name": "nanos",
+ "count": 6,
+ "VALIDITY": [
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1
+ ],
+ "DATA": [
+ {
+ "months": 21,
+ "days": 21,
+ "nanoseconds": 21000
+ },
+ {
+ "months": 22,
+ "days": 22,
+ "nanoseconds": 22000
+ },
+ {
+ "months": 23,
+ "days": 23,
+ "nanoseconds": 23000
+ },
+ {
+ "months": 24,
+ "days": 24,
+ "nanoseconds": 24000
+ },
+ {
+ "months": 25,
+ "days": 25,
+ "nanoseconds": 25000
+ },
+ {
+ "months": 0,
+ "days": 0,
+ "nanoseconds": 0
}
]
}
diff --git
a/go/arrow/internal/flight_integration/cmd/arrow-flight-integration-server/main.go
b/go/arrow/internal/flight_integration/cmd/arrow-flight-integration-server/main.go
index 7384a74..5459086 100644
---
a/go/arrow/internal/flight_integration/cmd/arrow-flight-integration-server/main.go
+++
b/go/arrow/internal/flight_integration/cmd/arrow-flight-integration-server/main.go
@@ -36,7 +36,6 @@ func main() {
s := flight_integration.GetScenario(*scenario)
srv := s.MakeServer(*port)
- srv.Init(fmt.Sprintf("0.0.0.0:%d", *port))
srv.SetShutdownOnSignals(syscall.SIGTERM, os.Interrupt)
_, p, _ := net.SplitHostPort(srv.Addr().String())
fmt.Printf("Server listening on localhost:%s\n", p)
diff --git a/go/arrow/internal/flight_integration/scenario.go
b/go/arrow/internal/flight_integration/scenario.go
index edafe05..32e5006 100644
--- a/go/arrow/internal/flight_integration/scenario.go
+++ b/go/arrow/internal/flight_integration/scenario.go
@@ -21,6 +21,7 @@ import (
"context"
"fmt"
"io"
+ "net"
"os"
"strconv"
@@ -58,6 +59,13 @@ func GetScenario(name string, args ...string) Scenario {
panic(fmt.Errorf("scenario not found: %s", name))
}
+func initServer(port int, srv flight.Server) int {
+ srv.Init(fmt.Sprintf("0.0.0.0:%d", port))
+ _, p, _ := net.SplitHostPort(srv.Addr().String())
+ port, _ = strconv.Atoi(p)
+ return port
+}
+
type integrationDataSet struct {
schema *arrow.Schema
chunks []array.Record
@@ -209,7 +217,6 @@ func (s *defaultIntegrationTester) RunClient(addr string,
opts ...grpc.DialOptio
}
func (s *defaultIntegrationTester) MakeServer(port int) flight.Server {
- s.port = port
s.uploadedChunks = make(map[string]integrationDataSet)
srv := flight.NewServerWithMiddleware(nil, nil)
srv.RegisterFlightService(&flight.FlightServiceService{
@@ -217,6 +224,7 @@ func (s *defaultIntegrationTester) MakeServer(port int)
flight.Server {
DoGet: s.DoGet,
DoPut: s.DoPut,
})
+ s.port = initServer(port, srv)
return srv
}
@@ -236,7 +244,7 @@ func (s *defaultIntegrationTester) GetFlightInfo(ctx
context.Context, in *flight
FlightDescriptor: in,
Endpoint: []*flight.FlightEndpoint{{
Ticket: &flight.Ticket{Ticket:
[]byte(in.Path[0])},
- Location: []*flight.Location{{Uri:
fmt.Sprintf("127.0.0.1:%d", s.port)}},
+ Location: []*flight.Location{{Uri:
fmt.Sprintf("grpc+tcp://127.0.0.1:%d", s.port)}},
}},
TotalRecords: 0,
TotalBytes: -1,
@@ -420,12 +428,13 @@ func (s *authBasicProtoTester) RunClient(addr string,
opts ...grpc.DialOption) e
return CheckActionResults(ctx, client, &flight.Action{},
[]string{authUsername})
}
-func (s *authBasicProtoTester) MakeServer(_ int) flight.Server {
+func (s *authBasicProtoTester) MakeServer(port int) flight.Server {
srv := flight.NewServerWithMiddleware(&authBasicValidator{
auth: flight.BasicAuth{Username: authUsername, Password:
authPassword}}, nil)
srv.RegisterFlightService(&flight.FlightServiceService{
DoAction: s.DoAction,
})
+ initServer(port, srv)
return srv
}
@@ -470,12 +479,13 @@ func (m *middlewareScenarioTester) RunClient(addr string,
opts ...grpc.DialOptio
return nil
}
-func (m *middlewareScenarioTester) MakeServer(_ int) flight.Server {
+func (m *middlewareScenarioTester) MakeServer(port int) flight.Server {
srv := flight.NewServerWithMiddleware(nil, []flight.ServerMiddleware{
flight.CreateServerMiddleware(testServerMiddleware{})})
srv.RegisterFlightService(&flight.FlightServiceService{
GetFlightInfo: m.GetFlightInfo,
})
+ initServer(port, srv)
return srv
}
@@ -489,7 +499,7 @@ func (m *middlewareScenarioTester) GetFlightInfo(ctx
context.Context, desc *flig
FlightDescriptor: desc,
Endpoint: []*flight.FlightEndpoint{{
Ticket: &flight.Ticket{Ticket: []byte("foo")},
- Location: []*flight.Location{{Uri: "localhost:10010"}},
+ Location: []*flight.Location{{Uri:
"grpc+tcp://localhost:10010"}},
}},
TotalRecords: -1,
TotalBytes: -1,
diff --git a/go/arrow/ipc/file_reader.go b/go/arrow/ipc/file_reader.go
index 04d736f..d744358 100644
--- a/go/arrow/ipc/file_reader.go
+++ b/go/arrow/ipc/file_reader.go
@@ -430,7 +430,7 @@ func (ctx *arrayLoaderContext) loadArray(dt arrow.DataType)
array.Interface {
*arrow.Time32Type, *arrow.Time64Type,
*arrow.TimestampType,
*arrow.Date32Type, *arrow.Date64Type,
- *arrow.MonthIntervalType, *arrow.DayTimeIntervalType,
+ *arrow.MonthIntervalType, *arrow.DayTimeIntervalType,
*arrow.MonthDayNanoIntervalType,
*arrow.DurationType:
return ctx.loadPrimitive(dt)
diff --git a/go/arrow/ipc/metadata.go b/go/arrow/ipc/metadata.go
index 9f6333b..9d2d7f0 100644
--- a/go/arrow/ipc/metadata.go
+++ b/go/arrow/ipc/metadata.go
@@ -370,6 +370,12 @@ func (fv *fieldVisitor) visit(field arrow.Field) {
flatbuf.IntervalAddUnit(fv.b, flatbuf.IntervalUnitDAY_TIME)
fv.offset = flatbuf.IntervalEnd(fv.b)
+ case *arrow.MonthDayNanoIntervalType:
+ fv.dtype = flatbuf.TypeInterval
+ flatbuf.IntervalStart(fv.b)
+ flatbuf.IntervalAddUnit(fv.b,
flatbuf.IntervalUnitMONTH_DAY_NANO)
+ fv.offset = flatbuf.IntervalEnd(fv.b)
+
case *arrow.DurationType:
fv.dtype = flatbuf.TypeDuration
unit := unitToFB(dt.Unit)
@@ -806,6 +812,8 @@ func intervalFromFB(data flatbuf.Interval) (arrow.DataType,
error) {
return arrow.FixedWidthTypes.MonthInterval, nil
case flatbuf.IntervalUnitDAY_TIME:
return arrow.FixedWidthTypes.DayTimeInterval, nil
+ case flatbuf.IntervalUnitMONTH_DAY_NANO:
+ return arrow.FixedWidthTypes.MonthDayNanoInterval, nil
}
return nil, xerrors.Errorf("arrow/ipc: Interval type with %d unit not
implemented", data.Unit())
}
diff --git a/go/arrow/scalar/parse.go b/go/arrow/scalar/parse.go
index 2a96372..78bbff8 100644
--- a/go/arrow/scalar/parse.go
+++ b/go/arrow/scalar/parse.go
@@ -150,6 +150,8 @@ func MakeScalar(val interface{}) Scalar {
return NewMonthIntervalScalar(v)
case arrow.DayTimeInterval:
return NewDayTimeIntervalScalar(v)
+ case arrow.MonthDayNanoInterval:
+ return NewMonthDayNanoIntervalScalar(v)
case arrow.DataType:
return MakeNullScalar(v)
}
diff --git a/go/arrow/scalar/scalar.go b/go/arrow/scalar/scalar.go
index 1662081..0275866 100644
--- a/go/arrow/scalar/scalar.go
+++ b/go/arrow/scalar/scalar.go
@@ -295,7 +295,7 @@ func (s *Decimal128) CastTo(to arrow.DataType) (Scalar,
error) {
}
switch to.ID() {
- case arrow.DECIMAL:
+ case arrow.DECIMAL128:
return NewDecimal128Scalar(s.Value, to), nil
case arrow.STRING:
dt := s.Type.(*arrow.Decimal128Type)
@@ -431,10 +431,14 @@ func init() {
if arrow.TypeEqual(dt,
arrow.FixedWidthTypes.MonthInterval) {
return &MonthInterval{scalar: scalar{dt, false}}
}
+ if arrow.TypeEqual(dt,
arrow.FixedWidthTypes.MonthDayNanoInterval) {
+ return &MonthDayNanoInterval{scalar: scalar{dt,
false}}
+ }
return &DayTimeInterval{scalar: scalar{dt, false}}
},
arrow.INTERVAL_MONTHS: func(dt arrow.DataType) Scalar {
return &MonthInterval{scalar: scalar{dt, false}} },
arrow.INTERVAL_DAY_TIME: func(dt arrow.DataType) Scalar {
return &DayTimeInterval{scalar: scalar{dt, false}} },
+ arrow.INTERVAL_MONTH_DAY_NANO: func(dt arrow.DataType) Scalar {
return &MonthDayNanoInterval{scalar: scalar{dt, false}} },
arrow.DECIMAL128: func(dt arrow.DataType) Scalar {
return &Decimal128{scalar: scalar{dt, false}} },
arrow.LIST: func(dt arrow.DataType) Scalar {
return &List{scalar: scalar{dt, false}} },
arrow.STRUCT: func(dt arrow.DataType) Scalar {
return &Struct{scalar: scalar{dt, false}} },
@@ -449,9 +453,7 @@ func init() {
arrow.EXTENSION: func(dt arrow.DataType) Scalar {
return &Extension{scalar: scalar{dt, false}} },
arrow.FIXED_SIZE_LIST: func(dt arrow.DataType) Scalar {
return &FixedSizeList{&List{scalar: scalar{dt, false}}} },
arrow.DURATION: func(dt arrow.DataType) Scalar {
return &Duration{scalar: scalar{dt, false}} },
- arrow.INTERVAL_MONTH_DAY_NANO: unsupportedScalarType,
-
- // invalid data types to fill out array size 2⁵-1
+ // invalid data types to fill out array size 2^6 - 1
63: invalidScalarType,
}
@@ -530,6 +532,8 @@ func GetScalar(arr array.Interface, idx int) (Scalar,
error) {
return NewMapScalar(slice), nil
case *array.MonthInterval:
return NewMonthIntervalScalar(arr.Value(idx)), nil
+ case *array.MonthDayNanoInterval:
+ return NewMonthDayNanoIntervalScalar(arr.Value(idx)), nil
case *array.Null:
return ScalarNull, nil
case *array.String:
@@ -773,6 +777,8 @@ func Hash(seed maphash.Seed, s Scalar) uint64 {
out ^= Hash(seed, s.Value)
case *DayTimeInterval:
return valueHash(s.Value.Days) & valueHash(s.Value.Milliseconds)
+ case *MonthDayNanoInterval:
+ return valueHash(s.Value.Months) & valueHash(s.Value.Days) &
valueHash(s.Value.Nanoseconds)
case PrimitiveScalar:
h.Write(s.Data())
hash()
diff --git a/go/arrow/scalar/scalar_test.go b/go/arrow/scalar/scalar_test.go
index 6791c4a..dc476e8 100644
--- a/go/arrow/scalar/scalar_test.go
+++ b/go/arrow/scalar/scalar_test.go
@@ -493,6 +493,31 @@ func TestDayTimeIntervalScalarBasics(t *testing.T) {
assert.False(t, scalar.Equals(tsNull, tsVal2))
}
+func TestMonthDayNanoIntervalScalarBasics(t *testing.T) {
+ typ := arrow.FixedWidthTypes.MonthDayNanoInterval
+
+ val1 := arrow.MonthDayNanoInterval{Months: 1, Days: 2, Nanoseconds:
3000}
+ val2 := arrow.MonthDayNanoInterval{Months: 2, Days: 3, Nanoseconds:
4000}
+ tsVal1 := scalar.NewMonthDayNanoIntervalScalar(val1)
+ tsVal2 := scalar.NewMonthDayNanoIntervalScalar(val2)
+ tsNull := scalar.MakeNullScalar(typ)
+ assert.NoError(t, tsVal1.ValidateFull())
+ assert.NoError(t, tsVal2.ValidateFull())
+ assert.NoError(t, tsNull.ValidateFull())
+
+ assert.Equal(t, val1, tsVal1.Value)
+
+ assert.True(t, arrow.TypeEqual(tsVal1.Type, typ))
+ assert.True(t, arrow.TypeEqual(tsVal2.DataType(), typ))
+ assert.True(t, tsVal1.Valid)
+ assert.False(t, tsNull.IsValid())
+ assert.True(t, arrow.TypeEqual(typ, tsNull.DataType()))
+
+ assert.False(t, scalar.Equals(tsVal1, tsVal2))
+ assert.False(t, scalar.Equals(tsVal1, tsNull))
+ assert.False(t, scalar.Equals(tsNull, tsVal2))
+}
+
func TestNumericScalarCasts(t *testing.T) {
tests := []arrow.DataType{
arrow.PrimitiveTypes.Int8,
@@ -793,6 +818,7 @@ func TestStructScalarValidateErrors(t *testing.T) {
func getScalars(mem memory.Allocator) []scalar.Scalar {
hello := memory.NewBufferBytes([]byte("hello"))
daytime := arrow.DayTimeInterval{Days: 1, Milliseconds: 100}
+ monthdaynano := arrow.MonthDayNanoInterval{Months: 5, Days: 4,
Nanoseconds: 100}
int8Bldr := array.NewInt8Builder(mem)
defer int8Bldr.Release()
@@ -828,6 +854,7 @@ func getScalars(mem memory.Allocator) []scalar.Scalar {
scalar.NewTimestampScalar(111,
arrow.FixedWidthTypes.Timestamp_ms),
scalar.NewMonthIntervalScalar(1),
scalar.NewDayTimeIntervalScalar(daytime),
+ scalar.NewMonthDayNanoIntervalScalar(monthdaynano),
scalar.NewDurationScalar(60, arrow.FixedWidthTypes.Duration_s),
scalar.NewBinaryScalar(hello, arrow.BinaryTypes.Binary),
scalar.NewFixedSizeBinaryScalar(hello,
&arrow.FixedSizeBinaryType{ByteWidth: hello.Len()}),
diff --git a/go/arrow/scalar/temporal.go b/go/arrow/scalar/temporal.go
index 47a4dec4..3dba569 100644
--- a/go/arrow/scalar/temporal.go
+++ b/go/arrow/scalar/temporal.go
@@ -464,6 +464,48 @@ func NewDayTimeIntervalScalar(val arrow.DayTimeInterval)
*DayTimeInterval {
return &DayTimeInterval{scalar{arrow.FixedWidthTypes.DayTimeInterval,
true}, val}
}
+type MonthDayNanoInterval struct {
+ scalar
+ Value arrow.MonthDayNanoInterval
+}
+
+func (MonthDayNanoInterval) temporal() {}
+func (MonthDayNanoInterval) interval() {}
+func (s *MonthDayNanoInterval) value() interface{} { return s.Value }
+func (s *MonthDayNanoInterval) Data() []byte {
+ return
(*[arrow.MonthDayNanoIntervalSizeBytes]byte)(unsafe.Pointer(&s.Value))[:]
+}
+func (s *MonthDayNanoInterval) String() string {
+ if !s.Valid {
+ return "null"
+ }
+ val, err := s.CastTo(arrow.BinaryTypes.String)
+ if err != nil {
+ return "..."
+ }
+ return string(val.(*String).Value.Bytes())
+}
+
+func (s *MonthDayNanoInterval) CastTo(to arrow.DataType) (Scalar, error) {
+ if !s.Valid {
+ return MakeNullScalar(to), nil
+ }
+
+ if !arrow.TypeEqual(s.DataType(), to) {
+ return nil, xerrors.Errorf("non-null month_day_nano_interval
scalar cannot be cast to anything other than monthinterval")
+ }
+
+ return s, nil
+}
+
+func (s *MonthDayNanoInterval) equals(rhs Scalar) bool {
+ return s.Value == rhs.(*MonthDayNanoInterval).Value
+}
+
+func NewMonthDayNanoIntervalScalar(val arrow.MonthDayNanoInterval)
*MonthDayNanoInterval {
+ return
&MonthDayNanoInterval{scalar{arrow.FixedWidthTypes.MonthDayNanoInterval, true},
val}
+}
+
var (
_ Scalar = (*Date32)(nil)
)
diff --git a/go/arrow/type_traits_interval.go b/go/arrow/type_traits_interval.go
index f4f4dfe..13ede6c 100644
--- a/go/arrow/type_traits_interval.go
+++ b/go/arrow/type_traits_interval.go
@@ -21,13 +21,21 @@ import (
"unsafe"
"github.com/apache/arrow/go/arrow/endian"
+ "github.com/apache/arrow/go/arrow/internal/debug"
)
var (
- MonthIntervalTraits monthTraits
- DayTimeIntervalTraits daytimeTraits
+ MonthIntervalTraits monthTraits
+ DayTimeIntervalTraits daytimeTraits
+ MonthDayNanoIntervalTraits monthDayNanoTraits
)
+func init() {
+ debug.Assert(MonthIntervalSizeBytes == 4, "MonthIntervalSizeBytes
should be 4")
+ debug.Assert(DayTimeIntervalSizeBytes == 8, "DayTimeIntervalSizeBytes
should be 8")
+ debug.Assert(MonthDayNanoIntervalSizeBytes == 16,
"MonthDayNanoIntervalSizeBytes should be 16")
+}
+
// MonthInterval traits
const (
@@ -124,3 +132,53 @@ func (daytimeTraits) CastToBytes(b []DayTimeInterval)
[]byte {
// Copy copies src to dst.
func (daytimeTraits) Copy(dst, src []DayTimeInterval) { copy(dst, src) }
+
+// DayTimeInterval traits
+
+const (
+ // MonthDayNanoIntervalSizeBytes specifies the number of bytes required
to store a single DayTimeInterval in memory
+ MonthDayNanoIntervalSizeBytes =
int(unsafe.Sizeof(MonthDayNanoInterval{}))
+)
+
+type monthDayNanoTraits struct{}
+
+// BytesRequired returns the number of bytes required to store n elements in
memory.
+func (monthDayNanoTraits) BytesRequired(n int) int { return
MonthDayNanoIntervalSizeBytes * n }
+
+// PutValue
+func (monthDayNanoTraits) PutValue(b []byte, v MonthDayNanoInterval) {
+ endian.Native.PutUint32(b[0:4], uint32(v.Months))
+ endian.Native.PutUint32(b[4:8], uint32(v.Days))
+ endian.Native.PutUint64(b[8:], uint64(v.Nanoseconds))
+}
+
+// CastFromBytes reinterprets the slice b to a slice of type
MonthDayNanoInterval.
+//
+// NOTE: len(b) must be a multiple of MonthDayNanoIntervalSizeBytes.
+func (monthDayNanoTraits) CastFromBytes(b []byte) []MonthDayNanoInterval {
+ h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+ var res []MonthDayNanoInterval
+ s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+ s.Data = h.Data
+ s.Len = h.Len / MonthDayNanoIntervalSizeBytes
+ s.Cap = h.Cap / MonthDayNanoIntervalSizeBytes
+
+ return res
+}
+
+// CastToBytes reinterprets the slice b to a slice of bytes.
+func (monthDayNanoTraits) CastToBytes(b []MonthDayNanoInterval) []byte {
+ h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+ var res []byte
+ s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+ s.Data = h.Data
+ s.Len = h.Len * MonthDayNanoIntervalSizeBytes
+ s.Cap = h.Cap * MonthDayNanoIntervalSizeBytes
+
+ return res
+}
+
+// Copy copies src to dst.
+func (monthDayNanoTraits) Copy(dst, src []MonthDayNanoInterval) { copy(dst,
src) }
diff --git a/go/arrow/type_traits_test.go b/go/arrow/type_traits_test.go
index 59ad06e..b367475 100644
--- a/go/arrow/type_traits_test.go
+++ b/go/arrow/type_traits_test.go
@@ -199,3 +199,37 @@ func TestDayTimeIntervalTraits(t *testing.T) {
t.Fatalf("invalid values:\nv1=%v\nv2=%v\n", v1, v2)
}
}
+
+func TestMonthDayNanoIntervalTraits(t *testing.T) {
+ const N = 10
+ b1 :=
arrow.MonthDayNanoIntervalTraits.CastToBytes([]arrow.MonthDayNanoInterval{
+ {0, 0, 0}, {1, 1, 1000}, {2, 2, 2000}, {3, 3, 3000}, {4, 4,
4000}, {5, 5, 5000}, {6, 6, 6000}, {7, 7, 7000}, {8, 8, 8000}, {9, 9, 9000},
+ })
+
+ b2 := make([]byte, arrow.MonthDayNanoIntervalTraits.BytesRequired(N))
+ for i := 0; i < N; i++ {
+ beg := i * arrow.MonthDayNanoIntervalSizeBytes
+ end := (i + 1) * arrow.MonthDayNanoIntervalSizeBytes
+ arrow.MonthDayNanoIntervalTraits.PutValue(b2[beg:end],
arrow.MonthDayNanoInterval{int32(i), int32(i), int64(i) * 1000})
+ }
+
+ if !reflect.DeepEqual(b1, b2) {
+ v1 := arrow.MonthDayNanoIntervalTraits.CastFromBytes(b1)
+ v2 := arrow.MonthDayNanoIntervalTraits.CastFromBytes(b2)
+ t.Fatalf("invalid values:\nb1=%v\nb2=%v\nv1=%v\nv2=%v\n", b1,
b2, v1, v2)
+ }
+
+ v1 := arrow.MonthDayNanoIntervalTraits.CastFromBytes(b1)
+ for i, v := range v1 {
+ if got, want := v, (arrow.MonthDayNanoInterval{int32(i),
int32(i), int64(i) * 1000}); got != want {
+ t.Fatalf("invalid value[%d]. got=%v, want=%v", i, got,
want)
+ }
+ }
+
+ v2 := make([]arrow.MonthDayNanoInterval, N)
+ arrow.MonthDayNanoIntervalTraits.Copy(v2, v1)
+
+ if !reflect.DeepEqual(v1, v2) {
+ t.Fatalf("invalid values:\nv1=%v\nv2=%v\n", v1, v2)
+ }
+}
diff --git
a/java/flight/flight-core/src/main/java/org/apache/arrow/flight/FlightStream.java
b/java/flight/flight-core/src/main/java/org/apache/arrow/flight/FlightStream.java
index 5ac22c0..03ce13c 100644
---
a/java/flight/flight-core/src/main/java/org/apache/arrow/flight/FlightStream.java
+++
b/java/flight/flight-core/src/main/java/org/apache/arrow/flight/FlightStream.java
@@ -399,6 +399,14 @@ public class FlightStream implements AutoCloseable {
}
case SCHEMA: {
Schema schema = msg.asSchema();
+
+ // if there is app metadata in the schema message, make sure
+ // that we don't leak it.
+ ArrowBuf meta = msg.getApplicationMetadata();
+ if (meta != null) {
+ meta.close();
+ }
+
final List<Field> fields = new ArrayList<>();
final Map<Long, Dictionary> dictionaryMap = new HashMap<>();
for (final Field originalField : schema.getFields()) {
@@ -419,7 +427,7 @@ public class FlightStream implements AutoCloseable {
}
synchronized (completed) {
- if (!completed.isDone()) {
+ if (!completed.isDone()) {
fulfilledRoot = VectorSchemaRoot.create(schema, allocator);
loader = new VectorLoader(fulfilledRoot);
if (msg.getDescriptor() != null) {