Skip to content

Commit dfcba35

Browse files
committed
Merge pull request #148 from go-sql-driver/v1.0.3
Release v1.0.3
2 parents fdeb568 + 069f1ba commit dfcba35

9 files changed

+103
-16
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa
44

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

7-
**Current tagged Release:** June 03, 2013 (Version 1.0.1)
7+
**Current tagged Release:** November 01, 2013 (Version 1.0.3)
88

99
---------------------------------------
1010
* [Features](#features)

connection.go

+23-3
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ func (mc *mysqlConn) handleParams() (err error) {
9696
}
9797

9898
func (mc *mysqlConn) Begin() (driver.Tx, error) {
99+
if mc.netConn == nil {
100+
return nil, errInvalidConn
101+
}
102+
99103
err := mc.exec("START TRANSACTION")
100104
if err == nil {
101105
return &mysqlTx{mc}, err
@@ -105,15 +109,24 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) {
105109
}
106110

107111
func (mc *mysqlConn) Close() (err error) {
108-
mc.writeCommandPacket(comQuit)
112+
// Makes Close idempotent
113+
if mc.netConn != nil {
114+
mc.writeCommandPacket(comQuit)
115+
mc.netConn.Close()
116+
mc.netConn = nil
117+
}
118+
109119
mc.cfg = nil
110120
mc.buf = nil
111-
mc.netConn.Close()
112-
mc.netConn = nil
121+
113122
return
114123
}
115124

116125
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
126+
if mc.netConn == nil {
127+
return nil, errInvalidConn
128+
}
129+
117130
// Send command
118131
err := mc.writeCommandPacketStr(comStmtPrepare, query)
119132
if err != nil {
@@ -143,6 +156,10 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
143156
}
144157

145158
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
159+
if mc.netConn == nil {
160+
return nil, errInvalidConn
161+
}
162+
146163
if len(args) == 0 { // no args, fastpath
147164
mc.affectedRows = 0
148165
mc.insertId = 0
@@ -186,6 +203,9 @@ func (mc *mysqlConn) exec(query string) (err error) {
186203
}
187204

188205
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
206+
if mc.netConn == nil {
207+
return nil, errInvalidConn
208+
}
189209
if len(args) == 0 { // no args, fastpath
190210
// Send command
191211
err := mc.writeCommandPacketStr(comQuery, query)

driver_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,41 @@ func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows)
101101
return rows
102102
}
103103

104+
func TestReuseClosedConnection(t *testing.T) {
105+
// this test does not use sql.database, it uses the driver directly
106+
if !available {
107+
t.Logf("MySQL-Server not running on %s. Skipping TestReuseClosedConnection", netAddr)
108+
return
109+
}
110+
driver := &mysqlDriver{}
111+
conn, err := driver.Open(dsn)
112+
if err != nil {
113+
t.Fatalf("Error connecting: %s", err.Error())
114+
}
115+
stmt, err := conn.Prepare("DO 1")
116+
if err != nil {
117+
t.Fatalf("Error preparing statement: %s", err.Error())
118+
}
119+
_, err = stmt.Exec(nil)
120+
if err != nil {
121+
t.Fatalf("Error executing statement: %s", err.Error())
122+
}
123+
err = conn.Close()
124+
if err != nil {
125+
t.Fatalf("Error closing connection: %s", err.Error())
126+
}
127+
defer func() {
128+
if err := recover(); err != nil {
129+
t.Errorf("Panic after reusing a closed connection: %v", err)
130+
}
131+
}()
132+
_, err = stmt.Exec(nil)
133+
if err != nil && err != errInvalidConn {
134+
t.Errorf("Unexpected error '%s', expected '%s'",
135+
err.Error(), errInvalidConn.Error())
136+
}
137+
}
138+
104139
func TestCharset(t *testing.T) {
105140
mustSetCharset := func(charsetParam, expected string) {
106141
db, err := sql.Open("mysql", strings.Replace(dsn, charset, charsetParam, 1))
@@ -578,6 +613,16 @@ func TestNULL(t *testing.T) {
578613
dbt.Error("Unexpected NullString value:" + ns.String + " (should be `1`)")
579614
}
580615

616+
// bytes
617+
// Check input==output with input!=nil
618+
b := []byte("")
619+
if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil {
620+
dbt.Fatal(err)
621+
}
622+
if b == nil {
623+
dbt.Error("nil echo from non-nil input")
624+
}
625+
581626
// Insert NULL
582627
dbt.mustExec("CREATE TABLE test (dummmy1 int, value int, dummy2 int)")
583628

errors.go

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

1919
var (
20+
errInvalidConn = errors.New("Invalid Connection")
2021
errMalformPkt = errors.New("Malformed Packet")
2122
errPktSync = errors.New("Commands out of sync. You can't run this command now")
2223
errPktSyncMul = errors.New("Commands out of sync. Did you run multiple statements at once?")

packets.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -1014,16 +1014,15 @@ func (rows *mysqlRows) readBinaryRow(dest []driver.Value) (err error) {
10141014
}
10151015
}
10161016

1017-
var sign byte
1017+
var sign string
10181018
if data[pos] == 1 {
1019-
sign = byte('-')
1019+
sign = "-"
10201020
}
10211021

10221022
switch num {
10231023
case 8:
10241024
dest[i] = []byte(fmt.Sprintf(
1025-
"%c%02d:%02d:%02d",
1026-
sign,
1025+
sign+"%02d:%02d:%02d",
10271026
uint16(data[pos+1])*24+uint16(data[pos+5]),
10281027
data[pos+6],
10291028
data[pos+7],
@@ -1032,8 +1031,7 @@ func (rows *mysqlRows) readBinaryRow(dest []driver.Value) (err error) {
10321031
continue
10331032
case 12:
10341033
dest[i] = []byte(fmt.Sprintf(
1035-
"%c%02d:%02d:%02d.%06d",
1036-
sign,
1034+
sign+"%02d:%02d:%02d.%06d",
10371035
uint16(data[pos+1])*24+uint16(data[pos+5]),
10381036
data[pos+6],
10391037
data[pos+7],

rows.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ package mysql
1111

1212
import (
1313
"database/sql/driver"
14-
"errors"
1514
"io"
1615
)
1716

@@ -43,11 +42,15 @@ func (rows *mysqlRows) Close() (err error) {
4342

4443
// Remove unread packets from stream
4544
if !rows.eof {
46-
if rows.mc == nil {
47-
return errors.New("Invalid Connection")
45+
if rows.mc == nil || rows.mc.netConn == nil {
46+
return errInvalidConn
4847
}
4948

5049
err = rows.mc.readUntilEOF()
50+
51+
// explicitly set because readUntilEOF might return early in case of an
52+
// error
53+
rows.eof = true
5154
}
5255

5356
return
@@ -58,8 +61,8 @@ func (rows *mysqlRows) Next(dest []driver.Value) error {
5861
return io.EOF
5962
}
6063

61-
if rows.mc == nil {
62-
return errors.New("Invalid Connection")
64+
if rows.mc == nil || rows.mc.netConn == nil {
65+
return errInvalidConn
6366
}
6467

6568
// Fetch next row from stream

statement.go

+12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ type mysqlStmt struct {
2121
}
2222

2323
func (stmt *mysqlStmt) Close() (err error) {
24+
if stmt.mc == nil || stmt.mc.netConn == nil {
25+
return errInvalidConn
26+
}
27+
2428
err = stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
2529
stmt.mc = nil
2630
return
@@ -31,6 +35,10 @@ func (stmt *mysqlStmt) NumInput() int {
3135
}
3236

3337
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
38+
if stmt.mc.netConn == nil {
39+
return nil, errInvalidConn
40+
}
41+
3442
stmt.mc.affectedRows = 0
3543
stmt.mc.insertId = 0
3644

@@ -66,6 +74,10 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
6674
}
6775

6876
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
77+
if stmt.mc.netConn == nil {
78+
return nil, errInvalidConn
79+
}
80+
6981
// Send command
7082
err := stmt.writeExecutePacket(args)
7183
if err != nil {

transaction.go

+8
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@ type mysqlTx struct {
1414
}
1515

1616
func (tx *mysqlTx) Commit() (err error) {
17+
if tx.mc == nil || tx.mc.netConn == nil {
18+
return errInvalidConn
19+
}
20+
1721
err = tx.mc.exec("COMMIT")
1822
tx.mc = nil
1923
return
2024
}
2125

2226
func (tx *mysqlTx) Rollback() (err error) {
27+
if tx.mc == nil || tx.mc.netConn == nil {
28+
return errInvalidConn
29+
}
30+
2331
err = tx.mc.exec("ROLLBACK")
2432
tx.mc = nil
2533
return

utils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func readLengthEnodedString(b []byte) ([]byte, bool, int, error) {
349349
// Get length
350350
num, isNull, n := readLengthEncodedInteger(b)
351351
if num < 1 {
352-
return nil, isNull, n, nil
352+
return b[n:n], isNull, n, nil
353353
}
354354

355355
n += int(num)

0 commit comments

Comments
 (0)