From af0ca3a39b16dc19b75f40fd5fe38a79c9b0b5a8 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 31 Oct 2020 17:12:16 -0500 Subject: [PATCH] Fix simple protocol empty array and original recursive empty array issue Original issue https://github.com/jackc/pgtype/issues/68 This crash occurred in the recursive assignment system used to support multidimensional arrays. This was fixed in 9639a69d451f55456f598c1aa8b93053f8df3088. However, that fix incorrectly used nil instead of an empty slice. In hindsight, it appears the fundamental error is that an assignment to a slice of a type that is not specified is handled with the recursive / reflection path. Or another way of looking at it is as an unexpected feature where []T can now be scanned if individual elements are assignable to T even if []T is not specifically handled. But this new reflection / recursive path did not handle empty arrays. This fix handles the reflection path for an empty slice by allocating an empty slice. --- aclitem_array.go | 11 +++++++---- aclitem_array_test.go | 2 +- bool_array.go | 11 +++++++---- bool_array_test.go | 2 +- bpchar_array.go | 11 +++++++---- bytea_array.go | 11 +++++++---- bytea_array_test.go | 2 +- cidr_array.go | 11 +++++++---- cidr_array_test.go | 4 ++-- date_array.go | 11 +++++++---- date_array_test.go | 2 +- enum_array.go | 11 +++++++---- enum_array_test.go | 2 +- float4_array.go | 11 +++++++---- float4_array_test.go | 2 +- float8_array.go | 11 +++++++---- float8_array_test.go | 2 +- hstore_array.go | 11 +++++++---- hstore_array_test.go | 2 +- inet_array.go | 11 +++++++---- inet_array_test.go | 4 ++-- int2_array.go | 11 +++++++---- int2_array_test.go | 2 +- int4_array.go | 11 +++++++---- int4_array_test.go | 2 +- int8_array.go | 11 +++++++---- int8_array_test.go | 2 +- jsonb_array.go | 11 +++++++---- macaddr_array.go | 11 +++++++---- macaddr_array_test.go | 2 +- numeric_array.go | 11 +++++++---- numeric_array_test.go | 2 +- text_array.go | 11 +++++++---- text_array_test.go | 2 +- timestamp_array.go | 11 +++++++---- timestamp_array_test.go | 2 +- timestamptz_array.go | 11 +++++++---- timestamptz_array_test.go | 2 +- tstzrange_array.go | 11 +++++++---- typed_array.go.erb | 11 +++++++---- uuid_array.go | 11 +++++++---- uuid_array_test.go | 4 ++-- varchar_array.go | 11 +++++++---- varchar_array_test.go | 2 +- 44 files changed, 191 insertions(+), 119 deletions(-) diff --git a/aclitem_array.go b/aclitem_array.go index 229136ec..f4b14433 100644 --- a/aclitem_array.go +++ b/aclitem_array.go @@ -190,10 +190,6 @@ func (dst ACLItemArray) Get() interface{} { func (src *ACLItemArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -232,6 +228,13 @@ func (src *ACLItemArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/aclitem_array_test.go b/aclitem_array_test.go index 8ebb8c8d..8f015f40 100644 --- a/aclitem_array_test.go +++ b/aclitem_array_test.go @@ -192,7 +192,7 @@ func TestACLItemArrayAssignTo(t *testing.T) { { src: pgtype.ACLItemArray{Status: pgtype.Present}, dst: &stringSlice, - expected: (([]string)(nil)), + expected: []string{}, }, { src: pgtype.ACLItemArray{ diff --git a/bool_array.go b/bool_array.go index 9c960b0f..41c6deda 100644 --- a/bool_array.go +++ b/bool_array.go @@ -192,10 +192,6 @@ func (dst BoolArray) Get() interface{} { func (src *BoolArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *BoolArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/bool_array_test.go b/bool_array_test.go index 4ff26bb5..be567e59 100644 --- a/bool_array_test.go +++ b/bool_array_test.go @@ -171,7 +171,7 @@ func TestBoolArrayAssignTo(t *testing.T) { { src: pgtype.BoolArray{Status: pgtype.Present}, dst: &boolSlice, - expected: (([]bool)(nil)), + expected: []bool{}, }, { src: pgtype.BoolArray{ diff --git a/bpchar_array.go b/bpchar_array.go index 89a14aa0..5fd7381a 100644 --- a/bpchar_array.go +++ b/bpchar_array.go @@ -192,10 +192,6 @@ func (dst BPCharArray) Get() interface{} { func (src *BPCharArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *BPCharArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/bytea_array.go b/bytea_array.go index 425ef954..9b5c9ee9 100644 --- a/bytea_array.go +++ b/bytea_array.go @@ -173,10 +173,6 @@ func (dst ByteaArray) Get() interface{} { func (src *ByteaArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -206,6 +202,13 @@ func (src *ByteaArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/bytea_array_test.go b/bytea_array_test.go index 4964771c..27c0382e 100644 --- a/bytea_array_test.go +++ b/bytea_array_test.go @@ -160,7 +160,7 @@ func TestByteaArrayAssignTo(t *testing.T) { { src: pgtype.ByteaArray{Status: pgtype.Present}, dst: &byteByteSlice, - expected: (([][]byte)(nil)), + expected: [][]byte{}, }, { src: pgtype.ByteaArray{ diff --git a/cidr_array.go b/cidr_array.go index 4ad10d8b..06192ddd 100644 --- a/cidr_array.go +++ b/cidr_array.go @@ -212,10 +212,6 @@ func (dst CIDRArray) Get() interface{} { func (src *CIDRArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -263,6 +259,13 @@ func (src *CIDRArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/cidr_array_test.go b/cidr_array_test.go index aa933b62..74c063fa 100644 --- a/cidr_array_test.go +++ b/cidr_array_test.go @@ -220,7 +220,7 @@ func TestCIDRArrayAssignTo(t *testing.T) { { src: pgtype.CIDRArray{Status: pgtype.Present}, dst: &ipnetSlice, - expected: (([]*net.IPNet)(nil)), + expected: []*net.IPNet{}, }, { src: pgtype.CIDRArray{Status: pgtype.Null}, @@ -230,7 +230,7 @@ func TestCIDRArrayAssignTo(t *testing.T) { { src: pgtype.CIDRArray{Status: pgtype.Present}, dst: &ipSlice, - expected: (([]net.IP)(nil)), + expected: []net.IP{}, }, { src: pgtype.CIDRArray{ diff --git a/date_array.go b/date_array.go index b29eee67..1961bf20 100644 --- a/date_array.go +++ b/date_array.go @@ -193,10 +193,6 @@ func (dst DateArray) Get() interface{} { func (src *DateArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -235,6 +231,13 @@ func (src *DateArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/date_array_test.go b/date_array_test.go index 8791c31f..4458abfe 100644 --- a/date_array_test.go +++ b/date_array_test.go @@ -185,7 +185,7 @@ func TestDateArrayAssignTo(t *testing.T) { { src: pgtype.DateArray{Status: pgtype.Present}, dst: &timeSlice, - expected: (([]time.Time)(nil)), + expected: []time.Time{}, }, { src: pgtype.DateArray{ diff --git a/enum_array.go b/enum_array.go index 76caac95..ebe838ad 100644 --- a/enum_array.go +++ b/enum_array.go @@ -190,10 +190,6 @@ func (dst EnumArray) Get() interface{} { func (src *EnumArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -232,6 +228,13 @@ func (src *EnumArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/enum_array_test.go b/enum_array_test.go index 9db8b49f..659340f0 100644 --- a/enum_array_test.go +++ b/enum_array_test.go @@ -170,7 +170,7 @@ func TestEnumArrayArrayAssignTo(t *testing.T) { { src: pgtype.EnumArray{Status: pgtype.Present}, dst: &stringSlice, - expected: (([]string)(nil)), + expected: []string{}, }, { src: pgtype.EnumArray{ diff --git a/float4_array.go b/float4_array.go index d314563c..44ba1fee 100644 --- a/float4_array.go +++ b/float4_array.go @@ -192,10 +192,6 @@ func (dst Float4Array) Get() interface{} { func (src *Float4Array) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *Float4Array) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/float4_array_test.go b/float4_array_test.go index 88d35fd6..db438999 100644 --- a/float4_array_test.go +++ b/float4_array_test.go @@ -170,7 +170,7 @@ func TestFloat4ArrayAssignTo(t *testing.T) { { src: pgtype.Float4Array{Status: pgtype.Present}, dst: &float32Slice, - expected: (([]float32)(nil)), + expected: []float32{}, }, { src: pgtype.Float4Array{ diff --git a/float8_array.go b/float8_array.go index 60d1a6d2..1065190d 100644 --- a/float8_array.go +++ b/float8_array.go @@ -192,10 +192,6 @@ func (dst Float8Array) Get() interface{} { func (src *Float8Array) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *Float8Array) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/float8_array_test.go b/float8_array_test.go index d7bf6ac3..85cb8f43 100644 --- a/float8_array_test.go +++ b/float8_array_test.go @@ -146,7 +146,7 @@ func TestFloat8ArrayAssignTo(t *testing.T) { { src: pgtype.Float8Array{Status: pgtype.Present}, dst: &float64Slice, - expected: (([]float64)(nil)), + expected: []float64{}, }, { src: pgtype.Float8Array{ diff --git a/hstore_array.go b/hstore_array.go index 02abe870..3899ae49 100644 --- a/hstore_array.go +++ b/hstore_array.go @@ -173,10 +173,6 @@ func (dst HstoreArray) Get() interface{} { func (src *HstoreArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -206,6 +202,13 @@ func (src *HstoreArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/hstore_array_test.go b/hstore_array_test.go index 3d85545a..672eca4a 100644 --- a/hstore_array_test.go +++ b/hstore_array_test.go @@ -303,7 +303,7 @@ func TestHstoreArrayAssignTo(t *testing.T) { src: pgtype.HstoreArray{Status: pgtype.Null}, dst: &hstoreSlice, expected: (([]map[string]string)(nil)), }, { - src: pgtype.HstoreArray{Status: pgtype.Present}, dst: &hstoreSlice, expected: (([]map[string]string)(nil)), + src: pgtype.HstoreArray{Status: pgtype.Present}, dst: &hstoreSlice, expected: []map[string]string{}, }, { src: pgtype.HstoreArray{ diff --git a/inet_array.go b/inet_array.go index 4f8211ab..5de138c0 100644 --- a/inet_array.go +++ b/inet_array.go @@ -212,10 +212,6 @@ func (dst InetArray) Get() interface{} { func (src *InetArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -263,6 +259,13 @@ func (src *InetArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/inet_array_test.go b/inet_array_test.go index 5beab960..46dc7d12 100644 --- a/inet_array_test.go +++ b/inet_array_test.go @@ -220,7 +220,7 @@ func TestInetArrayAssignTo(t *testing.T) { { src: pgtype.InetArray{Status: pgtype.Present}, dst: &ipnetSlice, - expected: (([]*net.IPNet)(nil)), + expected: []*net.IPNet{}, }, { src: pgtype.InetArray{Status: pgtype.Null}, @@ -230,7 +230,7 @@ func TestInetArrayAssignTo(t *testing.T) { { src: pgtype.InetArray{Status: pgtype.Present}, dst: &ipSlice, - expected: (([]net.IP)(nil)), + expected: []net.IP{}, }, { src: pgtype.InetArray{ diff --git a/int2_array.go b/int2_array.go index 180db652..6b4e4c8a 100644 --- a/int2_array.go +++ b/int2_array.go @@ -458,10 +458,6 @@ func (dst Int2Array) Get() interface{} { func (src *Int2Array) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -626,6 +622,13 @@ func (src *Int2Array) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/int2_array_test.go b/int2_array_test.go index da669f7d..17c37360 100644 --- a/int2_array_test.go +++ b/int2_array_test.go @@ -222,7 +222,7 @@ func TestInt2ArrayAssignTo(t *testing.T) { { src: pgtype.Int2Array{Status: pgtype.Present}, dst: &int16Slice, - expected: (([]int16)(nil)), + expected: []int16{}, }, { src: pgtype.Int2Array{ diff --git a/int4_array.go b/int4_array.go index d36071a0..8801947d 100644 --- a/int4_array.go +++ b/int4_array.go @@ -458,10 +458,6 @@ func (dst Int4Array) Get() interface{} { func (src *Int4Array) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -626,6 +622,13 @@ func (src *Int4Array) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/int4_array_test.go b/int4_array_test.go index a5aad827..110512a9 100644 --- a/int4_array_test.go +++ b/int4_array_test.go @@ -236,7 +236,7 @@ func TestInt4ArrayAssignTo(t *testing.T) { { src: pgtype.Int4Array{Status: pgtype.Present}, dst: &int32Slice, - expected: (([]int32)(nil)), + expected: []int32{}, }, { src: pgtype.Int4Array{ diff --git a/int8_array.go b/int8_array.go index 3adb2f02..13e20fca 100644 --- a/int8_array.go +++ b/int8_array.go @@ -458,10 +458,6 @@ func (dst Int8Array) Get() interface{} { func (src *Int8Array) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -626,6 +622,13 @@ func (src *Int8Array) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/int8_array_test.go b/int8_array_test.go index b0ee97ee..1d42a278 100644 --- a/int8_array_test.go +++ b/int8_array_test.go @@ -229,7 +229,7 @@ func TestInt8ArrayAssignTo(t *testing.T) { { src: pgtype.Int8Array{Status: pgtype.Present}, dst: &int64Slice, - expected: (([]int64)(nil)), + expected: []int64{}, }, { src: pgtype.Int8Array{ diff --git a/jsonb_array.go b/jsonb_array.go index 562b0654..f44f7fa5 100644 --- a/jsonb_array.go +++ b/jsonb_array.go @@ -192,10 +192,6 @@ func (dst JSONBArray) Get() interface{} { func (src *JSONBArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *JSONBArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/macaddr_array.go b/macaddr_array.go index 511cd9ca..5a27046f 100644 --- a/macaddr_array.go +++ b/macaddr_array.go @@ -193,10 +193,6 @@ func (dst MacaddrArray) Get() interface{} { func (src *MacaddrArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -235,6 +231,13 @@ func (src *MacaddrArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/macaddr_array_test.go b/macaddr_array_test.go index 6359a374..c1a8b72d 100644 --- a/macaddr_array_test.go +++ b/macaddr_array_test.go @@ -169,7 +169,7 @@ func TestMacaddrArrayAssignTo(t *testing.T) { { src: pgtype.MacaddrArray{Status: pgtype.Present}, dst: &macaddrSlice, - expected: (([]net.HardwareAddr)(nil)), + expected: []net.HardwareAddr{}, }, { src: pgtype.MacaddrArray{ diff --git a/numeric_array.go b/numeric_array.go index e3c18600..c281bfb3 100644 --- a/numeric_array.go +++ b/numeric_array.go @@ -306,10 +306,6 @@ func (dst NumericArray) Get() interface{} { func (src *NumericArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -402,6 +398,13 @@ func (src *NumericArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/numeric_array_test.go b/numeric_array_test.go index def8150d..7c1e8c3b 100644 --- a/numeric_array_test.go +++ b/numeric_array_test.go @@ -193,7 +193,7 @@ func TestNumericArrayAssignTo(t *testing.T) { { src: pgtype.NumericArray{Status: pgtype.Present}, dst: &float32Slice, - expected: (([]float32)(nil)), + expected: []float32{}, }, { src: pgtype.NumericArray{ diff --git a/text_array.go b/text_array.go index 5d0215c2..599764d8 100644 --- a/text_array.go +++ b/text_array.go @@ -192,10 +192,6 @@ func (dst TextArray) Get() interface{} { func (src *TextArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *TextArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/text_array_test.go b/text_array_test.go index a538c617..5a2317e3 100644 --- a/text_array_test.go +++ b/text_array_test.go @@ -171,7 +171,7 @@ func TestTextArrayAssignTo(t *testing.T) { { src: pgtype.TextArray{Status: pgtype.Present}, dst: &stringSlice, - expected: (([]string)(nil)), + expected: []string{}, }, { src: pgtype.TextArray{ diff --git a/timestamp_array.go b/timestamp_array.go index 2495f2c9..2f7176b8 100644 --- a/timestamp_array.go +++ b/timestamp_array.go @@ -193,10 +193,6 @@ func (dst TimestampArray) Get() interface{} { func (src *TimestampArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -235,6 +231,13 @@ func (src *TimestampArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/timestamp_array_test.go b/timestamp_array_test.go index 85db94bb..54d15b24 100644 --- a/timestamp_array_test.go +++ b/timestamp_array_test.go @@ -165,7 +165,7 @@ func TestTimestampArrayAssignTo(t *testing.T) { { src: pgtype.TimestampArray{Status: pgtype.Present}, dst: &timeSlice, - expected: (([]time.Time)(nil)), + expected: []time.Time{}, }, { src: pgtype.TimestampArray{ diff --git a/timestamptz_array.go b/timestamptz_array.go index 7ebcf9da..a10aaa8b 100644 --- a/timestamptz_array.go +++ b/timestamptz_array.go @@ -193,10 +193,6 @@ func (dst TimestamptzArray) Get() interface{} { func (src *TimestamptzArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -235,6 +231,13 @@ func (src *TimestamptzArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/timestamptz_array_test.go b/timestamptz_array_test.go index a4e1dded..9856e4e7 100644 --- a/timestamptz_array_test.go +++ b/timestamptz_array_test.go @@ -201,7 +201,7 @@ func TestTimestamptzArrayAssignTo(t *testing.T) { { src: pgtype.TimestamptzArray{Status: pgtype.Present}, dst: &timeSlice, - expected: (([]time.Time)(nil)), + expected: []time.Time{}, }, { src: pgtype.TimestamptzArray{ diff --git a/tstzrange_array.go b/tstzrange_array.go index dae022d0..7e57acfe 100644 --- a/tstzrange_array.go +++ b/tstzrange_array.go @@ -154,10 +154,6 @@ func (dst TstzrangeArray) Get() interface{} { func (src *TstzrangeArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -187,6 +183,13 @@ func (src *TstzrangeArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/typed_array.go.erb b/typed_array.go.erb index 9951bfcb..eb1a642e 100644 --- a/typed_array.go.erb +++ b/typed_array.go.erb @@ -174,10 +174,6 @@ func (dst <%= pgtype_array_type %>) Get() interface{} { func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1{ // Attempt to match to select common types: switch v := dst.(type) { @@ -207,6 +203,13 @@ func (src *<%= pgtype_array_type %>) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/uuid_array.go b/uuid_array.go index 89cadd91..fc1ea3b3 100644 --- a/uuid_array.go +++ b/uuid_array.go @@ -230,10 +230,6 @@ func (dst UUIDArray) Get() interface{} { func (src *UUIDArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -290,6 +286,13 @@ func (src *UUIDArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/uuid_array_test.go b/uuid_array_test.go index a1e14a04..7d822e7a 100644 --- a/uuid_array_test.go +++ b/uuid_array_test.go @@ -256,12 +256,12 @@ func TestUUIDArrayAssignTo(t *testing.T) { { src: pgtype.UUIDArray{Status: pgtype.Present}, dst: &byteSlice, - expected: ([]byte)(nil), + expected: []byte{}, }, { src: pgtype.UUIDArray{Status: pgtype.Present}, dst: &stringSlice, - expected: (([]string)(nil)), + expected: []string{}, }, { src: pgtype.UUIDArray{ diff --git a/varchar_array.go b/varchar_array.go index fd8de8a4..9326c72d 100644 --- a/varchar_array.go +++ b/varchar_array.go @@ -192,10 +192,6 @@ func (dst VarcharArray) Get() interface{} { func (src *VarcharArray) AssignTo(dst interface{}) error { switch src.Status { case Present: - if len(src.Elements) == 0 || len(src.Dimensions) == 0 { - // No values to assign - return nil - } if len(src.Dimensions) <= 1 { // Attempt to match to select common types: switch v := dst.(type) { @@ -234,6 +230,13 @@ func (src *VarcharArray) AssignTo(dst interface{}) error { value = value.Elem() } + if len(src.Elements) == 0 { + if value.Kind() == reflect.Slice { + value.Set(reflect.MakeSlice(value.Type(), 0, 0)) + return nil + } + } + elementCount, err := src.assignToRecursive(value, 0, 0) if err != nil { return err diff --git a/varchar_array_test.go b/varchar_array_test.go index ca9a15b7..5fb7326d 100644 --- a/varchar_array_test.go +++ b/varchar_array_test.go @@ -171,7 +171,7 @@ func TestVarcharArrayAssignTo(t *testing.T) { { src: pgtype.VarcharArray{Status: pgtype.Present}, dst: &stringSlice, - expected: (([]string)(nil)), + expected: []string{}, }, { src: pgtype.VarcharArray{