Home | History | Annotate | Download | only in sql
      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 	"testing"
     13 	"time"
     14 )
     15 
     16 var someTime = time.Unix(123, 0)
     17 var answer int64 = 42
     18 
     19 type conversionTest struct {
     20 	s, d interface{} // source and destination
     21 
     22 	// following are used if they're non-zero
     23 	wantint   int64
     24 	wantuint  uint64
     25 	wantstr   string
     26 	wantbytes []byte
     27 	wantraw   RawBytes
     28 	wantf32   float32
     29 	wantf64   float64
     30 	wanttime  time.Time
     31 	wantbool  bool // used if d is of type *bool
     32 	wanterr   string
     33 	wantiface interface{}
     34 	wantptr   *int64 // if non-nil, *d's pointed value must be equal to *wantptr
     35 	wantnil   bool   // if true, *d must be *int64(nil)
     36 }
     37 
     38 // Target variables for scanning into.
     39 var (
     40 	scanstr    string
     41 	scanbytes  []byte
     42 	scanraw    RawBytes
     43 	scanint    int
     44 	scanint8   int8
     45 	scanint16  int16
     46 	scanint32  int32
     47 	scanuint8  uint8
     48 	scanuint16 uint16
     49 	scanbool   bool
     50 	scanf32    float32
     51 	scanf64    float64
     52 	scantime   time.Time
     53 	scanptr    *int64
     54 	scaniface  interface{}
     55 )
     56 
     57 var conversionTests = []conversionTest{
     58 	// Exact conversions (destination pointer type matches source type)
     59 	{s: "foo", d: &scanstr, wantstr: "foo"},
     60 	{s: 123, d: &scanint, wantint: 123},
     61 	{s: someTime, d: &scantime, wanttime: someTime},
     62 
     63 	// To strings
     64 	{s: "string", d: &scanstr, wantstr: "string"},
     65 	{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
     66 	{s: 123, d: &scanstr, wantstr: "123"},
     67 	{s: int8(123), d: &scanstr, wantstr: "123"},
     68 	{s: int64(123), d: &scanstr, wantstr: "123"},
     69 	{s: uint8(123), d: &scanstr, wantstr: "123"},
     70 	{s: uint16(123), d: &scanstr, wantstr: "123"},
     71 	{s: uint32(123), d: &scanstr, wantstr: "123"},
     72 	{s: uint64(123), d: &scanstr, wantstr: "123"},
     73 	{s: 1.5, d: &scanstr, wantstr: "1.5"},
     74 
     75 	// To []byte
     76 	{s: nil, d: &scanbytes, wantbytes: nil},
     77 	{s: "string", d: &scanbytes, wantbytes: []byte("string")},
     78 	{s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
     79 	{s: 123, d: &scanbytes, wantbytes: []byte("123")},
     80 	{s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
     81 	{s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
     82 	{s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
     83 	{s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
     84 	{s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
     85 	{s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
     86 	{s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
     87 
     88 	// To RawBytes
     89 	{s: nil, d: &scanraw, wantraw: nil},
     90 	{s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
     91 	{s: 123, d: &scanraw, wantraw: RawBytes("123")},
     92 	{s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
     93 	{s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
     94 	{s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
     95 	{s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
     96 	{s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
     97 	{s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
     98 	{s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
     99 
    100 	// Strings to integers
    101 	{s: "255", d: &scanuint8, wantuint: 255},
    102 	{s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
    103 	{s: "256", d: &scanuint16, wantuint: 256},
    104 	{s: "-1", d: &scanint, wantint: -1},
    105 	{s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`},
    106 
    107 	// True bools
    108 	{s: true, d: &scanbool, wantbool: true},
    109 	{s: "True", d: &scanbool, wantbool: true},
    110 	{s: "TRUE", d: &scanbool, wantbool: true},
    111 	{s: "1", d: &scanbool, wantbool: true},
    112 	{s: 1, d: &scanbool, wantbool: true},
    113 	{s: int64(1), d: &scanbool, wantbool: true},
    114 	{s: uint16(1), d: &scanbool, wantbool: true},
    115 
    116 	// False bools
    117 	{s: false, d: &scanbool, wantbool: false},
    118 	{s: "false", d: &scanbool, wantbool: false},
    119 	{s: "FALSE", d: &scanbool, wantbool: false},
    120 	{s: "0", d: &scanbool, wantbool: false},
    121 	{s: 0, d: &scanbool, wantbool: false},
    122 	{s: int64(0), d: &scanbool, wantbool: false},
    123 	{s: uint16(0), d: &scanbool, wantbool: false},
    124 
    125 	// Not bools
    126 	{s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`},
    127 	{s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`},
    128 
    129 	// Floats
    130 	{s: float64(1.5), d: &scanf64, wantf64: float64(1.5)},
    131 	{s: int64(1), d: &scanf64, wantf64: float64(1)},
    132 	{s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
    133 	{s: "1.5", d: &scanf32, wantf32: float32(1.5)},
    134 	{s: "1.5", d: &scanf64, wantf64: float64(1.5)},
    135 
    136 	// Pointers
    137 	{s: interface{}(nil), d: &scanptr, wantnil: true},
    138 	{s: int64(42), d: &scanptr, wantptr: &answer},
    139 
    140 	// To interface{}
    141 	{s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
    142 	{s: int64(1), d: &scaniface, wantiface: int64(1)},
    143 	{s: "str", d: &scaniface, wantiface: "str"},
    144 	{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
    145 	{s: true, d: &scaniface, wantiface: true},
    146 	{s: nil, d: &scaniface},
    147 	{s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
    148 }
    149 
    150 func intPtrValue(intptr interface{}) interface{} {
    151 	return reflect.Indirect(reflect.Indirect(reflect.ValueOf(intptr))).Int()
    152 }
    153 
    154 func intValue(intptr interface{}) int64 {
    155 	return reflect.Indirect(reflect.ValueOf(intptr)).Int()
    156 }
    157 
    158 func uintValue(intptr interface{}) uint64 {
    159 	return reflect.Indirect(reflect.ValueOf(intptr)).Uint()
    160 }
    161 
    162 func float64Value(ptr interface{}) float64 {
    163 	return *(ptr.(*float64))
    164 }
    165 
    166 func float32Value(ptr interface{}) float32 {
    167 	return *(ptr.(*float32))
    168 }
    169 
    170 func timeValue(ptr interface{}) time.Time {
    171 	return *(ptr.(*time.Time))
    172 }
    173 
    174 func TestConversions(t *testing.T) {
    175 	for n, ct := range conversionTests {
    176 		err := convertAssign(ct.d, ct.s)
    177 		errstr := ""
    178 		if err != nil {
    179 			errstr = err.Error()
    180 		}
    181 		errf := func(format string, args ...interface{}) {
    182 			base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d)
    183 			t.Errorf(base+format, args...)
    184 		}
    185 		if errstr != ct.wanterr {
    186 			errf("got error %q, want error %q", errstr, ct.wanterr)
    187 		}
    188 		if ct.wantstr != "" && ct.wantstr != scanstr {
    189 			errf("want string %q, got %q", ct.wantstr, scanstr)
    190 		}
    191 		if ct.wantint != 0 && ct.wantint != intValue(ct.d) {
    192 			errf("want int %d, got %d", ct.wantint, intValue(ct.d))
    193 		}
    194 		if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) {
    195 			errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d))
    196 		}
    197 		if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) {
    198 			errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d))
    199 		}
    200 		if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) {
    201 			errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d))
    202 		}
    203 		if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" {
    204 			errf("want bool %v, got %v", ct.wantbool, *bp)
    205 		}
    206 		if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
    207 			errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
    208 		}
    209 		if ct.wantnil && *ct.d.(**int64) != nil {
    210 			errf("want nil, got %v", intPtrValue(ct.d))
    211 		}
    212 		if ct.wantptr != nil {
    213 			if *ct.d.(**int64) == nil {
    214 				errf("want pointer to %v, got nil", *ct.wantptr)
    215 			} else if *ct.wantptr != intPtrValue(ct.d) {
    216 				errf("want pointer to %v, got %v", *ct.wantptr, intPtrValue(ct.d))
    217 			}
    218 		}
    219 		if ifptr, ok := ct.d.(*interface{}); ok {
    220 			if !reflect.DeepEqual(ct.wantiface, scaniface) {
    221 				errf("want interface %#v, got %#v", ct.wantiface, scaniface)
    222 				continue
    223 			}
    224 			if srcBytes, ok := ct.s.([]byte); ok {
    225 				dstBytes := (*ifptr).([]byte)
    226 				if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] {
    227 					errf("copy into interface{} didn't copy []byte data")
    228 				}
    229 			}
    230 		}
    231 	}
    232 }
    233 
    234 func TestNullString(t *testing.T) {
    235 	var ns NullString
    236 	convertAssign(&ns, []byte("foo"))
    237 	if !ns.Valid {
    238 		t.Errorf("expecting not null")
    239 	}
    240 	if ns.String != "foo" {
    241 		t.Errorf("expecting foo; got %q", ns.String)
    242 	}
    243 	convertAssign(&ns, nil)
    244 	if ns.Valid {
    245 		t.Errorf("expecting null on nil")
    246 	}
    247 	if ns.String != "" {
    248 		t.Errorf("expecting blank on nil; got %q", ns.String)
    249 	}
    250 }
    251 
    252 type valueConverterTest struct {
    253 	c       driver.ValueConverter
    254 	in, out interface{}
    255 	err     string
    256 }
    257 
    258 var valueConverterTests = []valueConverterTest{
    259 	{driver.DefaultParameterConverter, NullString{"hi", true}, "hi", ""},
    260 	{driver.DefaultParameterConverter, NullString{"", false}, nil, ""},
    261 }
    262 
    263 func TestValueConverters(t *testing.T) {
    264 	for i, tt := range valueConverterTests {
    265 		out, err := tt.c.ConvertValue(tt.in)
    266 		goterr := ""
    267 		if err != nil {
    268 			goterr = err.Error()
    269 		}
    270 		if goterr != tt.err {
    271 			t.Errorf("test %d: %T(%T(%v)) error = %q; want error = %q",
    272 				i, tt.c, tt.in, tt.in, goterr, tt.err)
    273 		}
    274 		if tt.err != "" {
    275 			continue
    276 		}
    277 		if !reflect.DeepEqual(out, tt.out) {
    278 			t.Errorf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)",
    279 				i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out)
    280 		}
    281 	}
    282 }
    283 
    284 // Tests that assigning to RawBytes doesn't allocate (and also works).
    285 func TestRawBytesAllocs(t *testing.T) {
    286 	var tests = []struct {
    287 		name string
    288 		in   interface{}
    289 		want string
    290 	}{
    291 		{"uint64", uint64(12345678), "12345678"},
    292 		{"uint32", uint32(1234), "1234"},
    293 		{"uint16", uint16(12), "12"},
    294 		{"uint8", uint8(1), "1"},
    295 		{"uint", uint(123), "123"},
    296 		{"int", int(123), "123"},
    297 		{"int8", int8(1), "1"},
    298 		{"int16", int16(12), "12"},
    299 		{"int32", int32(1234), "1234"},
    300 		{"int64", int64(12345678), "12345678"},
    301 		{"float32", float32(1.5), "1.5"},
    302 		{"float64", float64(64), "64"},
    303 		{"bool", false, "false"},
    304 	}
    305 
    306 	buf := make(RawBytes, 10)
    307 	test := func(name string, in interface{}, want string) {
    308 		if err := convertAssign(&buf, in); err != nil {
    309 			t.Fatalf("%s: convertAssign = %v", name, err)
    310 		}
    311 		match := len(buf) == len(want)
    312 		if match {
    313 			for i, b := range buf {
    314 				if want[i] != b {
    315 					match = false
    316 					break
    317 				}
    318 			}
    319 		}
    320 		if !match {
    321 			t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want))
    322 		}
    323 	}
    324 
    325 	n := testing.AllocsPerRun(100, func() {
    326 		for _, tt := range tests {
    327 			test(tt.name, tt.in, tt.want)
    328 		}
    329 	})
    330 
    331 	// The numbers below are only valid for 64-bit interface word sizes,
    332 	// and gc. With 32-bit words there are more convT2E allocs, and
    333 	// with gccgo, only pointers currently go in interface data.
    334 	// So only care on amd64 gc for now.
    335 	measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
    336 
    337 	if n > 0.5 && measureAllocs {
    338 		t.Fatalf("allocs = %v; want 0", n)
    339 	}
    340 
    341 	// This one involves a convT2E allocation, string -> interface{}
    342 	n = testing.AllocsPerRun(100, func() {
    343 		test("string", "foo", "foo")
    344 	})
    345 	if n > 1.5 && measureAllocs {
    346 		t.Fatalf("allocs = %v; want max 1", n)
    347 	}
    348 }
    349