1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 var someTime
= time
.Unix(123, 0)
20 type userDefined
float64
22 type userDefinedSlice
[]int
24 type conversionTest
struct {
25 s
, d
interface{} // source and destination
27 // following are used if they're non-zero
36 wantbool
bool // used if d is of type *bool
39 wantptr
*int64 // if non-nil, *d's pointed value must be equal to *wantptr
40 wantnil
bool // if true, *d must be *int64(nil)
41 wantusrdef userDefined
44 // Target variables for scanning into.
63 var conversionTests
= []conversionTest
{
64 // Exact conversions (destination pointer type matches source type)
65 {s
: "foo", d
: &scanstr
, wantstr
: "foo"},
66 {s
: 123, d
: &scanint
, wantint
: 123},
67 {s
: someTime
, d
: &scantime
, wanttime
: someTime
},
70 {s
: "string", d
: &scanstr
, wantstr
: "string"},
71 {s
: []byte("byteslice"), d
: &scanstr
, wantstr
: "byteslice"},
72 {s
: 123, d
: &scanstr
, wantstr
: "123"},
73 {s
: int8(123), d
: &scanstr
, wantstr
: "123"},
74 {s
: int64(123), d
: &scanstr
, wantstr
: "123"},
75 {s
: uint8(123), d
: &scanstr
, wantstr
: "123"},
76 {s
: uint16(123), d
: &scanstr
, wantstr
: "123"},
77 {s
: uint32(123), d
: &scanstr
, wantstr
: "123"},
78 {s
: uint64(123), d
: &scanstr
, wantstr
: "123"},
79 {s
: 1.5, d
: &scanstr
, wantstr
: "1.5"},
82 {s
: time
.Unix(1, 0).UTC(), d
: &scanstr
, wantstr
: "1970-01-01T00:00:01Z"},
83 {s
: time
.Unix(1453874597, 0).In(time
.FixedZone("here", -3600*8)), d
: &scanstr
, wantstr
: "2016-01-26T22:03:17-08:00"},
84 {s
: time
.Unix(1, 2).UTC(), d
: &scanstr
, wantstr
: "1970-01-01T00:00:01.000000002Z"},
85 {s
: time
.Time
{}, d
: &scanstr
, wantstr
: "0001-01-01T00:00:00Z"},
86 {s
: time
.Unix(1, 2).UTC(), d
: &scanbytes
, wantbytes
: []byte("1970-01-01T00:00:01.000000002Z")},
87 {s
: time
.Unix(1, 2).UTC(), d
: &scaniface
, wantiface
: time
.Unix(1, 2).UTC()},
90 {s
: nil, d
: &scanbytes
, wantbytes
: nil},
91 {s
: "string", d
: &scanbytes
, wantbytes
: []byte("string")},
92 {s
: []byte("byteslice"), d
: &scanbytes
, wantbytes
: []byte("byteslice")},
93 {s
: 123, d
: &scanbytes
, wantbytes
: []byte("123")},
94 {s
: int8(123), d
: &scanbytes
, wantbytes
: []byte("123")},
95 {s
: int64(123), d
: &scanbytes
, wantbytes
: []byte("123")},
96 {s
: uint8(123), d
: &scanbytes
, wantbytes
: []byte("123")},
97 {s
: uint16(123), d
: &scanbytes
, wantbytes
: []byte("123")},
98 {s
: uint32(123), d
: &scanbytes
, wantbytes
: []byte("123")},
99 {s
: uint64(123), d
: &scanbytes
, wantbytes
: []byte("123")},
100 {s
: 1.5, d
: &scanbytes
, wantbytes
: []byte("1.5")},
103 {s
: nil, d
: &scanraw
, wantraw
: nil},
104 {s
: []byte("byteslice"), d
: &scanraw
, wantraw
: RawBytes("byteslice")},
105 {s
: 123, d
: &scanraw
, wantraw
: RawBytes("123")},
106 {s
: int8(123), d
: &scanraw
, wantraw
: RawBytes("123")},
107 {s
: int64(123), d
: &scanraw
, wantraw
: RawBytes("123")},
108 {s
: uint8(123), d
: &scanraw
, wantraw
: RawBytes("123")},
109 {s
: uint16(123), d
: &scanraw
, wantraw
: RawBytes("123")},
110 {s
: uint32(123), d
: &scanraw
, wantraw
: RawBytes("123")},
111 {s
: uint64(123), d
: &scanraw
, wantraw
: RawBytes("123")},
112 {s
: 1.5, d
: &scanraw
, wantraw
: RawBytes("1.5")},
114 // Strings to integers
115 {s
: "255", d
: &scanuint8
, wantuint
: 255},
116 {s
: "256", d
: &scanuint8
, wanterr
: "converting driver.Value type string (\"256\") to a uint8: value out of range"},
117 {s
: "256", d
: &scanuint16
, wantuint
: 256},
118 {s
: "-1", d
: &scanint
, wantint
: -1},
119 {s
: "foo", d
: &scanint
, wanterr
: "converting driver.Value type string (\"foo\") to a int: invalid syntax"},
121 // int64 to smaller integers
122 {s
: int64(5), d
: &scanuint8
, wantuint
: 5},
123 {s
: int64(256), d
: &scanuint8
, wanterr
: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"},
124 {s
: int64(256), d
: &scanuint16
, wantuint
: 256},
125 {s
: int64(65536), d
: &scanuint16
, wanterr
: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"},
128 {s
: true, d
: &scanbool
, wantbool
: true},
129 {s
: "True", d
: &scanbool
, wantbool
: true},
130 {s
: "TRUE", d
: &scanbool
, wantbool
: true},
131 {s
: "1", d
: &scanbool
, wantbool
: true},
132 {s
: 1, d
: &scanbool
, wantbool
: true},
133 {s
: int64(1), d
: &scanbool
, wantbool
: true},
134 {s
: uint16(1), d
: &scanbool
, wantbool
: true},
137 {s
: false, d
: &scanbool
, wantbool
: false},
138 {s
: "false", d
: &scanbool
, wantbool
: false},
139 {s
: "FALSE", d
: &scanbool
, wantbool
: false},
140 {s
: "0", d
: &scanbool
, wantbool
: false},
141 {s
: 0, d
: &scanbool
, wantbool
: false},
142 {s
: int64(0), d
: &scanbool
, wantbool
: false},
143 {s
: uint16(0), d
: &scanbool
, wantbool
: false},
146 {s
: "yup", d
: &scanbool
, wanterr
: `sql/driver: couldn't convert "yup" into type bool`},
147 {s
: 2, d
: &scanbool
, wanterr
: `sql/driver: couldn't convert 2 into type bool`},
150 {s
: float64(1.5), d
: &scanf64
, wantf64
: float64(1.5)},
151 {s
: int64(1), d
: &scanf64
, wantf64
: float64(1)},
152 {s
: float64(1.5), d
: &scanf32
, wantf32
: float32(1.5)},
153 {s
: "1.5", d
: &scanf32
, wantf32
: float32(1.5)},
154 {s
: "1.5", d
: &scanf64
, wantf64
: float64(1.5)},
157 {s
: interface{}(nil), d
: &scanptr
, wantnil
: true},
158 {s
: int64(42), d
: &scanptr
, wantptr
: &answer
},
161 {s
: float64(1.5), d
: &scaniface
, wantiface
: float64(1.5)},
162 {s
: int64(1), d
: &scaniface
, wantiface
: int64(1)},
163 {s
: "str", d
: &scaniface
, wantiface
: "str"},
164 {s
: []byte("byteslice"), d
: &scaniface
, wantiface
: []byte("byteslice")},
165 {s
: true, d
: &scaniface
, wantiface
: true},
166 {s
: nil, d
: &scaniface
},
167 {s
: []byte(nil), d
: &scaniface
, wantiface
: []byte(nil)},
169 // To a user-defined type
170 {s
: 1.5, d
: new(userDefined
), wantusrdef
: 1.5},
171 {s
: int64(123), d
: new(userDefined
), wantusrdef
: 123},
172 {s
: "1.5", d
: new(userDefined
), wantusrdef
: 1.5},
173 {s
: []byte{1, 2, 3}, d
: new(userDefinedSlice
), wanterr
: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`},
176 {s
: complex(1, 2), d
: &scanstr
, wanterr
: `unsupported Scan, storing driver.Value type complex128 into type *string`},
179 func intPtrValue(intptr
interface{}) interface{} {
180 return reflect
.Indirect(reflect
.Indirect(reflect
.ValueOf(intptr
))).Int()
183 func intValue(intptr
interface{}) int64 {
184 return reflect
.Indirect(reflect
.ValueOf(intptr
)).Int()
187 func uintValue(intptr
interface{}) uint64 {
188 return reflect
.Indirect(reflect
.ValueOf(intptr
)).Uint()
191 func float64Value(ptr
interface{}) float64 {
192 return *(ptr
.(*float64))
195 func float32Value(ptr
interface{}) float32 {
196 return *(ptr
.(*float32))
199 func timeValue(ptr
interface{}) time
.Time
{
200 return *(ptr
.(*time
.Time
))
203 func TestConversions(t
*testing
.T
) {
204 for n
, ct
:= range conversionTests
{
205 err
:= convertAssign(ct
.d
, ct
.s
)
210 errf
:= func(format
string, args
...interface{}) {
211 base
:= fmt
.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n
, ct
.s
, ct
.s
, ct
.d
)
212 t
.Errorf(base
+format
, args
...)
214 if errstr
!= ct
.wanterr
{
215 errf("got error %q, want error %q", errstr
, ct
.wanterr
)
217 if ct
.wantstr
!= "" && ct
.wantstr
!= scanstr
{
218 errf("want string %q, got %q", ct
.wantstr
, scanstr
)
220 if ct
.wantint
!= 0 && ct
.wantint
!= intValue(ct
.d
) {
221 errf("want int %d, got %d", ct
.wantint
, intValue(ct
.d
))
223 if ct
.wantuint
!= 0 && ct
.wantuint
!= uintValue(ct
.d
) {
224 errf("want uint %d, got %d", ct
.wantuint
, uintValue(ct
.d
))
226 if ct
.wantf32
!= 0 && ct
.wantf32
!= float32Value(ct
.d
) {
227 errf("want float32 %v, got %v", ct
.wantf32
, float32Value(ct
.d
))
229 if ct
.wantf64
!= 0 && ct
.wantf64
!= float64Value(ct
.d
) {
230 errf("want float32 %v, got %v", ct
.wantf64
, float64Value(ct
.d
))
232 if bp
, boolTest
:= ct
.d
.(*bool); boolTest
&& *bp
!= ct
.wantbool
&& ct
.wanterr
== "" {
233 errf("want bool %v, got %v", ct
.wantbool
, *bp
)
235 if !ct
.wanttime
.IsZero() && !ct
.wanttime
.Equal(timeValue(ct
.d
)) {
236 errf("want time %v, got %v", ct
.wanttime
, timeValue(ct
.d
))
238 if ct
.wantnil
&& *ct
.d
.(**int64) != nil {
239 errf("want nil, got %v", intPtrValue(ct
.d
))
241 if ct
.wantptr
!= nil {
242 if *ct
.d
.(**int64) == nil {
243 errf("want pointer to %v, got nil", *ct
.wantptr
)
244 } else if *ct
.wantptr
!= intPtrValue(ct
.d
) {
245 errf("want pointer to %v, got %v", *ct
.wantptr
, intPtrValue(ct
.d
))
248 if ifptr
, ok
:= ct
.d
.(*interface{}); ok
{
249 if !reflect
.DeepEqual(ct
.wantiface
, scaniface
) {
250 errf("want interface %#v, got %#v", ct
.wantiface
, scaniface
)
253 if srcBytes
, ok
:= ct
.s
.([]byte); ok
{
254 dstBytes
:= (*ifptr
).([]byte)
255 if len(srcBytes
) > 0 && &dstBytes
[0] == &srcBytes
[0] {
256 errf("copy into interface{} didn't copy []byte data")
260 if ct
.wantusrdef
!= 0 && ct
.wantusrdef
!= *ct
.d
.(*userDefined
) {
261 errf("want userDefined %f, got %f", ct
.wantusrdef
, *ct
.d
.(*userDefined
))
266 func TestNullString(t
*testing
.T
) {
268 convertAssign(&ns
, []byte("foo"))
270 t
.Errorf("expecting not null")
272 if ns
.String
!= "foo" {
273 t
.Errorf("expecting foo; got %q", ns
.String
)
275 convertAssign(&ns
, nil)
277 t
.Errorf("expecting null on nil")
280 t
.Errorf("expecting blank on nil; got %q", ns
.String
)
284 type valueConverterTest
struct {
285 c driver
.ValueConverter
290 var valueConverterTests
= []valueConverterTest
{
291 {driver
.DefaultParameterConverter
, NullString
{"hi", true}, "hi", ""},
292 {driver
.DefaultParameterConverter
, NullString
{"", false}, nil, ""},
295 func TestValueConverters(t
*testing
.T
) {
296 for i
, tt
:= range valueConverterTests
{
297 out
, err
:= tt
.c
.ConvertValue(tt
.in
)
302 if goterr
!= tt
.err
{
303 t
.Errorf("test %d: %T(%T(%v)) error = %q; want error = %q",
304 i
, tt
.c
, tt
.in
, tt
.in
, goterr
, tt
.err
)
309 if !reflect
.DeepEqual(out
, tt
.out
) {
310 t
.Errorf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)",
311 i
, tt
.c
, tt
.in
, tt
.in
, out
, out
, tt
.out
, tt
.out
)
316 // Tests that assigning to RawBytes doesn't allocate (and also works).
317 func TestRawBytesAllocs(t
*testing
.T
) {
318 var tests
= []struct {
323 {"uint64", uint64(12345678), "12345678"},
324 {"uint32", uint32(1234), "1234"},
325 {"uint16", uint16(12), "12"},
326 {"uint8", uint8(1), "1"},
327 {"uint", uint(123), "123"},
328 {"int", int(123), "123"},
329 {"int8", int8(1), "1"},
330 {"int16", int16(12), "12"},
331 {"int32", int32(1234), "1234"},
332 {"int64", int64(12345678), "12345678"},
333 {"float32", float32(1.5), "1.5"},
334 {"float64", float64(64), "64"},
335 {"bool", false, "false"},
338 buf
:= make(RawBytes
, 10)
339 test
:= func(name
string, in
interface{}, want
string) {
340 if err
:= convertAssign(&buf
, in
); err
!= nil {
341 t
.Fatalf("%s: convertAssign = %v", name
, err
)
343 match
:= len(buf
) == len(want
)
345 for i
, b
:= range buf
{
353 t
.Fatalf("%s: got %q (len %d); want %q (len %d)", name
, buf
, len(buf
), want
, len(want
))
357 n
:= testing
.AllocsPerRun(100, func() {
358 for _
, tt
:= range tests
{
359 test(tt
.name
, tt
.in
, tt
.want
)
363 // The numbers below are only valid for 64-bit interface word sizes,
364 // and gc. With 32-bit words there are more convT2E allocs, and
365 // with gccgo, only pointers currently go in interface data.
366 // So only care on amd64 gc for now.
367 measureAllocs
:= runtime
.GOARCH
== "amd64" && runtime
.Compiler
== "gc"
369 if n
> 0.5 && measureAllocs
{
370 t
.Fatalf("allocs = %v; want 0", n
)
373 // This one involves a convT2E allocation, string -> interface{}
374 n
= testing
.AllocsPerRun(100, func() {
375 test("string", "foo", "foo")
377 if n
> 1.5 && measureAllocs
{
378 t
.Fatalf("allocs = %v; want max 1", n
)
382 // https://github.com/golang/go/issues/13905
383 func TestUserDefinedBytes(t
*testing
.T
) {
384 type userDefinedBytes
[]byte
385 var u userDefinedBytes
390 t
.Fatal("userDefinedBytes got potentially dirty driver memory")
396 func (v Valuer_V
) Value() (driver
.Value
, error
) {
397 return strings
.ToUpper(string(v
)), nil
402 func (p
*Valuer_P
) Value() (driver
.Value
, error
) {
404 return "nil-to-str", nil
406 return strings
.ToUpper(string(*p
)), nil
409 func TestDriverArgs(t
*testing
.T
) {
410 var nilValuerVPtr
*Valuer_V
411 var nilValuerPPtr
*Valuer_P
412 var nilStrPtr
*string
415 want
[]driver
.NamedValue
418 args
: []interface{}{Valuer_V("foo")},
419 want
: []driver
.NamedValue
{
427 args
: []interface{}{nilValuerVPtr
},
428 want
: []driver
.NamedValue
{
436 args
: []interface{}{nilValuerPPtr
},
437 want
: []driver
.NamedValue
{
445 args
: []interface{}{"plain-str"},
446 want
: []driver
.NamedValue
{
454 args
: []interface{}{nilStrPtr
},
455 want
: []driver
.NamedValue
{
463 for i
, tt
:= range tests
{
464 ds
:= new(driverStmt
)
465 got
, err
:= driverArgs(ds
, tt
.args
)
467 t
.Errorf("test[%d]: %v", i
, err
)
470 if !reflect
.DeepEqual(got
, tt
.want
) {
471 t
.Errorf("test[%d]: got %v, want %v", i
, got
, tt
.want
)