mirror of
https://github.com/documize/community.git
synced 2025-07-19 21:29:42 +02:00
updated mysql driver and fixed pinned card scrolling
This commit is contained in:
parent
5cd4497467
commit
b6f74069b5
20 changed files with 1308 additions and 739 deletions
|
@ -8,13 +8,13 @@ The mission is to bring software dev inspired features (refactoring, testing, li
|
||||||
|
|
||||||
## Latest version
|
## Latest version
|
||||||
|
|
||||||
v0.37.0
|
v0.38.0
|
||||||
|
|
||||||
## OS Support
|
## OS Support
|
||||||
|
|
||||||
- Windows
|
- Windows
|
||||||
- Linux
|
- Linux
|
||||||
- OSX
|
- macOS
|
||||||
|
|
||||||
## Tech stack
|
## Tech stack
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,9 @@
|
||||||
top: 220px;
|
top: 220px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 80px;
|
||||||
overflow: scroll;
|
overflow-x: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
> .pin {
|
> .pin {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "documize",
|
"name": "documize",
|
||||||
"version": "0.37.0",
|
"version": "0.38.0",
|
||||||
"description": "The Document IDE",
|
"description": "The Document IDE",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "",
|
"repository": "",
|
||||||
|
|
|
@ -26,7 +26,7 @@ type ProdInfo struct {
|
||||||
// Product returns product edition details
|
// Product returns product edition details
|
||||||
func Product() (p ProdInfo) {
|
func Product() (p ProdInfo) {
|
||||||
p.Major = "0"
|
p.Major = "0"
|
||||||
p.Minor = "37"
|
p.Minor = "38"
|
||||||
p.Patch = "0"
|
p.Patch = "0"
|
||||||
p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch)
|
p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch)
|
||||||
p.Edition = "Community"
|
p.Edition = "Community"
|
||||||
|
|
File diff suppressed because one or more lines are too long
4
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
4
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
|
@ -31,19 +31,23 @@ Julien Lefevre <julien.lefevr at gmail.com>
|
||||||
Julien Schmidt <go-sql-driver at julienschmidt.com>
|
Julien Schmidt <go-sql-driver at julienschmidt.com>
|
||||||
Kamil Dziedzic <kamil at klecza.pl>
|
Kamil Dziedzic <kamil at klecza.pl>
|
||||||
Kevin Malachowski <kevin at chowski.com>
|
Kevin Malachowski <kevin at chowski.com>
|
||||||
|
Lennart Rudolph <lrudolph at hmc.edu>
|
||||||
Leonardo YongUk Kim <dalinaum at gmail.com>
|
Leonardo YongUk Kim <dalinaum at gmail.com>
|
||||||
Luca Looz <luca.looz92 at gmail.com>
|
Luca Looz <luca.looz92 at gmail.com>
|
||||||
Lucas Liu <extrafliu at gmail.com>
|
Lucas Liu <extrafliu at gmail.com>
|
||||||
Luke Scott <luke at webconnex.com>
|
Luke Scott <luke at webconnex.com>
|
||||||
Michael Woolnough <michael.woolnough at gmail.com>
|
Michael Woolnough <michael.woolnough at gmail.com>
|
||||||
Nicola Peduzzi <thenikso at gmail.com>
|
Nicola Peduzzi <thenikso at gmail.com>
|
||||||
|
Olivier Mengué <dolmen at cpan.org>
|
||||||
Paul Bonser <misterpib at gmail.com>
|
Paul Bonser <misterpib at gmail.com>
|
||||||
Runrioter Wung <runrioter at gmail.com>
|
Runrioter Wung <runrioter 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>
|
||||||
|
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>
|
||||||
|
Zhenye Xie <xiezhenye at gmail.com>
|
||||||
|
|
||||||
# Organizations
|
# Organizations
|
||||||
|
|
||||||
|
|
38
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
38
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
|
@ -1,18 +1,35 @@
|
||||||
## HEAD
|
## Version 1.3 (2016-12-01)
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
|
|
||||||
- Go 1.1 is no longer supported
|
- Go 1.1 is no longer supported
|
||||||
- Use decimals field from MySQL to format time types (#249)
|
- Use decimals fields in MySQL to format time types (#249)
|
||||||
- Buffer optimizations (#269)
|
- Buffer optimizations (#269)
|
||||||
- TLS ServerName defaults to the host (#283)
|
- TLS ServerName defaults to the host (#283)
|
||||||
|
- Refactoring (#400, #410, #437)
|
||||||
|
- Adjusted documentation for second generation CloudSQL (#485)
|
||||||
|
- Documented DSN system var quoting rules (#502)
|
||||||
|
- Made statement.Close() calls idempotent to avoid errors in Go 1.6+ (#512)
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
|
||||||
|
- Support for returning table alias on Columns() (#289, #359, #382)
|
||||||
|
- Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318, #490)
|
||||||
|
- Support for uint64 parameters with high bit set (#332, #345)
|
||||||
|
- Cleartext authentication plugin support (#327)
|
||||||
|
- Exported ParseDSN function and the Config struct (#403, #419, #429)
|
||||||
|
- Read / Write timeouts (#401)
|
||||||
|
- Support for JSON field type (#414)
|
||||||
|
- Support for multi-statements and multi-results (#411, #431)
|
||||||
|
- DSN parameter to set the driver-side max_allowed_packet value manually (#489)
|
||||||
|
- Native password authentication plugin support (#494, #524)
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
|
|
||||||
- Fixed handling of queries without columns and rows (#255)
|
- Fixed handling of queries without columns and rows (#255)
|
||||||
- Fixed a panic when SetKeepAlive() failed (#298)
|
- Fixed a panic when SetKeepAlive() failed (#298)
|
||||||
- Support receiving ERR packet while reading rows (#321)
|
- Handle ERR packets while reading rows (#321)
|
||||||
- Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)
|
- Fixed reading NULL length-encoded integers in MySQL 5.6+ (#349)
|
||||||
- Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)
|
- Fixed absolute paths support in LOAD LOCAL DATA INFILE (#356)
|
||||||
- Actually zero out bytes in handshake response (#378)
|
- Actually zero out bytes in handshake response (#378)
|
||||||
|
@ -20,13 +37,12 @@ Bugfixes:
|
||||||
- Fixed tests with MySQL 5.7.9+ (#380)
|
- Fixed tests with MySQL 5.7.9+ (#380)
|
||||||
- QueryUnescape TLS config names (#397)
|
- QueryUnescape TLS config names (#397)
|
||||||
- Fixed "broken pipe" error by writing to closed socket (#390)
|
- Fixed "broken pipe" error by writing to closed socket (#390)
|
||||||
|
- Fixed LOAD LOCAL DATA INFILE buffering (#424)
|
||||||
New Features:
|
- Fixed parsing of floats into float64 when placeholders are used (#434)
|
||||||
- Support for returning table alias on Columns() (#289, #359, #382)
|
- Fixed DSN tests with Go 1.7+ (#459)
|
||||||
- Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318)
|
- Handle ERR packets while waiting for EOF (#473)
|
||||||
- Support for uint64 parameters with high bit set (#332, #345)
|
- Invalidate connection on error while discarding additional results (#513)
|
||||||
- Cleartext authentication plugin support (#327)
|
- Allow terminating packets of length 0 (#516)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Version 1.2 (2014-06-03)
|
## Version 1.2 (2014-06-03)
|
||||||
|
|
61
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
61
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
|
@ -4,10 +4,6 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**Latest stable Release:** [Version 1.2 (June 03, 2014)](https://github.com/go-sql-driver/mysql/releases)
|
|
||||||
|
|
||||||
[](https://travis-ci.org/go-sql-driver/mysql)
|
|
||||||
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
* [Features](#features)
|
* [Features](#features)
|
||||||
* [Requirements](#requirements)
|
* [Requirements](#requirements)
|
||||||
|
@ -135,6 +131,15 @@ 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.
|
`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.
|
||||||
|
|
||||||
|
##### `allowNativePasswords`
|
||||||
|
|
||||||
|
```
|
||||||
|
Type: bool
|
||||||
|
Valid Values: true, false
|
||||||
|
Default: false
|
||||||
|
```
|
||||||
|
`allowNativePasswords=true` allows the usage of the mysql native password method.
|
||||||
|
|
||||||
##### `allowOldPasswords`
|
##### `allowOldPasswords`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -221,6 +226,14 @@ Note that this sets the location for time.Time values but does not change MySQL'
|
||||||
|
|
||||||
Please keep in mind, that param values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.
|
Please keep in mind, that param values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.
|
||||||
|
|
||||||
|
##### `maxAllowedPacket`
|
||||||
|
```
|
||||||
|
Type: decimal number
|
||||||
|
Default: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Max packet size allowed in bytes. Use `maxAllowedPacket=0` to automatically fetch the `max_allowed_packet` variable from server.
|
||||||
|
|
||||||
##### `multiStatements`
|
##### `multiStatements`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -233,7 +246,6 @@ Allow multiple statements in one query. While this allows batch queries, it also
|
||||||
|
|
||||||
When `multiStatements` is used, `?` parameters must only be used in the first statement.
|
When `multiStatements` is used, `?` parameters must only be used in the first statement.
|
||||||
|
|
||||||
|
|
||||||
##### `parseTime`
|
##### `parseTime`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -254,7 +266,6 @@ Default: 0
|
||||||
|
|
||||||
I/O read timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*.
|
I/O read timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*.
|
||||||
|
|
||||||
|
|
||||||
##### `strict`
|
##### `strict`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -263,10 +274,11 @@ Valid Values: true, false
|
||||||
Default: false
|
Default: false
|
||||||
```
|
```
|
||||||
|
|
||||||
`strict=true` enables the strict mode in which MySQL warnings are treated as errors.
|
`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations.
|
||||||
|
|
||||||
By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes. See the [examples](#examples) for an DSN example.
|
A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable.
|
||||||
|
|
||||||
|
By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes.
|
||||||
|
|
||||||
##### `timeout`
|
##### `timeout`
|
||||||
|
|
||||||
|
@ -277,7 +289,6 @@ Default: OS default
|
||||||
|
|
||||||
*Driver* side connection timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout).
|
*Driver* side connection timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout).
|
||||||
|
|
||||||
|
|
||||||
##### `tls`
|
##### `tls`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -288,7 +299,6 @@ Default: false
|
||||||
|
|
||||||
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](http://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
|
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](http://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
|
||||||
|
|
||||||
|
|
||||||
##### `writeTimeout`
|
##### `writeTimeout`
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -301,13 +311,21 @@ I/O write timeout. The value must be a decimal number with an unit suffix ( *"ms
|
||||||
|
|
||||||
##### System Variables
|
##### System Variables
|
||||||
|
|
||||||
All other parameters are interpreted as system variables:
|
Any other parameters are interpreted as system variables:
|
||||||
* `autocommit`: `"SET autocommit=<value>"`
|
* `<boolean_var>=<value>`: `SET <boolean_var>=<value>`
|
||||||
* [`time_zone`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `"SET time_zone=<value>"`
|
* `<enum_var>=<value>`: `SET <enum_var>=<value>`
|
||||||
* [`tx_isolation`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `"SET tx_isolation=<value>"`
|
* `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`
|
||||||
* `param`: `"SET <param>=<value>"`
|
|
||||||
|
Rules:
|
||||||
|
* The values for string variables must be quoted with '
|
||||||
|
* The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
|
||||||
|
(which implies values of string variables must be wrapped with `%27`)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
* `autocommit=1`: `SET autocommit=1`
|
||||||
|
* [`time_zone=%27Europe%2FParis%27`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `SET time_zone='Europe/Paris'`
|
||||||
|
* [`tx_isolation=%27REPEATABLE-READ%27`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `SET tx_isolation='REPEATABLE-READ'`
|
||||||
|
|
||||||
*The values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!*
|
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
```
|
```
|
||||||
|
@ -322,9 +340,9 @@ root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local
|
||||||
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
|
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the [strict mode](#strict) but ignore notes:
|
Treat warnings as errors by setting the system variable [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html):
|
||||||
```
|
```
|
||||||
user:password@/dbname?strict=true&sql_notes=false
|
user:password@/dbname?sql_mode=TRADITIONAL
|
||||||
```
|
```
|
||||||
|
|
||||||
TCP via IPv6:
|
TCP via IPv6:
|
||||||
|
@ -337,11 +355,16 @@ TCP on a remote host, e.g. Amazon RDS:
|
||||||
id:password@tcp(your-amazonaws-uri.com:3306)/dbname
|
id:password@tcp(your-amazonaws-uri.com:3306)/dbname
|
||||||
```
|
```
|
||||||
|
|
||||||
Google Cloud SQL on App Engine:
|
Google Cloud SQL on App Engine (First Generation MySQL Server):
|
||||||
```
|
```
|
||||||
user@cloudsql(project-id:instance-name)/dbname
|
user@cloudsql(project-id:instance-name)/dbname
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Google Cloud SQL on App Engine (Second Generation MySQL Server):
|
||||||
|
```
|
||||||
|
user@cloudsql(project-id:regionname:instance-name)/dbname
|
||||||
|
```
|
||||||
|
|
||||||
TCP using default port (3306) on localhost:
|
TCP using default port (3306) on localhost:
|
||||||
```
|
```
|
||||||
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
|
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
|
||||||
|
|
2
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
2
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
|
@ -220,7 +220,7 @@ func BenchmarkInterpolation(b *testing.B) {
|
||||||
InterpolateParams: true,
|
InterpolateParams: true,
|
||||||
Loc: time.UTC,
|
Loc: time.UTC,
|
||||||
},
|
},
|
||||||
maxPacketAllowed: maxPacketSize,
|
maxAllowedPacket: maxPacketSize,
|
||||||
maxWriteSize: maxPacketSize - 1,
|
maxWriteSize: maxPacketSize - 1,
|
||||||
buf: newBuffer(nil),
|
buf: newBuffer(nil),
|
||||||
}
|
}
|
||||||
|
|
9
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
9
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
|
@ -22,7 +22,7 @@ type mysqlConn struct {
|
||||||
affectedRows uint64
|
affectedRows uint64
|
||||||
insertId uint64
|
insertId uint64
|
||||||
cfg *Config
|
cfg *Config
|
||||||
maxPacketAllowed int
|
maxAllowedPacket int
|
||||||
maxWriteSize int
|
maxWriteSize int
|
||||||
writeTimeout time.Duration
|
writeTimeout time.Duration
|
||||||
flags clientFlag
|
flags clientFlag
|
||||||
|
@ -135,6 +135,11 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
|
func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) {
|
||||||
|
// Number of ? should be same to len(args)
|
||||||
|
if strings.Count(query, "?") != len(args) {
|
||||||
|
return "", driver.ErrSkip
|
||||||
|
}
|
||||||
|
|
||||||
buf := mc.buf.takeCompleteBuffer()
|
buf := mc.buf.takeCompleteBuffer()
|
||||||
if buf == nil {
|
if buf == 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
|
||||||
|
@ -241,7 +246,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||||
return "", driver.ErrSkip
|
return "", driver.ErrSkip
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(buf)+4 > mc.maxPacketAllowed {
|
if len(buf)+4 > mc.maxAllowedPacket {
|
||||||
return "", driver.ErrSkip
|
return "", driver.ErrSkip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
67
vendor/github.com/go-sql-driver/mysql/connection_test.go
generated
vendored
Normal file
67
vendor/github.com/go-sql-driver/mysql/connection_test.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||||
|
//
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"database/sql/driver"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInterpolateParams(t *testing.T) {
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(nil),
|
||||||
|
maxAllowedPacket: maxPacketSize,
|
||||||
|
cfg: &Config{
|
||||||
|
InterpolateParams: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42), "gopher"})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected err=nil, got %#v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expected := `SELECT 42+'gopher'`
|
||||||
|
if q != expected {
|
||||||
|
t.Errorf("Expected: %q\nGot: %q", expected, q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInterpolateParamsTooManyPlaceholders(t *testing.T) {
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(nil),
|
||||||
|
maxAllowedPacket: maxPacketSize,
|
||||||
|
cfg: &Config{
|
||||||
|
InterpolateParams: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := mc.interpolateParams("SELECT ?+?", []driver.Value{int64(42)})
|
||||||
|
if err != driver.ErrSkip {
|
||||||
|
t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't support placeholder in string literal for now.
|
||||||
|
// https://github.com/go-sql-driver/mysql/pull/490
|
||||||
|
func TestInterpolateParamsPlaceholderInString(t *testing.T) {
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(nil),
|
||||||
|
maxAllowedPacket: maxPacketSize,
|
||||||
|
cfg: &Config{
|
||||||
|
InterpolateParams: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := mc.interpolateParams("SELECT 'abc?xyz',?", []driver.Value{int64(42)})
|
||||||
|
// When InterpolateParams support string literal, this should return `"SELECT 'abc?xyz', 42`
|
||||||
|
if err != driver.ErrSkip {
|
||||||
|
t.Errorf("Expected err=driver.ErrSkip, got err=%#v, q=%#v", err, q)
|
||||||
|
}
|
||||||
|
}
|
32
vendor/github.com/go-sql-driver/mysql/driver.go
generated
vendored
32
vendor/github.com/go-sql-driver/mysql/driver.go
generated
vendored
|
@ -50,7 +50,7 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
|
|
||||||
// New mysqlConn
|
// New mysqlConn
|
||||||
mc := &mysqlConn{
|
mc := &mysqlConn{
|
||||||
maxPacketAllowed: maxPacketSize,
|
maxAllowedPacket: maxPacketSize,
|
||||||
maxWriteSize: maxPacketSize - 1,
|
maxWriteSize: maxPacketSize - 1,
|
||||||
}
|
}
|
||||||
mc.cfg, err = ParseDSN(dsn)
|
mc.cfg, err = ParseDSN(dsn)
|
||||||
|
@ -109,15 +109,19 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mc.cfg.MaxAllowedPacket > 0 {
|
||||||
|
mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
|
||||||
|
} else {
|
||||||
// Get max allowed packet size
|
// Get max allowed packet size
|
||||||
maxap, err := mc.getSystemVar("max_allowed_packet")
|
maxap, err := mc.getSystemVar("max_allowed_packet")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mc.Close()
|
mc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mc.maxPacketAllowed = stringToInt(maxap) - 1
|
mc.maxAllowedPacket = stringToInt(maxap) - 1
|
||||||
if mc.maxPacketAllowed < maxPacketSize {
|
}
|
||||||
mc.maxWriteSize = mc.maxPacketAllowed
|
if mc.maxAllowedPacket < maxPacketSize {
|
||||||
|
mc.maxWriteSize = mc.maxAllowedPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle DSN Params
|
// Handle DSN Params
|
||||||
|
@ -130,9 +134,9 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
return mc, nil
|
return mc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAuthResult(mc *mysqlConn, cipher []byte) error {
|
func handleAuthResult(mc *mysqlConn, oldCipher []byte) error {
|
||||||
// Read Result Packet
|
// Read Result Packet
|
||||||
err := mc.readResultOK()
|
cipher, err := mc.readResultOK()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil // auth successful
|
return nil // auth successful
|
||||||
}
|
}
|
||||||
|
@ -146,10 +150,17 @@ func handleAuthResult(mc *mysqlConn, cipher []byte) error {
|
||||||
// Retry with old authentication method. Note: there are edge cases
|
// Retry with old authentication method. Note: there are edge cases
|
||||||
// where this should work but doesn't; this is currently "wontfix":
|
// where this should work but doesn't; this is currently "wontfix":
|
||||||
// https://github.com/go-sql-driver/mysql/issues/184
|
// https://github.com/go-sql-driver/mysql/issues/184
|
||||||
|
|
||||||
|
// If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is
|
||||||
|
// sent and we have to keep using the cipher sent in the init packet.
|
||||||
|
if cipher == nil {
|
||||||
|
cipher = oldCipher
|
||||||
|
}
|
||||||
|
|
||||||
if err = mc.writeOldAuthPacket(cipher); err != nil {
|
if err = mc.writeOldAuthPacket(cipher); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mc.readResultOK()
|
_, err = mc.readResultOK()
|
||||||
} else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {
|
} else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {
|
||||||
// Retry with clear text password for
|
// Retry with clear text password for
|
||||||
// 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
|
||||||
|
@ -157,7 +168,12 @@ func handleAuthResult(mc *mysqlConn, cipher []byte) error {
|
||||||
if err = mc.writeClearAuthPacket(); err != nil {
|
if err = mc.writeClearAuthPacket(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = mc.readResultOK()
|
_, err = mc.readResultOK()
|
||||||
|
} else if mc.cfg.AllowNativePasswords && err == ErrNativePassword {
|
||||||
|
if err = mc.writeNativeAuthPacket(cipher); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = mc.readResultOK()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
47
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
47
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
|
@ -1855,3 +1855,50 @@ func TestUnixSocketAuthFail(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See Issue #422
|
||||||
|
func TestInterruptBySignal(t *testing.T) {
|
||||||
|
runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) {
|
||||||
|
dbt.mustExec(`
|
||||||
|
DROP PROCEDURE IF EXISTS test_signal;
|
||||||
|
CREATE PROCEDURE test_signal(ret INT)
|
||||||
|
BEGIN
|
||||||
|
SELECT ret;
|
||||||
|
SIGNAL SQLSTATE
|
||||||
|
'45001'
|
||||||
|
SET
|
||||||
|
MESSAGE_TEXT = "an error",
|
||||||
|
MYSQL_ERRNO = 45001;
|
||||||
|
END
|
||||||
|
`)
|
||||||
|
defer dbt.mustExec("DROP PROCEDURE test_signal")
|
||||||
|
|
||||||
|
var val int
|
||||||
|
|
||||||
|
// text protocol
|
||||||
|
rows, err := dbt.db.Query("CALL test_signal(42)")
|
||||||
|
if err != nil {
|
||||||
|
dbt.Fatalf("error on text query: %s", err.Error())
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
if err := rows.Scan(&val); err != nil {
|
||||||
|
dbt.Error(err)
|
||||||
|
} else if val != 42 {
|
||||||
|
dbt.Errorf("expected val to be 42")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary protocol
|
||||||
|
rows, err = dbt.db.Query("CALL test_signal(?)", 42)
|
||||||
|
if err != nil {
|
||||||
|
dbt.Fatalf("error on binary query: %s", err.Error())
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
if err := rows.Scan(&val); err != nil {
|
||||||
|
dbt.Error(err)
|
||||||
|
} else if val != 42 {
|
||||||
|
dbt.Errorf("expected val to be 42")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
37
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
37
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
|
@ -15,6 +15,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -36,6 +37,7 @@ type Config struct {
|
||||||
Params map[string]string // Connection parameters
|
Params map[string]string // Connection parameters
|
||||||
Collation string // Connection collation
|
Collation string // Connection collation
|
||||||
Loc *time.Location // Location for time.Time values
|
Loc *time.Location // Location for time.Time values
|
||||||
|
MaxAllowedPacket int // Max packet size allowed
|
||||||
TLSConfig string // TLS configuration name
|
TLSConfig string // TLS configuration name
|
||||||
tls *tls.Config // TLS configuration
|
tls *tls.Config // TLS configuration
|
||||||
Timeout time.Duration // Dial timeout
|
Timeout time.Duration // Dial timeout
|
||||||
|
@ -44,6 +46,7 @@ type Config struct {
|
||||||
|
|
||||||
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
|
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
|
||||||
AllowCleartextPasswords bool // Allows the cleartext client side plugin
|
AllowCleartextPasswords bool // Allows the cleartext client side plugin
|
||||||
|
AllowNativePasswords bool // Allows the native password authentication method
|
||||||
AllowOldPasswords bool // Allows the old insecure password method
|
AllowOldPasswords bool // Allows the old insecure password method
|
||||||
ClientFoundRows bool // Return number of matching rows instead of rows changed
|
ClientFoundRows bool // Return number of matching rows instead of rows changed
|
||||||
ColumnsWithAlias bool // Prepend table alias to column names
|
ColumnsWithAlias bool // Prepend table alias to column names
|
||||||
|
@ -99,6 +102,15 @@ func (cfg *Config) FormatDSN() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.AllowNativePasswords {
|
||||||
|
if hasParam {
|
||||||
|
buf.WriteString("&allowNativePasswords=true")
|
||||||
|
} else {
|
||||||
|
hasParam = true
|
||||||
|
buf.WriteString("?allowNativePasswords=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.AllowOldPasswords {
|
if cfg.AllowOldPasswords {
|
||||||
if hasParam {
|
if hasParam {
|
||||||
buf.WriteString("&allowOldPasswords=true")
|
buf.WriteString("&allowOldPasswords=true")
|
||||||
|
@ -222,6 +234,17 @@ func (cfg *Config) FormatDSN() string {
|
||||||
buf.WriteString(cfg.WriteTimeout.String())
|
buf.WriteString(cfg.WriteTimeout.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.MaxAllowedPacket > 0 {
|
||||||
|
if hasParam {
|
||||||
|
buf.WriteString("&maxAllowedPacket=")
|
||||||
|
} else {
|
||||||
|
hasParam = true
|
||||||
|
buf.WriteString("?maxAllowedPacket=")
|
||||||
|
}
|
||||||
|
buf.WriteString(strconv.Itoa(cfg.MaxAllowedPacket))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// other params
|
// other params
|
||||||
if cfg.Params != nil {
|
if cfg.Params != nil {
|
||||||
for param, value := range cfg.Params {
|
for param, value := range cfg.Params {
|
||||||
|
@ -368,6 +391,14 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||||
return errors.New("invalid bool value: " + value)
|
return errors.New("invalid bool value: " + value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use native password authentication
|
||||||
|
case "allowNativePasswords":
|
||||||
|
var isBool bool
|
||||||
|
cfg.AllowNativePasswords, isBool = readBool(value)
|
||||||
|
if !isBool {
|
||||||
|
return errors.New("invalid bool value: " + value)
|
||||||
|
}
|
||||||
|
|
||||||
// Use old authentication mode (pre MySQL 4.1)
|
// Use old authentication mode (pre MySQL 4.1)
|
||||||
case "allowOldPasswords":
|
case "allowOldPasswords":
|
||||||
var isBool bool
|
var isBool bool
|
||||||
|
@ -496,7 +527,11 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case "maxAllowedPacket":
|
||||||
|
cfg.MaxAllowedPacket, err = strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// lazy init
|
// lazy init
|
||||||
if cfg.Params == nil {
|
if cfg.Params == nil {
|
||||||
|
|
74
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
74
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
|
@ -12,36 +12,61 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testDSNs = []struct {
|
var testDSNs = []struct {
|
||||||
in string
|
in string
|
||||||
out string
|
out *Config
|
||||||
}{
|
}{{
|
||||||
{"username:password@protocol(address)/dbname?param=value", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
"username:password@protocol(address)/dbname?param=value",
|
||||||
{"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
&Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
{"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:true ParseTime:false Strict:false}"},
|
}, {
|
||||||
{"user@unix(/path/to/socket)/dbname?charset=utf8", "&{User:user Passwd: Net:unix Addr:/path/to/socket DBName:dbname Params:map[charset:utf8] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true",
|
||||||
{"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] Collation:utf8_general_ci Loc:UTC TLSConfig:true tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
&Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, ColumnsWithAlias: true},
|
||||||
{"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] Collation:utf8_general_ci Loc:UTC TLSConfig:skip-verify tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
}, {
|
||||||
{"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&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[] Collation:utf8mb4_unicode_ci Loc:UTC TLSConfig: tls:<nil> Timeout:30s ReadTimeout:1s WriteTimeout:1s AllowAllFiles:true AllowCleartextPasswords:false AllowOldPasswords:true ClientFoundRows:true ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true",
|
||||||
{"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[] Collation:utf8_general_ci Loc:Local TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
&Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, ColumnsWithAlias: true, MultiStatements: true},
|
||||||
{"/dbname", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
}, {
|
||||||
{"@/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
"user@unix(/path/to/socket)/dbname?charset=utf8",
|
||||||
{"/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
&Config{User: "user", Net: "unix", Addr: "/path/to/socket", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
{"", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
}, {
|
||||||
{"user:p@/ssword@/", "&{User:user Passwd:p@/ssword Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true",
|
||||||
{"unix/?arg=%2Fsome%2Fpath.ext", "&{User: Passwd: Net:unix Addr:/tmp/mysql.sock DBName: Params:map[arg:/some/path.ext] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
|
&Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, TLSConfig: "true"},
|
||||||
}
|
}, {
|
||||||
|
"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify",
|
||||||
|
&Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8mb4,utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, TLSConfig: "skip-verify"},
|
||||||
|
}, {
|
||||||
|
"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci&maxAllowedPacket=16777216",
|
||||||
|
&Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_unicode_ci", Loc: time.UTC, Timeout: 30 * time.Second, ReadTimeout: time.Second, WriteTimeout: time.Second, AllowAllFiles: true, AllowOldPasswords: true, ClientFoundRows: true, MaxAllowedPacket: 16777216},
|
||||||
|
}, {
|
||||||
|
"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local",
|
||||||
|
&Config{User: "user", Passwd: "p@ss(word)", Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:80", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.Local},
|
||||||
|
}, {
|
||||||
|
"/dbname",
|
||||||
|
&Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}, {
|
||||||
|
"@/",
|
||||||
|
&Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}, {
|
||||||
|
"/",
|
||||||
|
&Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}, {
|
||||||
|
"",
|
||||||
|
&Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}, {
|
||||||
|
"user:p@/ssword@/",
|
||||||
|
&Config{User: "user", Passwd: "p@/ssword", Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}, {
|
||||||
|
"unix/?arg=%2Fsome%2Fpath.ext",
|
||||||
|
&Config{Net: "unix", Addr: "/tmp/mysql.sock", Params: map[string]string{"arg": "/some/path.ext"}, Collation: "utf8_general_ci", Loc: time.UTC},
|
||||||
|
}}
|
||||||
|
|
||||||
func TestDSNParser(t *testing.T) {
|
func TestDSNParser(t *testing.T) {
|
||||||
var cfg *Config
|
|
||||||
var err error
|
|
||||||
var res string
|
|
||||||
|
|
||||||
for i, tst := range testDSNs {
|
for i, tst := range testDSNs {
|
||||||
cfg, err = ParseDSN(tst.in)
|
cfg, err := ParseDSN(tst.in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err.Error())
|
t.Error(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -49,9 +74,8 @@ func TestDSNParser(t *testing.T) {
|
||||||
// pointer not static
|
// pointer not static
|
||||||
cfg.tls = nil
|
cfg.tls = nil
|
||||||
|
|
||||||
res = fmt.Sprintf("%+v", cfg)
|
if !reflect.DeepEqual(cfg, tst.out) {
|
||||||
if res != tst.out {
|
t.Errorf("%d. ParseDSN(%q) mismatch:\ngot %+v\nwant %+v", i, tst.in, cfg, tst.out)
|
||||||
t.Errorf("%d. ParseDSN(%q) => %q, want %q", i, tst.in, res, tst.out)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/go-sql-driver/mysql/errors.go
generated
vendored
3
vendor/github.com/go-sql-driver/mysql/errors.go
generated
vendored
|
@ -22,8 +22,9 @@ var (
|
||||||
ErrInvalidConn = errors.New("invalid connection")
|
ErrInvalidConn = errors.New("invalid connection")
|
||||||
ErrMalformPkt = errors.New("malformed packet")
|
ErrMalformPkt = errors.New("malformed packet")
|
||||||
ErrNoTLS = errors.New("TLS requested but server does not support TLS")
|
ErrNoTLS = errors.New("TLS 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")
|
ErrCleartextPassword = errors.New("this user requires clear text authentication. If you still want to use it, please add 'allowCleartextPasswords=1' to your DSN")
|
||||||
|
ErrNativePassword = errors.New("this user requires mysql native password authentication.")
|
||||||
|
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")
|
||||||
ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
|
ErrUnknownPlugin = errors.New("this authentication plugin is not supported")
|
||||||
ErrOldProtocol = errors.New("MySQL server does not support required protocol 41+")
|
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")
|
ErrPktSync = errors.New("commands out of sync. You can't run this command now")
|
||||||
|
|
3
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
3
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
|
@ -173,7 +173,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||||
|
|
||||||
// read OK packet
|
// read OK packet
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return mc.readResultOK()
|
_, err = mc.readResultOK()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mc.readPacket()
|
mc.readPacket()
|
||||||
|
|
134
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
134
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
|
@ -25,9 +25,9 @@ import (
|
||||||
|
|
||||||
// Read packet to buffer 'data'
|
// Read packet to buffer 'data'
|
||||||
func (mc *mysqlConn) readPacket() ([]byte, error) {
|
func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||||
var payload []byte
|
var prevData []byte
|
||||||
for {
|
for {
|
||||||
// Read packet header
|
// read packet header
|
||||||
data, err := mc.buf.readNext(4)
|
data, err := mc.buf.readNext(4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLog.Print(err)
|
errLog.Print(err)
|
||||||
|
@ -35,16 +35,10 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||||
return nil, driver.ErrBadConn
|
return nil, driver.ErrBadConn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packet Length [24 bit]
|
// packet length [24 bit]
|
||||||
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
|
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
|
||||||
|
|
||||||
if pktLen < 1 {
|
// check packet sync [8 bit]
|
||||||
errLog.Print(ErrMalformPkt)
|
|
||||||
mc.Close()
|
|
||||||
return nil, driver.ErrBadConn
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Packet Sync [8 bit]
|
|
||||||
if data[3] != mc.sequence {
|
if data[3] != mc.sequence {
|
||||||
if data[3] > mc.sequence {
|
if data[3] > mc.sequence {
|
||||||
return nil, ErrPktSyncMul
|
return nil, ErrPktSyncMul
|
||||||
|
@ -53,7 +47,20 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||||
}
|
}
|
||||||
mc.sequence++
|
mc.sequence++
|
||||||
|
|
||||||
// Read packet body [pktLen bytes]
|
// packets with length 0 terminate a previous packet which is a
|
||||||
|
// multiple of (2^24)−1 bytes long
|
||||||
|
if pktLen == 0 {
|
||||||
|
// there was no previous packet
|
||||||
|
if prevData == nil {
|
||||||
|
errLog.Print(ErrMalformPkt)
|
||||||
|
mc.Close()
|
||||||
|
return nil, driver.ErrBadConn
|
||||||
|
}
|
||||||
|
|
||||||
|
return prevData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// read packet body [pktLen bytes]
|
||||||
data, err = mc.buf.readNext(pktLen)
|
data, err = mc.buf.readNext(pktLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLog.Print(err)
|
errLog.Print(err)
|
||||||
|
@ -61,18 +68,17 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||||
return nil, driver.ErrBadConn
|
return nil, driver.ErrBadConn
|
||||||
}
|
}
|
||||||
|
|
||||||
isLastPacket := (pktLen < maxPacketSize)
|
// return data if this was the last packet
|
||||||
|
if pktLen < maxPacketSize {
|
||||||
// Zero allocations for non-splitting packets
|
// zero allocations for non-split packets
|
||||||
if isLastPacket && payload == nil {
|
if prevData == nil {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
payload = append(payload, data...)
|
return append(prevData, data...), nil
|
||||||
|
|
||||||
if isLastPacket {
|
|
||||||
return payload, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prevData = append(prevData, data...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +86,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||||
func (mc *mysqlConn) writePacket(data []byte) error {
|
func (mc *mysqlConn) writePacket(data []byte) error {
|
||||||
pktLen := len(data) - 4
|
pktLen := len(data) - 4
|
||||||
|
|
||||||
if pktLen > mc.maxPacketAllowed {
|
if pktLen > mc.maxAllowedPacket {
|
||||||
return ErrPktTooLarge
|
return ErrPktTooLarge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,6 +378,26 @@ func (mc *mysqlConn) writeClearAuthPacket() error {
|
||||||
return mc.writePacket(data)
|
return mc.writePacket(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Native password authentication method
|
||||||
|
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
|
||||||
|
func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
|
||||||
|
scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))
|
||||||
|
|
||||||
|
// Calculate the packet length and add a tailing 0
|
||||||
|
pktLen := len(scrambleBuff)
|
||||||
|
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 scramble
|
||||||
|
copy(data[4:], scrambleBuff)
|
||||||
|
|
||||||
|
return mc.writePacket(data)
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Command Packets *
|
* Command Packets *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@ -445,36 +471,43 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// Returns error if Packet is not an 'Result OK'-Packet
|
// Returns error if Packet is not an 'Result OK'-Packet
|
||||||
func (mc *mysqlConn) readResultOK() error {
|
func (mc *mysqlConn) readResultOK() ([]byte, error) {
|
||||||
data, err := mc.readPacket()
|
data, err := mc.readPacket()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// packet indicator
|
// packet indicator
|
||||||
switch data[0] {
|
switch data[0] {
|
||||||
|
|
||||||
case iOK:
|
case iOK:
|
||||||
return mc.handleOkPacket(data)
|
return nil, mc.handleOkPacket(data)
|
||||||
|
|
||||||
case iEOF:
|
case iEOF:
|
||||||
if len(data) > 1 {
|
if len(data) > 1 {
|
||||||
plugin := string(data[1:bytes.IndexByte(data, 0x00)])
|
pluginEndIndex := bytes.IndexByte(data, 0x00)
|
||||||
|
plugin := string(data[1:pluginEndIndex])
|
||||||
|
cipher := data[pluginEndIndex+1 : len(data)-1]
|
||||||
|
|
||||||
if plugin == "mysql_old_password" {
|
if plugin == "mysql_old_password" {
|
||||||
// using old_passwords
|
// using old_passwords
|
||||||
return ErrOldPassword
|
return cipher, ErrOldPassword
|
||||||
} else if plugin == "mysql_clear_password" {
|
} else if plugin == "mysql_clear_password" {
|
||||||
// using clear text password
|
// using clear text password
|
||||||
return ErrCleartextPassword
|
return cipher, ErrCleartextPassword
|
||||||
|
} else if plugin == "mysql_native_password" {
|
||||||
|
// using mysql default authentication method
|
||||||
|
return cipher, ErrNativePassword
|
||||||
} else {
|
} else {
|
||||||
return ErrUnknownPlugin
|
return cipher, ErrUnknownPlugin
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ErrOldPassword
|
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
|
||||||
|
return nil, ErrOldPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // Error otherwise
|
default: // Error otherwise
|
||||||
return mc.handleErrorPacket(data)
|
return nil, mc.handleErrorPacket(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result Set Header Packet
|
// Result Set Header Packet
|
||||||
|
@ -674,11 +707,15 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||||
if data[0] == iEOF && len(data) == 5 {
|
if data[0] == iEOF && len(data) == 5 {
|
||||||
// server_status [2 bytes]
|
// server_status [2 bytes]
|
||||||
rows.mc.status = readStatus(data[3:])
|
rows.mc.status = readStatus(data[3:])
|
||||||
if err := rows.mc.discardResults(); err != nil {
|
err = rows.mc.discardResults()
|
||||||
return err
|
if err == nil {
|
||||||
|
err = io.EOF
|
||||||
|
} else {
|
||||||
|
// connection unusable
|
||||||
|
rows.mc.Close()
|
||||||
}
|
}
|
||||||
rows.mc = nil
|
rows.mc = nil
|
||||||
return io.EOF
|
return err
|
||||||
}
|
}
|
||||||
if data[0] == iERR {
|
if data[0] == iERR {
|
||||||
rows.mc = nil
|
rows.mc = nil
|
||||||
|
@ -729,16 +766,19 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||||
func (mc *mysqlConn) readUntilEOF() error {
|
func (mc *mysqlConn) readUntilEOF() error {
|
||||||
for {
|
for {
|
||||||
data, err := mc.readPacket()
|
data, err := mc.readPacket()
|
||||||
|
if err != nil {
|
||||||
// No Err and no EOF Packet
|
return err
|
||||||
if err == nil && data[0] != iEOF {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if err == nil && data[0] == iEOF && len(data) == 5 {
|
|
||||||
|
switch data[0] {
|
||||||
|
case iERR:
|
||||||
|
return mc.handleErrorPacket(data)
|
||||||
|
case iEOF:
|
||||||
|
if len(data) == 5 {
|
||||||
mc.status = readStatus(data[3:])
|
mc.status = readStatus(data[3:])
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
return err // Err or EOF
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +823,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
|
||||||
|
|
||||||
// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html
|
// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html
|
||||||
func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
||||||
maxLen := stmt.mc.maxPacketAllowed - 1
|
maxLen := stmt.mc.maxAllowedPacket - 1
|
||||||
pktLen := maxLen
|
pktLen := maxLen
|
||||||
|
|
||||||
// After the header (bytes 0-3) follows before the data:
|
// After the header (bytes 0-3) follows before the data:
|
||||||
|
@ -974,7 +1014,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||||
paramTypes[i+i] = fieldTypeString
|
paramTypes[i+i] = fieldTypeString
|
||||||
paramTypes[i+i+1] = 0x00
|
paramTypes[i+i+1] = 0x00
|
||||||
|
|
||||||
if len(v) < mc.maxPacketAllowed-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
||||||
paramValues = appendLengthEncodedInteger(paramValues,
|
paramValues = appendLengthEncodedInteger(paramValues,
|
||||||
uint64(len(v)),
|
uint64(len(v)),
|
||||||
)
|
)
|
||||||
|
@ -996,7 +1036,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||||
paramTypes[i+i] = fieldTypeString
|
paramTypes[i+i] = fieldTypeString
|
||||||
paramTypes[i+i+1] = 0x00
|
paramTypes[i+i+1] = 0x00
|
||||||
|
|
||||||
if len(v) < mc.maxPacketAllowed-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
||||||
paramValues = appendLengthEncodedInteger(paramValues,
|
paramValues = appendLengthEncodedInteger(paramValues,
|
||||||
uint64(len(v)),
|
uint64(len(v)),
|
||||||
)
|
)
|
||||||
|
@ -1076,11 +1116,15 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||||
// EOF Packet
|
// EOF Packet
|
||||||
if data[0] == iEOF && len(data) == 5 {
|
if data[0] == iEOF && len(data) == 5 {
|
||||||
rows.mc.status = readStatus(data[3:])
|
rows.mc.status = readStatus(data[3:])
|
||||||
if err := rows.mc.discardResults(); err != nil {
|
err = rows.mc.discardResults()
|
||||||
return err
|
if err == nil {
|
||||||
|
err = io.EOF
|
||||||
|
} else {
|
||||||
|
// connection unusable
|
||||||
|
rows.mc.Close()
|
||||||
}
|
}
|
||||||
rows.mc = nil
|
rows.mc = nil
|
||||||
return io.EOF
|
return err
|
||||||
}
|
}
|
||||||
rows.mc = nil
|
rows.mc = nil
|
||||||
|
|
||||||
|
|
282
vendor/github.com/go-sql-driver/mysql/packets_test.go
generated
vendored
Normal file
282
vendor/github.com/go-sql-driver/mysql/packets_test.go
generated
vendored
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||||
|
//
|
||||||
|
// Copyright 2016 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 (
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errConnClosed = errors.New("connection is closed")
|
||||||
|
errConnTooManyReads = errors.New("too many reads")
|
||||||
|
errConnTooManyWrites = errors.New("too many writes")
|
||||||
|
)
|
||||||
|
|
||||||
|
// struct to mock a net.Conn for testing purposes
|
||||||
|
type mockConn struct {
|
||||||
|
laddr net.Addr
|
||||||
|
raddr net.Addr
|
||||||
|
data []byte
|
||||||
|
closed bool
|
||||||
|
read int
|
||||||
|
written int
|
||||||
|
reads int
|
||||||
|
writes int
|
||||||
|
maxReads int
|
||||||
|
maxWrites int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockConn) Read(b []byte) (n int, err error) {
|
||||||
|
if m.closed {
|
||||||
|
return 0, errConnClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
m.reads++
|
||||||
|
if m.maxReads > 0 && m.reads > m.maxReads {
|
||||||
|
return 0, errConnTooManyReads
|
||||||
|
}
|
||||||
|
|
||||||
|
n = copy(b, m.data)
|
||||||
|
m.read += n
|
||||||
|
m.data = m.data[n:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (m *mockConn) Write(b []byte) (n int, err error) {
|
||||||
|
if m.closed {
|
||||||
|
return 0, errConnClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
m.writes++
|
||||||
|
if m.maxWrites > 0 && m.writes > m.maxWrites {
|
||||||
|
return 0, errConnTooManyWrites
|
||||||
|
}
|
||||||
|
|
||||||
|
n = len(b)
|
||||||
|
m.written += n
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (m *mockConn) Close() error {
|
||||||
|
m.closed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockConn) LocalAddr() net.Addr {
|
||||||
|
return m.laddr
|
||||||
|
}
|
||||||
|
func (m *mockConn) RemoteAddr() net.Addr {
|
||||||
|
return m.raddr
|
||||||
|
}
|
||||||
|
func (m *mockConn) SetDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (m *mockConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure mockConn implements the net.Conn interface
|
||||||
|
var _ net.Conn = new(mockConn)
|
||||||
|
|
||||||
|
func TestReadPacketSingleByte(t *testing.T) {
|
||||||
|
conn := new(mockConn)
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(conn),
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.data = []byte{0x01, 0x00, 0x00, 0x00, 0xff}
|
||||||
|
conn.maxReads = 1
|
||||||
|
packet, err := mc.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(packet) != 1 {
|
||||||
|
t.Fatalf("unexpected packet lenght: expected %d, got %d", 1, len(packet))
|
||||||
|
}
|
||||||
|
if packet[0] != 0xff {
|
||||||
|
t.Fatalf("unexpected packet content: expected %x, got %x", 0xff, packet[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadPacketWrongSequenceID(t *testing.T) {
|
||||||
|
conn := new(mockConn)
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(conn),
|
||||||
|
}
|
||||||
|
|
||||||
|
// too low sequence id
|
||||||
|
conn.data = []byte{0x01, 0x00, 0x00, 0x00, 0xff}
|
||||||
|
conn.maxReads = 1
|
||||||
|
mc.sequence = 1
|
||||||
|
_, err := mc.readPacket()
|
||||||
|
if err != ErrPktSync {
|
||||||
|
t.Errorf("expected ErrPktSync, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset
|
||||||
|
conn.reads = 0
|
||||||
|
mc.sequence = 0
|
||||||
|
mc.buf = newBuffer(conn)
|
||||||
|
|
||||||
|
// too high sequence id
|
||||||
|
conn.data = []byte{0x01, 0x00, 0x00, 0x42, 0xff}
|
||||||
|
_, err = mc.readPacket()
|
||||||
|
if err != ErrPktSyncMul {
|
||||||
|
t.Errorf("expected ErrPktSyncMul, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadPacketSplit(t *testing.T) {
|
||||||
|
conn := new(mockConn)
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(conn),
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, maxPacketSize*2+4*3)
|
||||||
|
const pkt2ofs = maxPacketSize + 4
|
||||||
|
const pkt3ofs = 2 * (maxPacketSize + 4)
|
||||||
|
|
||||||
|
// case 1: payload has length maxPacketSize
|
||||||
|
data = data[:pkt2ofs+4]
|
||||||
|
|
||||||
|
// 1st packet has maxPacketSize length and sequence id 0
|
||||||
|
// ff ff ff 00 ...
|
||||||
|
data[0] = 0xff
|
||||||
|
data[1] = 0xff
|
||||||
|
data[2] = 0xff
|
||||||
|
|
||||||
|
// mark the payload start and end of 1st packet so that we can check if the
|
||||||
|
// content was correctly appended
|
||||||
|
data[4] = 0x11
|
||||||
|
data[maxPacketSize+3] = 0x22
|
||||||
|
|
||||||
|
// 2nd packet has payload length 0 and squence id 1
|
||||||
|
// 00 00 00 01
|
||||||
|
data[pkt2ofs+3] = 0x01
|
||||||
|
|
||||||
|
conn.data = data
|
||||||
|
conn.maxReads = 3
|
||||||
|
packet, err := mc.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(packet) != maxPacketSize {
|
||||||
|
t.Fatalf("unexpected packet lenght: expected %d, got %d", maxPacketSize, len(packet))
|
||||||
|
}
|
||||||
|
if packet[0] != 0x11 {
|
||||||
|
t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0])
|
||||||
|
}
|
||||||
|
if packet[maxPacketSize-1] != 0x22 {
|
||||||
|
t.Fatalf("unexpected payload end: expected %x, got %x", 0x22, packet[maxPacketSize-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2: payload has length which is a multiple of maxPacketSize
|
||||||
|
data = data[:cap(data)]
|
||||||
|
|
||||||
|
// 2nd packet now has maxPacketSize length
|
||||||
|
data[pkt2ofs] = 0xff
|
||||||
|
data[pkt2ofs+1] = 0xff
|
||||||
|
data[pkt2ofs+2] = 0xff
|
||||||
|
|
||||||
|
// mark the payload start and end of the 2nd packet
|
||||||
|
data[pkt2ofs+4] = 0x33
|
||||||
|
data[pkt2ofs+maxPacketSize+3] = 0x44
|
||||||
|
|
||||||
|
// 3rd packet has payload length 0 and squence id 2
|
||||||
|
// 00 00 00 02
|
||||||
|
data[pkt3ofs+3] = 0x02
|
||||||
|
|
||||||
|
conn.data = data
|
||||||
|
conn.reads = 0
|
||||||
|
conn.maxReads = 5
|
||||||
|
mc.sequence = 0
|
||||||
|
packet, err = mc.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(packet) != 2*maxPacketSize {
|
||||||
|
t.Fatalf("unexpected packet lenght: expected %d, got %d", 2*maxPacketSize, len(packet))
|
||||||
|
}
|
||||||
|
if packet[0] != 0x11 {
|
||||||
|
t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0])
|
||||||
|
}
|
||||||
|
if packet[2*maxPacketSize-1] != 0x44 {
|
||||||
|
t.Fatalf("unexpected payload end: expected %x, got %x", 0x44, packet[2*maxPacketSize-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 3: payload has a length larger maxPacketSize, which is not an exact
|
||||||
|
// multiple of it
|
||||||
|
data = data[:pkt2ofs+4+42]
|
||||||
|
data[pkt2ofs] = 0x2a
|
||||||
|
data[pkt2ofs+1] = 0x00
|
||||||
|
data[pkt2ofs+2] = 0x00
|
||||||
|
data[pkt2ofs+4+41] = 0x44
|
||||||
|
|
||||||
|
conn.data = data
|
||||||
|
conn.reads = 0
|
||||||
|
conn.maxReads = 4
|
||||||
|
mc.sequence = 0
|
||||||
|
packet, err = mc.readPacket()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(packet) != maxPacketSize+42 {
|
||||||
|
t.Fatalf("unexpected packet lenght: expected %d, got %d", maxPacketSize+42, len(packet))
|
||||||
|
}
|
||||||
|
if packet[0] != 0x11 {
|
||||||
|
t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0])
|
||||||
|
}
|
||||||
|
if packet[maxPacketSize+41] != 0x44 {
|
||||||
|
t.Fatalf("unexpected payload end: expected %x, got %x", 0x44, packet[maxPacketSize+41])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadPacketFail(t *testing.T) {
|
||||||
|
conn := new(mockConn)
|
||||||
|
mc := &mysqlConn{
|
||||||
|
buf: newBuffer(conn),
|
||||||
|
}
|
||||||
|
|
||||||
|
// illegal empty (stand-alone) packet
|
||||||
|
conn.data = []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
conn.maxReads = 1
|
||||||
|
_, err := mc.readPacket()
|
||||||
|
if err != driver.ErrBadConn {
|
||||||
|
t.Errorf("expected ErrBadConn, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset
|
||||||
|
conn.reads = 0
|
||||||
|
mc.sequence = 0
|
||||||
|
mc.buf = newBuffer(conn)
|
||||||
|
|
||||||
|
// fail to read header
|
||||||
|
conn.closed = true
|
||||||
|
_, err = mc.readPacket()
|
||||||
|
if err != driver.ErrBadConn {
|
||||||
|
t.Errorf("expected ErrBadConn, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset
|
||||||
|
conn.closed = false
|
||||||
|
conn.reads = 0
|
||||||
|
mc.sequence = 0
|
||||||
|
mc.buf = newBuffer(conn)
|
||||||
|
|
||||||
|
// fail to read body
|
||||||
|
conn.maxReads = 1
|
||||||
|
_, err = mc.readPacket()
|
||||||
|
if err != driver.ErrBadConn {
|
||||||
|
t.Errorf("expected ErrBadConn, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
5
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
5
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
|
@ -24,7 +24,10 @@ type mysqlStmt struct {
|
||||||
|
|
||||||
func (stmt *mysqlStmt) Close() error {
|
func (stmt *mysqlStmt) Close() error {
|
||||||
if stmt.mc == nil || stmt.mc.netConn == nil {
|
if stmt.mc == nil || stmt.mc.netConn == nil {
|
||||||
errLog.Print(ErrInvalidConn)
|
// driver.Stmt.Close can be called more than once, thus this function
|
||||||
|
// has to be idempotent.
|
||||||
|
// See also Issue #450 and golang/go#16019.
|
||||||
|
//errLog.Print(ErrInvalidConn)
|
||||||
return driver.ErrBadConn
|
return driver.ErrBadConn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue