rollback mysql driver

this https://github.com/go-sql-driver/mysql/pull/302 seems to have pretty much
crippled the ability to use mysql, so we need to lock a version before that
until that issue gets fixed.
This commit is contained in:
Reed Allman
2017-09-19 14:14:42 -07:00
parent 8988d5996c
commit 1a55c8050e
45 changed files with 55 additions and 3802 deletions

View File

@@ -5,25 +5,18 @@ go:
- 1.6
- 1.7
- 1.8
- 1.9
- tip
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
before_script:
- echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf
- sudo service mysql restart
- .travis/wait_mysql.sh
- mysql -e 'create database gotest;'
matrix:
include:
- env: DB=MYSQL57
sudo: required
dist: trusty
go: 1.9
go: 1.8
services:
- docker
before_install:
@@ -45,7 +38,7 @@ matrix:
- env: DB=MARIA55
sudo: required
dist: trusty
go: 1.9
go: 1.8
services:
- docker
before_install:
@@ -67,7 +60,7 @@ matrix:
- env: DB=MARIA10_1
sudo: required
dist: trusty
go: 1.9
go: 1.8
services:
- docker
before_install:
@@ -86,6 +79,9 @@ matrix:
- export MYSQL_TEST_ADDR=127.0.0.1:3307
- export MYSQL_TEST_CONCURRENT=1
before_script:
- mysql -e 'create database gotest;'
script:
- go test -v -covermode=count -coverprofile=coverage.out
- go vet ./...

View File

@@ -47,7 +47,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
## Installation
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:
```bash
$ go get -u github.com/go-sql-driver/mysql
$ go get github.com/go-sql-driver/mysql
```
Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
@@ -344,9 +344,9 @@ Any other parameters are interpreted as system variables:
* `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`
Rules:
* The values for string variables must be quoted with `'`.
* The values for string variables must be quoted with '
* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
(which implies values of string variables must be wrapped with `%27`).
(which implies values of string variables must be wrapped with `%27`)
Examples:
* `autocommit=1`: `SET autocommit=1`
@@ -426,7 +426,7 @@ See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/my
### `time.Time` support
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.
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.
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.
@@ -466,13 +466,13 @@ Mozilla summarizes the license scope as follows:
That means:
* You can **use** the **unchanged** source code both in private and commercially.
* 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).
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**.
* You can **use** the **unchanged** source code both in private and commercially
* 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)
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**
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.
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
![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")

View File

@@ -81,36 +81,17 @@ func (mc *mysqlConn) handleParams() (err error) {
return
}
func (mc *mysqlConn) markBadConn(err error) error {
if mc == nil {
return err
}
if err != errBadConnNoWrite {
return err
}
return driver.ErrBadConn
}
func (mc *mysqlConn) Begin() (driver.Tx, error) {
return mc.begin(false)
}
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
if mc.closed.IsSet() {
errLog.Print(ErrInvalidConn)
return nil, driver.ErrBadConn
}
var q string
if readOnly {
q = "START TRANSACTION READ ONLY"
} else {
q = "START TRANSACTION"
}
err := mc.exec(q)
err := mc.exec("START TRANSACTION")
if err == nil {
return &mysqlTx{mc}, err
}
return nil, mc.markBadConn(err)
return nil, err
}
func (mc *mysqlConn) Close() (err error) {
@@ -161,7 +142,7 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
// Send command
err := mc.writeCommandPacketStr(comStmtPrepare, query)
if err != nil {
return nil, mc.markBadConn(err)
return nil, err
}
stmt := &mysqlStmt{
@@ -195,7 +176,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
if buf == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return "", ErrInvalidConn
return "", driver.ErrBadConn
}
buf = buf[:0]
argPos := 0
@@ -333,14 +314,14 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
insertId: int64(mc.insertId),
}, err
}
return nil, mc.markBadConn(err)
return nil, err
}
// Internal function to execute commands
func (mc *mysqlConn) exec(query string) error {
// Send command
if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
return mc.markBadConn(err)
return err
}
// Read Result
@@ -409,7 +390,7 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
return rows, err
}
}
return nil, mc.markBadConn(err)
return nil, err
}
// Gets the value of the given MySQL System Variable

View File

@@ -14,6 +14,7 @@ import (
"context"
"database/sql"
"database/sql/driver"
"errors"
)
// Ping implements driver.Pinger interface
@@ -40,9 +41,15 @@ func (mc *mysqlConn) Ping(ctx context.Context) error {
// BeginTx implements driver.ConnBeginTx interface
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
if opts.ReadOnly {
// TODO: support read-only transactions
return nil, errors.New("mysql: read-only transactions not supported")
}
if err := mc.watchCancel(ctx); err != nil {
return nil, err
}
defer mc.finish()
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
@@ -56,7 +63,7 @@ func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver
}
}
return mc.begin(opts.ReadOnly)
return mc.Begin()
}
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {

View File

@@ -520,41 +520,3 @@ func TestContextBeginIsolationLevel(t *testing.T) {
tx2.Commit()
})
}
func TestContextBeginReadOnly(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
dbt.mustExec("CREATE TABLE test (v INTEGER)")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
tx, err := dbt.db.BeginTx(ctx, &sql.TxOptions{
ReadOnly: true,
})
if _, ok := err.(*MySQLError); ok {
dbt.Skip("It seems that your MySQL does not support READ ONLY transactions")
return
} else if err != nil {
dbt.Fatal(err)
}
// INSERT queries fail in a READ ONLY transaction.
_, err = tx.ExecContext(ctx, "INSERT INTO test VALUES (1)")
if _, ok := err.(*MySQLError); !ok {
dbt.Errorf("expected MySQLError, got %v", err)
}
// SELECT queries can be executed.
var v int
row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM test")
if err := row.Scan(&v); err != nil {
dbt.Fatal(err)
}
if v != 0 {
dbt.Errorf("expected val to be 0, got %d", v)
}
if err := tx.Commit(); err != nil {
dbt.Fatal(err)
}
})
}

View File

@@ -31,12 +31,6 @@ var (
ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?")
ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
ErrBusyBuffer = errors.New("busy buffer")
// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
// to trigger a resend.
// See https://github.com/go-sql-driver/mysql/pull/302
errBadConnNoWrite = errors.New("bad connection")
)
var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))

View File

@@ -35,7 +35,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
}
errLog.Print(err)
mc.Close()
return nil, ErrInvalidConn
return nil, driver.ErrBadConn
}
// packet length [24 bit]
@@ -57,7 +57,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
if prevData == nil {
errLog.Print(ErrMalformPkt)
mc.Close()
return nil, ErrInvalidConn
return nil, driver.ErrBadConn
}
return prevData, nil
@@ -71,7 +71,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
}
errLog.Print(err)
mc.Close()
return nil, ErrInvalidConn
return nil, driver.ErrBadConn
}
// return data if this was the last packet
@@ -137,14 +137,10 @@ func (mc *mysqlConn) writePacket(data []byte) error {
if cerr := mc.canceled.Value(); cerr != nil {
return cerr
}
if n == 0 && pktLen == len(data)-4 {
// only for the first loop iteration when nothing was written yet
return errBadConnNoWrite
}
mc.cleanup()
errLog.Print(err)
}
return ErrInvalidConn
return driver.ErrBadConn
}
}
@@ -278,7 +274,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// ClientFlags [32 bit]
@@ -366,7 +362,7 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add the scrambled password [null terminated string]
@@ -385,7 +381,7 @@ func (mc *mysqlConn) writeClearAuthPacket() error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add the clear password [null terminated string]
@@ -408,7 +404,7 @@ func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add the scramble
@@ -429,7 +425,7 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add command byte
@@ -448,7 +444,7 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add command byte
@@ -469,7 +465,7 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// Add command byte
@@ -935,7 +931,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
if data == nil {
// can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
return errBadConnNoWrite
return driver.ErrBadConn
}
// command [1 byte]

View File

@@ -9,6 +9,7 @@
package mysql
import (
"database/sql/driver"
"errors"
"net"
"testing"
@@ -251,8 +252,8 @@ func TestReadPacketFail(t *testing.T) {
conn.data = []byte{0x00, 0x00, 0x00, 0x00}
conn.maxReads = 1
_, err := mc.readPacket()
if err != ErrInvalidConn {
t.Errorf("expected ErrInvalidConn, got %v", err)
if err != driver.ErrBadConn {
t.Errorf("expected ErrBadConn, got %v", err)
}
// reset
@@ -263,8 +264,8 @@ func TestReadPacketFail(t *testing.T) {
// fail to read header
conn.closed = true
_, err = mc.readPacket()
if err != ErrInvalidConn {
t.Errorf("expected ErrInvalidConn, got %v", err)
if err != driver.ErrBadConn {
t.Errorf("expected ErrBadConn, got %v", err)
}
// reset
@@ -276,7 +277,7 @@ func TestReadPacketFail(t *testing.T) {
// fail to read body
conn.maxReads = 1
_, err = mc.readPacket()
if err != ErrInvalidConn {
t.Errorf("expected ErrInvalidConn, got %v", err)
if err != driver.ErrBadConn {
t.Errorf("expected ErrBadConn, got %v", err)
}
}

View File

@@ -52,7 +52,7 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
// Send command
err := stmt.writeExecutePacket(args)
if err != nil {
return nil, stmt.mc.markBadConn(err)
return nil, err
}
mc := stmt.mc
@@ -100,7 +100,7 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
// Send command
err := stmt.writeExecutePacket(args)
if err != nil {
return nil, stmt.mc.markBadConn(err)
return nil, err
}
mc := stmt.mc