Skip to content

Commit f339392

Browse files
author
Brigitte Lamarche
committed
Merge branch 'master' into cr4
2 parents 26ea544 + 422ab6f commit f339392

10 files changed

+99
-16
lines changed

.travis.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go:
44
- 1.7.x
55
- 1.8.x
66
- 1.9.x
7+
- 1.10.x
78
- master
89

910
before_install:
@@ -21,7 +22,7 @@ matrix:
2122
- env: DB=MYSQL57
2223
sudo: required
2324
dist: trusty
24-
go: 1.9.x
25+
go: 1.10.x
2526
services:
2627
- docker
2728
before_install:
@@ -43,7 +44,7 @@ matrix:
4344
- env: DB=MARIA55
4445
sudo: required
4546
dist: trusty
46-
go: 1.9.x
47+
go: 1.10.x
4748
services:
4849
- docker
4950
before_install:
@@ -65,7 +66,7 @@ matrix:
6566
- env: DB=MARIA10_1
6667
sudo: required
6768
dist: trusty
68-
go: 1.9.x
69+
go: 1.10.x
6970
services:
7071
- docker
7172
before_install:
@@ -87,6 +88,6 @@ matrix:
8788
script:
8889
- go test -v -covermode=count -coverprofile=coverage.out
8990
- go vet ./...
90-
- test -z "$(gofmt -d -s . | tee /dev/stderr)"
91+
- .travis/gofmt.sh
9192
after_script:
9293
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci

.travis/gofmt.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
set -ev
3+
4+
# Only check for go1.10+ since the gofmt style changed
5+
if [[ $(go version) =~ go1\.([0-9]+) ]] && ((${BASH_REMATCH[1]} >= 10)); then
6+
test -z "$(gofmt -d -s . | tee /dev/stderr)"
7+
fi

AUTHORS

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
Aaron Hopkins <go-sql-driver at die.net>
1515
Achille Roussel <achille.roussel at gmail.com>
16+
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
17+
Andrew Reid <andrew.reid at tixtrack.com>
1618
Arne Hormann <arnehormann at gmail.com>
1719
Asta Xie <xiemengjun at gmail.com>
1820
B Lamarche <blam413 at gmail.com>
@@ -62,8 +64,8 @@ Paul Bonser <misterpib at gmail.com>
6264
Peter Schultz <peter.schultz at classmarkets.com>
6365
Rebecca Chin <rchin at pivotal.io>
6466
Reed Allman <rdallman10 at gmail.com>
65-
Runrioter Wung <runrioter at gmail.com>
6667
Robert Russell <robert at rrbrussell.com>
68+
Runrioter Wung <runrioter at gmail.com>
6769
Shuode Li <elemount at qq.com>
6870
Soroush Pour <me at soroushjp.com>
6971
Stan Putrya <root.vagner at gmail.com>
@@ -80,5 +82,6 @@ Counting Ltd.
8082
Google Inc.
8183
InfoSum Ltd.
8284
Keybase Inc.
85+
Percona LLC
8386
Pivotal Inc.
8487
Stripe Inc.

driver_go18_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,11 @@ func TestRowsColumnTypes(t *testing.T) {
796796
})
797797
}
798798
}
799+
800+
func TestValuerWithValueReceiverGivenNilValue(t *testing.T) {
801+
runTests(t, dsn, func(dbt *DBTest) {
802+
dbt.mustExec("CREATE TABLE test (value VARCHAR(255))")
803+
dbt.db.Exec("INSERT INTO test VALUES (?)", (*testValuer)(nil))
804+
// This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value()
805+
})
806+
}

driver_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,34 @@ func TestString(t *testing.T) {
499499
})
500500
}
501501

502+
func TestRawBytes(t *testing.T) {
503+
runTests(t, dsn, func(dbt *DBTest) {
504+
v1 := []byte("aaa")
505+
v2 := []byte("bbb")
506+
rows := dbt.mustQuery("SELECT ?, ?", v1, v2)
507+
if rows.Next() {
508+
var o1, o2 sql.RawBytes
509+
if err := rows.Scan(&o1, &o2); err != nil {
510+
dbt.Errorf("Got error: %v", err)
511+
}
512+
if !bytes.Equal(v1, o1) {
513+
dbt.Errorf("expected %v, got %v", v1, o1)
514+
}
515+
if !bytes.Equal(v2, o2) {
516+
dbt.Errorf("expected %v, got %v", v2, o2)
517+
}
518+
// https://github.com/go-sql-driver/mysql/issues/765
519+
// Appending to RawBytes shouldn't overwrite next RawBytes.
520+
o1 = append(o1, "xyzzy"...)
521+
if !bytes.Equal(v2, o2) {
522+
dbt.Errorf("expected %v, got %v", v2, o2)
523+
}
524+
} else {
525+
dbt.Errorf("no data")
526+
}
527+
})
528+
}
529+
502530
type testValuer struct {
503531
value string
504532
}

dsn.go

-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ type Config struct {
5858
MultiStatements bool // Allow multiple statements in one query
5959
ParseTime bool // Parse time values to time.Time
6060
RejectReadOnly bool // Reject read-only connections
61-
Compression bool // Compress packets
6261
}
6362

6463
// NewConfig creates a new Config and sets default values.

statement.go

+37-4
Original file line numberDiff line numberDiff line change
@@ -132,15 +132,25 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
132132

133133
type converter struct{}
134134

135+
// ConvertValue mirrors the reference/default converter in database/sql/driver
136+
// with _one_ exception. We support uint64 with their high bit and the default
137+
// implementation does not. This function should be kept in sync with
138+
// database/sql/driver defaultConverter.ConvertValue() except for that
139+
// deliberate difference.
135140
func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
136141
if driver.IsValue(v) {
137142
return v, nil
138143
}
139144

140-
if v != nil {
141-
if valuer, ok := v.(driver.Valuer); ok {
142-
return valuer.Value()
145+
if vr, ok := v.(driver.Valuer); ok {
146+
sv, err := callValuerValue(vr)
147+
if err != nil {
148+
return nil, err
149+
}
150+
if !driver.IsValue(sv) {
151+
return nil, fmt.Errorf("non-Value type %T returned from Value", sv)
143152
}
153+
return sv, nil
144154
}
145155

146156
rv := reflect.ValueOf(v)
@@ -149,8 +159,9 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
149159
// indirect pointers
150160
if rv.IsNil() {
151161
return nil, nil
162+
} else {
163+
return c.ConvertValue(rv.Elem().Interface())
152164
}
153-
return c.ConvertValue(rv.Elem().Interface())
154165
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
155166
return rv.Int(), nil
156167
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
@@ -176,3 +187,25 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
176187
}
177188
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
178189
}
190+
191+
var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
192+
193+
// callValuerValue returns vr.Value(), with one exception:
194+
// If vr.Value is an auto-generated method on a pointer type and the
195+
// pointer is nil, it would panic at runtime in the panicwrap
196+
// method. Treat it like nil instead.
197+
//
198+
// This is so people can implement driver.Value on value types and
199+
// still use nil pointers to those types to mean nil/NULL, just like
200+
// string/*string.
201+
//
202+
// This is an exact copy of the same-named unexported function from the
203+
// database/sql package.
204+
func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
205+
if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
206+
rv.IsNil() &&
207+
rv.Type().Elem().Implements(valuerReflectType) {
208+
return nil, nil
209+
}
210+
return vr.Value()
211+
}

utils.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ func readLengthEncodedString(b []byte) ([]byte, bool, int, error) {
537537

538538
// Check data length
539539
if len(b) >= n {
540-
return b[n-int(num) : n], false, n, nil
540+
return b[n-int(num) : n : n], false, n, nil
541541
}
542542
return nil, false, n, io.EOF
543543
}
@@ -800,7 +800,7 @@ func (ab *atomicBool) TrySet(value bool) bool {
800800
return atomic.SwapUint32(&ab.value, 0) > 0
801801
}
802802

803-
// atomicBool is a wrapper for atomically accessed error values
803+
// atomicError is a wrapper for atomically accessed error values
804804
type atomicError struct {
805805
_noCopy noCopy
806806
value atomic.Value

utils_go18.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"database/sql"
1616
"database/sql/driver"
1717
"errors"
18+
"fmt"
1819
)
1920

2021
func cloneTLSConfig(c *tls.Config) *tls.Config {
@@ -44,6 +45,6 @@ func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
4445
case sql.LevelSerializable:
4546
return "SERIALIZABLE", nil
4647
default:
47-
return "", errors.New("mysql: unsupported isolation level: " + string(level))
48+
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
4849
}
4950
}

utils_go18_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
)
1818

1919
func TestIsolationLevelMapping(t *testing.T) {
20-
2120
data := []struct {
2221
level driver.IsolationLevel
2322
expected string
@@ -47,8 +46,12 @@ func TestIsolationLevelMapping(t *testing.T) {
4746
}
4847

4948
// check unsupported mapping
50-
if actual, err := mapIsolationLevel(driver.IsolationLevel(sql.LevelLinearizable)); actual != "" || err == nil {
49+
expectedErr := "mysql: unsupported isolation level: 7"
50+
actual, err := mapIsolationLevel(driver.IsolationLevel(sql.LevelLinearizable))
51+
if actual != "" || err == nil {
5152
t.Fatal("Expected error on unsupported isolation level")
5253
}
53-
54+
if err.Error() != expectedErr {
55+
t.Fatalf("Expected error to be %q, got %q", expectedErr, err)
56+
}
5457
}

0 commit comments

Comments
 (0)