| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | // 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/.// +build go1.8package mysqlimport (	"context"	"database/sql"	"database/sql/driver")// Ping implements driver.Pinger interfacefunc (mc *mysqlConn) Ping(ctx context.Context) (err error) {	if mc.closed.IsSet() {		errLog.Print(ErrInvalidConn)		return driver.ErrBadConn	}	if err = mc.watchCancel(ctx); err != nil {		return	}	defer mc.finish()	if err = mc.writeCommandPacket(comPing); err != nil {		return	}	return mc.readResultOK()}// BeginTx implements driver.ConnBeginTx interfacefunc (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {	if err := mc.watchCancel(ctx); err != nil {		return nil, err	}	defer mc.finish()	if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {		level, err := mapIsolationLevel(opts.Isolation)		if err != nil {			return nil, err		}		err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)		if err != nil {			return nil, err		}	}	return mc.begin(opts.ReadOnly)}func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {	dargs, err := namedValueToValue(args)	if err != nil {		return nil, err	}	if err := mc.watchCancel(ctx); err != nil {		return nil, err	}	rows, err := mc.query(query, dargs)	if err != nil {		mc.finish()		return nil, err	}	rows.finish = mc.finish	return rows, err}func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {	dargs, err := namedValueToValue(args)	if err != nil {		return nil, err	}	if err := mc.watchCancel(ctx); err != nil {		return nil, err	}	defer mc.finish()	return mc.Exec(query, dargs)}func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {	if err := mc.watchCancel(ctx); err != nil {		return nil, err	}	stmt, err := mc.Prepare(query)	mc.finish()	if err != nil {		return nil, err	}	select {	default:	case <-ctx.Done():		stmt.Close()		return nil, ctx.Err()	}	return stmt, nil}func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {	dargs, err := namedValueToValue(args)	if err != nil {		return nil, err	}	if err := stmt.mc.watchCancel(ctx); err != nil {		return nil, err	}	rows, err := stmt.query(dargs)	if err != nil {		stmt.mc.finish()		return nil, err	}	rows.finish = stmt.mc.finish	return rows, err}func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {	dargs, err := namedValueToValue(args)	if err != nil {		return nil, err	}	if err := stmt.mc.watchCancel(ctx); err != nil {		return nil, err	}	defer stmt.mc.finish()	return stmt.Exec(dargs)}func (mc *mysqlConn) watchCancel(ctx context.Context) error {	if mc.watching {		// Reach here if canceled,		// so the connection is already invalid		mc.cleanup()		return nil	}	if ctx.Done() == nil {		return nil	}	mc.watching = true	select {	default:	case <-ctx.Done():		return ctx.Err()	}	if mc.watcher == nil {		return nil	}	mc.watcher <- ctx	return nil}func (mc *mysqlConn) startWatcher() {	watcher := make(chan mysqlContext, 1)	mc.watcher = watcher	finished := make(chan struct{})	mc.finished = finished	go func() {		for {			var ctx mysqlContext			select {			case ctx = <-watcher:			case <-mc.closech:				return			}			select {			case <-ctx.Done():				mc.cancel(ctx.Err())			case <-finished:			case <-mc.closech:				return			}		}	}()}func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {	nv.Value, err = converter{}.ConvertValue(nv.Value)	return}// ResetSession implements driver.SessionResetter.// (From Go 1.10)func (mc *mysqlConn) ResetSession(ctx context.Context) error {	if mc.closed.IsSet() {		return driver.ErrBadConn	}	return nil}
 |