Skip to content

Commit 749ddf1

Browse files
shogo82148julienschmidt
authored andcommitted
Drop Go 1.7 Support (go-sql-driver#823)
* Remove Go 1.7 from travis.yml * drop Go 1.7 support * remove the watcher interface * update gofmt * remove cloneTLSConfig, and use (*tls.Config).Clone directly instead.
1 parent 2307b45 commit 749ddf1

15 files changed

+1144
-1294
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
sudo: false
22
language: go
33
go:
4-
- 1.7.x
54
- 1.8.x
65
- 1.9.x
76
- 1.10.x

benchmark_go18_test.go

-93
This file was deleted.

benchmark_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ package mysql
1010

1111
import (
1212
"bytes"
13+
"context"
1314
"database/sql"
1415
"database/sql/driver"
16+
"fmt"
1517
"math"
18+
"runtime"
1619
"strings"
1720
"sync"
1821
"sync/atomic"
@@ -240,3 +243,77 @@ func BenchmarkInterpolation(b *testing.B) {
240243
}
241244
}
242245
}
246+
247+
func benchmarkQueryContext(b *testing.B, db *sql.DB, p int) {
248+
ctx, cancel := context.WithCancel(context.Background())
249+
defer cancel()
250+
db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0))
251+
252+
tb := (*TB)(b)
253+
stmt := tb.checkStmt(db.PrepareContext(ctx, "SELECT val FROM foo WHERE id=?"))
254+
defer stmt.Close()
255+
256+
b.SetParallelism(p)
257+
b.ReportAllocs()
258+
b.ResetTimer()
259+
b.RunParallel(func(pb *testing.PB) {
260+
var got string
261+
for pb.Next() {
262+
tb.check(stmt.QueryRow(1).Scan(&got))
263+
if got != "one" {
264+
b.Fatalf("query = %q; want one", got)
265+
}
266+
}
267+
})
268+
}
269+
270+
func BenchmarkQueryContext(b *testing.B) {
271+
db := initDB(b,
272+
"DROP TABLE IF EXISTS foo",
273+
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
274+
`INSERT INTO foo VALUES (1, "one")`,
275+
`INSERT INTO foo VALUES (2, "two")`,
276+
)
277+
defer db.Close()
278+
for _, p := range []int{1, 2, 3, 4} {
279+
b.Run(fmt.Sprintf("%d", p), func(b *testing.B) {
280+
benchmarkQueryContext(b, db, p)
281+
})
282+
}
283+
}
284+
285+
func benchmarkExecContext(b *testing.B, db *sql.DB, p int) {
286+
ctx, cancel := context.WithCancel(context.Background())
287+
defer cancel()
288+
db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0))
289+
290+
tb := (*TB)(b)
291+
stmt := tb.checkStmt(db.PrepareContext(ctx, "DO 1"))
292+
defer stmt.Close()
293+
294+
b.SetParallelism(p)
295+
b.ReportAllocs()
296+
b.ResetTimer()
297+
b.RunParallel(func(pb *testing.PB) {
298+
for pb.Next() {
299+
if _, err := stmt.ExecContext(ctx); err != nil {
300+
b.Fatal(err)
301+
}
302+
}
303+
})
304+
}
305+
306+
func BenchmarkExecContext(b *testing.B) {
307+
db := initDB(b,
308+
"DROP TABLE IF EXISTS foo",
309+
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
310+
`INSERT INTO foo VALUES (1, "one")`,
311+
`INSERT INTO foo VALUES (2, "two")`,
312+
)
313+
defer db.Close()
314+
for _, p := range []int{1, 2, 3, 4} {
315+
b.Run(fmt.Sprintf("%d", p), func(b *testing.B) {
316+
benchmarkQueryContext(b, db, p)
317+
})
318+
}
319+
}

connection.go

+193
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
package mysql
1010

1111
import (
12+
"context"
13+
"database/sql"
1214
"database/sql/driver"
1315
"io"
1416
"net"
@@ -459,3 +461,194 @@ func (mc *mysqlConn) finish() {
459461
case <-mc.closech:
460462
}
461463
}
464+
465+
// Ping implements driver.Pinger interface
466+
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
467+
if mc.closed.IsSet() {
468+
errLog.Print(ErrInvalidConn)
469+
return driver.ErrBadConn
470+
}
471+
472+
if err = mc.watchCancel(ctx); err != nil {
473+
return
474+
}
475+
defer mc.finish()
476+
477+
if err = mc.writeCommandPacket(comPing); err != nil {
478+
return
479+
}
480+
481+
return mc.readResultOK()
482+
}
483+
484+
// BeginTx implements driver.ConnBeginTx interface
485+
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
486+
if err := mc.watchCancel(ctx); err != nil {
487+
return nil, err
488+
}
489+
defer mc.finish()
490+
491+
if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
492+
level, err := mapIsolationLevel(opts.Isolation)
493+
if err != nil {
494+
return nil, err
495+
}
496+
err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
497+
if err != nil {
498+
return nil, err
499+
}
500+
}
501+
502+
return mc.begin(opts.ReadOnly)
503+
}
504+
505+
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
506+
dargs, err := namedValueToValue(args)
507+
if err != nil {
508+
return nil, err
509+
}
510+
511+
if err := mc.watchCancel(ctx); err != nil {
512+
return nil, err
513+
}
514+
515+
rows, err := mc.query(query, dargs)
516+
if err != nil {
517+
mc.finish()
518+
return nil, err
519+
}
520+
rows.finish = mc.finish
521+
return rows, err
522+
}
523+
524+
func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
525+
dargs, err := namedValueToValue(args)
526+
if err != nil {
527+
return nil, err
528+
}
529+
530+
if err := mc.watchCancel(ctx); err != nil {
531+
return nil, err
532+
}
533+
defer mc.finish()
534+
535+
return mc.Exec(query, dargs)
536+
}
537+
538+
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
539+
if err := mc.watchCancel(ctx); err != nil {
540+
return nil, err
541+
}
542+
543+
stmt, err := mc.Prepare(query)
544+
mc.finish()
545+
if err != nil {
546+
return nil, err
547+
}
548+
549+
select {
550+
default:
551+
case <-ctx.Done():
552+
stmt.Close()
553+
return nil, ctx.Err()
554+
}
555+
return stmt, nil
556+
}
557+
558+
func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
559+
dargs, err := namedValueToValue(args)
560+
if err != nil {
561+
return nil, err
562+
}
563+
564+
if err := stmt.mc.watchCancel(ctx); err != nil {
565+
return nil, err
566+
}
567+
568+
rows, err := stmt.query(dargs)
569+
if err != nil {
570+
stmt.mc.finish()
571+
return nil, err
572+
}
573+
rows.finish = stmt.mc.finish
574+
return rows, err
575+
}
576+
577+
func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
578+
dargs, err := namedValueToValue(args)
579+
if err != nil {
580+
return nil, err
581+
}
582+
583+
if err := stmt.mc.watchCancel(ctx); err != nil {
584+
return nil, err
585+
}
586+
defer stmt.mc.finish()
587+
588+
return stmt.Exec(dargs)
589+
}
590+
591+
func (mc *mysqlConn) watchCancel(ctx context.Context) error {
592+
if mc.watching {
593+
// Reach here if canceled,
594+
// so the connection is already invalid
595+
mc.cleanup()
596+
return nil
597+
}
598+
if ctx.Done() == nil {
599+
return nil
600+
}
601+
602+
mc.watching = true
603+
select {
604+
default:
605+
case <-ctx.Done():
606+
return ctx.Err()
607+
}
608+
if mc.watcher == nil {
609+
return nil
610+
}
611+
612+
mc.watcher <- ctx
613+
614+
return nil
615+
}
616+
617+
func (mc *mysqlConn) startWatcher() {
618+
watcher := make(chan mysqlContext, 1)
619+
mc.watcher = watcher
620+
finished := make(chan struct{})
621+
mc.finished = finished
622+
go func() {
623+
for {
624+
var ctx mysqlContext
625+
select {
626+
case ctx = <-watcher:
627+
case <-mc.closech:
628+
return
629+
}
630+
631+
select {
632+
case <-ctx.Done():
633+
mc.cancel(ctx.Err())
634+
case <-finished:
635+
case <-mc.closech:
636+
return
637+
}
638+
}
639+
}()
640+
}
641+
642+
func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
643+
nv.Value, err = converter{}.ConvertValue(nv.Value)
644+
return
645+
}
646+
647+
// ResetSession implements driver.SessionResetter.
648+
// (From Go 1.10)
649+
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
650+
if mc.closed.IsSet() {
651+
return driver.ErrBadConn
652+
}
653+
return nil
654+
}

0 commit comments

Comments
 (0)