-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add context support #586
Add context support #586
Changes from 1 commit
94e3ba7
669fc71
2abb4ae
691ec98
6d7e804
ce38c4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -418,6 +418,11 @@ Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAM | |
|
||
See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support. | ||
|
||
## Context Support | ||
Since go1.8, context is introduced to `database/sql` for better control on timeout and cancellation. | ||
New interfaces such as `driver.QueryerContext`, `driver.ExecerContext` are introduced. See more details on [context support to database/sql package](https://golang.org/doc/go1.8#database_sql, "sql"). | ||
|
||
In Go-MySQL-Driver, we implemented these interfaces for structs `mysqlConn`, `mysqlStmt` and `mysqlTx`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
|
||
## Testing / Development | ||
To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,7 @@ func (mc *mysqlConn) handleParams() (err error) { | |
charsets := strings.Split(val, ",") | ||
for i := range charsets { | ||
// ignore errors here - a charset may not exist | ||
err = mc.exec("SET NAMES " + charsets[i]) | ||
err = mc.exec(backgroundCtx(), "SET NAMES "+charsets[i]) | ||
if err == nil { | ||
break | ||
} | ||
|
@@ -53,7 +53,7 @@ func (mc *mysqlConn) handleParams() (err error) { | |
|
||
// System Vars | ||
default: | ||
err = mc.exec("SET " + param + "=" + val + "") | ||
err = mc.exec(backgroundCtx(), "SET "+param+"="+val+"") | ||
if err != nil { | ||
return | ||
} | ||
|
@@ -63,12 +63,17 @@ func (mc *mysqlConn) handleParams() (err error) { | |
return | ||
} | ||
|
||
// Begin implements driver.Conn interface | ||
func (mc *mysqlConn) Begin() (driver.Tx, error) { | ||
return mc.beginTx(backgroundCtx(), txOptions{}) | ||
} | ||
|
||
func (mc *mysqlConn) beginTx(ctx mysqlContext, opts txOptions) (driver.Tx, error) { | ||
if mc.netConn == nil { | ||
errLog.Print(ErrInvalidConn) | ||
return nil, driver.ErrBadConn | ||
} | ||
err := mc.exec("START TRANSACTION") | ||
err := mc.exec(ctx, "START TRANSACTION") | ||
if err == nil { | ||
return &mysqlTx{mc}, err | ||
} | ||
|
@@ -79,7 +84,7 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) { | |
func (mc *mysqlConn) Close() (err error) { | ||
// Makes Close idempotent | ||
if mc.netConn != nil { | ||
err = mc.writeCommandPacket(comQuit) | ||
err = mc.writeCommandPacket(backgroundCtx(), comQuit) | ||
} | ||
|
||
mc.cleanup() | ||
|
@@ -104,12 +109,16 @@ func (mc *mysqlConn) cleanup() { | |
} | ||
|
||
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { | ||
return mc.prepareContext(backgroundCtx(), query) | ||
} | ||
|
||
func (mc *mysqlConn) prepareContext(ctx mysqlContext, query string) (driver.Stmt, error) { | ||
if mc.netConn == nil { | ||
errLog.Print(ErrInvalidConn) | ||
return nil, driver.ErrBadConn | ||
} | ||
// Send command | ||
err := mc.writeCommandPacketStr(comStmtPrepare, query) | ||
err := mc.writeCommandPacketStr(ctx, comStmtPrepare, query) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -258,6 +267,10 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin | |
} | ||
|
||
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { | ||
return mc.ExecContext(backgroundCtx(), query, args) | ||
} | ||
|
||
func (mc *mysqlConn) ExecContext(ctx mysqlContext, query string, args []driver.Value) (driver.Result, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The interface defined in note the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's why there should be simple initialization tests, to check if our driver implements the respective interfaces, i.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is an example of what I mean: e1cf7db |
||
if mc.netConn == nil { | ||
errLog.Print(ErrInvalidConn) | ||
return nil, driver.ErrBadConn | ||
|
@@ -276,7 +289,7 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err | |
mc.affectedRows = 0 | ||
mc.insertId = 0 | ||
|
||
err := mc.exec(query) | ||
err := mc.exec(ctx, query) | ||
if err == nil { | ||
return &mysqlResult{ | ||
affectedRows: int64(mc.affectedRows), | ||
|
@@ -287,9 +300,9 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err | |
} | ||
|
||
// Internal function to execute commands | ||
func (mc *mysqlConn) exec(query string) error { | ||
func (mc *mysqlConn) exec(ctx mysqlContext, query string) error { | ||
// Send command | ||
if err := mc.writeCommandPacketStr(comQuery, query); err != nil { | ||
if err := mc.writeCommandPacketStr(ctx, comQuery, query); err != nil { | ||
return err | ||
} | ||
|
||
|
@@ -314,7 +327,12 @@ func (mc *mysqlConn) exec(query string) error { | |
return mc.discardResults() | ||
} | ||
|
||
// Query implements driver.Queryer interface | ||
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { | ||
return mc.queryContext(backgroundCtx(), query, args) | ||
} | ||
|
||
func (mc *mysqlConn) queryContext(ctx mysqlContext, query string, args []driver.Value) (driver.Rows, error) { | ||
if mc.netConn == nil { | ||
errLog.Print(ErrInvalidConn) | ||
return nil, driver.ErrBadConn | ||
|
@@ -331,7 +349,7 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro | |
query = prepared | ||
} | ||
// Send command | ||
err := mc.writeCommandPacketStr(comQuery, query) | ||
err := mc.writeCommandPacketStr(ctx, comQuery, query) | ||
if err == nil { | ||
// Read Result | ||
var resLen int | ||
|
@@ -362,7 +380,7 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro | |
// The returned byte slice is only valid until the next read | ||
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { | ||
// Send command | ||
if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { | ||
if err := mc.writeCommandPacketStr(backgroundCtx(), comQuery, "SELECT @@"+name); err != nil { | ||
return nil, err | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// +build go1.8 | ||
|
||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package | ||
// | ||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package mysql | ||
|
||
import ( | ||
"context" | ||
"database/sql/driver" | ||
) | ||
|
||
// Ping implements driver.Pinger interface | ||
func (mc *mysqlConn) Ping(ctx context.Context) error { | ||
if mc.netConn == nil { | ||
errLog.Print(ErrInvalidConn) | ||
return driver.ErrBadConn | ||
} | ||
if err := mc.writeCommandPacket(ctx, comPing); err != nil { | ||
errLog.Print(err) | ||
return err | ||
} | ||
|
||
if _, err := mc.readResultOK(); err != nil { | ||
errLog.Print(err) | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// BeginTx implements driver.ConnBeginTx interface | ||
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { | ||
return mc.beginTx(ctx, txOptions(opts)) | ||
} | ||
|
||
func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { | ||
return mc.prepareContext(ctx, query) | ||
} | ||
|
||
// QueryContext implements driver.QueryerContext interface | ||
func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.Value) (driver.Rows, error) { | ||
return mc.queryContext(ctx, query, args) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// +build !go1.8 | ||
|
||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package | ||
// | ||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package mysql | ||
|
||
import ( | ||
"time" | ||
) | ||
|
||
// txOptions is defined for compatibility with Go 1.8's driver.TxOptions struct. | ||
type txOptions struct { | ||
Isolation int | ||
ReadOnly bool | ||
} | ||
|
||
// mysqlContext is a copy of context.Context from Go 1.7 and later. | ||
type mysqlContext interface { | ||
Deadline() (deadline time.Time, ok bool) | ||
|
||
Done() <-chan struct{} | ||
|
||
Err() error | ||
|
||
Value(key interface{}) interface{} | ||
} | ||
|
||
// emptyCtx is copied from Go 1.7's context package. | ||
type emptyCtx int | ||
|
||
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { | ||
return | ||
} | ||
|
||
func (*emptyCtx) Done() <-chan struct{} { | ||
return nil | ||
} | ||
|
||
func (*emptyCtx) Err() error { | ||
return nil | ||
} | ||
|
||
func (*emptyCtx) Value(key interface{}) interface{} { | ||
return nil | ||
} | ||
|
||
func (e *emptyCtx) String() string { | ||
return "context.Background" | ||
} | ||
|
||
var background = new(emptyCtx) | ||
|
||
func backgroundCtx() mysqlContext { | ||
return background | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// +build go1.8 | ||
|
||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package | ||
// | ||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. | ||
// | ||
// This Source Code Form is subject to the terms of the Mozilla Public | ||
// License, v. 2.0. If a copy of the MPL was not distributed with this file, | ||
// You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
package mysql | ||
|
||
import ( | ||
"context" | ||
"database/sql/driver" | ||
) | ||
|
||
// The definitions below are for compatibility with older Go versions. | ||
// See ctx_backport.go for the definitions used in older Go versions. | ||
|
||
type txOptions driver.TxOptions | ||
|
||
type mysqlContext context.Context | ||
|
||
func backgroundCtx() mysqlContext { | ||
return context.Background() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interfaces are driver implementation internals which do not interest the average driver user