Skip to content

Commit 0963109

Browse files
authored
Merge branch 'master' into add-aurora-errno-to-reject
2 parents 1802ef0 + eb92a8d commit 0963109

16 files changed

+243
-310
lines changed

.travis.yml

+10-6
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,25 @@ go:
55
- 1.6
66
- 1.7
77
- 1.8
8+
- 1.9
89
- tip
910

1011
before_install:
1112
- go get golang.org/x/tools/cmd/cover
1213
- go get github.com/mattn/goveralls
1314

15+
before_script:
16+
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf
17+
- sudo service mysql restart
18+
- .travis/wait_mysql.sh
19+
- mysql -e 'create database gotest;'
20+
1421
matrix:
1522
include:
1623
- env: DB=MYSQL57
1724
sudo: required
1825
dist: trusty
19-
go: 1.8
26+
go: 1.9
2027
services:
2128
- docker
2229
before_install:
@@ -38,7 +45,7 @@ matrix:
3845
- env: DB=MARIA55
3946
sudo: required
4047
dist: trusty
41-
go: 1.8
48+
go: 1.9
4249
services:
4350
- docker
4451
before_install:
@@ -60,7 +67,7 @@ matrix:
6067
- env: DB=MARIA10_1
6168
sudo: required
6269
dist: trusty
63-
go: 1.8
70+
go: 1.9
6471
services:
6572
- docker
6673
before_install:
@@ -79,9 +86,6 @@ matrix:
7986
- export MYSQL_TEST_ADDR=127.0.0.1:3307
8087
- export MYSQL_TEST_CONCURRENT=1
8188

82-
83-
before_script:
84-
- mysql -e 'create database gotest;'
8589
script:
8690
- go test -v -covermode=count -coverprofile=coverage.out
8791
- go vet ./...

AUTHORS

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ INADA Naoki <songofacandy at gmail.com>
3434
Jacek Szwec <szwec.jacek at gmail.com>
3535
James Harr <james.harr at gmail.com>
3636
Jeffrey Charles <jeffreycharles at gmail.com>
37+
Jeff Hodges <jeff at somethingsimilar.com>
3738
Jian Zhen <zhenjl at gmail.com>
3839
Joshua Prunier <joshua.prunier at gmail.com>
3940
Julien Lefevre <julien.lefevr at gmail.com>
@@ -56,6 +57,7 @@ Paul Bonser <misterpib at gmail.com>
5657
Peter Schultz <peter.schultz at classmarkets.com>
5758
Rebecca Chin <rchin at pivotal.io>
5859
Runrioter Wung <runrioter at gmail.com>
60+
Shuode Li <elemount at qq.com>
5961
Soroush Pour <me at soroushjp.com>
6062
Stan Putrya <root.vagner at gmail.com>
6163
Stanley Gunawan <gunawan.stanley at gmail.com>

README.md

+16-27
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
4747
## Installation
4848
Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
4949
```bash
50-
$ go get github.com/go-sql-driver/mysql
50+
$ go get -u github.com/go-sql-driver/mysql
5151
```
5252
Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
5353

@@ -101,7 +101,8 @@ See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which netw
101101
In general you should use an Unix domain socket if available and TCP otherwise for best performance.
102102

103103
#### Address
104-
For TCP and UDP networks, addresses have the form `host:port`.
104+
For TCP and UDP networks, addresses have the form `host[:port]`.
105+
If `port` is omitted, the default port will be used.
105106
If `host` is a literal IPv6 address, it must be enclosed in square brackets.
106107
The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
107108

@@ -138,9 +139,9 @@ Default: false
138139
```
139140
Type: bool
140141
Valid Values: true, false
141-
Default: false
142+
Default: true
142143
```
143-
`allowNativePasswords=true` allows the usage of the mysql native password method.
144+
`allowNativePasswords=false` disallows the usage of MySQL native password method.
144145

145146
##### `allowOldPasswords`
146147

@@ -231,10 +232,10 @@ Please keep in mind, that param values must be [url.QueryEscape](https://golang.
231232
##### `maxAllowedPacket`
232233
```
233234
Type: decimal number
234-
Default: 0
235+
Default: 4194304
235236
```
236237

237-
Max packet size allowed in bytes. Use `maxAllowedPacket=0` to automatically fetch the `max_allowed_packet` variable from server.
238+
Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
238239

239240
##### `multiStatements`
240241

@@ -298,20 +299,6 @@ other cases. You should ensure your application will never cause an ERROR 1290
298299
except for `read-only` mode when enabling this option.
299300

300301

301-
##### `strict`
302-
303-
```
304-
Type: bool
305-
Valid Values: true, false
306-
Default: false
307-
```
308-
309-
`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations.
310-
311-
A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable.
312-
313-
By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes.
314-
315302
##### `timeout`
316303

317304
```
@@ -321,6 +308,7 @@ Default: OS default
321308

322309
Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
323310

311+
324312
##### `tls`
325313

326314
```
@@ -331,6 +319,7 @@ Default: false
331319

332320
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
333321

322+
334323
##### `writeTimeout`
335324

336325
```
@@ -349,9 +338,9 @@ Any other parameters are interpreted as system variables:
349338
* `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`
350339

351340
Rules:
352-
* The values for string variables must be quoted with '
341+
* The values for string variables must be quoted with `'`.
353342
* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
354-
(which implies values of string variables must be wrapped with `%27`)
343+
(which implies values of string variables must be wrapped with `%27`).
355344

356345
Examples:
357346
* `autocommit=1`: `SET autocommit=1`
@@ -431,7 +420,7 @@ See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/my
431420

432421

433422
### `time.Time` support
434-
The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm.
423+
The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program.
435424

436425
However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
437426

@@ -471,13 +460,13 @@ Mozilla summarizes the license scope as follows:
471460
472461

473462
That means:
474-
* You can **use** the **unchanged** source code both in private and commercially
475-
* When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0)
476-
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**
463+
* You can **use** the **unchanged** source code both in private and commercially.
464+
* When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0).
465+
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**.
477466

478467
Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.
479468

480-
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
469+
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
481470

482471
![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
483472

benchmark_test.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,7 @@ func initDB(b *testing.B, queries ...string) *sql.DB {
4848
db := tb.checkDB(sql.Open("mysql", dsn))
4949
for _, query := range queries {
5050
if _, err := db.Exec(query); err != nil {
51-
if w, ok := err.(MySQLWarnings); ok {
52-
b.Logf("warning on %q: %v", query, w)
53-
} else {
54-
b.Fatalf("error on %q: %v", query, err)
55-
}
51+
b.Fatalf("error on %q: %v", query, err)
5652
}
5753
}
5854
return db

connection.go

+27-9
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ type mysqlConn struct {
4040
status statusFlag
4141
sequence uint8
4242
parseTime bool
43-
strict bool
4443

4544
// for context support (Go 1.8+)
4645
watching bool
@@ -81,17 +80,36 @@ func (mc *mysqlConn) handleParams() (err error) {
8180
return
8281
}
8382

83+
func (mc *mysqlConn) markBadConn(err error) error {
84+
if mc == nil {
85+
return err
86+
}
87+
if err != errBadConnNoWrite {
88+
return err
89+
}
90+
return driver.ErrBadConn
91+
}
92+
8493
func (mc *mysqlConn) Begin() (driver.Tx, error) {
94+
return mc.begin(false)
95+
}
96+
97+
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
8598
if mc.closed.IsSet() {
8699
errLog.Print(ErrInvalidConn)
87100
return nil, driver.ErrBadConn
88101
}
89-
err := mc.exec("START TRANSACTION")
102+
var q string
103+
if readOnly {
104+
q = "START TRANSACTION READ ONLY"
105+
} else {
106+
q = "START TRANSACTION"
107+
}
108+
err := mc.exec(q)
90109
if err == nil {
91110
return &mysqlTx{mc}, err
92111
}
93-
94-
return nil, err
112+
return nil, mc.markBadConn(err)
95113
}
96114

97115
func (mc *mysqlConn) Close() (err error) {
@@ -142,7 +160,7 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
142160
// Send command
143161
err := mc.writeCommandPacketStr(comStmtPrepare, query)
144162
if err != nil {
145-
return nil, err
163+
return nil, mc.markBadConn(err)
146164
}
147165

148166
stmt := &mysqlStmt{
@@ -176,7 +194,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
176194
if buf == nil {
177195
// can not take the buffer. Something must be wrong with the connection
178196
errLog.Print(ErrBusyBuffer)
179-
return "", driver.ErrBadConn
197+
return "", ErrInvalidConn
180198
}
181199
buf = buf[:0]
182200
argPos := 0
@@ -314,14 +332,14 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
314332
insertId: int64(mc.insertId),
315333
}, err
316334
}
317-
return nil, err
335+
return nil, mc.markBadConn(err)
318336
}
319337

320338
// Internal function to execute commands
321339
func (mc *mysqlConn) exec(query string) error {
322340
// Send command
323341
if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
324-
return err
342+
return mc.markBadConn(err)
325343
}
326344

327345
// Read Result
@@ -390,7 +408,7 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
390408
return rows, err
391409
}
392410
}
393-
return nil, err
411+
return nil, mc.markBadConn(err)
394412
}
395413

396414
// Gets the value of the given MySQL System Variable

connection_go18.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"context"
1515
"database/sql"
1616
"database/sql/driver"
17-
"errors"
1817
)
1918

2019
// Ping implements driver.Pinger interface
@@ -41,15 +40,9 @@ func (mc *mysqlConn) Ping(ctx context.Context) error {
4140

4241
// BeginTx implements driver.ConnBeginTx interface
4342
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
44-
if opts.ReadOnly {
45-
// TODO: support read-only transactions
46-
return nil, errors.New("mysql: read-only transactions not supported")
47-
}
48-
4943
if err := mc.watchCancel(ctx); err != nil {
5044
return nil, err
5145
}
52-
5346
defer mc.finish()
5447

5548
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
@@ -63,7 +56,7 @@ func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver
6356
}
6457
}
6558

66-
return mc.Begin()
59+
return mc.begin(opts.ReadOnly)
6760
}
6861

6962
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {

const.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
package mysql
1010

1111
const (
12-
minProtocolVersion byte = 10
12+
defaultMaxAllowedPacket = 4 << 20 // 4 MiB
13+
minProtocolVersion = 10
1314
maxPacketSize = 1<<24 - 1
1415
timeFormat = "2006-01-02 15:04:05.999999"
1516
)

driver.go

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
6464
return nil, err
6565
}
6666
mc.parseTime = mc.cfg.ParseTime
67-
mc.strict = mc.cfg.Strict
6867

6968
// Connect to Server
7069
if dial, ok := dials[mc.cfg.Net]; ok {

driver_go18_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -520,3 +520,41 @@ func TestContextBeginIsolationLevel(t *testing.T) {
520520
tx2.Commit()
521521
})
522522
}
523+
524+
func TestContextBeginReadOnly(t *testing.T) {
525+
runTests(t, dsn, func(dbt *DBTest) {
526+
dbt.mustExec("CREATE TABLE test (v INTEGER)")
527+
ctx, cancel := context.WithCancel(context.Background())
528+
defer cancel()
529+
530+
tx, err := dbt.db.BeginTx(ctx, &sql.TxOptions{
531+
ReadOnly: true,
532+
})
533+
if _, ok := err.(*MySQLError); ok {
534+
dbt.Skip("It seems that your MySQL does not support READ ONLY transactions")
535+
return
536+
} else if err != nil {
537+
dbt.Fatal(err)
538+
}
539+
540+
// INSERT queries fail in a READ ONLY transaction.
541+
_, err = tx.ExecContext(ctx, "INSERT INTO test VALUES (1)")
542+
if _, ok := err.(*MySQLError); !ok {
543+
dbt.Errorf("expected MySQLError, got %v", err)
544+
}
545+
546+
// SELECT queries can be executed.
547+
var v int
548+
row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM test")
549+
if err := row.Scan(&v); err != nil {
550+
dbt.Fatal(err)
551+
}
552+
if v != 0 {
553+
dbt.Errorf("expected val to be 0, got %d", v)
554+
}
555+
556+
if err := tx.Commit(); err != nil {
557+
dbt.Fatal(err)
558+
}
559+
})
560+
}

0 commit comments

Comments
 (0)