github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/database/sql/convert_test.go (about) 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. 4 5 package sql 6 7 import ( 8 "database/sql/driver" 9 "fmt" 10 "reflect" 11 "runtime" 12 "strings" 13 "testing" 14 "time" 15 ) 16 17 var someTime = time.Unix(123, 0) 18 var answer int64 = 42 19 20 type ( 21 userDefined float64 22 userDefinedSlice []int 23 userDefinedString string 24 ) 25 26 type conversionTest struct { 27 s, d interface{} // source and destination 28 29 // following are used if they're non-zero 30 wantint int64 31 wantuint uint64 32 wantstr string 33 wantbytes []byte 34 wantraw RawBytes 35 wantf32 float32 36 wantf64 float64 37 wanttime time.Time 38 wantbool bool // used if d is of type *bool 39 wanterr string 40 wantiface interface{} 41 wantptr *int64 // if non-nil, *d's pointed value must be equal to *wantptr 42 wantnil bool // if true, *d must be *int64(nil) 43 wantusrdef userDefined 44 wantusrstr userDefinedString 45 } 46 47 // Target variables for scanning into. 48 var ( 49 scanstr string 50 scanbytes []byte 51 scanraw RawBytes 52 scanint int 53 scanint8 int8 54 scanint16 int16 55 scanint32 int32 56 scanuint8 uint8 57 scanuint16 uint16 58 scanbool bool 59 scanf32 float32 60 scanf64 float64 61 scantime time.Time 62 scanptr *int64 63 scaniface interface{} 64 ) 65 66 var conversionTests = []conversionTest{ 67 // Exact conversions (destination pointer type matches source type) 68 {s: "foo", d: &scanstr, wantstr: "foo"}, 69 {s: 123, d: &scanint, wantint: 123}, 70 {s: someTime, d: &scantime, wanttime: someTime}, 71 72 // To strings 73 {s: "string", d: &scanstr, wantstr: "string"}, 74 {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"}, 75 {s: 123, d: &scanstr, wantstr: "123"}, 76 {s: int8(123), d: &scanstr, wantstr: "123"}, 77 {s: int64(123), d: &scanstr, wantstr: "123"}, 78 {s: uint8(123), d: &scanstr, wantstr: "123"}, 79 {s: uint16(123), d: &scanstr, wantstr: "123"}, 80 {s: uint32(123), d: &scanstr, wantstr: "123"}, 81 {s: uint64(123), d: &scanstr, wantstr: "123"}, 82 {s: 1.5, d: &scanstr, wantstr: "1.5"}, 83 84 // From time.Time: 85 {s: time.Unix(1, 0).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01Z"}, 86 {s: time.Unix(1453874597, 0).In(time.FixedZone("here", -3600*8)), d: &scanstr, wantstr: "2016-01-26T22:03:17-08:00"}, 87 {s: time.Unix(1, 2).UTC(), d: &scanstr, wantstr: "1970-01-01T00:00:01.000000002Z"}, 88 {s: time.Time{}, d: &scanstr, wantstr: "0001-01-01T00:00:00Z"}, 89 {s: time.Unix(1, 2).UTC(), d: &scanbytes, wantbytes: []byte("1970-01-01T00:00:01.000000002Z")}, 90 {s: time.Unix(1, 2).UTC(), d: &scaniface, wantiface: time.Unix(1, 2).UTC()}, 91 92 // To []byte 93 {s: nil, d: &scanbytes, wantbytes: nil}, 94 {s: "string", d: &scanbytes, wantbytes: []byte("string")}, 95 {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")}, 96 {s: 123, d: &scanbytes, wantbytes: []byte("123")}, 97 {s: int8(123), d: &scanbytes, wantbytes: []byte("123")}, 98 {s: int64(123), d: &scanbytes, wantbytes: []byte("123")}, 99 {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")}, 100 {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")}, 101 {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")}, 102 {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")}, 103 {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")}, 104 105 // To RawBytes 106 {s: nil, d: &scanraw, wantraw: nil}, 107 {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")}, 108 {s: 123, d: &scanraw, wantraw: RawBytes("123")}, 109 {s: int8(123), d: &scanraw, wantraw: RawBytes("123")}, 110 {s: int64(123), d: &scanraw, wantraw: RawBytes("123")}, 111 {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")}, 112 {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")}, 113 {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")}, 114 {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")}, 115 {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")}, 116 117 // Strings to integers 118 {s: "255", d: &scanuint8, wantuint: 255}, 119 {s: "256", d: &scanuint8, wanterr: "converting driver.Value type string (\"256\") to a uint8: value out of range"}, 120 {s: "256", d: &scanuint16, wantuint: 256}, 121 {s: "-1", d: &scanint, wantint: -1}, 122 {s: "foo", d: &scanint, wanterr: "converting driver.Value type string (\"foo\") to a int: invalid syntax"}, 123 124 // int64 to smaller integers 125 {s: int64(5), d: &scanuint8, wantuint: 5}, 126 {s: int64(256), d: &scanuint8, wanterr: "converting driver.Value type int64 (\"256\") to a uint8: value out of range"}, 127 {s: int64(256), d: &scanuint16, wantuint: 256}, 128 {s: int64(65536), d: &scanuint16, wanterr: "converting driver.Value type int64 (\"65536\") to a uint16: value out of range"}, 129 130 // True bools 131 {s: true, d: &scanbool, wantbool: true}, 132 {s: "True", d: &scanbool, wantbool: true}, 133 {s: "TRUE", d: &scanbool, wantbool: true}, 134 {s: "1", d: &scanbool, wantbool: true}, 135 {s: 1, d: &scanbool, wantbool: true}, 136 {s: int64(1), d: &scanbool, wantbool: true}, 137 {s: uint16(1), d: &scanbool, wantbool: true}, 138 139 // False bools 140 {s: false, d: &scanbool, wantbool: false}, 141 {s: "false", d: &scanbool, wantbool: false}, 142 {s: "FALSE", d: &scanbool, wantbool: false}, 143 {s: "0", d: &scanbool, wantbool: false}, 144 {s: 0, d: &scanbool, wantbool: false}, 145 {s: int64(0), d: &scanbool, wantbool: false}, 146 {s: uint16(0), d: &scanbool, wantbool: false}, 147 148 // Not bools 149 {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`}, 150 {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`}, 151 152 // Floats 153 {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)}, 154 {s: int64(1), d: &scanf64, wantf64: float64(1)}, 155 {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)}, 156 {s: "1.5", d: &scanf32, wantf32: float32(1.5)}, 157 {s: "1.5", d: &scanf64, wantf64: float64(1.5)}, 158 159 // Pointers 160 {s: interface{}(nil), d: &scanptr, wantnil: true}, 161 {s: int64(42), d: &scanptr, wantptr: &answer}, 162 163 // To interface{} 164 {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)}, 165 {s: int64(1), d: &scaniface, wantiface: int64(1)}, 166 {s: "str", d: &scaniface, wantiface: "str"}, 167 {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")}, 168 {s: true, d: &scaniface, wantiface: true}, 169 {s: nil, d: &scaniface}, 170 {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)}, 171 172 // To a user-defined type 173 {s: 1.5, d: new(userDefined), wantusrdef: 1.5}, 174 {s: int64(123), d: new(userDefined), wantusrdef: 123}, 175 {s: "1.5", d: new(userDefined), wantusrdef: 1.5}, 176 {s: []byte{1, 2, 3}, d: new(userDefinedSlice), wanterr: `unsupported Scan, storing driver.Value type []uint8 into type *sql.userDefinedSlice`}, 177 {s: "str", d: new(userDefinedString), wantusrstr: "str"}, 178 179 // Other errors 180 {s: complex(1, 2), d: &scanstr, wanterr: `unsupported Scan, storing driver.Value type complex128 into type *string`}, 181 } 182 183 func intPtrValue(intptr interface{}) interface{} { 184 return reflect.Indirect(reflect.Indirect(reflect.ValueOf(intptr))).Int() 185 } 186 187 func intValue(intptr interface{}) int64 { 188 return reflect.Indirect(reflect.ValueOf(intptr)).Int() 189 } 190 191 func uintValue(intptr interface{}) uint64 { 192 return reflect.Indirect(reflect.ValueOf(intptr)).Uint() 193 } 194 195 func float64Value(ptr interface{}) float64 { 196 return *(ptr.(*float64)) 197 } 198 199 func float32Value(ptr interface{}) float32 { 200 return *(ptr.(*float32)) 201 } 202 203 func timeValue(ptr interface{}) time.Time { 204 return *(ptr.(*time.Time)) 205 } 206 207 func TestConversions(t *testing.T) { 208 for n, ct := range conversionTests { 209 err := convertAssign(ct.d, ct.s) 210 errstr := "" 211 if err != nil { 212 errstr = err.Error() 213 } 214 errf := func(format string, args ...interface{}) { 215 base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d) 216 t.Errorf(base+format, args...) 217 } 218 if errstr != ct.wanterr { 219 errf("got error %q, want error %q", errstr, ct.wanterr) 220 } 221 if ct.wantstr != "" && ct.wantstr != scanstr { 222 errf("want string %q, got %q", ct.wantstr, scanstr) 223 } 224 if ct.wantint != 0 && ct.wantint != intValue(ct.d) { 225 errf("want int %d, got %d", ct.wantint, intValue(ct.d)) 226 } 227 if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) { 228 errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d)) 229 } 230 if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) { 231 errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d)) 232 } 233 if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) { 234 errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d)) 235 } 236 if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" { 237 errf("want bool %v, got %v", ct.wantbool, *bp) 238 } 239 if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) { 240 errf("want time %v, got %v", ct.wanttime, timeValue(ct.d)) 241 } 242 if ct.wantnil && *ct.d.(**int64) != nil { 243 errf("want nil, got %v", intPtrValue(ct.d)) 244 } 245 if ct.wantptr != nil { 246 if *ct.d.(**int64) == nil { 247 errf("want pointer to %v, got nil", *ct.wantptr) 248 } else if *ct.wantptr != intPtrValue(ct.d) { 249 errf("want pointer to %v, got %v", *ct.wantptr, intPtrValue(ct.d)) 250 } 251 } 252 if ifptr, ok := ct.d.(*interface{}); ok { 253 if !reflect.DeepEqual(ct.wantiface, scaniface) { 254 errf("want interface %#v, got %#v", ct.wantiface, scaniface) 255 continue 256 } 257 if srcBytes, ok := ct.s.([]byte); ok { 258 dstBytes := (*ifptr).([]byte) 259 if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] { 260 errf("copy into interface{} didn't copy []byte data") 261 } 262 } 263 } 264 if ct.wantusrdef != 0 && ct.wantusrdef != *ct.d.(*userDefined) { 265 errf("want userDefined %f, got %f", ct.wantusrdef, *ct.d.(*userDefined)) 266 } 267 if len(ct.wantusrstr) != 0 && ct.wantusrstr != *ct.d.(*userDefinedString) { 268 errf("want userDefined %q, got %q", ct.wantusrstr, *ct.d.(*userDefinedString)) 269 } 270 } 271 } 272 273 func TestNullString(t *testing.T) { 274 var ns NullString 275 convertAssign(&ns, []byte("foo")) 276 if !ns.Valid { 277 t.Errorf("expecting not null") 278 } 279 if ns.String != "foo" { 280 t.Errorf("expecting foo; got %q", ns.String) 281 } 282 convertAssign(&ns, nil) 283 if ns.Valid { 284 t.Errorf("expecting null on nil") 285 } 286 if ns.String != "" { 287 t.Errorf("expecting blank on nil; got %q", ns.String) 288 } 289 } 290 291 type valueConverterTest struct { 292 c driver.ValueConverter 293 in, out interface{} 294 err string 295 } 296 297 var valueConverterTests = []valueConverterTest{ 298 {driver.DefaultParameterConverter, NullString{"hi", true}, "hi", ""}, 299 {driver.DefaultParameterConverter, NullString{"", false}, nil, ""}, 300 } 301 302 func TestValueConverters(t *testing.T) { 303 for i, tt := range valueConverterTests { 304 out, err := tt.c.ConvertValue(tt.in) 305 goterr := "" 306 if err != nil { 307 goterr = err.Error() 308 } 309 if goterr != tt.err { 310 t.Errorf("test %d: %T(%T(%v)) error = %q; want error = %q", 311 i, tt.c, tt.in, tt.in, goterr, tt.err) 312 } 313 if tt.err != "" { 314 continue 315 } 316 if !reflect.DeepEqual(out, tt.out) { 317 t.Errorf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)", 318 i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) 319 } 320 } 321 } 322 323 // Tests that assigning to RawBytes doesn't allocate (and also works). 324 func TestRawBytesAllocs(t *testing.T) { 325 var tests = []struct { 326 name string 327 in interface{} 328 want string 329 }{ 330 {"uint64", uint64(12345678), "12345678"}, 331 {"uint32", uint32(1234), "1234"}, 332 {"uint16", uint16(12), "12"}, 333 {"uint8", uint8(1), "1"}, 334 {"uint", uint(123), "123"}, 335 {"int", int(123), "123"}, 336 {"int8", int8(1), "1"}, 337 {"int16", int16(12), "12"}, 338 {"int32", int32(1234), "1234"}, 339 {"int64", int64(12345678), "12345678"}, 340 {"float32", float32(1.5), "1.5"}, 341 {"float64", float64(64), "64"}, 342 {"bool", false, "false"}, 343 } 344 345 buf := make(RawBytes, 10) 346 test := func(name string, in interface{}, want string) { 347 if err := convertAssign(&buf, in); err != nil { 348 t.Fatalf("%s: convertAssign = %v", name, err) 349 } 350 match := len(buf) == len(want) 351 if match { 352 for i, b := range buf { 353 if want[i] != b { 354 match = false 355 break 356 } 357 } 358 } 359 if !match { 360 t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want)) 361 } 362 } 363 364 n := testing.AllocsPerRun(100, func() { 365 for _, tt := range tests { 366 test(tt.name, tt.in, tt.want) 367 } 368 }) 369 370 // The numbers below are only valid for 64-bit interface word sizes, 371 // and gc. With 32-bit words there are more convT2E allocs, and 372 // with gccgo, only pointers currently go in interface data. 373 // So only care on amd64 gc for now. 374 measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc" 375 376 if n > 0.5 && measureAllocs { 377 t.Fatalf("allocs = %v; want 0", n) 378 } 379 380 // This one involves a convT2E allocation, string -> interface{} 381 n = testing.AllocsPerRun(100, func() { 382 test("string", "foo", "foo") 383 }) 384 if n > 1.5 && measureAllocs { 385 t.Fatalf("allocs = %v; want max 1", n) 386 } 387 } 388 389 // https://github.com/golang/go/issues/13905 390 func TestUserDefinedBytes(t *testing.T) { 391 type userDefinedBytes []byte 392 var u userDefinedBytes 393 v := []byte("foo") 394 395 convertAssign(&u, v) 396 if &u[0] == &v[0] { 397 t.Fatal("userDefinedBytes got potentially dirty driver memory") 398 } 399 } 400 401 type Valuer_V string 402 403 func (v Valuer_V) Value() (driver.Value, error) { 404 return strings.ToUpper(string(v)), nil 405 } 406 407 type Valuer_P string 408 409 func (p *Valuer_P) Value() (driver.Value, error) { 410 if p == nil { 411 return "nil-to-str", nil 412 } 413 return strings.ToUpper(string(*p)), nil 414 } 415 416 func TestDriverArgs(t *testing.T) { 417 var nilValuerVPtr *Valuer_V 418 var nilValuerPPtr *Valuer_P 419 var nilStrPtr *string 420 tests := []struct { 421 args []interface{} 422 want []driver.NamedValue 423 }{ 424 0: { 425 args: []interface{}{Valuer_V("foo")}, 426 want: []driver.NamedValue{ 427 driver.NamedValue{ 428 Ordinal: 1, 429 Value: "FOO", 430 }, 431 }, 432 }, 433 1: { 434 args: []interface{}{nilValuerVPtr}, 435 want: []driver.NamedValue{ 436 driver.NamedValue{ 437 Ordinal: 1, 438 Value: nil, 439 }, 440 }, 441 }, 442 2: { 443 args: []interface{}{nilValuerPPtr}, 444 want: []driver.NamedValue{ 445 driver.NamedValue{ 446 Ordinal: 1, 447 Value: "nil-to-str", 448 }, 449 }, 450 }, 451 3: { 452 args: []interface{}{"plain-str"}, 453 want: []driver.NamedValue{ 454 driver.NamedValue{ 455 Ordinal: 1, 456 Value: "plain-str", 457 }, 458 }, 459 }, 460 4: { 461 args: []interface{}{nilStrPtr}, 462 want: []driver.NamedValue{ 463 driver.NamedValue{ 464 Ordinal: 1, 465 Value: nil, 466 }, 467 }, 468 }, 469 } 470 for i, tt := range tests { 471 ds := new(driverStmt) 472 got, err := driverArgs(ds, tt.args) 473 if err != nil { 474 t.Errorf("test[%d]: %v", i, err) 475 continue 476 } 477 if !reflect.DeepEqual(got, tt.want) { 478 t.Errorf("test[%d]: got %v, want %v", i, got, tt.want) 479 } 480 } 481 }