summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/go-sql-driver/mysql
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/go-sql-driver/mysql')
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS4
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md14
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go33
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go9
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go24
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go20
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go32
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go56
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go6
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go7
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go14
-rw-r--r--Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go26
12 files changed, 187 insertions, 58 deletions
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS
index 4b65bf363..6dd0167f3 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS
@@ -20,9 +20,11 @@ Frederick Mayle <frederickmayle at gmail.com>
Gustavo Kristic <gkristic at gmail.com>
Hanno Braun <mail at hannobraun.com>
Henri Yandell <flamefew at gmail.com>
+Hirotaka Yamamoto <ymmt2005 at gmail.com>
INADA Naoki <songofacandy at gmail.com>
James Harr <james.harr at gmail.com>
Jian Zhen <zhenjl at gmail.com>
+Joshua Prunier <joshua.prunier at gmail.com>
Julien Schmidt <go-sql-driver at julienschmidt.com>
Kamil Dziedzic <kamil at klecza.pl>
Leonardo YongUk Kim <dalinaum at gmail.com>
@@ -32,8 +34,10 @@ Michael Woolnough <michael.woolnough at gmail.com>
Nicola Peduzzi <thenikso at gmail.com>
Runrioter Wung <runrioter at gmail.com>
Soroush Pour <me at soroushjp.com>
+Stan Putrya <root.vagner at gmail.com>
Xiaobing Jiang <s7v7nislands at gmail.com>
Xiuming Chen <cc at cxm.cc>
+Julien Lefevre <julien.lefevr at gmail.com>
# Organizations
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md
index 9edb7628b..706b7ef2e 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md
@@ -30,7 +30,7 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa
## Features
* Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance")
* Native Go implementation. No C-bindings, just pure Go
- * Connections over TCP/IPv4, TCP/IPv6 or Unix domain sockets
+ * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](http://godoc.org/github.com/go-sql-driver/mysql#DialFunc)
* Automatic handling of broken connections
* Automatic Connection Pooling *(by database/sql package)*
* Supports queries larger than 16MB
@@ -123,6 +123,16 @@ Default: false
`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files.
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
+##### `allowCleartextPasswords`
+
+```
+Type: bool
+Valid Values: true, false
+Default: false
+```
+
+`allowCleartextPasswords=true` allows using the [cleartext client side plugin](http://dev.mysql.com/doc/en/cleartext-authentication-plugin.html) if required by an account, such as one defined with the [PAM authentication plugin](http://dev.mysql.com/doc/en/pam-authentication-plugin.html). Sending passwords in clear text may be a security problem in some configurations. To avoid problems if there is any possibility that the password would be intercepted, clients should connect to MySQL Server using a method that protects the password. Possibilities include [TLS / SSL](#tls), IPsec, or a private network.
+
##### `allowOldPasswords`
```
@@ -321,7 +331,7 @@ import "github.com/go-sql-driver/mysql"
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
-To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then.
+To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore.
See the [godoc of Go-MySQL-Driver](http://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go
index a6d39bec9..72ed09d69 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go
@@ -34,21 +34,22 @@ type mysqlConn struct {
}
type config struct {
- user string
- passwd string
- net string
- addr string
- dbname string
- params map[string]string
- loc *time.Location
- tls *tls.Config
- timeout time.Duration
- collation uint8
- allowAllFiles bool
- allowOldPasswords bool
- clientFoundRows bool
- columnsWithAlias bool
- interpolateParams bool
+ user string
+ passwd string
+ net string
+ addr string
+ dbname string
+ params map[string]string
+ loc *time.Location
+ tls *tls.Config
+ timeout time.Duration
+ collation uint8
+ allowAllFiles bool
+ allowOldPasswords bool
+ allowCleartextPasswords bool
+ clientFoundRows bool
+ columnsWithAlias bool
+ interpolateParams bool
}
// Handles parameters set in DSN after the connection is established
@@ -252,7 +253,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
if v == nil {
buf = append(buf, "NULL"...)
} else {
- buf = append(buf, '\'')
+ buf = append(buf, "_binary'"...)
if mc.status&statusNoBackslashEscapes == 0 {
buf = escapeBytesBackslash(buf, v)
} else {
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go
index 3cbbe6031..d310624ad 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go
@@ -107,6 +107,15 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
mc.Close()
return nil, err
}
+ } else if mc.cfg != nil && mc.cfg.allowCleartextPasswords && err == ErrCleartextPassword {
+ if err = mc.writeClearAuthPacket(); err != nil {
+ mc.Close()
+ return nil, err
+ }
+ if err = mc.readResultOK(); err != nil {
+ mc.Close()
+ return nil, err
+ }
} else {
mc.Close()
return nil, err
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go
index cb0d5f5ec..f9da416ec 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go
@@ -1246,6 +1246,30 @@ func TestCollation(t *testing.T) {
}
}
+func TestColumnsWithAlias(t *testing.T) {
+ runTests(t, dsn+"&columnsWithAlias=true", func(dbt *DBTest) {
+ rows := dbt.mustQuery("SELECT 1 AS A")
+ defer rows.Close()
+ cols, _ := rows.Columns()
+ if len(cols) != 1 {
+ t.Fatalf("expected 1 column, got %d", len(cols))
+ }
+ if cols[0] != "A" {
+ t.Fatalf("expected column name \"A\", got \"%s\"", cols[0])
+ }
+ rows.Close()
+
+ rows = dbt.mustQuery("SELECT * FROM (SELECT 1 AS one) AS A")
+ cols, _ = rows.Columns()
+ if len(cols) != 1 {
+ t.Fatalf("expected 1 column, got %d", len(cols))
+ }
+ if cols[0] != "A.one" {
+ t.Fatalf("expected column name \"A.one\", got \"%s\"", cols[0])
+ }
+ })
+}
+
func TestRawBytesResultExceedsBuffer(t *testing.T) {
runTests(t, dsn, func(dbt *DBTest) {
// defaultBufSize from buffer.go
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go
index 97d7b3996..44cf30db6 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go
@@ -19,15 +19,17 @@ import (
// Various errors the driver might return. Can change between driver versions.
var (
- ErrInvalidConn = errors.New("Invalid Connection")
- ErrMalformPkt = errors.New("Malformed Packet")
- ErrNoTLS = errors.New("TLS encryption requested but server does not support TLS")
- ErrOldPassword = errors.New("This server only supports the insecure old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
- ErrOldProtocol = errors.New("MySQL-Server does not support required Protocol 41+")
- ErrPktSync = errors.New("Commands out of sync. You can't run this command now")
- ErrPktSyncMul = errors.New("Commands out of sync. Did you run multiple statements at once?")
- ErrPktTooLarge = errors.New("Packet for query is too large. You can change this value on the server by adjusting the 'max_allowed_packet' variable.")
- ErrBusyBuffer = errors.New("Busy buffer")
+ ErrInvalidConn = errors.New("Invalid Connection")
+ ErrMalformPkt = errors.New("Malformed Packet")
+ ErrNoTLS = errors.New("TLS encryption requested but server does not support TLS")
+ ErrOldPassword = errors.New("This user requires old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
+ ErrCleartextPassword = errors.New("This user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN.")
+ ErrUnknownPlugin = errors.New("The authentication plugin is not supported.")
+ ErrOldProtocol = errors.New("MySQL-Server does not support required Protocol 41+")
+ ErrPktSync = errors.New("Commands out of sync. You can't run this command now")
+ ErrPktSyncMul = errors.New("Commands out of sync. Did you run multiple statements at once?")
+ ErrPktTooLarge = errors.New("Packet for query is too large. You can change this value on the server by adjusting the 'max_allowed_packet' variable.")
+ ErrBusyBuffer = errors.New("Busy buffer")
)
var errLog Logger = log.New(os.Stderr, "[MySQL] ", log.Ldate|log.Ltime|log.Lshortfile)
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go
index 121a04c71..84c53a99c 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go
@@ -13,11 +13,14 @@ import (
"io"
"os"
"strings"
+ "sync"
)
var (
- fileRegister map[string]bool
- readerRegister map[string]func() io.Reader
+ fileRegister map[string]bool
+ fileRegisterLock sync.RWMutex
+ readerRegister map[string]func() io.Reader
+ readerRegisterLock sync.RWMutex
)
// RegisterLocalFile adds the given file to the file whitelist,
@@ -32,17 +35,21 @@ var (
// ...
//
func RegisterLocalFile(filePath string) {
+ fileRegisterLock.Lock()
// lazy map init
if fileRegister == nil {
fileRegister = make(map[string]bool)
}
fileRegister[strings.Trim(filePath, `"`)] = true
+ fileRegisterLock.Unlock()
}
// DeregisterLocalFile removes the given filepath from the whitelist.
func DeregisterLocalFile(filePath string) {
+ fileRegisterLock.Lock()
delete(fileRegister, strings.Trim(filePath, `"`))
+ fileRegisterLock.Unlock()
}
// RegisterReaderHandler registers a handler function which is used
@@ -61,18 +68,22 @@ func DeregisterLocalFile(filePath string) {
// ...
//
func RegisterReaderHandler(name string, handler func() io.Reader) {
+ readerRegisterLock.Lock()
// lazy map init
if readerRegister == nil {
readerRegister = make(map[string]func() io.Reader)
}
readerRegister[name] = handler
+ readerRegisterLock.Unlock()
}
// DeregisterReaderHandler removes the ReaderHandler function with
// the given name from the registry.
func DeregisterReaderHandler(name string) {
+ readerRegisterLock.Lock()
delete(readerRegister, name)
+ readerRegisterLock.Unlock()
}
func deferredClose(err *error, closer io.Closer) {
@@ -86,9 +97,15 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
var rdr io.Reader
var data []byte
- if strings.HasPrefix(name, "Reader::") { // io.Reader
- name = name[8:]
- if handler, inMap := readerRegister[name]; inMap {
+ if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader
+ // The server might return an an absolute path. See issue #355.
+ name = name[idx+8:]
+
+ readerRegisterLock.RLock()
+ handler, inMap := readerRegister[name]
+ readerRegisterLock.RUnlock()
+
+ if inMap {
rdr = handler()
if rdr != nil {
data = make([]byte, 4+mc.maxWriteSize)
@@ -104,7 +121,10 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
}
} else { // File
name = strings.Trim(name, `"`)
- if mc.cfg.allowAllFiles || fileRegister[name] {
+ fileRegisterLock.RLock()
+ fr := fileRegister[name]
+ fileRegisterLock.RUnlock()
+ if mc.cfg.allowAllFiles || fr {
var file *os.File
var fi os.FileInfo
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go
index 290a3887a..76cb7c84e 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go
@@ -196,7 +196,11 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
// return
//}
//return ErrMalformPkt
- return cipher, nil
+
+ // make a memory safe copy of the cipher slice
+ var b [20]byte
+ copy(b[:], cipher)
+ return b[:], nil
}
// make a memory safe copy of the cipher slice
@@ -214,6 +218,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
clientLongPassword |
clientTransactions |
clientLocalFiles |
+ clientPluginAuth |
mc.flags&clientLongFlag
if mc.cfg.clientFoundRows {
@@ -228,7 +233,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
// User Password
scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.passwd))
- pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.user) + 1 + 1 + len(scrambleBuff)
+ pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.user) + 1 + 1 + len(scrambleBuff) + 21 + 1
// To specify a db name
if n := len(mc.cfg.dbname); n > 0 {
@@ -277,7 +282,10 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
}
// Filler [23 bytes] (all 0x00)
- pos := 13 + 23
+ pos := 13
+ for ; pos < 13+23; pos++ {
+ data[pos] = 0
+ }
// User [null terminated string]
if len(mc.cfg.user) > 0 {
@@ -294,8 +302,13 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
if len(mc.cfg.dbname) > 0 {
pos += copy(data[pos:], mc.cfg.dbname)
data[pos] = 0x00
+ pos++
}
+ // Assume native client during response
+ pos += copy(data[pos:], "mysql_native_password")
+ data[pos] = 0x00
+
// Send Auth packet
return mc.writePacket(data)
}
@@ -306,7 +319,7 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
// User password
scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.passwd))
- // Calculate the packet lenght and add a tailing 0
+ // Calculate the packet length and add a tailing 0
pktLen := len(scrambleBuff) + 1
data := mc.buf.takeSmallBuffer(4 + pktLen)
if data == nil {
@@ -322,6 +335,25 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
return mc.writePacket(data)
}
+// Client clear text authentication packet
+// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
+func (mc *mysqlConn) writeClearAuthPacket() error {
+ // Calculate the packet length and add a tailing 0
+ pktLen := len(mc.cfg.passwd) + 1
+ data := mc.buf.takeSmallBuffer(4 + pktLen)
+ if data == nil {
+ // can not take the buffer. Something must be wrong with the connection
+ errLog.Print(ErrBusyBuffer)
+ return driver.ErrBadConn
+ }
+
+ // Add the clear password [null terminated string]
+ copy(data[4:], mc.cfg.passwd)
+ data[4+pktLen-1] = 0x00
+
+ return mc.writePacket(data)
+}
+
/******************************************************************************
* Command Packets *
******************************************************************************/
@@ -405,8 +437,20 @@ func (mc *mysqlConn) readResultOK() error {
return mc.handleOkPacket(data)
case iEOF:
- // someone is using old_passwords
- return ErrOldPassword
+ if len(data) > 1 {
+ plugin := string(data[1:bytes.IndexByte(data, 0x00)])
+ if plugin == "mysql_old_password" {
+ // using old_passwords
+ return ErrOldPassword
+ } else if plugin == "mysql_clear_password" {
+ // using clear text password
+ return ErrCleartextPassword
+ } else {
+ return ErrUnknownPlugin
+ }
+ } else {
+ return ErrOldPassword
+ }
default: // Error otherwise
return mc.handleErrorPacket(data)
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go
index 9d97d6d4f..ba606e146 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go
@@ -40,7 +40,11 @@ func (rows *mysqlRows) Columns() []string {
columns := make([]string, len(rows.columns))
if rows.mc.cfg.columnsWithAlias {
for i := range columns {
- columns[i] = rows.columns[i].tableName + "." + rows.columns[i].name
+ if tableName := rows.columns[i].tableName; len(tableName) > 0 {
+ columns[i] = tableName + "." + rows.columns[i].name
+ } else {
+ columns[i] = rows.columns[i].name
+ }
}
} else {
for i := range columns {
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go
index f9dae03fa..6e869b340 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go
@@ -12,6 +12,7 @@ import (
"database/sql/driver"
"fmt"
"reflect"
+ "strconv"
)
type mysqlStmt struct {
@@ -119,7 +120,7 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
type converter struct{}
-func (converter) ConvertValue(v interface{}) (driver.Value, error) {
+func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
if driver.IsValue(v) {
return v, nil
}
@@ -131,7 +132,7 @@ func (converter) ConvertValue(v interface{}) (driver.Value, error) {
if rv.IsNil() {
return nil, nil
}
- return driver.DefaultParameterConverter.ConvertValue(rv.Elem().Interface())
+ return c.ConvertValue(rv.Elem().Interface())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return rv.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
@@ -139,7 +140,7 @@ func (converter) ConvertValue(v interface{}) (driver.Value, error) {
case reflect.Uint64:
u64 := rv.Uint()
if u64 >= 1<<63 {
- return fmt.Sprintf("%d", u64), nil
+ return strconv.FormatUint(u64, 10), nil
}
return int64(u64), nil
case reflect.Float32, reflect.Float64:
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go
index 6693d2970..6a26ad129 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go
@@ -80,8 +80,6 @@ func parseDSN(dsn string) (cfg *config, err error) {
collation: defaultCollation,
}
- // TODO: use strings.IndexByte when we can depend on Go 1.2
-
// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]
// Find the last '/' (since the password or the net addr might contain a '/')
foundSlash := false
@@ -201,6 +199,14 @@ func parseDSNParams(cfg *config, params string) (err error) {
return fmt.Errorf("Invalid Bool value: %s", value)
}
+ // Use cleartext authentication mode (MySQL 5.5.10+)
+ case "allowCleartextPasswords":
+ var isBool bool
+ cfg.allowCleartextPasswords, isBool = readBool(value)
+ if !isBool {
+ return fmt.Errorf("Invalid Bool value: %s", value)
+ }
+
// Use old authentication mode (pre MySQL 4.1)
case "allowOldPasswords":
var isBool bool
@@ -771,6 +777,10 @@ func skipLengthEncodedString(b []byte) (int, error) {
// returns the number read, whether the value is NULL and the number of bytes read
func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
+ // See issue #349
+ if len(b) == 0 {
+ return 0, true, 1
+ }
switch b[0] {
// 251: NULL
diff --git a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go
index adb8dcbd1..79fbdd1eb 100644
--- a/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go
+++ b/Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go
@@ -22,19 +22,19 @@ var testDSNs = []struct {
out string
loc *time.Location
}{
- {"username:password@protocol(address)/dbname?param=value", "&{user:username passwd:password net:protocol addr:address dbname:dbname params:map[param:value] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{user:username passwd:password net:protocol addr:address dbname:dbname params:map[param:value] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:true interpolateParams:false}", time.UTC},
- {"user@unix(/path/to/socket)/dbname?charset=utf8", "&{user:user passwd: net:unix addr:/path/to/socket dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8mb4,utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"user:password@/dbname?loc=UTC&timeout=30s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{user:user passwd:password net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:30000000000 collation:224 allowAllFiles:true allowOldPasswords:true clientFoundRows:true columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{user:user passwd:p@ss(word) net:tcp addr:[de:ad:be:ef::ca:fe]:80 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.Local},
- {"/dbname", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"@/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"user:p@/ssword@/", "&{user:user passwd:p@/ssword net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
- {"unix/?arg=%2Fsome%2Fpath.ext", "&{user: passwd: net:unix addr:/tmp/mysql.sock dbname: params:map[arg:/some/path.ext] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"username:password@protocol(address)/dbname?param=value", "&{user:username passwd:password net:protocol addr:address dbname:dbname params:map[param:value] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{user:username passwd:password net:protocol addr:address dbname:dbname params:map[param:value] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:true interpolateParams:false}", time.UTC},
+ {"user@unix(/path/to/socket)/dbname?charset=utf8", "&{user:user passwd: net:unix addr:/path/to/socket dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8mb4,utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"user:password@/dbname?loc=UTC&timeout=30s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{user:user passwd:password net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:30000000000 collation:224 allowAllFiles:true allowOldPasswords:true allowCleartextPasswords:false clientFoundRows:true columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{user:user passwd:p@ss(word) net:tcp addr:[de:ad:be:ef::ca:fe]:80 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.Local},
+ {"/dbname", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"@/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"user:p@/ssword@/", "&{user:user passwd:p@/ssword net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
+ {"unix/?arg=%2Fsome%2Fpath.ext", "&{user: passwd: net:unix addr:/tmp/mysql.sock dbname: params:map[arg:/some/path.ext] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false allowCleartextPasswords:false clientFoundRows:false columnsWithAlias:false interpolateParams:false}", time.UTC},
}
func TestDSNParser(t *testing.T) {