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 3d3c31d  ARROW-14155: [Go] add fingerprint and hash functions for 
types and scalars
3d3c31d is described below

commit 3d3c31d3e30779950249720edf540c60517e48ab
Author: Matthew Topol <[email protected]>
AuthorDate: Tue Oct 5 10:41:04 2021 -0400

    ARROW-14155: [Go] add fingerprint and hash functions for types and scalars
    
    This is going to be needed for creating field path / field reference 
handling leading into Datums and Expressions
    
    Closes #11260 from zeroshade/arrow-14155
    
    Authored-by: Matthew Topol <[email protected]>
    Signed-off-by: Matthew Topol <[email protected]>
---
 go/arrow/array/array_test.go          |   7 ++-
 go/arrow/array/binary.go              |   2 +-
 go/arrow/array/data.go                |  14 +++++
 go/arrow/array/fixedsize_binary.go    |   2 +-
 go/arrow/datatype.go                  |  37 ++++++++++++
 go/arrow/datatype_binary.go           |  18 +++---
 go/arrow/datatype_extension.go        |   2 +
 go/arrow/datatype_fixedwidth.go       |  52 +++++++++++-----
 go/arrow/datatype_nested.go           |  65 ++++++++++++++++++++
 go/arrow/datatype_null.go             |   7 ++-
 go/arrow/datatype_numeric.gen.go      | 108 +++++++++++++++++++---------------
 go/arrow/datatype_numeric.gen.go.tmpl |  10 ++--
 go/arrow/go.sum                       |  51 ----------------
 go/arrow/scalar/parse.go              |   2 +
 go/arrow/scalar/scalar.go             |  73 +++++++++++++++++++++++
 go/arrow/scalar/scalar_test.go        |   3 +
 go/arrow/schema.go                    |  21 +++++++
 go/arrow/schema_test.go               |   5 ++
 18 files changed, 343 insertions(+), 136 deletions(-)

diff --git a/go/arrow/array/array_test.go b/go/arrow/array/array_test.go
index 3a2101a..da8ecd7 100644
--- a/go/arrow/array/array_test.go
+++ b/go/arrow/array/array_test.go
@@ -31,9 +31,10 @@ type testDataType struct {
        id arrow.Type
 }
 
-func (d *testDataType) ID() arrow.Type { return d.id }
-func (d *testDataType) Name() string   { panic("implement me") }
-func (d *testDataType) BitWidth() int  { return 8 }
+func (d *testDataType) ID() arrow.Type      { return d.id }
+func (d *testDataType) Name() string        { panic("implement me") }
+func (d *testDataType) BitWidth() int       { return 8 }
+func (d *testDataType) Fingerprint() string { return "" }
 
 func TestMakeFromData(t *testing.T) {
        tests := []struct {
diff --git a/go/arrow/array/binary.go b/go/arrow/array/binary.go
index ed58910..865a59d 100644
--- a/go/arrow/array/binary.go
+++ b/go/arrow/array/binary.go
@@ -122,7 +122,7 @@ func arrayEqualBinary(left, right *Binary) bool {
                if left.IsNull(i) {
                        continue
                }
-               if bytes.Compare(left.Value(i), right.Value(i)) != 0 {
+               if !bytes.Equal(left.Value(i), right.Value(i)) {
                        return false
                }
        }
diff --git a/go/arrow/array/data.go b/go/arrow/array/data.go
index 2648961..a680317 100644
--- a/go/arrow/array/data.go
+++ b/go/arrow/array/data.go
@@ -17,7 +17,10 @@
 package array
 
 import (
+       "hash/maphash"
+       "math/bits"
        "sync/atomic"
+       "unsafe"
 
        "github.com/apache/arrow/go/arrow"
        "github.com/apache/arrow/go/arrow/internal/debug"
@@ -177,3 +180,14 @@ func NewSliceData(data *Data, i, j int64) *Data {
 
        return o
 }
+
+func Hash(h *maphash.Hash, a *Data) {
+       h.Write((*[bits.UintSize / 8]byte)(unsafe.Pointer(&a.length))[:])
+       h.Write((*[bits.UintSize / 8]byte)(unsafe.Pointer(&a.length))[:])
+       if len(a.buffers) > 0 && a.buffers[0] != nil {
+               h.Write(a.buffers[0].Bytes())
+       }
+       for _, c := range a.childData {
+               Hash(h, c)
+       }
+}
diff --git a/go/arrow/array/fixedsize_binary.go 
b/go/arrow/array/fixedsize_binary.go
index 502fb99..5827414 100644
--- a/go/arrow/array/fixedsize_binary.go
+++ b/go/arrow/array/fixedsize_binary.go
@@ -83,7 +83,7 @@ func arrayEqualFixedSizeBinary(left, right *FixedSizeBinary) 
bool {
                if left.IsNull(i) {
                        continue
                }
-               if bytes.Compare(left.Value(i), right.Value(i)) != 0 {
+               if !bytes.Equal(left.Value(i), right.Value(i)) {
                        return false
                }
        }
diff --git a/go/arrow/datatype.go b/go/arrow/datatype.go
index 5a9936e..9386ebf 100644
--- a/go/arrow/datatype.go
+++ b/go/arrow/datatype.go
@@ -16,6 +16,12 @@
 
 package arrow
 
+import (
+       "hash/maphash"
+
+       "github.com/apache/arrow/go/arrow/internal/debug"
+)
+
 // Type is a logical type. They can be expressed as
 // either a primitive physical type (bytes or bits of some fixed size), a
 // nested type consisting of other data types, or another data type (e.g. a
@@ -127,6 +133,7 @@ type DataType interface {
        ID() Type
        // Name is name of the data type.
        Name() string
+       Fingerprint() string
 }
 
 // FixedWidthDataType is the representation of an Arrow type that
@@ -141,3 +148,33 @@ type BinaryDataType interface {
        DataType
        binary()
 }
+
+func HashType(seed maphash.Seed, dt DataType) uint64 {
+       var h maphash.Hash
+       h.SetSeed(seed)
+       h.WriteString(dt.Fingerprint())
+       return h.Sum64()
+}
+
+func typeIDFingerprint(id Type) string {
+       c := string(rune(int(id) + int('A')))
+       return "@" + c
+}
+
+func typeFingerprint(typ DataType) string { return typeIDFingerprint(typ.ID()) 
}
+
+func timeUnitFingerprint(unit TimeUnit) rune {
+       switch unit {
+       case Second:
+               return 's'
+       case Millisecond:
+               return 'm'
+       case Microsecond:
+               return 'u'
+       case Nanosecond:
+               return 'n'
+       default:
+               debug.Assert(false, "unexpected time unit")
+               return rune(0)
+       }
+}
diff --git a/go/arrow/datatype_binary.go b/go/arrow/datatype_binary.go
index 4fc0162..110ef49 100644
--- a/go/arrow/datatype_binary.go
+++ b/go/arrow/datatype_binary.go
@@ -18,17 +18,19 @@ package arrow
 
 type BinaryType struct{}
 
-func (t *BinaryType) ID() Type       { return BINARY }
-func (t *BinaryType) Name() string   { return "binary" }
-func (t *BinaryType) String() string { return "binary" }
-func (t *BinaryType) binary()        {}
+func (t *BinaryType) ID() Type            { return BINARY }
+func (t *BinaryType) Name() string        { return "binary" }
+func (t *BinaryType) String() string      { return "binary" }
+func (t *BinaryType) binary()             {}
+func (t *BinaryType) Fingerprint() string { return typeFingerprint(t) }
 
 type StringType struct{}
 
-func (t *StringType) ID() Type       { return STRING }
-func (t *StringType) Name() string   { return "utf8" }
-func (t *StringType) String() string { return "utf8" }
-func (t *StringType) binary()        {}
+func (t *StringType) ID() Type            { return STRING }
+func (t *StringType) Name() string        { return "utf8" }
+func (t *StringType) String() string      { return "utf8" }
+func (t *StringType) binary()             {}
+func (t *StringType) Fingerprint() string { return typeFingerprint(t) }
 
 var (
        BinaryTypes = struct {
diff --git a/go/arrow/datatype_extension.go b/go/arrow/datatype_extension.go
index 52e6887..90b9a15 100644
--- a/go/arrow/datatype_extension.go
+++ b/go/arrow/datatype_extension.go
@@ -155,6 +155,8 @@ func (e *ExtensionBase) String() string { return 
fmt.Sprintf("extension_type<sto
 // written against the ExtensionType interface can access the storage type.
 func (e *ExtensionBase) StorageType() DataType { return e.Storage }
 
+func (e *ExtensionBase) Fingerprint() string { return typeFingerprint(e) + 
e.Storage.Fingerprint() }
+
 // this no-op exists to ensure that this type must be embedded in any 
user-defined extension type.
 func (ExtensionBase) mustEmbedExtensionBase() {}
 
diff --git a/go/arrow/datatype_fixedwidth.go b/go/arrow/datatype_fixedwidth.go
index d2e9304..6efc81d 100644
--- a/go/arrow/datatype_fixedwidth.go
+++ b/go/arrow/datatype_fixedwidth.go
@@ -24,9 +24,10 @@ import (
 
 type BooleanType struct{}
 
-func (t *BooleanType) ID() Type       { return BOOL }
-func (t *BooleanType) Name() string   { return "bool" }
-func (t *BooleanType) String() string { return "bool" }
+func (t *BooleanType) ID() Type            { return BOOL }
+func (t *BooleanType) Name() string        { return "bool" }
+func (t *BooleanType) String() string      { return "bool" }
+func (t *BooleanType) Fingerprint() string { return typeFingerprint(t) }
 
 // BitWidth returns the number of bits required to store a single element of 
this data type in memory.
 func (t *BooleanType) BitWidth() int { return 1 }
@@ -35,10 +36,10 @@ type FixedSizeBinaryType struct {
        ByteWidth int
 }
 
-func (*FixedSizeBinaryType) ID() Type        { return FIXED_SIZE_BINARY }
-func (*FixedSizeBinaryType) Name() string    { return "fixed_size_binary" }
-func (t *FixedSizeBinaryType) BitWidth() int { return 8 * t.ByteWidth }
-
+func (*FixedSizeBinaryType) ID() Type              { return FIXED_SIZE_BINARY }
+func (*FixedSizeBinaryType) Name() string          { return 
"fixed_size_binary" }
+func (t *FixedSizeBinaryType) BitWidth() int       { return 8 * t.ByteWidth }
+func (t *FixedSizeBinaryType) Fingerprint() string { return typeFingerprint(t) 
}
 func (t *FixedSizeBinaryType) String() string {
        return "fixed_size_binary[" + strconv.Itoa(t.ByteWidth) + "]"
 }
@@ -85,6 +86,10 @@ func (t *TimestampType) String() string {
        }
 }
 
+func (t *TimestampType) Fingerprint() string {
+       return fmt.Sprintf("%s%d:%s", 
typeFingerprint(t)+string(timeUnitFingerprint(t.Unit)), len(t.TimeZone), 
t.TimeZone)
+}
+
 // BitWidth returns the number of bits required to store a single element of 
this data type in memory.
 func (*TimestampType) BitWidth() int { return 64 }
 
@@ -97,6 +102,9 @@ func (*Time32Type) ID() Type         { return TIME32 }
 func (*Time32Type) Name() string     { return "time32" }
 func (*Time32Type) BitWidth() int    { return 32 }
 func (t *Time32Type) String() string { return "time32[" + t.Unit.String() + 
"]" }
+func (t *Time32Type) Fingerprint() string {
+       return typeFingerprint(t) + string(timeUnitFingerprint(t.Unit))
+}
 
 // Time64Type is encoded as a 64-bit signed integer, representing either 
microseconds or nanoseconds since midnight.
 type Time64Type struct {
@@ -107,6 +115,9 @@ func (*Time64Type) ID() Type         { return TIME64 }
 func (*Time64Type) Name() string     { return "time64" }
 func (*Time64Type) BitWidth() int    { return 64 }
 func (t *Time64Type) String() string { return "time64[" + t.Unit.String() + 
"]" }
+func (t *Time64Type) Fingerprint() string {
+       return typeFingerprint(t) + string(timeUnitFingerprint(t.Unit))
+}
 
 // DurationType is encoded as a 64-bit signed integer, representing an amount
 // of elapsed time without any relation to a calendar artifact.
@@ -118,13 +129,17 @@ func (*DurationType) ID() Type         { return DURATION }
 func (*DurationType) Name() string     { return "duration" }
 func (*DurationType) BitWidth() int    { return 64 }
 func (t *DurationType) String() string { return "duration[" + t.Unit.String() 
+ "]" }
+func (t *DurationType) Fingerprint() string {
+       return typeFingerprint(t) + string(timeUnitFingerprint(t.Unit))
+}
 
 // Float16Type represents a floating point value encoded with a 16-bit 
precision.
 type Float16Type struct{}
 
-func (t *Float16Type) ID() Type       { return FLOAT16 }
-func (t *Float16Type) Name() string   { return "float16" }
-func (t *Float16Type) String() string { return "float16" }
+func (t *Float16Type) ID() Type            { return FLOAT16 }
+func (t *Float16Type) Name() string        { return "float16" }
+func (t *Float16Type) String() string      { return "float16" }
+func (t *Float16Type) Fingerprint() string { return typeFingerprint(t) }
 
 // BitWidth returns the number of bits required to store a single element of 
this data type in memory.
 func (t *Float16Type) BitWidth() int { return 16 }
@@ -141,6 +156,9 @@ func (*Decimal128Type) BitWidth() int { return 128 }
 func (t *Decimal128Type) String() string {
        return fmt.Sprintf("%s(%d, %d)", t.Name(), t.Precision, t.Scale)
 }
+func (t *Decimal128Type) Fingerprint() string {
+       return fmt.Sprintf("%s[%d,%d,%d]", typeFingerprint(t), t.BitWidth(), 
t.Precision, t.Scale)
+}
 
 // MonthInterval represents a number of months.
 type MonthInterval int32
@@ -149,9 +167,10 @@ type MonthInterval int32
 // representing a number of months.
 type MonthIntervalType struct{}
 
-func (*MonthIntervalType) ID() Type       { return INTERVAL }
-func (*MonthIntervalType) Name() string   { return "month_interval" }
-func (*MonthIntervalType) String() string { return "month_interval" }
+func (*MonthIntervalType) ID() Type            { return INTERVAL }
+func (*MonthIntervalType) Name() string        { return "month_interval" }
+func (*MonthIntervalType) String() string      { return "month_interval" }
+func (*MonthIntervalType) Fingerprint() string { return 
typeIDFingerprint(INTERVAL) + "M" }
 
 // BitWidth returns the number of bits required to store a single element of 
this data type in memory.
 func (t *MonthIntervalType) BitWidth() int { return 32 }
@@ -166,9 +185,10 @@ type DayTimeInterval struct {
 // representing a number of days and milliseconds (fraction of day).
 type DayTimeIntervalType struct{}
 
-func (*DayTimeIntervalType) ID() Type       { return INTERVAL }
-func (*DayTimeIntervalType) Name() string   { return "day_time_interval" }
-func (*DayTimeIntervalType) String() string { return "day_time_interval" }
+func (*DayTimeIntervalType) ID() Type            { return INTERVAL }
+func (*DayTimeIntervalType) Name() string        { return "day_time_interval" }
+func (*DayTimeIntervalType) String() string      { return "day_time_interval" }
+func (*DayTimeIntervalType) Fingerprint() string { return 
typeIDFingerprint(INTERVAL) + "d" }
 
 // 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 }
diff --git a/go/arrow/datatype_nested.go b/go/arrow/datatype_nested.go
index c4f5557..993950a 100644
--- a/go/arrow/datatype_nested.go
+++ b/go/arrow/datatype_nested.go
@@ -42,6 +42,13 @@ func ListOf(t DataType) *ListType {
 func (*ListType) ID() Type         { return LIST }
 func (*ListType) Name() string     { return "list" }
 func (t *ListType) String() string { return fmt.Sprintf("list<item: %v>", 
t.elem) }
+func (t *ListType) Fingerprint() string {
+       child := t.elem.Fingerprint()
+       if len(child) > 0 {
+               return typeFingerprint(t) + "{" + child + "}"
+       }
+       return ""
+}
 
 // Elem returns the ListType's element type.
 func (t *ListType) Elem() DataType { return t.elem }
@@ -80,6 +87,14 @@ func (t *FixedSizeListType) Elem() DataType { return t.elem }
 // Len returns the FixedSizeListType's size.
 func (t *FixedSizeListType) Len() int32 { return t.n }
 
+func (t *FixedSizeListType) Fingerprint() string {
+       child := t.elem.Fingerprint()
+       if len(child) > 0 {
+               return fmt.Sprintf("%s[%d]{%s}", typeFingerprint(t), t.n, child)
+       }
+       return ""
+}
+
 // StructType describes a nested type parameterized by an ordered sequence
 // of relative types, called its fields.
 type StructType struct {
@@ -153,6 +168,22 @@ func (t *StructType) FieldIdx(name string) (int, bool) {
        return i, ok
 }
 
+func (t *StructType) Fingerprint() string {
+       var b strings.Builder
+       b.WriteString(typeFingerprint(t))
+       b.WriteByte('{')
+       for _, c := range t.fields {
+               child := c.Fingerprint()
+               if len(child) == 0 {
+                       return ""
+               }
+               b.WriteString(child)
+               b.WriteByte(';')
+       }
+       b.WriteByte('}')
+       return b.String()
+}
+
 type MapType struct {
        value      *ListType
        KeysSorted bool
@@ -187,6 +218,20 @@ func (t *MapType) ItemField() Field       { return 
t.value.Elem().(*StructType).
 func (t *MapType) ItemType() DataType     { return t.ItemField().Type }
 func (t *MapType) ValueType() *StructType { return 
t.value.Elem().(*StructType) }
 
+func (t *MapType) Fingerprint() string {
+       keyFingerprint := t.KeyType().Fingerprint()
+       itemFingerprint := t.ItemType().Fingerprint()
+       if keyFingerprint == "" || itemFingerprint == "" {
+               return ""
+       }
+
+       fingerprint := typeFingerprint(t)
+       if t.KeysSorted {
+               fingerprint += "s"
+       }
+       return fingerprint + "{" + keyFingerprint + itemFingerprint + "}"
+}
+
 type Field struct {
        Name     string   // Field name
        Type     DataType // The field's data type
@@ -194,6 +239,26 @@ type Field struct {
        Metadata Metadata // The field's metadata, if any
 }
 
+func (f Field) Fingerprint() string {
+       typeFingerprint := f.Type.Fingerprint()
+       if typeFingerprint == "" {
+               return ""
+       }
+
+       var b strings.Builder
+       b.WriteByte('F')
+       if f.Nullable {
+               b.WriteByte('n')
+       } else {
+               b.WriteByte('N')
+       }
+       b.WriteString(f.Name)
+       b.WriteByte('{')
+       b.WriteString(typeFingerprint)
+       b.WriteByte('}')
+       return b.String()
+}
+
 func (f Field) HasMetadata() bool { return f.Metadata.Len() != 0 }
 
 func (f Field) Equal(o Field) bool {
diff --git a/go/arrow/datatype_null.go b/go/arrow/datatype_null.go
index 5882dfe..253e6ed 100644
--- a/go/arrow/datatype_null.go
+++ b/go/arrow/datatype_null.go
@@ -19,9 +19,10 @@ package arrow
 // NullType describes a degenerate array, with zero physical storage.
 type NullType struct{}
 
-func (*NullType) ID() Type       { return NULL }
-func (*NullType) Name() string   { return "null" }
-func (*NullType) String() string { return "null" }
+func (*NullType) ID() Type            { return NULL }
+func (*NullType) Name() string        { return "null" }
+func (*NullType) String() string      { return "null" }
+func (*NullType) Fingerprint() string { return typeIDFingerprint(NULL) }
 
 var (
        Null *NullType
diff --git a/go/arrow/datatype_numeric.gen.go b/go/arrow/datatype_numeric.gen.go
index d5b34d7..d23ff8f 100644
--- a/go/arrow/datatype_numeric.gen.go
+++ b/go/arrow/datatype_numeric.gen.go
@@ -20,87 +20,99 @@ package arrow
 
 type Int8Type struct{}
 
-func (t *Int8Type) ID() Type       { return INT8 }
-func (t *Int8Type) Name() string   { return "int8" }
-func (t *Int8Type) String() string { return "int8" }
-func (t *Int8Type) BitWidth() int  { return 8 }
+func (t *Int8Type) ID() Type            { return INT8 }
+func (t *Int8Type) Name() string        { return "int8" }
+func (t *Int8Type) String() string      { return "int8" }
+func (t *Int8Type) BitWidth() int       { return 8 }
+func (t *Int8Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Int16Type struct{}
 
-func (t *Int16Type) ID() Type       { return INT16 }
-func (t *Int16Type) Name() string   { return "int16" }
-func (t *Int16Type) String() string { return "int16" }
-func (t *Int16Type) BitWidth() int  { return 16 }
+func (t *Int16Type) ID() Type            { return INT16 }
+func (t *Int16Type) Name() string        { return "int16" }
+func (t *Int16Type) String() string      { return "int16" }
+func (t *Int16Type) BitWidth() int       { return 16 }
+func (t *Int16Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Int32Type struct{}
 
-func (t *Int32Type) ID() Type       { return INT32 }
-func (t *Int32Type) Name() string   { return "int32" }
-func (t *Int32Type) String() string { return "int32" }
-func (t *Int32Type) BitWidth() int  { return 32 }
+func (t *Int32Type) ID() Type            { return INT32 }
+func (t *Int32Type) Name() string        { return "int32" }
+func (t *Int32Type) String() string      { return "int32" }
+func (t *Int32Type) BitWidth() int       { return 32 }
+func (t *Int32Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Int64Type struct{}
 
-func (t *Int64Type) ID() Type       { return INT64 }
-func (t *Int64Type) Name() string   { return "int64" }
-func (t *Int64Type) String() string { return "int64" }
-func (t *Int64Type) BitWidth() int  { return 64 }
+func (t *Int64Type) ID() Type            { return INT64 }
+func (t *Int64Type) Name() string        { return "int64" }
+func (t *Int64Type) String() string      { return "int64" }
+func (t *Int64Type) BitWidth() int       { return 64 }
+func (t *Int64Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Uint8Type struct{}
 
-func (t *Uint8Type) ID() Type       { return UINT8 }
-func (t *Uint8Type) Name() string   { return "uint8" }
-func (t *Uint8Type) String() string { return "uint8" }
-func (t *Uint8Type) BitWidth() int  { return 8 }
+func (t *Uint8Type) ID() Type            { return UINT8 }
+func (t *Uint8Type) Name() string        { return "uint8" }
+func (t *Uint8Type) String() string      { return "uint8" }
+func (t *Uint8Type) BitWidth() int       { return 8 }
+func (t *Uint8Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Uint16Type struct{}
 
-func (t *Uint16Type) ID() Type       { return UINT16 }
-func (t *Uint16Type) Name() string   { return "uint16" }
-func (t *Uint16Type) String() string { return "uint16" }
-func (t *Uint16Type) BitWidth() int  { return 16 }
+func (t *Uint16Type) ID() Type            { return UINT16 }
+func (t *Uint16Type) Name() string        { return "uint16" }
+func (t *Uint16Type) String() string      { return "uint16" }
+func (t *Uint16Type) BitWidth() int       { return 16 }
+func (t *Uint16Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Uint32Type struct{}
 
-func (t *Uint32Type) ID() Type       { return UINT32 }
-func (t *Uint32Type) Name() string   { return "uint32" }
-func (t *Uint32Type) String() string { return "uint32" }
-func (t *Uint32Type) BitWidth() int  { return 32 }
+func (t *Uint32Type) ID() Type            { return UINT32 }
+func (t *Uint32Type) Name() string        { return "uint32" }
+func (t *Uint32Type) String() string      { return "uint32" }
+func (t *Uint32Type) BitWidth() int       { return 32 }
+func (t *Uint32Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Uint64Type struct{}
 
-func (t *Uint64Type) ID() Type       { return UINT64 }
-func (t *Uint64Type) Name() string   { return "uint64" }
-func (t *Uint64Type) String() string { return "uint64" }
-func (t *Uint64Type) BitWidth() int  { return 64 }
+func (t *Uint64Type) ID() Type            { return UINT64 }
+func (t *Uint64Type) Name() string        { return "uint64" }
+func (t *Uint64Type) String() string      { return "uint64" }
+func (t *Uint64Type) BitWidth() int       { return 64 }
+func (t *Uint64Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Float32Type struct{}
 
-func (t *Float32Type) ID() Type       { return FLOAT32 }
-func (t *Float32Type) Name() string   { return "float32" }
-func (t *Float32Type) String() string { return "float32" }
-func (t *Float32Type) BitWidth() int  { return 32 }
+func (t *Float32Type) ID() Type            { return FLOAT32 }
+func (t *Float32Type) Name() string        { return "float32" }
+func (t *Float32Type) String() string      { return "float32" }
+func (t *Float32Type) BitWidth() int       { return 32 }
+func (t *Float32Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Float64Type struct{}
 
-func (t *Float64Type) ID() Type       { return FLOAT64 }
-func (t *Float64Type) Name() string   { return "float64" }
-func (t *Float64Type) String() string { return "float64" }
-func (t *Float64Type) BitWidth() int  { return 64 }
+func (t *Float64Type) ID() Type            { return FLOAT64 }
+func (t *Float64Type) Name() string        { return "float64" }
+func (t *Float64Type) String() string      { return "float64" }
+func (t *Float64Type) BitWidth() int       { return 64 }
+func (t *Float64Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Date32Type struct{}
 
-func (t *Date32Type) ID() Type       { return DATE32 }
-func (t *Date32Type) Name() string   { return "date32" }
-func (t *Date32Type) String() string { return "date32" }
-func (t *Date32Type) BitWidth() int  { return 32 }
+func (t *Date32Type) ID() Type            { return DATE32 }
+func (t *Date32Type) Name() string        { return "date32" }
+func (t *Date32Type) String() string      { return "date32" }
+func (t *Date32Type) BitWidth() int       { return 32 }
+func (t *Date32Type) Fingerprint() string { return typeFingerprint(t) }
 
 type Date64Type struct{}
 
-func (t *Date64Type) ID() Type       { return DATE64 }
-func (t *Date64Type) Name() string   { return "date64" }
-func (t *Date64Type) String() string { return "date64" }
-func (t *Date64Type) BitWidth() int  { return 64 }
+func (t *Date64Type) ID() Type            { return DATE64 }
+func (t *Date64Type) Name() string        { return "date64" }
+func (t *Date64Type) String() string      { return "date64" }
+func (t *Date64Type) BitWidth() int       { return 64 }
+func (t *Date64Type) Fingerprint() string { return typeFingerprint(t) }
 
 var (
        PrimitiveTypes = struct {
diff --git a/go/arrow/datatype_numeric.gen.go.tmpl 
b/go/arrow/datatype_numeric.gen.go.tmpl
index 193cf09..dd4c92f 100644
--- a/go/arrow/datatype_numeric.gen.go.tmpl
+++ b/go/arrow/datatype_numeric.gen.go.tmpl
@@ -19,11 +19,11 @@ package arrow
 {{range .In}}
 type {{.Name}}Type struct {}
 
-func (t *{{.Name}}Type) ID() Type       { return {{.Name|upper}} }
-func (t *{{.Name}}Type) Name() string   { return "{{.Name|lower}}" }
-func (t *{{.Name}}Type) String() string { return "{{.Name|lower}}" }
-func (t *{{.Name}}Type) BitWidth() int  { return {{.Size}} }
-
+func (t *{{.Name}}Type) ID() Type            { return {{.Name|upper}} }
+func (t *{{.Name}}Type) Name() string        { return "{{.Name|lower}}" }
+func (t *{{.Name}}Type) String() string      { return "{{.Name|lower}}" }
+func (t *{{.Name}}Type) BitWidth() int       { return {{.Size}} }
+func (t *{{.Name}}Type) Fingerprint() string { return typeFingerprint(t) }
 
 {{end}}
 
diff --git a/go/arrow/go.sum b/go/arrow/go.sum
index 9a1bcef..207218e 100644
--- a/go/arrow/go.sum
+++ b/go/arrow/go.sum
@@ -1,28 +1,16 @@
 cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 
h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod 
h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-gioui.org v0.0.0-20210308172011-57750fc8a0a6 
h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho=
 gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod 
h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
-github.com/BurntSushi/toml v0.3.1 
h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 
h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod 
h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af 
h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ=
 github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod 
h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
-github.com/antihax/optional v1.0.0 
h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
 github.com/antihax/optional v1.0.0/go.mod 
h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
-github.com/boombuler/barcode v1.0.0 
h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
 github.com/boombuler/barcode v1.0.0/go.mod 
h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
-github.com/census-instrumentation/opencensus-proto v0.2.1 
h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/client9/misspell v0.3.4 
h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod 
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 
h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod 
h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed 
h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c=
 github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod 
h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -32,32 +20,19 @@ github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.m
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod 
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane 
v0.9.9-0.20201210154907-fd9021fe5dad/go.mod 
h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane 
v0.9.9-0.20210217033140-668b12f5399d/go.mod 
h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 
h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s=
 github.com/envoyproxy/go-control-plane 
v0.9.9-0.20210512163311-63b5d3c536b0/go.mod 
h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
-github.com/envoyproxy/protoc-gen-validate v0.1.0 
h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod 
h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
 github.com/fogleman/gg v1.3.0/go.mod 
h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-fonts/dejavu v0.1.0 
h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ=
 github.com/go-fonts/dejavu v0.1.0/go.mod 
h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
-github.com/go-fonts/latin-modern v0.2.0 
h1:5/Tv1Ek/QCr20C6ZOz15vw3g7GELYL98KWr8Hgo+3vk=
 github.com/go-fonts/latin-modern v0.2.0/go.mod 
h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
-github.com/go-fonts/liberation v0.1.1 
h1:wBrPaMkrXFBW3qXpXAjiKljdVUMxn9bX2ia3XjPHoik=
 github.com/go-fonts/liberation v0.1.1/go.mod 
h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
-github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg=
 github.com/go-fonts/stix v0.1.0/go.mod 
h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 
h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07 
h1:OTlfMvwR1rLyf9goVmXfuS5AJn80+Vmj4rTf4n46SOs=
 github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod 
h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 
h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod 
h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b 
h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod 
h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
 github.com/golang/mock v1.1.1/go.mod 
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -85,46 +60,33 @@ github.com/google/go-cmp v0.5.0/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
 github.com/google/uuid v1.1.2/go.mod 
h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 
h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod 
h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/jung-kurt/gofpdf v1.0.0/go.mod 
h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
-github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5 
h1:PJr+ZMXIecYc1Ey2zucXdR73SMBtgjPgwa31099IMv0=
 github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod 
h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
 github.com/klauspost/compress v1.13.1 
h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
 github.com/klauspost/compress v1.13.1/go.mod 
h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
-github.com/phpdave11/gofpdf v1.4.2 
h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ=
 github.com/phpdave11/gofpdf v1.4.2/go.mod 
h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
-github.com/phpdave11/gofpdi v1.0.12 
h1:RZb9NG62cw/RW0rHAduVRo+98R8o/G1krcg2ns7DakQ=
 github.com/phpdave11/gofpdi v1.0.12/go.mod 
h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pierrec/lz4/v4 v4.1.8 
h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4=
 github.com/pierrec/lz4/v4 v4.1.8/go.mod 
h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 
h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod 
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rogpeppe/fastuuid v1.2.0 
h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod 
h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 
h1:nlG4Wa5+minh3S9LVFtNoY+GVRiudA2e3EVfcCi3RCA=
 github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod 
h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.5.1/go.mod 
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0 
h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
 github.com/yuin/goldmark v1.3.5/go.mod 
h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-go.opentelemetry.io/proto/otlp v0.7.0 
h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod 
h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 
h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod 
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -141,18 +103,14 @@ golang.org/x/image 
v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+o
 golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod 
h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod 
h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod 
h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20210216034530-4410531fe030 
h1:lP9pYkih3DUSC641giIXa2XqfTIbbbRr0w2EOTA7wHA=
 golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod 
h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod 
h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod 
h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 
h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod 
h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 
h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod 
h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod 
h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -166,13 +124,11 @@ golang.org/x/net 
v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210614182718-04defd469f4e 
h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
 golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod 
h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod 
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d 
h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c 
h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -186,7 +142,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod 
h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c 
h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 
h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -203,7 +158,6 @@ golang.org/x/tools 
v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
 golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod 
h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod 
h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.1.4 h1:cVngSRcfgyZCzys3KYOpCFa+4dqX/Oub9tAq00ttGVs=
 golang.org/x/tools v0.1.4/go.mod 
h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -217,10 +171,8 @@ gonum.org/v1/gonum v0.9.3/go.mod 
h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 
h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod 
h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
 gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod 
h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
-gonum.org/v1/plot v0.9.0 h1:3sEo36Uopv1/SA/dMFFaxXoL5XyikJ9Sf2Vll/k6+2E=
 gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
 google.golang.org/appengine v1.1.0/go.mod 
h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0 
h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
 google.golang.org/appengine v1.4.0/go.mod 
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod 
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
@@ -253,12 +205,9 @@ google.golang.org/protobuf v1.27.1/go.mod 
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 
h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c 
h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc 
h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/go/arrow/scalar/parse.go b/go/arrow/scalar/parse.go
index e5bb827..2a96372 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.DataType:
+               return MakeNullScalar(v)
        }
 
        panic(xerrors.Errorf("makescalar not implemented for type value %#v", 
val))
diff --git a/go/arrow/scalar/scalar.go b/go/arrow/scalar/scalar.go
index 03a7d03..6d6ab95 100644
--- a/go/arrow/scalar/scalar.go
+++ b/go/arrow/scalar/scalar.go
@@ -17,7 +17,9 @@
 package scalar
 
 import (
+       "encoding/binary"
        "fmt"
+       "hash/maphash"
        "math"
        "math/big"
        "reflect"
@@ -28,6 +30,7 @@ import (
        "github.com/apache/arrow/go/arrow/array"
        "github.com/apache/arrow/go/arrow/bitutil"
        "github.com/apache/arrow/go/arrow/decimal128"
+       "github.com/apache/arrow/go/arrow/endian"
        "github.com/apache/arrow/go/arrow/float16"
        "github.com/apache/arrow/go/arrow/internal/debug"
        "github.com/apache/arrow/go/arrow/memory"
@@ -708,3 +711,73 @@ func MakeArrayFromScalar(sc Scalar, length int, mem 
memory.Allocator) (array.Int
                return nil, xerrors.Errorf("array from scalar not yet 
implemented for type %s", sc.DataType())
        }
 }
+
+func Hash(seed maphash.Seed, s Scalar) uint64 {
+       var h maphash.Hash
+       h.SetSeed(seed)
+       binary.Write(&h, endian.Native, arrow.HashType(seed, s.DataType()))
+
+       out := h.Sum64()
+       if !s.IsValid() {
+               return out
+       }
+
+       hash := func() {
+               out ^= h.Sum64()
+               h.Reset()
+       }
+
+       valueHash := func(v interface{}) {
+               switch v := v.(type) {
+               case int32:
+                       h.Write((*[4]byte)(unsafe.Pointer(&v))[:])
+               case arrow.Date32:
+                       binary.Write(&h, endian.Native, uint32(v))
+               case arrow.Time32:
+                       binary.Write(&h, endian.Native, uint32(v))
+               case arrow.MonthInterval:
+                       binary.Write(&h, endian.Native, uint32(v))
+               case arrow.Duration:
+                       binary.Write(&h, endian.Native, uint64(v))
+               case arrow.Date64:
+                       binary.Write(&h, endian.Native, uint64(v))
+               case arrow.Time64:
+                       binary.Write(&h, endian.Native, uint64(v))
+               case arrow.Timestamp:
+                       binary.Write(&h, endian.Native, uint64(v))
+               case float16.Num:
+                       binary.Write(&h, endian.Native, v.Uint16())
+               case decimal128.Num:
+                       binary.Write(&h, endian.Native, v.LowBits())
+                       hash()
+                       binary.Write(&h, endian.Native, uint64(v.HighBits()))
+               }
+               hash()
+       }
+
+       h.Reset()
+       switch s := s.(type) {
+       case *Null:
+       case *Extension:
+               out ^= Hash(seed, s.Value)
+       case *DayTimeInterval:
+               valueHash(s.Value.Days)
+               valueHash(s.Value.Milliseconds)
+       case PrimitiveScalar:
+               h.Write(s.Data())
+               hash()
+       case TemporalScalar:
+               valueHash(s.value())
+       case ListScalar:
+               array.Hash(&h, s.GetList().Data())
+               hash()
+       case *Struct:
+               for _, c := range s.Value {
+                       if c.IsValid() {
+                               out ^= Hash(seed, c)
+                       }
+               }
+       }
+
+       return out
+}
diff --git a/go/arrow/scalar/scalar_test.go b/go/arrow/scalar/scalar_test.go
index 49c5c59..6791c4a 100644
--- a/go/arrow/scalar/scalar_test.go
+++ b/go/arrow/scalar/scalar_test.go
@@ -18,6 +18,7 @@ package scalar_test
 
 import (
        "bytes"
+       "hash/maphash"
        "math/bits"
        "testing"
        "time"
@@ -33,6 +34,8 @@ import (
 
 func assertScalarsEqual(t *testing.T, expected, actual scalar.Scalar) {
        assert.Truef(t, scalar.Equals(expected, actual), 
"Expected:\n%s\nActual:\n%s", expected, actual)
+       seed := maphash.MakeSeed()
+       assert.Equal(t, scalar.Hash(seed, expected), scalar.Hash(seed, actual))
 }
 
 func assertMakeScalarParam(t *testing.T, expected scalar.Scalar, dt 
arrow.DataType, val interface{}) {
diff --git a/go/arrow/schema.go b/go/arrow/schema.go
index f278308..80a45bd 100644
--- a/go/arrow/schema.go
+++ b/go/arrow/schema.go
@@ -220,3 +220,24 @@ func (s *Schema) String() string {
        }
        return o.String()
 }
+
+func (s *Schema) Fingerprint() string {
+       if s == nil {
+               return ""
+       }
+
+       var b strings.Builder
+       b.WriteString("S{")
+       for _, f := range s.Fields() {
+               fieldFingerprint := f.Fingerprint()
+               if fieldFingerprint == "" {
+                       return ""
+               }
+
+               b.WriteString(fieldFingerprint)
+               b.WriteByte(';')
+       }
+       // endianness
+       b.WriteByte('}')
+       return b.String()
+}
diff --git a/go/arrow/schema_test.go b/go/arrow/schema_test.go
index 31f8739..0c7dc90 100644
--- a/go/arrow/schema_test.go
+++ b/go/arrow/schema_test.go
@@ -354,10 +354,15 @@ func TestSchemaEqual(t *testing.T) {
                        if ab != tc.want {
                                t.Fatalf("got=%v, want=%v", ab, tc.want)
                        }
+
                        ba := tc.b.Equal(tc.a)
                        if ab != ba {
                                t.Fatalf("ab != ba")
                        }
+
+                       if (tc.a.Fingerprint() == tc.b.Fingerprint()) != 
tc.want {
+                               t.Fatalf("fingerprint: got=%v;%v, wanted=%v", 
tc.a.Fingerprint(), tc.b.Fingerprint(), tc.want)
+                       }
                })
        }
 }

Reply via email to