mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
updated go-sql-driver
This commit is contained in:
parent
e5a5bef200
commit
bd3f825a6e
8
vendor/github.com/go-sql-driver/mysql/.gitignore
generated
vendored
8
vendor/github.com/go-sql-driver/mysql/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
Icon?
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
11
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
11
vendor/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
@ -1,11 +0,0 @@
|
||||
sudo: false
|
||||
language: go
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- tip
|
||||
|
||||
before_script:
|
||||
- mysql -e 'create database gotest;'
|
9
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
9
vendor/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
@ -16,13 +16,16 @@ Arne Hormann <arnehormann at gmail.com>
|
||||
Carlos Nieto <jose.carlos at menteslibres.net>
|
||||
Chris Moos <chris at tech9computers.com>
|
||||
Daniel Nichter <nil at codenode.com>
|
||||
Daniël van Eeden <git at myname.nl>
|
||||
DisposaBoy <disposaboy at dby.me>
|
||||
Egor Smolyakov <egorsmkv at gmail.com>
|
||||
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>
|
||||
Jacek Szwec <szwec.jacek at gmail.com>
|
||||
James Harr <james.harr at gmail.com>
|
||||
Jian Zhen <zhenjl at gmail.com>
|
||||
Joshua Prunier <joshua.prunier at gmail.com>
|
||||
@ -30,18 +33,24 @@ Julien Lefevre <julien.lefevr at gmail.com>
|
||||
Julien Schmidt <go-sql-driver at julienschmidt.com>
|
||||
Kamil Dziedzic <kamil at klecza.pl>
|
||||
Kevin Malachowski <kevin at chowski.com>
|
||||
Lennart Rudolph <lrudolph at hmc.edu>
|
||||
Leonardo YongUk Kim <dalinaum at gmail.com>
|
||||
Luca Looz <luca.looz92 at gmail.com>
|
||||
Lucas Liu <extrafliu at gmail.com>
|
||||
Luke Scott <luke at webconnex.com>
|
||||
Michael Woolnough <michael.woolnough at gmail.com>
|
||||
Nicola Peduzzi <thenikso at gmail.com>
|
||||
Olivier Mengué <dolmen at cpan.org>
|
||||
Paul Bonser <misterpib at gmail.com>
|
||||
Peter Schultz <peter.schultz at classmarkets.com>
|
||||
Runrioter Wung <runrioter at gmail.com>
|
||||
Soroush Pour <me at soroushjp.com>
|
||||
Stan Putrya <root.vagner at gmail.com>
|
||||
Stanley Gunawan <gunawan.stanley at gmail.com>
|
||||
Xiangyu Hu <xiangyu.hu at outlook.com>
|
||||
Xiaobing Jiang <s7v7nislands at gmail.com>
|
||||
Xiuming Chen <cc at cxm.cc>
|
||||
Zhenye Xie <xiezhenye at gmail.com>
|
||||
|
||||
# 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:
|
||||
|
||||
- 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)
|
||||
- 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:
|
||||
|
||||
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP (#249)
|
||||
- Fixed handling of queries without columns and rows (#255)
|
||||
- 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 absolute paths support in LOAD LOCAL DATA INFILE (#356)
|
||||
- Actually zero out bytes in handshake response (#378)
|
||||
@ -20,13 +37,12 @@ Bugfixes:
|
||||
- Fixed tests with MySQL 5.7.9+ (#380)
|
||||
- QueryUnescape TLS config names (#397)
|
||||
- Fixed "broken pipe" error by writing to closed socket (#390)
|
||||
|
||||
New Features:
|
||||
- Support for returning table alias on Columns() (#289, #359, #382)
|
||||
- Placeholder interpolation, can be actived with the DSN parameter `interpolateParams=true` (#309, #318)
|
||||
- Support for uint64 parameters with high bit set (#332, #345)
|
||||
- Cleartext authentication plugin support (#327)
|
||||
|
||||
- Fixed LOAD LOCAL DATA INFILE buffering (#424)
|
||||
- Fixed parsing of floats into float64 when placeholders are used (#434)
|
||||
- Fixed DSN tests with Go 1.7+ (#459)
|
||||
- Handle ERR packets while waiting for EOF (#473)
|
||||
- Invalidate connection on error while discarding additional results (#513)
|
||||
- Allow terminating packets of length 0 (#516)
|
||||
|
||||
|
||||
## Version 1.2 (2014-06-03)
|
||||
|
17
vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md
generated
vendored
17
vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md
generated
vendored
@ -4,28 +4,11 @@
|
||||
|
||||
Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed).
|
||||
|
||||
Please provide the following minimum information:
|
||||
* Your Go-MySQL-Driver version (or git SHA)
|
||||
* Your Go version (run `go version` in your console)
|
||||
* A detailed issue description
|
||||
* Error Log if present
|
||||
* If possible, a short example
|
||||
|
||||
|
||||
## Contributing Code
|
||||
|
||||
By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file.
|
||||
Don't forget to add yourself to the AUTHORS file.
|
||||
|
||||
### Pull Requests Checklist
|
||||
|
||||
Please check the following points before submitting your pull request:
|
||||
- [x] Code compiles correctly
|
||||
- [x] Created tests, if possible
|
||||
- [x] All tests pass
|
||||
- [x] Extended the README / documentation, if necessary
|
||||
- [x] Added yourself to the AUTHORS file
|
||||
|
||||
### Code Review
|
||||
|
||||
Everyone is invited to review and comment on pull requests.
|
||||
|
109
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
109
vendor/github.com/go-sql-driver/mysql/README.md
generated
vendored
@ -1,13 +1,9 @@
|
||||
# Go-MySQL-Driver
|
||||
|
||||
A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) package
|
||||
A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package
|
||||
|
||||

|
||||
|
||||
**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)
|
||||
* [Requirements](#requirements)
|
||||
@ -19,6 +15,7 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa
|
||||
* [Address](#address)
|
||||
* [Parameters](#parameters)
|
||||
* [Examples](#examples)
|
||||
* [Connection pool and timeouts](#connection-pool-and-timeouts)
|
||||
* [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)
|
||||
* [time.Time support](#timetime-support)
|
||||
* [Unicode support](#unicode-support)
|
||||
@ -30,11 +27,11 @@ 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, Unix domain sockets or [custom protocols](http://godoc.org/github.com/go-sql-driver/mysql#DialFunc)
|
||||
* Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://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
|
||||
* Full [`sql.RawBytes`](http://golang.org/pkg/database/sql/#RawBytes) support.
|
||||
* Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support.
|
||||
* Intelligent `LONG DATA` handling in prepared statements
|
||||
* Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support
|
||||
* Optional `time.Time` parsing
|
||||
@ -47,14 +44,14 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa
|
||||
---------------------------------------
|
||||
|
||||
## Installation
|
||||
Simple install the package to your [$GOPATH](http://code.google.com/p/go-wiki/wiki/GOPATH "GOPATH") with the [go tool](http://golang.org/cmd/go/ "go command") from shell:
|
||||
Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
|
||||
```bash
|
||||
$ go get github.com/go-sql-driver/mysql
|
||||
```
|
||||
Make sure [Git is installed](http://git-scm.com/downloads) on your machine and in your system's `PATH`.
|
||||
Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
|
||||
|
||||
## Usage
|
||||
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](http://golang.org/pkg/database/sql) API then.
|
||||
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then.
|
||||
|
||||
Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
|
||||
```go
|
||||
@ -99,13 +96,13 @@ Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mys
|
||||
Passwords can consist of any character. Escaping is **not** necessary.
|
||||
|
||||
#### Protocol
|
||||
See [net.Dial](http://golang.org/pkg/net/#Dial) for more information which networks are available.
|
||||
See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available.
|
||||
In general you should use an Unix domain socket if available and TCP otherwise for best performance.
|
||||
|
||||
#### Address
|
||||
For TCP and UDP networks, addresses have the form `host:port`.
|
||||
If `host` is a literal IPv6 address, it must be enclosed in square brackets.
|
||||
The functions [net.JoinHostPort](http://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](http://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
|
||||
The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
|
||||
|
||||
For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`.
|
||||
|
||||
@ -135,6 +132,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.
|
||||
|
||||
##### `allowNativePasswords`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
`allowNativePasswords=true` allows the usage of the mysql native password method.
|
||||
|
||||
##### `allowOldPasswords`
|
||||
|
||||
```
|
||||
@ -215,11 +221,19 @@ Valid Values: <escaped name>
|
||||
Default: UTC
|
||||
```
|
||||
|
||||
Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](http://golang.org/pkg/time/#LoadLocation) for details.
|
||||
Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details.
|
||||
|
||||
Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter.
|
||||
|
||||
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](https://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`
|
||||
|
||||
@ -231,6 +245,7 @@ Default: false
|
||||
|
||||
Allow multiple statements in one query. While this allows batch queries, it also greatly increases the risk of SQL injections. Only the result of the first query is returned, all other results are silently discarded.
|
||||
|
||||
When `multiStatements` is used, `?` parameters must only be used in the first statement.
|
||||
|
||||
##### `parseTime`
|
||||
|
||||
@ -246,12 +261,11 @@ Default: false
|
||||
##### `readTimeout`
|
||||
|
||||
```
|
||||
Type: decimal number
|
||||
Type: duration
|
||||
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 a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
|
||||
|
||||
##### `strict`
|
||||
|
||||
@ -261,20 +275,20 @@ Valid Values: true, 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`
|
||||
|
||||
```
|
||||
Type: decimal number
|
||||
Type: duration
|
||||
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).
|
||||
|
||||
Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
|
||||
|
||||
##### `tls`
|
||||
|
||||
@ -284,28 +298,35 @@ Valid Values: true, false, skip-verify, <name>
|
||||
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`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
|
||||
|
||||
##### `writeTimeout`
|
||||
|
||||
```
|
||||
Type: decimal number
|
||||
Type: duration
|
||||
Default: 0
|
||||
```
|
||||
|
||||
I/O write 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 write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
|
||||
|
||||
|
||||
##### System Variables
|
||||
|
||||
All other parameters are interpreted as system variables:
|
||||
* `autocommit`: `"SET autocommit=<value>"`
|
||||
* [`time_zone`](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html): `"SET time_zone=<value>"`
|
||||
* [`tx_isolation`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `"SET tx_isolation=<value>"`
|
||||
* `param`: `"SET <param>=<value>"`
|
||||
Any other parameters are interpreted as system variables:
|
||||
* `<boolean_var>=<value>`: `SET <boolean_var>=<value>`
|
||||
* `<enum_var>=<value>`: `SET <enum_var>=<value>`
|
||||
* `<string_var>=%27<value>%27`: `SET <string_var>='<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
|
||||
```
|
||||
@ -320,9 +341,9 @@ root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local
|
||||
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:
|
||||
@ -335,11 +356,16 @@ TCP on a remote host, e.g. Amazon RDS:
|
||||
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
|
||||
```
|
||||
|
||||
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:
|
||||
```
|
||||
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
|
||||
@ -355,6 +381,11 @@ No Database preselected:
|
||||
user:password@/
|
||||
```
|
||||
|
||||
|
||||
### Connection pool and timeouts
|
||||
The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.
|
||||
|
||||
|
||||
### `LOAD DATA LOCAL INFILE` support
|
||||
For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
|
||||
```go
|
||||
@ -365,17 +396,17 @@ Files must be whitelisted by registering them with `mysql.RegisterLocalFile(file
|
||||
|
||||
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.
|
||||
See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
|
||||
|
||||
|
||||
### `time.Time` support
|
||||
The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm.
|
||||
|
||||
However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](http://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
|
||||
However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
|
||||
|
||||
**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
|
||||
|
||||
Alternatively you can use the [`NullTime`](http://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.
|
||||
Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.
|
||||
|
||||
|
||||
### Unicode support
|
||||
@ -410,7 +441,7 @@ That means:
|
||||
* When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0)
|
||||
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**
|
||||
|
||||
Please read the [MPL 2.0 FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) if you have further questions regarding the license.
|
||||
Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.
|
||||
|
||||
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
|
||||
|
||||
|
246
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
246
vendor/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
@ -1,246 +0,0 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 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 (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"math"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TB testing.B
|
||||
|
||||
func (tb *TB) check(err error) {
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB {
|
||||
tb.check(err)
|
||||
return db
|
||||
}
|
||||
|
||||
func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows {
|
||||
tb.check(err)
|
||||
return rows
|
||||
}
|
||||
|
||||
func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
|
||||
tb.check(err)
|
||||
return stmt
|
||||
}
|
||||
|
||||
func initDB(b *testing.B, queries ...string) *sql.DB {
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
for _, query := range queries {
|
||||
if _, err := db.Exec(query); err != nil {
|
||||
if w, ok := err.(MySQLWarnings); ok {
|
||||
b.Logf("warning on %q: %v", query, w)
|
||||
} else {
|
||||
b.Fatalf("error on %q: %v", query, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
const concurrencyLevel = 10
|
||||
|
||||
func BenchmarkQuery(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := initDB(b,
|
||||
"DROP TABLE IF EXISTS foo",
|
||||
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
|
||||
`INSERT INTO foo VALUES (1, "one")`,
|
||||
`INSERT INTO foo VALUES (2, "two")`,
|
||||
)
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
var got string
|
||||
tb.check(stmt.QueryRow(1).Scan(&got))
|
||||
if got != "one" {
|
||||
b.Errorf("query = %q; want one", got)
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExec(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("DO 1"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := stmt.Exec(); err != nil {
|
||||
b.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// data, but no db writes
|
||||
var roundtripSample []byte
|
||||
|
||||
func initRoundtripBenchmarks() ([]byte, int, int) {
|
||||
if roundtripSample == nil {
|
||||
roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
|
||||
}
|
||||
return roundtripSample, 16, len(roundtripSample)
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripTxt(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
sampleString := string(sample)
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
b.StartTimer()
|
||||
var result string
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sampleString[0:length]
|
||||
rows := tb.checkRows(db.Query(`SELECT "` + test + `"`))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if result != test {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripBin(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT ?"))
|
||||
defer stmt.Close()
|
||||
b.StartTimer()
|
||||
var result sql.RawBytes
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sample[0:length]
|
||||
rows := tb.checkRows(stmt.Query(test))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if !bytes.Equal(result, test) {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInterpolation(b *testing.B) {
|
||||
mc := &mysqlConn{
|
||||
cfg: &Config{
|
||||
InterpolateParams: true,
|
||||
Loc: time.UTC,
|
||||
},
|
||||
maxPacketAllowed: maxPacketSize,
|
||||
maxWriteSize: maxPacketSize - 1,
|
||||
buf: newBuffer(nil),
|
||||
}
|
||||
|
||||
args := []driver.Value{
|
||||
int64(42424242),
|
||||
float64(math.Pi),
|
||||
false,
|
||||
time.Unix(1423411542, 807015000),
|
||||
[]byte("bytes containing special chars ' \" \a \x00"),
|
||||
"string containing special chars ' \" \a \x00",
|
||||
}
|
||||
q := "SELECT ?, ?, ?, ?, ?, ?"
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := mc.interpolateParams(q, args)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
43
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
43
vendor/github.com/go-sql-driver/mysql/connection.go
generated
vendored
@ -10,6 +10,7 @@ package mysql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -22,7 +23,7 @@ type mysqlConn struct {
|
||||
affectedRows uint64
|
||||
insertId uint64
|
||||
cfg *Config
|
||||
maxPacketAllowed int
|
||||
maxAllowedPacket int
|
||||
maxWriteSize int
|
||||
writeTimeout time.Duration
|
||||
flags clientFlag
|
||||
@ -135,6 +136,11 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, 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()
|
||||
if buf == nil {
|
||||
// can not take the buffer. Something must be wrong with the connection
|
||||
@ -241,7 +247,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||
return "", driver.ErrSkip
|
||||
}
|
||||
|
||||
if len(buf)+4 > mc.maxPacketAllowed {
|
||||
if len(buf)+4 > mc.maxAllowedPacket {
|
||||
return "", driver.ErrSkip
|
||||
}
|
||||
}
|
||||
@ -284,22 +290,29 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
|
||||
// Internal function to execute commands
|
||||
func (mc *mysqlConn) exec(query string) error {
|
||||
// Send command
|
||||
err := mc.writeCommandPacketStr(comQuery, query)
|
||||
if err != nil {
|
||||
if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err == nil && resLen > 0 {
|
||||
if err = mc.readUntilEOF(); err != nil {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resLen > 0 {
|
||||
// columns
|
||||
if err := mc.readUntilEOF(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mc.readUntilEOF()
|
||||
// rows
|
||||
if err := mc.readUntilEOF(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return mc.discardResults()
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||
@ -330,11 +343,17 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro
|
||||
rows.mc = mc
|
||||
|
||||
if resLen == 0 {
|
||||
// no columns, no more data
|
||||
return emptyRows{}, nil
|
||||
rows.rs.done = true
|
||||
|
||||
switch err := rows.NextResultSet(); err {
|
||||
case nil, io.EOF:
|
||||
return rows, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Columns
|
||||
rows.columns, err = mc.readColumns(resLen)
|
||||
rows.rs.columns, err = mc.readColumns(resLen)
|
||||
return rows, err
|
||||
}
|
||||
}
|
||||
@ -354,7 +373,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
|
||||
if err == nil {
|
||||
rows := new(textRows)
|
||||
rows.mc = mc
|
||||
rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
|
||||
rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
|
||||
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
|
42
vendor/github.com/go-sql-driver/mysql/driver.go
generated
vendored
42
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
|
||||
mc := &mysqlConn{
|
||||
maxPacketAllowed: maxPacketSize,
|
||||
maxAllowedPacket: maxPacketSize,
|
||||
maxWriteSize: maxPacketSize - 1,
|
||||
}
|
||||
mc.cfg, err = ParseDSN(dsn)
|
||||
@ -109,15 +109,19 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get max allowed packet size
|
||||
maxap, err := mc.getSystemVar("max_allowed_packet")
|
||||
if err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
if mc.cfg.MaxAllowedPacket > 0 {
|
||||
mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket
|
||||
} else {
|
||||
// Get max allowed packet size
|
||||
maxap, err := mc.getSystemVar("max_allowed_packet")
|
||||
if err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
mc.maxAllowedPacket = stringToInt(maxap) - 1
|
||||
}
|
||||
mc.maxPacketAllowed = stringToInt(maxap) - 1
|
||||
if mc.maxPacketAllowed < maxPacketSize {
|
||||
mc.maxWriteSize = mc.maxPacketAllowed
|
||||
if mc.maxAllowedPacket < maxPacketSize {
|
||||
mc.maxWriteSize = mc.maxAllowedPacket
|
||||
}
|
||||
|
||||
// Handle DSN Params
|
||||
@ -130,9 +134,9 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||
return mc, nil
|
||||
}
|
||||
|
||||
func handleAuthResult(mc *mysqlConn, cipher []byte) error {
|
||||
func handleAuthResult(mc *mysqlConn, oldCipher []byte) error {
|
||||
// Read Result Packet
|
||||
err := mc.readResultOK()
|
||||
cipher, err := mc.readResultOK()
|
||||
if err == nil {
|
||||
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
|
||||
// where this should work but doesn't; this is currently "wontfix":
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
err = mc.readResultOK()
|
||||
_, err = mc.readResultOK()
|
||||
} else if mc.cfg.AllowCleartextPasswords && err == ErrCleartextPassword {
|
||||
// Retry with clear text password for
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
1811
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
1811
vendor/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
63
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
63
vendor/github.com/go-sql-driver/mysql/dsn.go
generated
vendored
@ -15,6 +15,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -28,22 +29,24 @@ var (
|
||||
|
||||
// Config is a configuration parsed from a DSN string
|
||||
type Config struct {
|
||||
User string // Username
|
||||
Passwd string // Password
|
||||
Net string // Network type
|
||||
Addr string // Network address
|
||||
DBName string // Database name
|
||||
Params map[string]string // Connection parameters
|
||||
Collation string // Connection collation
|
||||
Loc *time.Location // Location for time.Time values
|
||||
TLSConfig string // TLS configuration name
|
||||
tls *tls.Config // TLS configuration
|
||||
Timeout time.Duration // Dial timeout
|
||||
ReadTimeout time.Duration // I/O read timeout
|
||||
WriteTimeout time.Duration // I/O write timeout
|
||||
User string // Username
|
||||
Passwd string // Password (requires User)
|
||||
Net string // Network type
|
||||
Addr string // Network address (requires Net)
|
||||
DBName string // Database name
|
||||
Params map[string]string // Connection parameters
|
||||
Collation string // Connection collation
|
||||
Loc *time.Location // Location for time.Time values
|
||||
MaxAllowedPacket int // Max packet size allowed
|
||||
TLSConfig string // TLS configuration name
|
||||
tls *tls.Config // TLS configuration
|
||||
Timeout time.Duration // Dial timeout
|
||||
ReadTimeout time.Duration // I/O read timeout
|
||||
WriteTimeout time.Duration // I/O write timeout
|
||||
|
||||
AllowAllFiles bool // Allow all files to be used with LOAD DATA LOCAL INFILE
|
||||
AllowCleartextPasswords bool // Allows the cleartext client side plugin
|
||||
AllowNativePasswords bool // Allows the native password authentication method
|
||||
AllowOldPasswords bool // Allows the old insecure password method
|
||||
ClientFoundRows bool // Return number of matching rows instead of rows changed
|
||||
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 hasParam {
|
||||
buf.WriteString("&allowOldPasswords=true")
|
||||
@ -222,6 +234,17 @@ func (cfg *Config) FormatDSN() 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
|
||||
if cfg.Params != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
case "allowOldPasswords":
|
||||
var isBool bool
|
||||
@ -496,7 +527,11 @@ func parseDSNParams(cfg *Config, params string) (err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
case "maxAllowedPacket":
|
||||
cfg.MaxAllowedPacket, err = strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
// lazy init
|
||||
if cfg.Params == nil {
|
||||
|
207
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
207
vendor/github.com/go-sql-driver/mysql/dsn_test.go
generated
vendored
@ -1,207 +0,0 @@
|
||||
// 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 (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testDSNs = []struct {
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{"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&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}"},
|
||||
{"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}"},
|
||||
{"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}"},
|
||||
{"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}"},
|
||||
{"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}"},
|
||||
{"/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: 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: 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}"},
|
||||
{"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}"},
|
||||
}
|
||||
|
||||
func TestDSNParser(t *testing.T) {
|
||||
var cfg *Config
|
||||
var err error
|
||||
var res string
|
||||
|
||||
for i, tst := range testDSNs {
|
||||
cfg, err = ParseDSN(tst.in)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
// pointer not static
|
||||
cfg.tls = nil
|
||||
|
||||
res = fmt.Sprintf("%+v", cfg)
|
||||
if res != tst.out {
|
||||
t.Errorf("%d. ParseDSN(%q) => %q, want %q", i, tst.in, res, tst.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNParserInvalid(t *testing.T) {
|
||||
var invalidDSNs = []string{
|
||||
"@net(addr/", // no closing brace
|
||||
"@tcp(/", // no closing brace
|
||||
"tcp(/", // no closing brace
|
||||
"(/", // no closing brace
|
||||
"net(addr)//", // unescaped
|
||||
"User:pass@tcp(1.2.3.4:3306)", // no trailing slash
|
||||
//"/dbname?arg=/some/unescaped/path",
|
||||
}
|
||||
|
||||
for i, tst := range invalidDSNs {
|
||||
if _, err := ParseDSN(tst); err == nil {
|
||||
t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNReformat(t *testing.T) {
|
||||
for i, tst := range testDSNs {
|
||||
dsn1 := tst.in
|
||||
cfg1, err := ParseDSN(dsn1)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
cfg1.tls = nil // pointer not static
|
||||
res1 := fmt.Sprintf("%+v", cfg1)
|
||||
|
||||
dsn2 := cfg1.FormatDSN()
|
||||
cfg2, err := ParseDSN(dsn2)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
cfg2.tls = nil // pointer not static
|
||||
res2 := fmt.Sprintf("%+v", cfg2)
|
||||
|
||||
if res1 != res2 {
|
||||
t.Errorf("%d. %q does not match %q", i, res2, res1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNWithCustomTLS(t *testing.T) {
|
||||
baseDSN := "User:password@tcp(localhost:5555)/dbname?tls="
|
||||
tlsCfg := tls.Config{}
|
||||
|
||||
RegisterTLSConfig("utils_test", &tlsCfg)
|
||||
|
||||
// Custom TLS is missing
|
||||
tst := baseDSN + "invalid_tls"
|
||||
cfg, err := ParseDSN(tst)
|
||||
if err == nil {
|
||||
t.Errorf("invalid custom TLS in DSN (%s) but did not error. Got config: %#v", tst, cfg)
|
||||
}
|
||||
|
||||
tst = baseDSN + "utils_test"
|
||||
|
||||
// Custom TLS with a server name
|
||||
name := "foohost"
|
||||
tlsCfg.ServerName = name
|
||||
cfg, err = ParseDSN(tst)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, tst)
|
||||
}
|
||||
|
||||
// Custom TLS without a server name
|
||||
name = "localhost"
|
||||
tlsCfg.ServerName = ""
|
||||
cfg, err = ParseDSN(tst)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst)
|
||||
}
|
||||
|
||||
DeregisterTLSConfig("utils_test")
|
||||
}
|
||||
|
||||
func TestDSNWithCustomTLSQueryEscape(t *testing.T) {
|
||||
const configKey = "&%!:"
|
||||
dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey)
|
||||
name := "foohost"
|
||||
tlsCfg := tls.Config{ServerName: name}
|
||||
|
||||
RegisterTLSConfig(configKey, &tlsCfg)
|
||||
|
||||
cfg, err := ParseDSN(dsn)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if cfg.tls.ServerName != name {
|
||||
t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, dsn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNUnsafeCollation(t *testing.T) {
|
||||
_, err := ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=true")
|
||||
if err != errInvalidDSNUnsafeCollation {
|
||||
t.Errorf("expected %v, got %v", errInvalidDSNUnsafeCollation, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=false")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=gbk_chinese_ci")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=ascii_bin&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=latin1_german1_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=utf8_general_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
|
||||
_, err = ParseDSN("/dbname?collation=utf8mb4_general_ci&interpolateParams=true")
|
||||
if err != nil {
|
||||
t.Errorf("expected %v, got %v", nil, err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseDSN(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tst := range testDSNs {
|
||||
if _, err := ParseDSN(tst.in); err != nil {
|
||||
b.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
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")
|
||||
ErrMalformPkt = errors.New("malformed packet")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
|
42
vendor/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
42
vendor/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
@ -1,42 +0,0 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 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 (
|
||||
"bytes"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorsSetLogger(t *testing.T) {
|
||||
previous := errLog
|
||||
defer func() {
|
||||
errLog = previous
|
||||
}()
|
||||
|
||||
// set up logger
|
||||
const expected = "prefix: test\n"
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 64))
|
||||
logger := log.New(buffer, "prefix: ", 0)
|
||||
|
||||
// print
|
||||
SetLogger(logger)
|
||||
errLog.Print("test")
|
||||
|
||||
// check result
|
||||
if actual := buffer.String(); actual != expected {
|
||||
t.Errorf("expected %q, got %q", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsStrictIgnoreNotes(t *testing.T) {
|
||||
runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) {
|
||||
dbt.mustExec("DROP TABLE IF EXISTS does_not_exist")
|
||||
})
|
||||
}
|
18
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
18
vendor/github.com/go-sql-driver/mysql/infile.go
generated
vendored
@ -96,6 +96,10 @@ func deferredClose(err *error, closer io.Closer) {
|
||||
func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
var rdr io.Reader
|
||||
var data []byte
|
||||
packetSize := 16 * 1024 // 16KB is small enough for disk readahead and large enough for TCP
|
||||
if mc.maxWriteSize < packetSize {
|
||||
packetSize = mc.maxWriteSize
|
||||
}
|
||||
|
||||
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.
|
||||
@ -108,8 +112,6 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
if inMap {
|
||||
rdr = handler()
|
||||
if rdr != nil {
|
||||
data = make([]byte, 4+mc.maxWriteSize)
|
||||
|
||||
if cl, ok := rdr.(io.Closer); ok {
|
||||
defer deferredClose(&err, cl)
|
||||
}
|
||||
@ -134,12 +136,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
// get file size
|
||||
if fi, err = file.Stat(); err == nil {
|
||||
rdr = file
|
||||
if fileSize := int(fi.Size()); fileSize <= mc.maxWriteSize {
|
||||
data = make([]byte, 4+fileSize)
|
||||
} else if fileSize <= mc.maxPacketAllowed {
|
||||
data = make([]byte, 4+mc.maxWriteSize)
|
||||
} else {
|
||||
err = fmt.Errorf("local file '%s' too large: size: %d, max: %d", name, fileSize, mc.maxPacketAllowed)
|
||||
if fileSize := int(fi.Size()); fileSize < packetSize {
|
||||
packetSize = fileSize
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,6 +148,7 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
|
||||
// send content packets
|
||||
if err == nil {
|
||||
data := make([]byte, 4+packetSize)
|
||||
var n int
|
||||
for err == nil {
|
||||
n, err = rdr.Read(data[4:])
|
||||
@ -174,7 +173,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
|
||||
// read OK packet
|
||||
if err == nil {
|
||||
return mc.readResultOK()
|
||||
_, err = mc.readResultOK()
|
||||
return err
|
||||
}
|
||||
|
||||
mc.readPacket()
|
||||
|
168
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
168
vendor/github.com/go-sql-driver/mysql/packets.go
generated
vendored
@ -25,9 +25,9 @@ import (
|
||||
|
||||
// Read packet to buffer 'data'
|
||||
func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
var payload []byte
|
||||
var prevData []byte
|
||||
for {
|
||||
// Read packet header
|
||||
// read packet header
|
||||
data, err := mc.buf.readNext(4)
|
||||
if err != nil {
|
||||
errLog.Print(err)
|
||||
@ -35,16 +35,10 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
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)
|
||||
|
||||
if pktLen < 1 {
|
||||
errLog.Print(ErrMalformPkt)
|
||||
mc.Close()
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
|
||||
// Check Packet Sync [8 bit]
|
||||
// check packet sync [8 bit]
|
||||
if data[3] != mc.sequence {
|
||||
if data[3] > mc.sequence {
|
||||
return nil, ErrPktSyncMul
|
||||
@ -53,7 +47,20 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
errLog.Print(err)
|
||||
@ -61,18 +68,17 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
|
||||
isLastPacket := (pktLen < maxPacketSize)
|
||||
// return data if this was the last packet
|
||||
if pktLen < maxPacketSize {
|
||||
// zero allocations for non-split packets
|
||||
if prevData == nil {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Zero allocations for non-splitting packets
|
||||
if isLastPacket && payload == nil {
|
||||
return data, nil
|
||||
return append(prevData, data...), nil
|
||||
}
|
||||
|
||||
payload = append(payload, data...)
|
||||
|
||||
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 {
|
||||
pktLen := len(data) - 4
|
||||
|
||||
if pktLen > mc.maxPacketAllowed {
|
||||
if pktLen > mc.maxAllowedPacket {
|
||||
return ErrPktTooLarge
|
||||
}
|
||||
|
||||
@ -372,6 +378,26 @@ func (mc *mysqlConn) writeClearAuthPacket() error {
|
||||
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 *
|
||||
******************************************************************************/
|
||||
@ -445,36 +471,43 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
|
||||
******************************************************************************/
|
||||
|
||||
// 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()
|
||||
if err == nil {
|
||||
// packet indicator
|
||||
switch data[0] {
|
||||
|
||||
case iOK:
|
||||
return mc.handleOkPacket(data)
|
||||
return nil, mc.handleOkPacket(data)
|
||||
|
||||
case iEOF:
|
||||
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" {
|
||||
// using old_passwords
|
||||
return ErrOldPassword
|
||||
return cipher, ErrOldPassword
|
||||
} else if plugin == "mysql_clear_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 {
|
||||
return ErrUnknownPlugin
|
||||
return cipher, ErrUnknownPlugin
|
||||
}
|
||||
} else {
|
||||
return ErrOldPassword
|
||||
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
|
||||
return nil, ErrOldPassword
|
||||
}
|
||||
|
||||
default: // Error otherwise
|
||||
return mc.handleErrorPacket(data)
|
||||
return nil, mc.handleErrorPacket(data)
|
||||
}
|
||||
}
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Result Set Header Packet
|
||||
@ -551,8 +584,8 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error {
|
||||
|
||||
// server_status [2 bytes]
|
||||
mc.status = readStatus(data[1+n+m : 1+n+m+2])
|
||||
if err := mc.discardResults(); err != nil {
|
||||
return err
|
||||
if mc.status&statusMoreResultsExists != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// warning count [2 bytes]
|
||||
@ -665,6 +698,10 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
|
||||
func (rows *textRows) readRow(dest []driver.Value) error {
|
||||
mc := rows.mc
|
||||
|
||||
if rows.rs.done {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
data, err := mc.readPacket()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -674,10 +711,10 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||
if data[0] == iEOF && len(data) == 5 {
|
||||
// server_status [2 bytes]
|
||||
rows.mc.status = readStatus(data[3:])
|
||||
if err := rows.mc.discardResults(); err != nil {
|
||||
return err
|
||||
rows.rs.done = true
|
||||
if !rows.HasNextResultSet() {
|
||||
rows.mc = nil
|
||||
}
|
||||
rows.mc = nil
|
||||
return io.EOF
|
||||
}
|
||||
if data[0] == iERR {
|
||||
@ -699,7 +736,7 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||
if !mc.parseTime {
|
||||
continue
|
||||
} else {
|
||||
switch rows.columns[i].fieldType {
|
||||
switch rows.rs.columns[i].fieldType {
|
||||
case fieldTypeTimestamp, fieldTypeDateTime,
|
||||
fieldTypeDate, fieldTypeNewDate:
|
||||
dest[i], err = parseDateTime(
|
||||
@ -729,16 +766,19 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
||||
func (mc *mysqlConn) readUntilEOF() error {
|
||||
for {
|
||||
data, err := mc.readPacket()
|
||||
|
||||
// No Err and no EOF Packet
|
||||
if err == nil && data[0] != iEOF {
|
||||
continue
|
||||
}
|
||||
if err == nil && data[0] == iEOF && len(data) == 5 {
|
||||
mc.status = readStatus(data[3:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err // Err or EOF
|
||||
switch data[0] {
|
||||
case iERR:
|
||||
return mc.handleErrorPacket(data)
|
||||
case iEOF:
|
||||
if len(data) == 5 {
|
||||
mc.status = readStatus(data[3:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -783,7 +823,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html
|
||||
func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
||||
maxLen := stmt.mc.maxPacketAllowed - 1
|
||||
maxLen := stmt.mc.maxAllowedPacket - 1
|
||||
pktLen := maxLen
|
||||
|
||||
// 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+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,
|
||||
uint64(len(v)),
|
||||
)
|
||||
@ -996,7 +1036,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
paramTypes[i+i] = fieldTypeString
|
||||
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,
|
||||
uint64(len(v)),
|
||||
)
|
||||
@ -1057,8 +1097,6 @@ func (mc *mysqlConn) discardResults() error {
|
||||
if err := mc.readUntilEOF(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
mc.status &^= statusMoreResultsExists
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -1076,10 +1114,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
// EOF Packet
|
||||
if data[0] == iEOF && len(data) == 5 {
|
||||
rows.mc.status = readStatus(data[3:])
|
||||
if err := rows.mc.discardResults(); err != nil {
|
||||
return err
|
||||
rows.rs.done = true
|
||||
if !rows.HasNextResultSet() {
|
||||
rows.mc = nil
|
||||
}
|
||||
rows.mc = nil
|
||||
return io.EOF
|
||||
}
|
||||
rows.mc = nil
|
||||
@ -1101,14 +1139,14 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
}
|
||||
|
||||
// Convert to byte-coded string
|
||||
switch rows.columns[i].fieldType {
|
||||
switch rows.rs.columns[i].fieldType {
|
||||
case fieldTypeNULL:
|
||||
dest[i] = nil
|
||||
continue
|
||||
|
||||
// Numeric Types
|
||||
case fieldTypeTiny:
|
||||
if rows.columns[i].flags&flagUnsigned != 0 {
|
||||
if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
||||
dest[i] = int64(data[pos])
|
||||
} else {
|
||||
dest[i] = int64(int8(data[pos]))
|
||||
@ -1117,7 +1155,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
continue
|
||||
|
||||
case fieldTypeShort, fieldTypeYear:
|
||||
if rows.columns[i].flags&flagUnsigned != 0 {
|
||||
if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
||||
dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
|
||||
} else {
|
||||
dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
|
||||
@ -1126,7 +1164,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
continue
|
||||
|
||||
case fieldTypeInt24, fieldTypeLong:
|
||||
if rows.columns[i].flags&flagUnsigned != 0 {
|
||||
if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
||||
dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
|
||||
} else {
|
||||
dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
|
||||
@ -1135,7 +1173,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
continue
|
||||
|
||||
case fieldTypeLongLong:
|
||||
if rows.columns[i].flags&flagUnsigned != 0 {
|
||||
if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
||||
val := binary.LittleEndian.Uint64(data[pos : pos+8])
|
||||
if val > math.MaxInt64 {
|
||||
dest[i] = uint64ToString(val)
|
||||
@ -1149,7 +1187,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
continue
|
||||
|
||||
case fieldTypeFloat:
|
||||
dest[i] = float64(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])))
|
||||
dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])))
|
||||
pos += 4
|
||||
continue
|
||||
|
||||
@ -1189,10 +1227,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
case isNull:
|
||||
dest[i] = nil
|
||||
continue
|
||||
case rows.columns[i].fieldType == fieldTypeTime:
|
||||
case rows.rs.columns[i].fieldType == fieldTypeTime:
|
||||
// database/sql does not support an equivalent to TIME, return a string
|
||||
var dstlen uint8
|
||||
switch decimals := rows.columns[i].decimals; decimals {
|
||||
switch decimals := rows.rs.columns[i].decimals; decimals {
|
||||
case 0x00, 0x1f:
|
||||
dstlen = 8
|
||||
case 1, 2, 3, 4, 5, 6:
|
||||
@ -1200,7 +1238,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"protocol error, illegal decimals value %d",
|
||||
rows.columns[i].decimals,
|
||||
rows.rs.columns[i].decimals,
|
||||
)
|
||||
}
|
||||
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
|
||||
@ -1208,10 +1246,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
|
||||
default:
|
||||
var dstlen uint8
|
||||
if rows.columns[i].fieldType == fieldTypeDate {
|
||||
if rows.rs.columns[i].fieldType == fieldTypeDate {
|
||||
dstlen = 10
|
||||
} else {
|
||||
switch decimals := rows.columns[i].decimals; decimals {
|
||||
switch decimals := rows.rs.columns[i].decimals; decimals {
|
||||
case 0x00, 0x1f:
|
||||
dstlen = 19
|
||||
case 1, 2, 3, 4, 5, 6:
|
||||
@ -1219,7 +1257,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"protocol error, illegal decimals value %d",
|
||||
rows.columns[i].decimals,
|
||||
rows.rs.columns[i].decimals,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1235,7 +1273,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
|
||||
// Please report if this happens!
|
||||
default:
|
||||
return fmt.Errorf("unknown field type %d", rows.columns[i].fieldType)
|
||||
return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType)
|
||||
}
|
||||
}
|
||||
|
||||
|
122
vendor/github.com/go-sql-driver/mysql/rows.go
generated
vendored
122
vendor/github.com/go-sql-driver/mysql/rows.go
generated
vendored
@ -21,40 +21,49 @@ type mysqlField struct {
|
||||
decimals byte
|
||||
}
|
||||
|
||||
type mysqlRows struct {
|
||||
mc *mysqlConn
|
||||
type resultSet struct {
|
||||
columns []mysqlField
|
||||
done bool
|
||||
}
|
||||
|
||||
type mysqlRows struct {
|
||||
mc *mysqlConn
|
||||
rs resultSet
|
||||
}
|
||||
|
||||
type binaryRows struct {
|
||||
mysqlRows
|
||||
// stmtCols is a pointer to the statement's cached columns for different
|
||||
// result sets.
|
||||
stmtCols *[][]mysqlField
|
||||
// i is a number of the current result set. It is used to fetch proper
|
||||
// columns from stmtCols.
|
||||
i int
|
||||
}
|
||||
|
||||
type textRows struct {
|
||||
mysqlRows
|
||||
}
|
||||
|
||||
type emptyRows struct{}
|
||||
|
||||
func (rows *mysqlRows) Columns() []string {
|
||||
columns := make([]string, len(rows.columns))
|
||||
columns := make([]string, len(rows.rs.columns))
|
||||
if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
|
||||
for i := range columns {
|
||||
if tableName := rows.columns[i].tableName; len(tableName) > 0 {
|
||||
columns[i] = tableName + "." + rows.columns[i].name
|
||||
if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 {
|
||||
columns[i] = tableName + "." + rows.rs.columns[i].name
|
||||
} else {
|
||||
columns[i] = rows.columns[i].name
|
||||
columns[i] = rows.rs.columns[i].name
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := range columns {
|
||||
columns[i] = rows.columns[i].name
|
||||
columns[i] = rows.rs.columns[i].name
|
||||
}
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func (rows *mysqlRows) Close() error {
|
||||
func (rows *mysqlRows) Close() (err error) {
|
||||
mc := rows.mc
|
||||
if mc == nil {
|
||||
return nil
|
||||
@ -64,7 +73,9 @@ func (rows *mysqlRows) Close() error {
|
||||
}
|
||||
|
||||
// Remove unread packets from stream
|
||||
err := mc.readUntilEOF()
|
||||
if !rows.rs.done {
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
if err == nil {
|
||||
if err = mc.discardResults(); err != nil {
|
||||
return err
|
||||
@ -75,6 +86,73 @@ func (rows *mysqlRows) Close() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (rows *mysqlRows) HasNextResultSet() (b bool) {
|
||||
if rows.mc == nil {
|
||||
return false
|
||||
}
|
||||
return rows.mc.status&statusMoreResultsExists != 0
|
||||
}
|
||||
|
||||
func (rows *mysqlRows) nextResultSet() (int, error) {
|
||||
if rows.mc == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if rows.mc.netConn == nil {
|
||||
return 0, ErrInvalidConn
|
||||
}
|
||||
|
||||
// Remove unread packets from stream
|
||||
if !rows.rs.done {
|
||||
if err := rows.mc.readUntilEOF(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rows.rs.done = true
|
||||
}
|
||||
|
||||
if !rows.HasNextResultSet() {
|
||||
rows.mc = nil
|
||||
return 0, io.EOF
|
||||
}
|
||||
rows.rs = resultSet{}
|
||||
return rows.mc.readResultSetHeaderPacket()
|
||||
}
|
||||
|
||||
func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {
|
||||
for {
|
||||
resLen, err := rows.nextResultSet()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if resLen > 0 {
|
||||
return resLen, nil
|
||||
}
|
||||
|
||||
rows.rs.done = true
|
||||
}
|
||||
}
|
||||
|
||||
func (rows *binaryRows) NextResultSet() (err error) {
|
||||
resLen, err := rows.nextNotEmptyResultSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get columns, if not cached, read them and cache them.
|
||||
if rows.i >= len(*rows.stmtCols) {
|
||||
rows.rs.columns, err = rows.mc.readColumns(resLen)
|
||||
*rows.stmtCols = append(*rows.stmtCols, rows.rs.columns)
|
||||
} else {
|
||||
rows.rs.columns = (*rows.stmtCols)[rows.i]
|
||||
if err := rows.mc.readUntilEOF(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rows.i++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rows *binaryRows) Next(dest []driver.Value) error {
|
||||
if mc := rows.mc; mc != nil {
|
||||
if mc.netConn == nil {
|
||||
@ -87,6 +165,16 @@ func (rows *binaryRows) Next(dest []driver.Value) error {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
func (rows *textRows) NextResultSet() (err error) {
|
||||
resLen, err := rows.nextNotEmptyResultSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rows.rs.columns, err = rows.mc.readColumns(resLen)
|
||||
return err
|
||||
}
|
||||
|
||||
func (rows *textRows) Next(dest []driver.Value) error {
|
||||
if mc := rows.mc; mc != nil {
|
||||
if mc.netConn == nil {
|
||||
@ -98,15 +186,3 @@ func (rows *textRows) Next(dest []driver.Value) error {
|
||||
}
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
func (rows emptyRows) Columns() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rows emptyRows) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rows emptyRows) Next(dest []driver.Value) error {
|
||||
return io.EOF
|
||||
}
|
||||
|
61
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
61
vendor/github.com/go-sql-driver/mysql/statement.go
generated
vendored
@ -11,6 +11,7 @@ package mysql
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
@ -19,12 +20,15 @@ type mysqlStmt struct {
|
||||
mc *mysqlConn
|
||||
id uint32
|
||||
paramCount int
|
||||
columns []mysqlField // cached from the first query
|
||||
columns [][]mysqlField // cached from the first query
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Close() error {
|
||||
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
|
||||
}
|
||||
|
||||
@ -59,26 +63,30 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err == nil {
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
err = mc.readUntilEOF()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Rows
|
||||
err = mc.readUntilEOF()
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
if err = mc.readUntilEOF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil {
|
||||
return &mysqlResult{
|
||||
affectedRows: int64(mc.affectedRows),
|
||||
insertId: int64(mc.insertId),
|
||||
}, nil
|
||||
|
||||
// Rows
|
||||
if err := mc.readUntilEOF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
if err := mc.discardResults(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &mysqlResult{
|
||||
affectedRows: int64(mc.affectedRows),
|
||||
insertId: int64(mc.insertId),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
|
||||
@ -101,18 +109,29 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
|
||||
}
|
||||
|
||||
rows := new(binaryRows)
|
||||
rows.stmtCols = &stmt.columns
|
||||
|
||||
if resLen > 0 {
|
||||
rows.mc = mc
|
||||
rows.i++
|
||||
// Columns
|
||||
// If not cached, read them and cache them
|
||||
if stmt.columns == nil {
|
||||
rows.columns, err = mc.readColumns(resLen)
|
||||
stmt.columns = rows.columns
|
||||
if len(stmt.columns) == 0 {
|
||||
rows.rs.columns, err = mc.readColumns(resLen)
|
||||
stmt.columns = append(stmt.columns, rows.rs.columns)
|
||||
} else {
|
||||
rows.columns = stmt.columns
|
||||
rows.rs.columns = stmt.columns[0]
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
} else {
|
||||
rows.rs.done = true
|
||||
|
||||
switch err := rows.NextResultSet(); err {
|
||||
case nil, io.EOF:
|
||||
return rows, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return rows, err
|
||||
|
197
vendor/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
197
vendor/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
@ -1,197 +0,0 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 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 (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestScanNullTime(t *testing.T) {
|
||||
var scanTests = []struct {
|
||||
in interface{}
|
||||
error bool
|
||||
valid bool
|
||||
time time.Time
|
||||
}{
|
||||
{tDate, false, true, tDate},
|
||||
{sDate, false, true, tDate},
|
||||
{[]byte(sDate), false, true, tDate},
|
||||
{tDateTime, false, true, tDateTime},
|
||||
{sDateTime, false, true, tDateTime},
|
||||
{[]byte(sDateTime), false, true, tDateTime},
|
||||
{tDate0, false, true, tDate0},
|
||||
{sDate0, false, true, tDate0},
|
||||
{[]byte(sDate0), false, true, tDate0},
|
||||
{sDateTime0, false, true, tDate0},
|
||||
{[]byte(sDateTime0), false, true, tDate0},
|
||||
{"", true, false, tDate0},
|
||||
{"1234", true, false, tDate0},
|
||||
{0, true, false, tDate0},
|
||||
}
|
||||
|
||||
var nt = NullTime{}
|
||||
var err error
|
||||
|
||||
for _, tst := range scanTests {
|
||||
err = nt.Scan(tst.in)
|
||||
if (err != nil) != tst.error {
|
||||
t.Errorf("%v: expected error status %t, got %t", tst.in, tst.error, (err != nil))
|
||||
}
|
||||
if nt.Valid != tst.valid {
|
||||
t.Errorf("%v: expected valid status %t, got %t", tst.in, tst.valid, nt.Valid)
|
||||
}
|
||||
if nt.Time != tst.time {
|
||||
t.Errorf("%v: expected time %v, got %v", tst.in, tst.time, nt.Time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLengthEncodedInteger(t *testing.T) {
|
||||
var integerTests = []struct {
|
||||
num uint64
|
||||
encoded []byte
|
||||
}{
|
||||
{0x0000000000000000, []byte{0x00}},
|
||||
{0x0000000000000012, []byte{0x12}},
|
||||
{0x00000000000000fa, []byte{0xfa}},
|
||||
{0x0000000000000100, []byte{0xfc, 0x00, 0x01}},
|
||||
{0x0000000000001234, []byte{0xfc, 0x34, 0x12}},
|
||||
{0x000000000000ffff, []byte{0xfc, 0xff, 0xff}},
|
||||
{0x0000000000010000, []byte{0xfd, 0x00, 0x00, 0x01}},
|
||||
{0x0000000000123456, []byte{0xfd, 0x56, 0x34, 0x12}},
|
||||
{0x0000000000ffffff, []byte{0xfd, 0xff, 0xff, 0xff}},
|
||||
{0x0000000001000000, []byte{0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}},
|
||||
{0x123456789abcdef0, []byte{0xfe, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}},
|
||||
{0xffffffffffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
|
||||
}
|
||||
|
||||
for _, tst := range integerTests {
|
||||
num, isNull, numLen := readLengthEncodedInteger(tst.encoded)
|
||||
if isNull {
|
||||
t.Errorf("%x: expected %d, got NULL", tst.encoded, tst.num)
|
||||
}
|
||||
if num != tst.num {
|
||||
t.Errorf("%x: expected %d, got %d", tst.encoded, tst.num, num)
|
||||
}
|
||||
if numLen != len(tst.encoded) {
|
||||
t.Errorf("%x: expected size %d, got %d", tst.encoded, len(tst.encoded), numLen)
|
||||
}
|
||||
encoded := appendLengthEncodedInteger(nil, num)
|
||||
if !bytes.Equal(encoded, tst.encoded) {
|
||||
t.Errorf("%v: expected %x, got %x", num, tst.encoded, encoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldPass(t *testing.T) {
|
||||
scramble := []byte{9, 8, 7, 6, 5, 4, 3, 2}
|
||||
vectors := []struct {
|
||||
pass string
|
||||
out string
|
||||
}{
|
||||
{" pass", "47575c5a435b4251"},
|
||||
{"pass ", "47575c5a435b4251"},
|
||||
{"123\t456", "575c47505b5b5559"},
|
||||
{"C0mpl!ca ted#PASS123", "5d5d554849584a45"},
|
||||
}
|
||||
for _, tuple := range vectors {
|
||||
ours := scrambleOldPassword(scramble, []byte(tuple.pass))
|
||||
if tuple.out != fmt.Sprintf("%x", ours) {
|
||||
t.Errorf("Failed old password %q", tuple.pass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatBinaryDateTime(t *testing.T) {
|
||||
rawDate := [11]byte{}
|
||||
binary.LittleEndian.PutUint16(rawDate[:2], 1978) // years
|
||||
rawDate[2] = 12 // months
|
||||
rawDate[3] = 30 // days
|
||||
rawDate[4] = 15 // hours
|
||||
rawDate[5] = 46 // minutes
|
||||
rawDate[6] = 23 // seconds
|
||||
binary.LittleEndian.PutUint32(rawDate[7:], 987654) // microseconds
|
||||
expect := func(expected string, inlen, outlen uint8) {
|
||||
actual, _ := formatBinaryDateTime(rawDate[:inlen], outlen, false)
|
||||
bytes, ok := actual.([]byte)
|
||||
if !ok {
|
||||
t.Errorf("formatBinaryDateTime must return []byte, was %T", actual)
|
||||
}
|
||||
if string(bytes) != expected {
|
||||
t.Errorf(
|
||||
"expected %q, got %q for length in %d, out %d",
|
||||
bytes, actual, inlen, outlen,
|
||||
)
|
||||
}
|
||||
}
|
||||
expect("0000-00-00", 0, 10)
|
||||
expect("0000-00-00 00:00:00", 0, 19)
|
||||
expect("1978-12-30", 4, 10)
|
||||
expect("1978-12-30 15:46:23", 7, 19)
|
||||
expect("1978-12-30 15:46:23.987654", 11, 26)
|
||||
}
|
||||
|
||||
func TestEscapeBackslash(t *testing.T) {
|
||||
expect := func(expected, value string) {
|
||||
actual := string(escapeBytesBackslash([]byte{}, []byte(value)))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
|
||||
actual = string(escapeStringBackslash([]byte{}, value))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
expect("foo\\0bar", "foo\x00bar")
|
||||
expect("foo\\nbar", "foo\nbar")
|
||||
expect("foo\\rbar", "foo\rbar")
|
||||
expect("foo\\Zbar", "foo\x1abar")
|
||||
expect("foo\\\"bar", "foo\"bar")
|
||||
expect("foo\\\\bar", "foo\\bar")
|
||||
expect("foo\\'bar", "foo'bar")
|
||||
}
|
||||
|
||||
func TestEscapeQuotes(t *testing.T) {
|
||||
expect := func(expected, value string) {
|
||||
actual := string(escapeBytesQuotes([]byte{}, []byte(value)))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
|
||||
actual = string(escapeStringQuotes([]byte{}, value))
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"expected %s, got %s",
|
||||
expected, actual,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
expect("foo\x00bar", "foo\x00bar") // not affected
|
||||
expect("foo\nbar", "foo\nbar") // not affected
|
||||
expect("foo\rbar", "foo\rbar") // not affected
|
||||
expect("foo\x1abar", "foo\x1abar") // not affected
|
||||
expect("foo''bar", "foo'bar") // affected
|
||||
expect("foo\"bar", "foo\"bar") // not affected
|
||||
}
|
10
vendor/vendor.json
vendored
10
vendor/vendor.json
vendored
@ -2,6 +2,10 @@
|
||||
"comment": "",
|
||||
"ignore": "test",
|
||||
"package": [
|
||||
{
|
||||
"path": "appengine/cloudsql",
|
||||
"revision": ""
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "QLOmSL4B0UFqEIFwCe0TMwehlfE=",
|
||||
"path": "github.com/aws/aws-sdk-go",
|
||||
@ -322,6 +326,12 @@
|
||||
"version": "v1.21.1",
|
||||
"versionExact": "v1.21.1"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "42vkdsxNaLyPu+FktCzZ/8zsNSE=",
|
||||
"path": "github.com/go-sql-driver/mysql",
|
||||
"revision": "9dee4ca50b83acdf57a35fb9e6fb4be640afa2f3",
|
||||
"revisionTime": "2017-03-27T11:30:21Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "B4bk7vdV9aD7AhrtATXfgEacdqE=",
|
||||
"path": "github.com/gorilla/websocket",
|
||||
|
Loading…
Reference in New Issue
Block a user