From: Gordon Klaus Date: Mon, 5 Oct 2015 20:12:46 +0000 (+0200) Subject: database/sql: fix conversions to and from user-defined types X-Git-Tag: go1.6beta1~893 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=40457745e51eb327751de5be4c69c9079db69f66;p=gostls13.git database/sql: fix conversions to and from user-defined types In particular, don't assume that one reflect.Value can be assigned to another just because they have the same reflect.Kind. Fixes #12401 Change-Id: Ia4605a5c46557ff8f8f1d44f26d492850666c6d1 Reviewed-on: https://go-review.googlesource.com/15420 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go index c0b38a2494..bba5a8843a 100644 --- a/src/database/sql/convert.go +++ b/src/database/sql/convert.go @@ -203,11 +203,16 @@ func convertAssign(dest, src interface{}) error { } dv := reflect.Indirect(dpv) - if dv.Kind() == sv.Kind() { + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { dv.Set(sv) return nil } + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + switch dv.Kind() { case reflect.Ptr: if src == nil { diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go index 98af9fb64c..1fab282b40 100644 --- a/src/database/sql/convert_test.go +++ b/src/database/sql/convert_test.go @@ -16,23 +16,28 @@ import ( var someTime = time.Unix(123, 0) var answer int64 = 42 +type userDefined float64 + +type userDefinedSlice []int + type conversionTest struct { s, d interface{} // source and destination // following are used if they're non-zero - wantint int64 - wantuint uint64 - wantstr string - wantbytes []byte - wantraw RawBytes - wantf32 float32 - wantf64 float64 - wanttime time.Time - wantbool bool // used if d is of type *bool - wanterr string - wantiface interface{} - wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr - wantnil bool // if true, *d must be *int64(nil) + wantint int64 + wantuint uint64 + wantstr string + wantbytes []byte + wantraw RawBytes + wantf32 float32 + wantf64 float64 + wanttime time.Time + wantbool bool // used if d is of type *bool + wanterr string + wantiface interface{} + wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr + wantnil bool // if true, *d must be *int64(nil) + wantusrdef userDefined } // Target variables for scanning into. @@ -145,6 +150,12 @@ var conversionTests = []conversionTest{ {s: true, d: &scaniface, wantiface: true}, {s: nil, d: &scaniface}, {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)}, + + // To a user-defined type + {s: 1.5, d: new(userDefined), wantusrdef: 1.5}, + {s: int64(123), d: new(userDefined), wantusrdef: 123}, + {s: "1.5", d: new(userDefined), wantusrdef: 1.5}, + {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported driver -> Scan pair: []uint8 -> *sql.userDefinedSlice`}, } func intPtrValue(intptr interface{}) interface{} { @@ -228,6 +239,9 @@ func TestConversions(t *testing.T) { } } } + if ct.wantusrdef != 0 && ct.wantusrdef != *ct.d.(*userDefined) { + errf("want userDefined %f, got %f", ct.wantusrdef, *ct.d.(*userDefined)) + } } }