Browse Source

upgrade go-sql-driver/mysql to fix invalid connection error (#5748)

should fix #5736
tags/v1.9.0-dev
Lunny Xiao 5 years ago
parent
commit
477a80f658

+ 2
- 2
Gopkg.lock View File

revision = "a77f45a7ce909c0ff14b28279fa1a2b674acb70f" revision = "a77f45a7ce909c0ff14b28279fa1a2b674acb70f"


[[projects]] [[projects]]
digest = "1:747c1fcb10f8f6734551465ab73c6ed9c551aa6e66250fb6683d1624f554546a"
digest = "1:dce58f88343bd78f4d32dd9601aab4fa5d9994fd2cafa185c51bbd858851cdf9"
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
revision = "c45f530f8e7fe40f4687eaa50d0c8c5f1b66f9e0"


[[projects]] [[projects]]
digest = "1:06d21295033f211588d0ad7ff391cc1b27e72b60cb6d4b7db0d70cffae4cf228" digest = "1:06d21295033f211588d0ad7ff391cc1b27e72b60cb6d4b7db0d70cffae4cf228"

+ 1
- 1
Gopkg.toml View File



[[override]] [[override]]
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
revision = "c45f530f8e7fe40f4687eaa50d0c8c5f1b66f9e0"


[[override]] [[override]]
name = "github.com/mattn/go-sqlite3" name = "github.com/mattn/go-sqlite3"

+ 5
- 0
vendor/github.com/go-sql-driver/mysql/AUTHORS View File

Henri Yandell <flamefew at gmail.com> Henri Yandell <flamefew at gmail.com>
Hirotaka Yamamoto <ymmt2005 at gmail.com> Hirotaka Yamamoto <ymmt2005 at gmail.com>
ICHINOSE Shogo <shogo82148 at gmail.com> ICHINOSE Shogo <shogo82148 at gmail.com>
Ilia Cimpoes <ichimpoesh at gmail.com>
INADA Naoki <songofacandy at gmail.com> INADA Naoki <songofacandy at gmail.com>
Jacek Szwec <szwec.jacek at gmail.com> Jacek Szwec <szwec.jacek at gmail.com>
James Harr <james.harr at gmail.com> James Harr <james.harr at gmail.com>
Soroush Pour <me at soroushjp.com> Soroush Pour <me at soroushjp.com>
Stan Putrya <root.vagner at gmail.com> Stan Putrya <root.vagner at gmail.com>
Stanley Gunawan <gunawan.stanley at gmail.com> Stanley Gunawan <gunawan.stanley at gmail.com>
Steven Hartland <steven.hartland at multiplay.co.uk>
Thomas Wodarek <wodarekwebpage at gmail.com>
Tom Jenkinson <tom at tjenkinson.me>
Xiangyu Hu <xiangyu.hu at outlook.com> Xiangyu Hu <xiangyu.hu at outlook.com>
Xiaobing Jiang <s7v7nislands at gmail.com> Xiaobing Jiang <s7v7nislands at gmail.com>
Xiuming Chen <cc at cxm.cc> Xiuming Chen <cc at cxm.cc>
Percona LLC Percona LLC
Pivotal Inc. Pivotal Inc.
Stripe Inc. Stripe Inc.
Multiplay Ltd.

+ 23
- 21
vendor/github.com/go-sql-driver/mysql/auth.go View File

if err != nil { if err != nil {
return err return err
} }
return mc.writeAuthSwitchPacket(enc, false)
return mc.writeAuthSwitchPacket(enc)
} }


func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, bool, error) {
func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
switch plugin { switch plugin {
case "caching_sha2_password": case "caching_sha2_password":
authResp := scrambleSHA256Password(authData, mc.cfg.Passwd) authResp := scrambleSHA256Password(authData, mc.cfg.Passwd)
return authResp, (authResp == nil), nil
return authResp, nil


case "mysql_old_password": case "mysql_old_password":
if !mc.cfg.AllowOldPasswords { if !mc.cfg.AllowOldPasswords {
return nil, false, ErrOldPassword
return nil, ErrOldPassword
} }
// Note: there are edge cases where this should work but doesn't; // Note: there are edge cases where this should work but doesn't;
// this is currently "wontfix": // this is currently "wontfix":
// https://github.com/go-sql-driver/mysql/issues/184 // https://github.com/go-sql-driver/mysql/issues/184
authResp := scrambleOldPassword(authData[:8], mc.cfg.Passwd)
return authResp, true, nil
authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0)
return authResp, nil


case "mysql_clear_password": case "mysql_clear_password":
if !mc.cfg.AllowCleartextPasswords { if !mc.cfg.AllowCleartextPasswords {
return nil, false, ErrCleartextPassword
return nil, ErrCleartextPassword
} }
// http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
// http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
return []byte(mc.cfg.Passwd), true, nil
return append([]byte(mc.cfg.Passwd), 0), nil


case "mysql_native_password": case "mysql_native_password":
if !mc.cfg.AllowNativePasswords { if !mc.cfg.AllowNativePasswords {
return nil, false, ErrNativePassword
return nil, ErrNativePassword
} }
// https://dev.mysql.com/doc/internals/en/secure-password-authentication.html // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
// Native password authentication only need and will need 20-byte challenge. // Native password authentication only need and will need 20-byte challenge.
authResp := scramblePassword(authData[:20], mc.cfg.Passwd) authResp := scramblePassword(authData[:20], mc.cfg.Passwd)
return authResp, false, nil
return authResp, nil


case "sha256_password": case "sha256_password":
if len(mc.cfg.Passwd) == 0 { if len(mc.cfg.Passwd) == 0 {
return nil, true, nil
return []byte{0}, nil
} }
if mc.cfg.tls != nil || mc.cfg.Net == "unix" { if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
// write cleartext auth packet // write cleartext auth packet
return []byte(mc.cfg.Passwd), true, nil
return append([]byte(mc.cfg.Passwd), 0), nil
} }


pubKey := mc.cfg.pubKey pubKey := mc.cfg.pubKey
if pubKey == nil { if pubKey == nil {
// request public key from server // request public key from server
return []byte{1}, false, nil
return []byte{1}, nil
} }


// encrypted password // encrypted password
enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey) enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
return enc, false, err
return enc, err


default: default:
errLog.Print("unknown auth plugin:", plugin) errLog.Print("unknown auth plugin:", plugin)
return nil, false, ErrUnknownPlugin
return nil, ErrUnknownPlugin
} }
} }




plugin = newPlugin plugin = newPlugin


authResp, addNUL, err := mc.auth(authData, plugin)
authResp, err := mc.auth(authData, plugin)
if err != nil { if err != nil {
return err return err
} }
if err = mc.writeAuthSwitchPacket(authResp, addNUL); err != nil {
if err = mc.writeAuthSwitchPacket(authResp); err != nil {
return err return err
} }


case cachingSha2PasswordPerformFullAuthentication: case cachingSha2PasswordPerformFullAuthentication:
if mc.cfg.tls != nil || mc.cfg.Net == "unix" { if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
// write cleartext auth packet // write cleartext auth packet
err = mc.writeAuthSwitchPacket([]byte(mc.cfg.Passwd), true)
err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0))
if err != nil { if err != nil {
return err return err
} }
pubKey := mc.cfg.pubKey pubKey := mc.cfg.pubKey
if pubKey == nil { if pubKey == nil {
// request public key from server // request public key from server
data := mc.buf.takeSmallBuffer(4 + 1)
data, err := mc.buf.takeSmallBuffer(4 + 1)
if err != nil {
return err
}
data[4] = cachingSha2PasswordRequestPublicKey data[4] = cachingSha2PasswordRequestPublicKey
mc.writePacket(data) mc.writePacket(data)


// parse public key // parse public key
data, err := mc.readPacket()
if err != nil {
if data, err = mc.readPacket(); err != nil {
return err return err
} }



+ 31
- 18
vendor/github.com/go-sql-driver/mysql/buffer.go View File

// The buffer is similar to bufio.Reader / Writer but zero-copy-ish // The buffer is similar to bufio.Reader / Writer but zero-copy-ish
// Also highly optimized for this particular use case. // Also highly optimized for this particular use case.
type buffer struct { type buffer struct {
buf []byte
buf []byte // buf is a byte buffer who's length and capacity are equal.
nc net.Conn nc net.Conn
idx int idx int
length int length int
timeout time.Duration timeout time.Duration
} }


// newBuffer allocates and returns a new buffer.
func newBuffer(nc net.Conn) buffer { func newBuffer(nc net.Conn) buffer {
var b [defaultBufSize]byte
return buffer{ return buffer{
buf: b[:],
buf: make([]byte, defaultBufSize),
nc: nc, nc: nc,
} }
} }
return b.buf[offset:b.idx], nil return b.buf[offset:b.idx], nil
} }


// returns a buffer with the requested size.
// takeBuffer returns a buffer with the requested size.
// If possible, a slice from the existing buffer is returned. // If possible, a slice from the existing buffer is returned.
// Otherwise a bigger buffer is made. // Otherwise a bigger buffer is made.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeBuffer(length int) []byte {
func (b *buffer) takeBuffer(length int) ([]byte, error) {
if b.length > 0 { if b.length > 0 {
return nil
return nil, ErrBusyBuffer
} }


// test (cheap) general case first // test (cheap) general case first
if length <= defaultBufSize || length <= cap(b.buf) {
return b.buf[:length]
if length <= cap(b.buf) {
return b.buf[:length], nil
} }


if length < maxPacketSize { if length < maxPacketSize {
b.buf = make([]byte, length) b.buf = make([]byte, length)
return b.buf
return b.buf, nil
} }
return make([]byte, length)

// buffer is larger than we want to store.
return make([]byte, length), nil
} }


// shortcut which can be used if the requested buffer is guaranteed to be
// smaller than defaultBufSize
// takeSmallBuffer is shortcut which can be used if length is
// known to be smaller than defaultBufSize.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeSmallBuffer(length int) []byte {
func (b *buffer) takeSmallBuffer(length int) ([]byte, error) {
if b.length > 0 { if b.length > 0 {
return nil
return nil, ErrBusyBuffer
} }
return b.buf[:length]
return b.buf[:length], nil
} }


// takeCompleteBuffer returns the complete existing buffer. // takeCompleteBuffer returns the complete existing buffer.
// This can be used if the necessary buffer size is unknown. // This can be used if the necessary buffer size is unknown.
// cap and len of the returned buffer will be equal.
// Only one buffer (total) can be used at a time. // Only one buffer (total) can be used at a time.
func (b *buffer) takeCompleteBuffer() []byte {
func (b *buffer) takeCompleteBuffer() ([]byte, error) {
if b.length > 0 {
return nil, ErrBusyBuffer
}
return b.buf, nil
}

// store stores buf, an updated buffer, if its suitable to do so.
func (b *buffer) store(buf []byte) error {
if b.length > 0 { if b.length > 0 {
return nil
return ErrBusyBuffer
} else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) {
b.buf = buf[:cap(buf)]
} }
return b.buf
return nil
} }

+ 196
- 14
vendor/github.com/go-sql-driver/mysql/connection.go View File

package mysql package mysql


import ( import (
"context"
"database/sql"
"database/sql/driver" "database/sql/driver"
"io" "io"
"net" "net"
"time" "time"
) )


// a copy of context.Context for Go 1.7 and earlier
type mysqlContext interface {
Done() <-chan struct{}
Err() error

// defined in context.Context, but not used in this driver:
// Deadline() (deadline time.Time, ok bool)
// Value(key interface{}) interface{}
}

type mysqlConn struct { type mysqlConn struct {
buf buffer buf buffer
netConn net.Conn netConn net.Conn


// for context support (Go 1.8+) // for context support (Go 1.8+)
watching bool watching bool
watcher chan<- mysqlContext
watcher chan<- context.Context
closech chan struct{} closech chan struct{}
finished chan<- struct{} finished chan<- struct{}
canceled atomicError // set non-nil if conn is canceled canceled atomicError // set non-nil if conn is canceled
return "", driver.ErrSkip return "", driver.ErrSkip
} }


buf := mc.buf.takeCompleteBuffer()
if buf == nil {
buf, err := mc.buf.takeCompleteBuffer()
if err != nil {
// can not take the buffer. Something must be wrong with the connection // can not take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return "", ErrInvalidConn return "", ErrInvalidConn
} }
buf = buf[:0] buf = buf[:0]
case <-mc.closech: case <-mc.closech:
} }
} }

// Ping implements driver.Pinger interface
func (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 mc.markBadConn(err)
}

return mc.readResultOK()
}

// BeginTx implements driver.ConnBeginTx interface
func (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
}
// When ctx is already cancelled, don't watch it.
if err := ctx.Err(); err != nil {
return err
}
// When ctx is not cancellable, don't watch it.
if ctx.Done() == nil {
return nil
}
// When watcher is not alive, can't watch it.
if mc.watcher == nil {
return nil
}

mc.watching = true
mc.watcher <- ctx
return nil
}

func (mc *mysqlConn) startWatcher() {
watcher := make(chan context.Context, 1)
mc.watcher = watcher
finished := make(chan struct{})
mc.finished = finished
go func() {
for {
var ctx context.Context
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
}

+ 0
- 208
vendor/github.com/go-sql-driver/mysql/connection_go18.go View File

// 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.8

package mysql

import (
"context"
"database/sql"
"database/sql/driver"
)

// Ping implements driver.Pinger interface
func (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 interface
func (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
}

+ 12
- 12
vendor/github.com/go-sql-driver/mysql/driver.go View File

"sync" "sync"
) )


// watcher interface is used for context support (From Go 1.8)
type watcher interface {
startWatcher()
}

// MySQLDriver is exported to make the driver directly accessible. // MySQLDriver is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package. // In general the driver is used via the database/sql package.
type MySQLDriver struct{} type MySQLDriver struct{}


// Open new Connection. // Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how // See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formated
// the DSN string is formatted
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
var err error var err error


mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr) mc.netConn, err = nd.Dial(mc.cfg.Net, mc.cfg.Addr)
} }
if err != nil { if err != nil {
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
errLog.Print("net.Error from Dial()': ", nerr.Error())
return nil, driver.ErrBadConn
}
return nil, err return nil, err
} }


} }


// Call startWatcher for context support (From Go 1.8) // Call startWatcher for context support (From Go 1.8)
if s, ok := interface{}(mc).(watcher); ok {
s.startWatcher()
}
mc.startWatcher()


mc.buf = newBuffer(mc.netConn) mc.buf = newBuffer(mc.netConn)


mc.cleanup() mc.cleanup()
return nil, err return nil, err
} }
if plugin == "" {
plugin = defaultAuthPlugin
}


// Send Client Authentication Packet // Send Client Authentication Packet
authResp, addNUL, err := mc.auth(authData, plugin)
authResp, err := mc.auth(authData, plugin)
if err != nil { if err != nil {
// try the default auth plugin, if using the requested plugin failed // try the default auth plugin, if using the requested plugin failed
errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
plugin = defaultAuthPlugin plugin = defaultAuthPlugin
authResp, addNUL, err = mc.auth(authData, plugin)
authResp, err = mc.auth(authData, plugin)
if err != nil { if err != nil {
mc.cleanup() mc.cleanup()
return nil, err return nil, err
} }
} }
if err = mc.writeHandshakeResponsePacket(authResp, addNUL, plugin); err != nil {
if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
mc.cleanup() mc.cleanup()
return nil, err return nil, err
} }

+ 1
- 1
vendor/github.com/go-sql-driver/mysql/dsn.go View File

} else { } else {
cfg.TLSConfig = "false" cfg.TLSConfig = "false"
} }
} else if vl := strings.ToLower(value); vl == "skip-verify" {
} else if vl := strings.ToLower(value); vl == "skip-verify" || vl == "preferred" {
cfg.TLSConfig = vl cfg.TLSConfig = vl
cfg.tls = &tls.Config{InsecureSkipVerify: true} cfg.tls = &tls.Config{InsecureSkipVerify: true}
} else { } else {

+ 47
- 52
vendor/github.com/go-sql-driver/mysql/packets.go View File

mc.sequence++ mc.sequence++


// packets with length 0 terminate a previous packet which is a // packets with length 0 terminate a previous packet which is a
// multiple of (2^24)1 bytes long
// multiple of (2^24)-1 bytes long
if pktLen == 0 { if pktLen == 0 {
// there was no previous packet // there was no previous packet
if prevData == nil { if prevData == nil {


// Handshake Initialization Packet // Handshake Initialization Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
data, err := mc.readPacket()
func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) {
data, err = mc.readPacket()
if err != nil { if err != nil {
// for init we can rewrite this to ErrBadConn for sql.Driver to retry, since // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
// in connection initialization we don't risk retrying non-idempotent actions. // in connection initialization we don't risk retrying non-idempotent actions.
if err == ErrInvalidConn { if err == ErrInvalidConn {
return nil, "", driver.ErrBadConn return nil, "", driver.ErrBadConn
} }
return nil, "", err
return
} }


if data[0] == iERR { if data[0] == iERR {
return nil, "", ErrOldProtocol return nil, "", ErrOldProtocol
} }
if mc.flags&clientSSL == 0 && mc.cfg.tls != nil { if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
return nil, "", ErrNoTLS
if mc.cfg.TLSConfig == "preferred" {
mc.cfg.tls = nil
} else {
return nil, "", ErrNoTLS
}
} }
pos += 2 pos += 2


plugin := ""
if len(data) > pos { if len(data) > pos {
// character set [1 byte] // character set [1 byte]
// status flags [2 bytes] // status flags [2 bytes]
return b[:], plugin, nil return b[:], plugin, nil
} }


plugin = defaultAuthPlugin

// make a memory safe copy of the cipher slice // make a memory safe copy of the cipher slice
var b [8]byte var b [8]byte
copy(b[:], authData) copy(b[:], authData)


// Client Authentication Packet // Client Authentication Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error {
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error {
// Adjust client flags based on server support // Adjust client flags based on server support
clientFlags := clientProtocol41 | clientFlags := clientProtocol41 |
clientSecureConn | clientSecureConn |


// encode length of the auth plugin data // encode length of the auth plugin data
var authRespLEIBuf [9]byte var authRespLEIBuf [9]byte
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp)))
authRespLen := len(authResp)
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen))
if len(authRespLEI) > 1 { if len(authRespLEI) > 1 {
// if the length can not be written in 1 byte, it must be written as a // if the length can not be written in 1 byte, it must be written as a
// length encoded integer // length encoded integer
} }


pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
if addNUL {
pktLen++
}


// To specify a db name // To specify a db name
if n := len(mc.cfg.DBName); n > 0 { if n := len(mc.cfg.DBName); n > 0 {
} }


// Calculate packet length and get buffer with that size // Calculate packet length and get buffer with that size
data := mc.buf.takeSmallBuffer(pktLen + 4)
if data == nil {
data, err := mc.buf.takeSmallBuffer(pktLen + 4)
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


// Auth Data [length encoded integer] // Auth Data [length encoded integer]
pos += copy(data[pos:], authRespLEI) pos += copy(data[pos:], authRespLEI)
pos += copy(data[pos:], authResp) pos += copy(data[pos:], authResp)
if addNUL {
data[pos] = 0x00
pos++
}


// Databasename [null terminated string] // Databasename [null terminated string]
if len(mc.cfg.DBName) > 0 { if len(mc.cfg.DBName) > 0 {


pos += copy(data[pos:], plugin) pos += copy(data[pos:], plugin)
data[pos] = 0x00 data[pos] = 0x00
pos++


// Send Auth packet // Send Auth packet
return mc.writePacket(data)
return mc.writePacket(data[:pos])
} }


// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error {
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
pktLen := 4 + len(authData) pktLen := 4 + len(authData)
if addNUL {
pktLen++
}
data := mc.buf.takeSmallBuffer(pktLen)
if data == nil {
data, err := mc.buf.takeSmallBuffer(pktLen)
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


// Add the auth data [EOF] // Add the auth data [EOF]
copy(data[4:], authData) copy(data[4:], authData)
if addNUL {
data[pktLen-1] = 0x00
}

return mc.writePacket(data) return mc.writePacket(data)
} }


// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.sequence = 0


data := mc.buf.takeSmallBuffer(4 + 1)
if data == nil {
data, err := mc.buf.takeSmallBuffer(4 + 1)
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


mc.sequence = 0 mc.sequence = 0


pktLen := 1 + len(arg) pktLen := 1 + len(arg)
data := mc.buf.takeBuffer(pktLen + 4)
if data == nil {
data, err := mc.buf.takeBuffer(pktLen + 4)
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


// Reset Packet Sequence // Reset Packet Sequence
mc.sequence = 0 mc.sequence = 0


data := mc.buf.takeSmallBuffer(4 + 1 + 4)
if data == nil {
data, err := mc.buf.takeSmallBuffer(4 + 1 + 4)
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


return data[1:], "", err return data[1:], "", err


case iEOF: case iEOF:
if len(data) < 1 {
if len(data) == 1 {
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
return nil, "mysql_old_password", nil return nil, "mysql_old_password", nil
} }
const minPktLen = 4 + 1 + 4 + 1 + 4 const minPktLen = 4 + 1 + 4 + 1 + 4
mc := stmt.mc mc := stmt.mc


// Determine threshould dynamically to avoid packet size shortage.
// Determine threshold dynamically to avoid packet size shortage.
longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
if longDataSize < 64 { if longDataSize < 64 {
longDataSize = 64 longDataSize = 64
mc.sequence = 0 mc.sequence = 0


var data []byte var data []byte
var err error


if len(args) == 0 { if len(args) == 0 {
data = mc.buf.takeBuffer(minPktLen)
data, err = mc.buf.takeBuffer(minPktLen)
} else { } else {
data = mc.buf.takeCompleteBuffer()
data, err = mc.buf.takeCompleteBuffer()
// In this case the len(data) == cap(data) which is used to optimise the flow below.
} }
if data == nil {
if err != nil {
// cannot take the buffer. Something must be wrong with the connection // cannot take the buffer. Something must be wrong with the connection
errLog.Print(ErrBusyBuffer)
errLog.Print(err)
return errBadConnNoWrite return errBadConnNoWrite
} }


pos := minPktLen pos := minPktLen


var nullMask []byte var nullMask []byte
if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) {
if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= cap(data) {
// buffer has to be extended but we don't know by how much so // buffer has to be extended but we don't know by how much so
// we depend on append after all data with known sizes fit. // we depend on append after all data with known sizes fit.
// We stop at that because we deal with a lot of columns here // We stop at that because we deal with a lot of columns here
copy(tmp[:pos], data[:pos]) copy(tmp[:pos], data[:pos])
data = tmp data = tmp
nullMask = data[pos : pos+maskLen] nullMask = data[pos : pos+maskLen]
// No need to clean nullMask as make ensures that.
pos += maskLen pos += maskLen
} else { } else {
nullMask = data[pos : pos+maskLen] nullMask = data[pos : pos+maskLen]
for i := 0; i < maskLen; i++ {
for i := range nullMask {
nullMask[i] = 0 nullMask[i] = 0
} }
pos += maskLen pos += maskLen
// In that case we must build the data packet with the new values buffer // In that case we must build the data packet with the new values buffer
if valuesCap != cap(paramValues) { if valuesCap != cap(paramValues) {
data = append(data[:pos], paramValues...) data = append(data[:pos], paramValues...)
mc.buf.buf = data
if err = mc.buf.store(data); err != nil {
errLog.Print(err)
return errBadConnNoWrite
}
} }


pos += len(paramValues) pos += len(paramValues)
rows.rs.columns[i].decimals, rows.rs.columns[i].decimals,
) )
} }
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen)
case rows.mc.parseTime: case rows.mc.parseTime:
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
default: default:
) )
} }
} }
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, false)
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen)
} }


if err == nil { if err == nil {

+ 148
- 103
vendor/github.com/go-sql-driver/mysql/utils.go View File



import ( import (
"crypto/tls" "crypto/tls"
"database/sql"
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
"strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
func getTLSConfigClone(key string) (config *tls.Config) { func getTLSConfigClone(key string) (config *tls.Config) {
tlsConfigLock.RLock() tlsConfigLock.RLock()
if v, ok := tlsConfigRegistry[key]; ok { if v, ok := tlsConfigRegistry[key]; ok {
config = cloneTLSConfig(v)
config = v.Clone()
} }
tlsConfigLock.RUnlock() tlsConfigLock.RUnlock()
return return
const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"


func formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value, error) {
// length expects the deterministic length of the zero value,
// negative time and 100+ hours are automatically added if needed
if len(src) == 0 {
if justTime {
return zeroDateTime[11 : 11+length], nil
}
return zeroDateTime[:length], nil
func appendMicrosecs(dst, src []byte, decimals int) []byte {
if decimals <= 0 {
return dst
} }
var dst []byte // return value
var pt, p1, p2, p3 byte // current digit pair
var zOffs byte // offset of value in zeroDateTime
if justTime {
switch length {
case
8, // time (can be up to 10 when negative and 100+ hours)
10, 11, 12, 13, 14, 15: // time with fractional seconds
default:
return nil, fmt.Errorf("illegal TIME length %d", length)
}
switch len(src) {
case 8, 12:
default:
return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
}
// +2 to enable negative time and 100+ hours
dst = make([]byte, 0, length+2)
if src[0] == 1 {
dst = append(dst, '-')
}
if src[1] != 0 {
hour := uint16(src[1])*24 + uint16(src[5])
pt = byte(hour / 100)
p1 = byte(hour - 100*uint16(pt))
dst = append(dst, digits01[pt])
} else {
p1 = src[5]
}
zOffs = 11
src = src[6:]
} else {
switch length {
case 10, 19, 21, 22, 23, 24, 25, 26:
default:
t := "DATE"
if length > 10 {
t += "TIME"
}
return nil, fmt.Errorf("illegal %s length %d", t, length)
}
switch len(src) {
case 4, 7, 11:
default:
t := "DATE"
if length > 10 {
t += "TIME"
}
return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
}
dst = make([]byte, 0, length)
// start with the date
year := binary.LittleEndian.Uint16(src[:2])
pt = byte(year / 100)
p1 = byte(year - 100*uint16(pt))
p2, p3 = src[2], src[3]
dst = append(dst,
digits10[pt], digits01[pt],
digits10[p1], digits01[p1], '-',
digits10[p2], digits01[p2], '-',
digits10[p3], digits01[p3],
)
if length == 10 {
return dst, nil
}
if len(src) == 4 {
return append(dst, zeroDateTime[10:length]...), nil
}
dst = append(dst, ' ')
p1 = src[4] // hour
src = src[5:]
}
// p1 is 2-digit hour, src is after hour
p2, p3 = src[0], src[1]
dst = append(dst,
digits10[p1], digits01[p1], ':',
digits10[p2], digits01[p2], ':',
digits10[p3], digits01[p3],
)
if length <= byte(len(dst)) {
return dst, nil
}
src = src[2:]
if len(src) == 0 { if len(src) == 0 {
return append(dst, zeroDateTime[19:zOffs+length]...), nil
return append(dst, ".000000"[:decimals+1]...)
} }

microsecs := binary.LittleEndian.Uint32(src[:4]) microsecs := binary.LittleEndian.Uint32(src[:4])
p1 = byte(microsecs / 10000)
p1 := byte(microsecs / 10000)
microsecs -= 10000 * uint32(p1) microsecs -= 10000 * uint32(p1)
p2 = byte(microsecs / 100)
p2 := byte(microsecs / 100)
microsecs -= 100 * uint32(p2) microsecs -= 100 * uint32(p2)
p3 = byte(microsecs)
switch decimals := zOffs + length - 20; decimals {
p3 := byte(microsecs)

switch decimals {
default: default:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits01[p1], digits10[p1], digits01[p1],
digits10[p2], digits01[p2], digits10[p2], digits01[p2],
digits10[p3], digits01[p3], digits10[p3], digits01[p3],
), nil
)
case 1: case 1:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits10[p1],
), nil
)
case 2: case 2:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits01[p1], digits10[p1], digits01[p1],
), nil
)
case 3: case 3:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits01[p1], digits10[p1], digits01[p1],
digits10[p2], digits10[p2],
), nil
)
case 4: case 4:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits01[p1], digits10[p1], digits01[p1],
digits10[p2], digits01[p2], digits10[p2], digits01[p2],
), nil
)
case 5: case 5:
return append(dst, '.', return append(dst, '.',
digits10[p1], digits01[p1], digits10[p1], digits01[p1],
digits10[p2], digits01[p2], digits10[p2], digits01[p2],
digits10[p3], digits10[p3],
), nil
)
} }
} }


func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) {
// length expects the deterministic length of the zero value,
// negative time and 100+ hours are automatically added if needed
if len(src) == 0 {
return zeroDateTime[:length], nil
}
var dst []byte // return value
var p1, p2, p3 byte // current digit pair

switch length {
case 10, 19, 21, 22, 23, 24, 25, 26:
default:
t := "DATE"
if length > 10 {
t += "TIME"
}
return nil, fmt.Errorf("illegal %s length %d", t, length)
}
switch len(src) {
case 4, 7, 11:
default:
t := "DATE"
if length > 10 {
t += "TIME"
}
return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
}
dst = make([]byte, 0, length)
// start with the date
year := binary.LittleEndian.Uint16(src[:2])
pt := year / 100
p1 = byte(year - 100*uint16(pt))
p2, p3 = src[2], src[3]
dst = append(dst,
digits10[pt], digits01[pt],
digits10[p1], digits01[p1], '-',
digits10[p2], digits01[p2], '-',
digits10[p3], digits01[p3],
)
if length == 10 {
return dst, nil
}
if len(src) == 4 {
return append(dst, zeroDateTime[10:length]...), nil
}
dst = append(dst, ' ')
p1 = src[4] // hour
src = src[5:]

// p1 is 2-digit hour, src is after hour
p2, p3 = src[0], src[1]
dst = append(dst,
digits10[p1], digits01[p1], ':',
digits10[p2], digits01[p2], ':',
digits10[p3], digits01[p3],
)
return appendMicrosecs(dst, src[2:], int(length)-20), nil
}

func formatBinaryTime(src []byte, length uint8) (driver.Value, error) {
// length expects the deterministic length of the zero value,
// negative time and 100+ hours are automatically added if needed
if len(src) == 0 {
return zeroDateTime[11 : 11+length], nil
}
var dst []byte // return value

switch length {
case
8, // time (can be up to 10 when negative and 100+ hours)
10, 11, 12, 13, 14, 15: // time with fractional seconds
default:
return nil, fmt.Errorf("illegal TIME length %d", length)
}
switch len(src) {
case 8, 12:
default:
return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
}
// +2 to enable negative time and 100+ hours
dst = make([]byte, 0, length+2)
if src[0] == 1 {
dst = append(dst, '-')
}
days := binary.LittleEndian.Uint32(src[1:5])
hours := int64(days)*24 + int64(src[5])

if hours >= 100 {
dst = strconv.AppendInt(dst, hours, 10)
} else {
dst = append(dst, digits10[hours], digits01[hours])
}

min, sec := src[6], src[7]
dst = append(dst, ':',
digits10[min], digits01[min], ':',
digits10[sec], digits01[sec],
)
return appendMicrosecs(dst, src[8:], int(length)-9), nil
}

/****************************************************************************** /******************************************************************************
* Convert from and to bytes * * Convert from and to bytes *
******************************************************************************/ ******************************************************************************/
} }
return nil return nil
} }

func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
dargs := make([]driver.Value, len(named))
for n, param := range named {
if len(param.Name) > 0 {
// TODO: support the use of Named Parameters #561
return nil, errors.New("mysql: driver does not support the use of Named Parameters")
}
dargs[n] = param.Value
}
return dargs, nil
}

func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
switch sql.IsolationLevel(level) {
case sql.LevelRepeatableRead:
return "REPEATABLE READ", nil
case sql.LevelReadCommitted:
return "READ COMMITTED", nil
case sql.LevelReadUncommitted:
return "READ UNCOMMITTED", nil
case sql.LevelSerializable:
return "SERIALIZABLE", nil
default:
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
}
}

+ 0
- 40
vendor/github.com/go-sql-driver/mysql/utils_go17.go View File

// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2017 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.7
// +build !go1.8

package mysql

import "crypto/tls"

func cloneTLSConfig(c *tls.Config) *tls.Config {
return &tls.Config{
Rand: c.Rand,
Time: c.Time,
Certificates: c.Certificates,
NameToCertificate: c.NameToCertificate,
GetCertificate: c.GetCertificate,
RootCAs: c.RootCAs,
NextProtos: c.NextProtos,
ServerName: c.ServerName,
ClientAuth: c.ClientAuth,
ClientCAs: c.ClientCAs,
InsecureSkipVerify: c.InsecureSkipVerify,
CipherSuites: c.CipherSuites,
PreferServerCipherSuites: c.PreferServerCipherSuites,
SessionTicketsDisabled: c.SessionTicketsDisabled,
SessionTicketKey: c.SessionTicketKey,
ClientSessionCache: c.ClientSessionCache,
MinVersion: c.MinVersion,
MaxVersion: c.MaxVersion,
CurvePreferences: c.CurvePreferences,
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
Renegotiation: c.Renegotiation,
}
}

+ 0
- 50
vendor/github.com/go-sql-driver/mysql/utils_go18.go View File

// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2017 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.8

package mysql

import (
"crypto/tls"
"database/sql"
"database/sql/driver"
"errors"
"fmt"
)

func cloneTLSConfig(c *tls.Config) *tls.Config {
return c.Clone()
}

func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
dargs := make([]driver.Value, len(named))
for n, param := range named {
if len(param.Name) > 0 {
// TODO: support the use of Named Parameters #561
return nil, errors.New("mysql: driver does not support the use of Named Parameters")
}
dargs[n] = param.Value
}
return dargs, nil
}

func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
switch sql.IsolationLevel(level) {
case sql.LevelRepeatableRead:
return "REPEATABLE READ", nil
case sql.LevelReadCommitted:
return "READ COMMITTED", nil
case sql.LevelReadUncommitted:
return "READ UNCOMMITTED", nil
case sql.LevelSerializable:
return "SERIALIZABLE", nil
default:
return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
}
}

Loading…
Cancel
Save