Commit 40457745 authored by Gordon Klaus's avatar Gordon Klaus Committed by Brad Fitzpatrick

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/15420Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 50ad3372
...@@ -203,11 +203,16 @@ func convertAssign(dest, src interface{}) error { ...@@ -203,11 +203,16 @@ func convertAssign(dest, src interface{}) error {
} }
dv := reflect.Indirect(dpv) dv := reflect.Indirect(dpv)
if dv.Kind() == sv.Kind() { if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
dv.Set(sv) dv.Set(sv)
return nil return nil
} }
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
dv.Set(sv.Convert(dv.Type()))
return nil
}
switch dv.Kind() { switch dv.Kind() {
case reflect.Ptr: case reflect.Ptr:
if src == nil { if src == nil {
......
...@@ -16,23 +16,28 @@ import ( ...@@ -16,23 +16,28 @@ import (
var someTime = time.Unix(123, 0) var someTime = time.Unix(123, 0)
var answer int64 = 42 var answer int64 = 42
type userDefined float64
type userDefinedSlice []int
type conversionTest struct { type conversionTest struct {
s, d interface{} // source and destination s, d interface{} // source and destination
// following are used if they're non-zero // following are used if they're non-zero
wantint int64 wantint int64
wantuint uint64 wantuint uint64
wantstr string wantstr string
wantbytes []byte wantbytes []byte
wantraw RawBytes wantraw RawBytes
wantf32 float32 wantf32 float32
wantf64 float64 wantf64 float64
wanttime time.Time wanttime time.Time
wantbool bool // used if d is of type *bool wantbool bool // used if d is of type *bool
wanterr string wanterr string
wantiface interface{} wantiface interface{}
wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr
wantnil bool // if true, *d must be *int64(nil) wantnil bool // if true, *d must be *int64(nil)
wantusrdef userDefined
} }
// Target variables for scanning into. // Target variables for scanning into.
...@@ -145,6 +150,12 @@ var conversionTests = []conversionTest{ ...@@ -145,6 +150,12 @@ var conversionTests = []conversionTest{
{s: true, d: &scaniface, wantiface: true}, {s: true, d: &scaniface, wantiface: true},
{s: nil, d: &scaniface}, {s: nil, d: &scaniface},
{s: []byte(nil), d: &scaniface, wantiface: []byte(nil)}, {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{} { func intPtrValue(intptr interface{}) interface{} {
...@@ -228,6 +239,9 @@ func TestConversions(t *testing.T) { ...@@ -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))
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment