Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package

Go-MySQL-Driver

A MySQL-Driver for Go's database/sql package

Go-MySQL-Driver logo



Features

  • Lightweight and fast
  • Native Go implementation. No C-bindings, just pure Go
  • Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or custom protocols
  • Automatic handling of broken connections
  • Automatic Connection Pooling (by database/sql package)
  • Supports queries larger than 16MB
  • Full sql.RawBytes support.
  • Intelligent LONG DATA handling in prepared statements
  • Secure LOAD DATA LOCAL INFILE support with file allowlisting and io.Reader support
  • Optional time.Time parsing
  • Optional placeholder interpolation

Requirements

  • Go 1.10 or higher. We aim to support the 3 latest versions of Go.
  • MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)

Installation

Simple install the package to your $GOPATH with the go tool from shell:

$ go get -u github.com/go-sql-driver/mysql

Make sure Git is installed 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 API then.

Use mysql as driverName and a valid DSN as dataSourceName:

import (
	"database/sql"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

// ...

db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
	panic(err)
}
// See "Important settings" section.
db.SetConnMaxLifetime(time.Minute * 3)
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)

Examples are available in our Wiki.

Important settings

db.SetConnMaxLifetime() is required to ensure connections are closed by the driver safely before connection is closed by MySQL server, OS, or other middlewares. Since some middlewares close idle connections by 5 minutes, we recommend timeout shorter than 5 minutes. This setting helps load balancing and changing system variables too.

db.SetMaxOpenConns() is highly recommended to limit the number of connection used by the application. There is no recommended limit number because it depends on application and MySQL server.

db.SetMaxIdleConns() is recommended to be set same to (or greater than) db.SetMaxOpenConns(). When it is smaller than SetMaxOpenConns(), connections can be opened and closed very frequently than you expect. Idle connections can be closed by the db.SetConnMaxLifetime(). If you want to close idle connections more rapidly, you can use db.SetConnMaxIdleTime() since Go 1.15.

DSN (Data Source Name)

The Data Source Name has a common format, like e.g. PEAR DB uses it, but without type-prefix (optional parts marked by squared brackets):

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

A DSN in its fullest form:

username:password@protocol(address)/dbname?param=value

Except for the databasename, all values are optional. So the minimal DSN is:

/dbname

If you do not want to preselect a database, leave dbname empty:

/

This has the same effect as an empty DSN string:


Alternatively, Config.FormatDSN can be used to create a DSN string by filling a struct.

Password

Passwords can consist of any character. Escaping is not necessary.

Protocol

See 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 port is omitted, the default port will be used. If host is a literal IPv6 address, it must be enclosed in square brackets. The functions net.JoinHostPort and 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.

Parameters

Parameters are case-sensitive!

Notice that any of true, TRUE, True or 1 is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: false, FALSE, False or 0.

allowAllFiles
Type:           bool
Valid Values:   true, false
Default:        false

allowAllFiles=true disables the file allowlist for LOAD DATA LOCAL INFILE and allows all files. Might be insecure!

allowCleartextPasswords
Type:           bool
Valid Values:   true, false
Default:        false

allowCleartextPasswords=true allows using the cleartext client side plugin if required by an account, such as one defined with the PAM authentication plugin. 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, IPsec, or a private network.

allowNativePasswords
Type:           bool
Valid Values:   true, false
Default:        true

allowNativePasswords=false disallows the usage of MySQL native password method.

allowOldPasswords
Type:           bool
Valid Values:   true, false
Default:        false

allowOldPasswords=true allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also the old_passwords wiki page.

charset
Type:           string
Valid Values:   <name>
Default:        none

Sets the charset used for client-server interaction ("SET NAMES <value>"). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for utf8mb4 (introduced in MySQL 5.5.3) with fallback to utf8 for older servers (charset=utf8mb4,utf8).

Usage of the charset parameter is discouraged because it issues additional queries to the server. Unless you need the fallback behavior, please use collation instead.

checkConnLiveness
Type:           bool
Valid Values:   true, false
Default:        true

On supported platforms connections retrieved from the connection pool are checked for liveness before using them. If the check fails, the respective connection is marked as bad and the query retried with another connection. checkConnLiveness=false disables this liveness check of connections.

collation
Type:           string
Valid Values:   <name>
Default:        utf8mb4_general_ci

Sets the collation used for client-server interaction on connection. In contrast to charset, collation does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail.

A list of valid charsets for a server is retrievable with SHOW COLLATION.

The default collation (utf8mb4_general_ci) is supported from MySQL 5.5. You should use an older collation (e.g. utf8_general_ci) for older MySQL.

Collations for charset "ucs2", "utf16", "utf16le", and "utf32" can not be used (ref).

clientFoundRows
Type:           bool
Valid Values:   true, false
Default:        false

clientFoundRows=true causes an UPDATE to return the number of matching rows instead of the number of rows changed.

columnsWithAlias
Type:           bool
Valid Values:   true, false
Default:        false

When columnsWithAlias is true, calls to sql.Rows.Columns() will return the table alias and the column name separated by a dot. For example:

SELECT u.id FROM users as u

will return u.id instead of just id if columnsWithAlias=true.

interpolateParams
Type:           bool
Valid Values:   true, false
Default:        false

If interpolateParams is true, placeholders (?) in calls to db.Query() and db.Exec() are interpolated into a single query string with given parameters. This reduces the number of roundtrips, since the driver has to prepare a statement, execute it with given parameters and close the statement again with interpolateParams=false.

This can not be used together with the multibyte encodings BIG5, CP932, GB2312, GBK or SJIS. These are rejected as they may introduce a SQL injection vulnerability!

loc
Type:           string
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 for details.

Note that this sets the location for time.Time values but does not change MySQL's time_zone setting. For that see the time_zone system variable, which can also be set as a DSN parameter.

Please keep in mind, that param values must be 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:       4194304

Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. maxAllowedPacket=0 can be used to automatically fetch the max_allowed_packet variable from server on every connection.

multiStatements
Type:           bool
Valid Values:   true, false
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
Type:           bool
Valid Values:   true, false
Default:        false

parseTime=true changes the output type of DATE and DATETIME values to time.Time instead of []byte / string The date or datetime like 0000-00-00 00:00:00 is converted into zero value of time.Time.

readTimeout
Type:           duration
Default:        0

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".

rejectReadOnly
Type:           bool
Valid Values:   true, false
Default:        false

rejectReadOnly=true causes the driver to reject read-only connections. This is for a possible race condition during an automatic failover, where the mysql client gets connected to a read-only replica after the failover.

Note that this should be a fairly rare case, as an automatic failover normally happens when the primary is down, and the race condition shouldn't happen unless it comes back up online as soon as the failover is kicked off. On the other hand, when this happens, a MySQL application can get stuck on a read-only connection until restarted. It is however fairly easy to reproduce, for example, using a manual failover on AWS Aurora's MySQL-compatible cluster.

If you are not relying on read-only transactions to reject writes that aren't supposed to happen, setting this on some MySQL providers (such as AWS Aurora) is safer for failovers.

Note that ERROR 1290 can be returned for a read-only server and this option will cause a retry for that error. However the same error number is used for some other cases. You should ensure your application will never cause an ERROR 1290 except for read-only mode when enabling this option.

serverPubKey
Type:           string
Valid Values:   <name>
Default:        none

Server public keys can be registered with mysql.RegisterServerPubKey, which can then be used by the assigned name in the DSN. Public keys are used to transmit encrypted data, e.g. for authentication. If the server's public key is known, it should be set manually to avoid expensive and potentially insecure transmissions of the public key from the server to the client each time it is required.

timeout
Type:           duration
Default:        OS default

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
Type:           bool / string
Valid Values:   true, false, skip-verify, preferred, <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) or use preferred to use TLS only when advertised by the server. This is similar to skip-verify, but additionally allows a fallback to a connection which is not encrypted. Neither skip-verify nor preferred add any reliable security. You can use a custom TLS config after registering it with mysql.RegisterTLSConfig.

writeTimeout
Type:           duration
Default:        0

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

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'ed! (which implies values of string variables must be wrapped with %27).

Examples:

Examples

user@unix(/path/to/socket)/dbname
root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true

Treat warnings as errors by setting the system variable sql_mode:

user:password@/dbname?sql_mode=TRADITIONAL

TCP via IPv6:

user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci

TCP on a remote host, e.g. Amazon RDS:

id:password@tcp(your-amazonaws-uri.com:3306)/dbname

Google Cloud SQL on App Engine:

user:password@unix(/cloudsql/project-id:region-name:instance-name)/dbname

TCP using default port (3306) on localhost:

user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped

Use the default protocol (tcp) and host (localhost:3306):

user:password@/dbname

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. The read, write, and dial timeouts for each individual connection are configured with the DSN parameters readTimeout, writeTimeout, and timeout, respectively.

ColumnType Support

This driver supports the ColumnType interface introduced in Go 1.8, with the exception of ColumnType.Length(), which is currently not supported.

context.Context Support

Go 1.8 added database/sql support for context.Context. This driver supports query timeouts and cancellation via contexts. See context support in the database/sql package for more details.

LOAD DATA LOCAL INFILE support

For this feature you need direct access to the package. Therefore you must change the import path (no _):

import "github.com/go-sql-driver/mysql"

Files must be explicitly allowed by registering them with mysql.RegisterLocalFile(filepath) (recommended) or the allowlist check must be deactivated by using the DSN parameter allowAllFiles=true (Might be insecure!).

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 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 program.

However, many want to scan MySQL DATE and DATETIME values into time.Time variables, which is the logical equivalent 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 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.

Unicode support

Since version 1.5 Go-MySQL-Driver automatically uses the collation utf8mb4_general_ci by default.

Other collations / charsets can be set using the collation DSN parameter.

Version 1.0 of the driver recommended adding &charset=utf8 (alias for SET NAMES utf8) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The collation parameter should be preferred to set another collation / charset than the default.

See http://dev.mysql.com/doc/refman/8.0/en/charset-unicode.html for more details on MySQL's Unicode support.

Testing / Development

To run the driver tests you may need to adjust the configuration. See the Testing Wiki-Page for details.

Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated. If you want to contribute, you can work on an open issue or review a pull request.

See the Contribution Guidelines for details.


License

Go-MySQL-Driver is licensed under the Mozilla Public License Version 2.0

Mozilla summarizes the license scope as follows:

MPL: The copyleft applies to any files containing MPLed code.

That means:

  • You can use the unchanged source code both in private and commercially.
  • 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 if you have further questions regarding the license.

You can read the full terms here: LICENSE.

Go Gopher and MySQL Dolphin

Comments
  • packets.go: read tcp [ip-address]: connection timed out

    packets.go: read tcp [ip-address]: connection timed out

    UPDATE: My resolution was to remove all "Idle" connections from the pool. See this comment:

    https://github.com/go-sql-driver/mysql/issues/257#issuecomment-53886663

    I am currently experiencing a stalling or broken web app after a period of idle between 15 to 48 minutes. The most critical issue is described below:

    • Visit a URL, any url on the site, and load the page completely (as in, the page actually loads and the logs show a complete page has loaded).
    • Close browser, and wait.

    A typical request is logged like this:

    2014/07/13 15:29:54 INFO template rendering: index
    2014/07/13 15:29:54 METRIC, URL: /, HANDLER TIME: 7.2339ms, CTX TIME: 5.0894ms, TOTAL TIME: 12.3258ms
    

    After a long period of time (ranging from 15m to 48m), the system all of a sudden logs these lines below with no interaction - the web app has been idle this entire time:

    [MySQL] 2014/07/13 16:00:09 packets.go:32: read tcp remote-mysql-server-address:3306: connection timed out
    [MySQL] 2014/07/13 16:00:09 packets.go:118: write tcp remote-mysql-server-address:3306: broken pipe
    2014/07/13 16:00:10 INFO template rendering: index
    2014/07/13 16:00:10 METRIC, URL: /, HANDLER TIME: 8.8574ms, CTX TIME: 31m19.2606723s, TOTAL TIME: 31m19.2695329s
    

    Notice the "TOTAL TIME" is 31 minutes and 19 seconds? Also, notice the MySql driver error that is logged at the same time?

    There was no activity / no web request made. The web app was simply idle.

    The most critical issue is what comes next after these log messages: _the very next web request is stalls completely, never returning a response_:

    user@govm1:~$ wget http://localhost
    --2014-07-13 17:11:18--  http://localhost/
    Resolving localhost (localhost)... 127.0.0.1
    Connecting to localhost (localhost)|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... Read error (Connection timed out) in headers.
    Retrying.
    
    --2014-07-13 17:26:19--  (try: 2)  http://localhost/
    Connecting to localhost (localhost)|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: unspecified [text/html]
    Saving to: `index.html.4'
    
        [ <=>                                                                                  ] 6,310       --.-K/s   in 0.001s
    
    2014-07-13 17:26:20 (9.61 MB/s) - `index.html.4' saved [6310]
    

    And it sits idle, no response, for 15 minutes until wget times out.

    Now, if I make a 2nd or 3rd request immediately after this one is stalled and anytime while it is stalled, the go web app responds and returns a full page for other requests. No issues. And then, the cycle starts over from the last request I make and let it site idle.

    After this 15m, you can guess exactly what is logged next:

    [MySQL] 2014/07/13 17:26:57 packets.go:32: read tcp remote-mysql-server-address:3306: connection timed out
    [MySQL] 2014/07/13 17:26:57 packets.go:118: write tcp remote-mysql-server-address:3306: broken pipe
    2014/07/13 17:26:57 INFO template rendering: index
    2014/07/13 17:26:57 METRIC, URL: /, HANDLER TIME: 6.8938ms, CTX TIME: 15m39.1718434s, TOTAL TIME: 15m39.1787398s
    

    Another 15m wait time.

    I eliminated Windows Azure, the Cluster VIP and Firewall/Linux VM running the go web app as an issue because I ran wget http://localhost locally on the same box, and I get this "stalled" request that never completes and never sends back anything.

    There are a number of factors in my web app so I will try to outline them accordingly.

    Using:

    • Go 1.3
    • go-sql-driver/mysql ## Version 1.2 (2014-06-03)
    • Ubuntu 12.04 LTS, ~June 2014 Updates
    • Windows Azure

    Do note that the Linux box running MySql is a different Linux box running the cluster of GoLang apps - and they are in separate dedicated Cloud Services. The MySql vm is a single VM, no cluserting.

    Here is some related code:

    // global handler for our DB
    var db *sql.DB
    
    // CLI parameter
    var dbdsn string
    
    func init() {
    
        flag.StringVar(&dbdsn, "dbdsn", "root:root@tcp(localhost:3306)/prod?timeout=5s&tls=false&autocommit=true", "Specifies the MySql DSN connection.")
        flag.Parse()
    
        var err error
        db, err = sql.Open("mysql", dbdsn)
        if err != nil {
            log.Printf("ERROR in sql.Open(): %v", err)
        }
    
        //db.SetMaxIdleConns(5)
    
        // verify the DSN is setup properly1
        err = db.Ping()
        if err != nil {
            panic("PANIC when pinging db: " + err.Error()) // proper error handling instead of panic in your app
        }
    }
    
    // **********
    // * omitted is the Gorilla MUX router and http handler registrations
    // **********
    
    func ArticleHandler(w http.ResponseWriter, r *http.Request, c *Context) (err error) {
    
        m := NewArticle(c)
        id := c.Vars["id"]
    
        var pid int
        var title, body, excerpt, date, slug, fi, fv, region, region_slug string
        err = db.QueryRow(
            "SELECT p.ID, p.post_title, p.post_content, p.post_excerpt, p.post_date, p.post_name, "+
                "(SELECT fpim.meta_value FROM wp_postmeta fpim WHERE fpim.meta_key = '_wp_attached_file' AND fpim.post_id = (SELECT fpim2.meta_value FROM wp_postmeta fpim2 WHERE fpim2.post_id = p.ID AND fpim2.meta_key = '_thumbnail_id' LIMIT 1) LIMIT 1) AS featured_image, "+
                "(SELECT fpim3.meta_value FROM wp_postmeta fpim3 WHERE fpim3.meta_key = 'fv_video' AND fpim3.post_id = p.ID LIMIT 1) AS featured_video, "+
                "t.name as region, t.slug as region_slug "+
                "FROM wp_posts p "+
                "JOIN wp_term_relationships tr ON tr.object_id=p.ID "+
                "JOIN wp_term_taxonomy tt ON tt.term_taxonomy_id=tr.term_taxonomy_id "+
                "JOIN wp_terms t ON t.term_id=tt.term_id "+
                "WHERE p.post_name=? AND p.post_type='post' AND p.post_status='publish' AND p.post_date <= UTC_TIMESTAMP()"+
                "AND tr.object_id=p.ID AND tt.parent = (SELECT t3.term_id FROM wp_terms t3 WHERE t3.name=? LIMIT 1) LIMIT 1",
            id, RegionsParentCategory).
            Scan(&pid, &title, &body, &excerpt, &date, &slug, &fi, &fv, &region, &region_slug)
    
        if err != nil {
            if err == sql.ErrNoRows {
    
                // snipped code for redirects
    
                // article was not found
                return handleNotFound(w, r, c)
    
            } else {
                log.Printf("ERROR in .Scan(): %v", err)
            }
        } else {
            m.Region = Region{
                Name: region,
                Slug: region_slug,
            }
            m.Id = pid
            m.Title = title
            m.Body = template.HTML(body) // render the raw html
            m.Excerpt = excerpt
            m.Datetime = date
            m.Slug = slug
            m.FeaturedImageUrl = fi
            m.FeaturedVideoUrl = fv
        }
    
        web.RenderTemplate(w, "article", m)
        return
    }
    

    5 more DB queries, per request

    In addition to this query, my "Context" you see being passed into the handler runs 4 to 6 additional SQL queries. Therefore, each "article" handler that loads runs about 5 to 7 SQL queries, minimal, using the exact same pattern and *db global variable you see above.

    Timeouts / errors are always on the same DB query

    Here's one of the "context" queries as a comparison:

    rows2, err := db.Query(
        "SELECT p.post_title, p.post_name "+
            "FROM wp_posts p "+
            "WHERE p.post_type='page' AND p.post_status='publish' AND p.post_date <= UTC_TIMESTAMP() "+
            "AND p.post_parent = (SELECT p2.ID FROM wp_posts p2 WHERE p2.post_name=? LIMIT 1) "+
            "ORDER BY p.menu_order",
        FooterPagesParentNameSlug)
    if err != nil {
        log.Printf("ERROR in AllPages .Query() : %v", err)
    } else {
        defer rows2.Close()
        c.AllFooterPages = make([]FooterPage, 0)
        for rows2.Next() {
            var name, slug string
            err := rows2.Scan(&name, &slug)
            if err != nil {
                log.Printf("ERROR in AllPages row.Scan() : %v", err)
            } else {
                p := FooterPage{
                    Page: Page{
                        Title: name,
                        Slug:  slug,
                    },
                }
                c.AllFooterPages = append(c.AllFooterPages, p)
            }
        }
    }
    

    Nothing special there.

    I do call defer rows2.Close() only if there was no error. Perhaps that is part of the issue? This particular SQL query seems to log errors under load tests as no response or mysql driver timing out.

    Questions

    Why am I getting request timeouts logged in excess of 15 to 30 minutes, from an idle site? That seems like a bug with the mysql driver I am using, possibly holding a connection open. But, the last http request was successful and returned a complete page + template.

    I even have the Timeout set in the connection string, which is 5 seconds. Even if it is a problem with the mysql server, why the 15 minute timeout/request logged? Where did that request come from?

    It still could be a MySql driver issue, blocking the request from completing - maybe being blocked by the MySql dedicated VM and an issue there. If that is the case, then how come nothing is logged? What is this random timeout of 15m to 49m minutes? It is usually only 15m or 31m, but sometimes 48m is logged.

    It is very interesting on the "15m" multiples there in the timeouts (@15m, 31m and 48m), allotting for some padding there in seconds.

    Thanks in advance.

  • Still can't authenticate with allowOldPasswords=1

    Still can't authenticate with allowOldPasswords=1

    We're running Go 1.1.1, MySQL 5.0.22 on a separate server (but the database is legacy and MySQL itself has been upgraded a few times, I'm sure it was 4.x at some point.) and "old_passwords" is set to ON. (verified with SHOW VARIABLES.)

    I'm converting a batch of Perl and Ruby scripts to Go, and the Perl and Ruby scripts can connect to this legacy database with no problem. I'm trying to determine if I'm doing something wrong (relatively new to Go) or not.

    In packets.go readResultOK(), the first time through it returns errOldPassword (data=[254]) as expected. Second time through it hits the default branch of the case statement, ultimately returning a "Error 1045: Access denied for user" back to the calling script.

    I'm going to see if I can get the DBA to set "old_passwords" to OFF, but am still curious if I'm missing something. Thanks!

  • Best practice

    Best practice

    With this driver, is it best practice to every HTTP request open the database using Open("mysql","...") and close it using Close() at the end of every requst cycle

    OR

    just open it once and never close it irrespective of the request cycle?

  • EOF error in packets.go readPacket() not propagating

    EOF error in packets.go readPacket() not propagating

    I'm running a query that is returning around 250k rows from a MySQL 5.1 server. Occasionally I will get incomplete result sets without an error being returned to my invocation of the API methods. The following is printed:

    [MySQL] 2013/07/10 11:18:38 packets.go:67: EOF
    

    The relevant snippet of code:

    errLog.Print(err.Error())
    return nil, driver.ErrBadConn
    

    Replacing "Print" with "Panic" shows the following stack trace:

    [MySQL] 2013/07/10 11:23:33 packets.go:67: EOF panic: EOF

    goroutine 1 [running]: log.(_Logger).Panic(0xc2000aa1e0, 0x7fd696a4f460, 0x1, 0x1) /usr/local/go/src/pkg/log/log.go:193 +0xa7 github.com/go-sql-driver/mysql.(_mysqlConn).readPacket(0xc2000c3770, 0xc200100000, 0x66, 0x1000, 0xc2000ae000, ...) ROOT/src/github.com/go-sql-driver/mysql/packets.go:67 +0x683 github.com/go-sql-driver/mysql.(_mysqlRows).readBinaryRow(0xc2000fe540, 0xc2000f6680, 0x4, 0x4, 0x0, ...) ROOT/src/github.com/go-sql-driver/mysql/packets.go:861 +0x4e github.com/go-sql-driver/mysql.(_mysqlRows).Next(0xc2000fe540, 0xc2000f6680, 0x4, 0x4, 0x0, ...) ROOT/src/github.com/go-sql-driver/mysql/rows.go:68 +0x120 database/sql.(*Rows).Next(0xc2000c24e0, 0x676020) /usr/local/go/src/pkg/database/sql/sql.go:1310 +0xc1 main.writeBooks(0xc2000c2120, 0xc2000aa5f0) ROOT/src/example.com/sitemap/sitemapgenerator.go:152 +0x167 main.main() ROOT/src/example.com/sitemap/sitemapgenerator.go:280 +0x87e

    goroutine 2 [syscall]: exit status 2

    It looks like readBinaryRow is not actually returning the non-nil error, and instead returning early with a nil error:

    func (rows *mysqlRows) readBinaryRow(dest []driver.Value) (err error) { data, err := rows.mc.readPacket() if err != nil { return }

    This bug is particularly insidious because it is happening in a call to .Next(), which means that callers will be operating on partial result sets without knowing it.

    System:

    • Ubuntu 13.04 64-bit
    • go 1.1
    • MySQL 5.1.63-0ubuntu0.10.04.1-log

    This happens with both an SSH port forward and when on a proper network connection (rackspace cloud).

  • packets.go:66: unexpected EOF followed by packets.go:412: busy buffer followed by driver: bad connection followed by connection.go:319: invalid connection

    packets.go:66: unexpected EOF followed by packets.go:412: busy buffer followed by driver: bad connection followed by connection.go:319: invalid connection

    Issue description

    MySQL SELECT queries fail unexpectedly at random times in a long running CLI script.

    Example code

    I can't really provide a sample code, but I can tell you that I only do simple SELECTqueries in my CLI program. I don't do any transactions, nor any UPDATEs. All the MySQL operations in my program are read-only (just a lot of SELECTs only). My program is doing just ONE query at a time, it runs on a single core virtual machine ($5 DigitalOcean Droplet) with only one go routine running at a time. I do not run out of RAM, I checked that, the swap file is only barely used on this virtual machine.

    Error log

    [mysql] 2017/05/02 16:48:51 packets.go:66: unexpected EOF
    [mysql] 2017/05/02 16:48:52 packets.go:412: busy buffer
    driver: bad connection
    [mysql] 2017/05/02 16:48:52 connection.go:319: invalid connection
    

    Configuration

    Driver version (or git SHA): git log shows: commit 147bd02c2c516cf9a8878cb75898ee8a9eea0228 Author: astaxie [email protected] Date: Sat Apr 29 00:02:31 2017 +0800

    But the exact same issue is happening with a version from December, 2016. With that version the log is:

    [mysql] 2017/05/01 09:55:47 packets.go:66: unexpected EOF
    [mysql] 2017/05/01 09:55:47 packets.go:412: busy buffer
    driver: bad connection
    [mysql] 2017/05/01 09:55:48 connection.go:312: invalid connection
    

    So this problem is not new. I first noticed this issue this year. Sometime last fall I was using the exact same program on the exact same database, compiled by the then latest stable version of Go (probably Go 1.7), and at that time I never ran into this issue. So this must be something new, it must be related to some change(s) that occurred right around or before Go 1.8 got released.

    Go version: go version go1.8.1 linux/amd64

    Server version: mysql-5.5.55

    Server OS: CentOS release 6.9 (but I compiled the program under Debian 8.7 (jessie), transferred the binary file over to the CentOS 6.9 droplet and ran it under CentOS 6.9 -- thanks to static builds this should not be a problem. I do the same with a bunch of other Go programs and this is the only one which fails)

    I noticed today that someone else also ran into this error pattern ( "packets.go:66: unexpected EOF followwed by packets.go:412: busy buffer followed by driver: bad connection" ) recently, please see his Edit#2 on this StackOverflow page: http://stackoverflow.com/questions/43696607/mysql-to-json-inconsistent-extraction

    This is a showstopper bug for me. I might need to switch back to Go 1.7.x and recompile my program and see if that fixes this issue or not. Or do you have a better idea on how to debug this?

    BTW, my program is doing millions of SELECT queries and only a few of them fail. On every run different queries fail, it seems to me totally random.

  • Google Cloud SQL on App Engine - Connection String Outdated?

    Google Cloud SQL on App Engine - Connection String Outdated?

    Issue description

    In the readme for this driver, the connection string for connecting to Google Cloud SQL on App Engine is given as:

    user@cloudsql(project-id:instance-name)/dbname

    While Google's cloudsql package documentation also affirms this for your driver, there are posts on Stack Overflow such as this one which claim that one needs to use projectid:regionname:instancename rather than projectid:instancename.

    What is the correct connection string? Neither of these is currently working.

    Example code

    A more detailed post can be found here: http://stackoverflow.com/questions/39668672/trouble-connecting-to-google-cloud-sql-server-from-deployed-app

    Error log

    My server is returning a 500 response whenever I make a call to an endpoint that uses the Cloud SQL database. The database connection works fine when I am connecting to the server from a locally served version of my app.

    I have tried a variety of connection strings, and here are some errors that were logged in the Google Cloud Console:

    5447 [Warning] 'user' entry 'root@localhost' ignored in --skip-name-resolve mode.
    
    5447 [Warning] entry 'root'@'localhost' in mysql.user is ignored because it duplicates entry in mysql.system_user
    
    14409 [Note] Aborted connection 14409 to db: 'User' user: 'root' host: 'xxx.xxx.xxx.xxx' (Got an error reading communication packets)
    

    (No password was specified in the connection string because the documentation does not specify the need for a password.This postmentions that the connection password must be null when the app attempts to connect to the server using root@localhost.)

    6170 [Note] Access denied for user 'root'@'cloudsqlproxy~xx.xxx.xxx.xx' (using password: NO) 
    

    I also tried connecting with a user other than the root user (username: newuser):

    5447 [Warning] 'user' entry 'newuser@localhost' ignored in --skip-name-resolve mode.
    

    Configuration

    Driver version (or git SHA): https://github.com/go-sql-driver/mysql/tree/3654d25ec346ee8ce71a68431025458d52a38ac0

    Go version: go version go1.6.2 linux/amd64

    Server version: The Google Cloud SQL instance is running MySQL 5.7

    Server OS: From the Compute Engine tab, it looks like the server hosting the most recent version of my app is running Debian 7.11 (Wheezy)

  • packets.go:417: busy buffer, packets.go:436: busy buffer

    packets.go:417: busy buffer, packets.go:436: busy buffer

    Issue description

    Tell us what should happen and what happens instead

    in console output: Scenarion 1: `[mysql] 2019/07/10 14:54:46 packets.go:417: busy buffer

    [mysql] 2019/07/10 14:54:46 packets.go:417: busy buffer

    [mysql] 2019/07/10 14:54:47 packets.go:436: busy buffer

    [mysql] 2019/07/10 14:54:47 packets.go:417: busy buffer

    commands out of sync. You can't run this command now

    [mysql] 2019/07/10 14:54:47 packets.go:436: busy buffer

    [mysql] 2019/07/10 14:54:47 packets.go:417: busy buffer

    commands out of sync. You can't run this command now

    [mysql] 2019/07/10 14:54:47 packets.go:436: busy buffer

    [mysql] 2019/07/10 14:54:47 packets.go:417: busy buffer

    commands out of sync. You can't run this command now

    [mysql] 2019/07/10 14:54:47 packets.go:436: busy buffer

    [mysql] 2019/07/10 14:54:47 packets.go:417: busy buffer

    [mysql] 2019/07/10 14:54:48 packets.go:436: busy buffer

    [mysql] 2019/07/10 14:54:48 packets.go:417: busy buffer sql: expected 4 arguments, got 2 sql: expected 4 arguments, got 2 sql: expected 4 arguments, got 2 **Scenario 2:**[mysql] 2019/07/10 14:58:53 packets.go:417: busy buffer

    [mysql] 2019/07/10 14:59:11 packets.go:417: busy buffer

    [mysql] 2019/07/10 14:59:43 packets.go:417: busy buffer`

    Example code

    Scenario 1: I got a http message to API, create another goroutine (and close a first one to let free http connection) and do something with message, try to get data from MySQL.. all fine if I mak a tests with <100 messages and all bad if I got more then 100 messages per second. Output in the top...

    Scenario 2 ok just like a test I create new logic with separate DB connection for each incoming message, works better but expensive by connections resources... and one buffer error. Output in top

    Results:

    Some part of messages was processed, some (with errors in output, no)... if we get first error in console any other Querys not work, if we try to use ping method before send - hi return nil... All errors handled by mysql golang driver and just printed with log. but not returned to upper level (????!!!) So like a result impossible to detect error and establish new connection. And yes all fine if you have <100 requests and <100 DB querys.

    P.S. I have found issue (dated by 2015) about same problems in multi routines mode, but this absolutely not explained why we cant handle error on app level and why we still get :417 error in each 1 goroutine=1 DB connector mode. Any Ideas how to solve this?

    If possible, please enter some example code here to reproduce the issue.
    

    Error log

    If you have an error log, please paste it here.
    

    Configuration

    Driver version (or git SHA): last

    Go version: run go version in your console 1.12.6

    Server version: E.g. MySQL 5.6, MariaDB 10.0.20

    Server OS: E.g. Debian 8.1 (Jessie), Windows 10 Windows 10

  • Multi Result support

    Multi Result support

    I am getting the following error when calling on my stored procedure

    Error 1312: PROCEDURE mydb.GetAllNotes can't return a result set in the given context
    

    I am calling on my stored procedure with this code

    db.Query("CALL MyStoredProcedure()")
    
  • fix driver.ErrBadConn behavior, stop repeated queries

    fix driver.ErrBadConn behavior, stop repeated queries

    The docs for database/sql/driver note that driver.ErrBadConn should only be returned when a connection is in a bad state. We overused it, which has lead to re-executed queries in some cases.

    With this change, all instances of driver.ErrBadConn are replaced with ErrInvalidConn unless they are in an exported function and appear before the network is hit. I also replaced it as a return value in Close, where retrying makes no sense whatsoever (EDIT database/sql does not retry in that case anyway).

    I'm on the fence, maybe we should drop it altogether - usage is optional anyway.

    Inspired by / fixes #295 Probably also fixes at least parts of #185 and maybe even #257 and #281...

    This could impact legacy client code - but only if it ignores errors and has no internal retry logic.

  • Set a nil date to NULL rather than 0000-00-00

    Set a nil date to NULL rather than 0000-00-00

    I've got a row defined: "date_disconnect" datetime DEFAULT NULL

    I'm also running mysql in strictmode:

    > select @@global.sql_mode\G
    *************************** 1. row ***************************
    @@global.sql_mode: REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    

    I set these modes because if I want to indicate the absence of a data, I like to use NULL, rather than set an "arbitrary" date 2015 years ago. In line with ANSI SQL.

    The DSN used: root:@tcp(localhost:3306)/cluegetter?sql_notes=false&strict=true

    Please let me know what you think of this PR. I'll get some tests if you agree on the chosen approach.

  • Connection Pool seems not to be used properly (any longer)

    Connection Pool seems not to be used properly (any longer)

    Issue description

    the connection pooling to the database server seems to be broken since golang version 1.13.1 or with the latest commit (14bb9c0).

    running in version 1.12.9 and up to git commit 877a977 everything seemed to work

    I have two servers, running each GO applications, that held two different connection pools to the same database-server - one connection is heavily used (DB1 with 20 Requests per second) and one is rarely used (DB2 with 1 Request per Minute)

    server1 runs since round about 5-10 minutes, server 2 runs since round about 3 days.

    broken means that a part of the connections is no longer used and seems to be stale:

    MariaDB [(none)]> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST where HOST like '%server1%';
    +--------+------+---------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    | ID     | USER | HOST          | DB     | COMMAND | TIME | STATE | INFO | TIME_MS    | STAGE | MAX_STAGE | PROGRESS | MEMORY_USED | EXAMINED_ROWS | QUERY_ID  |
    +--------+------+---------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    | 599325 | dbuser | server1:41744 | DB1  | Sleep   |    0 |       | NULL |    423.089 |     0 |         0 |    0.000 |       83672 |             0 | 653926700 |
    | 599233 | dbuser | server1:38024 | DB2 | Sleep   |   57 |       | NULL |  57283.466 |     0 |         0 |    0.000 |       83680 |             0 | 653885165 |
    | 599232 | dbuser | server1:38022 | DB2 | Sleep   |  117 |       | NULL | 117233.167 |     0 |         0 |    0.000 |       83680 |             0 | 653840343 |
    | 599205 | dbuser | server1:37538 | DB1  | Sleep   |    0 |       | NULL |    523.742 |     0 |         0 |    0.000 |       83680 |             0 | 653926568 |
    | 599204 | dbuser | server1:37534 | DB1  | Sleep   |    0 |       | NULL |    356.378 |     0 |         0 |    0.000 |       83672 |             0 | 653926789 |
    | 599203 | dbuser | server1:37532 | DB1  | Sleep   |    0 |       | NULL |    120.182 |     0 |         0 |    0.000 |       83672 |             0 | 653927036 |
    | 599164 | dbuser | server1:36566 | DB1  | Sleep   |    0 |       | NULL |    118.011 |     0 |         0 |    0.000 |      100544 |             0 | 653927037 |
    | 599163 | dbuser | server1:36522 | DB1  | Sleep   |    0 |       | NULL |    368.234 |     0 |         0 |    0.000 |       83688 |             0 | 653926767 |
    | 599162 | dbuser | server1:36498 | DB1  | Sleep   |    0 |       | NULL |    413.715 |     0 |         0 |    0.000 |       83672 |             0 | 653926722 |
    | 599161 | dbuser | server1:36496 | DB1  | Sleep   |    0 |       | NULL |    182.833 |     0 |         0 |    0.000 |       83688 |             0 | 653926948 |
    | 599160 | dbuser | server1:36488 | DB1  | Sleep   |    0 |       | NULL |    170.804 |     0 |         0 |    0.000 |       83680 |             0 | 653926989 |
    | 599159 | dbuser | server1:36486 | DB1  | Sleep   |    0 |       | NULL |    480.610 |     0 |         0 |    0.000 |       83672 |             0 | 653926634 |
    | 599157 | dbuser | server1:36482 | DB2 | Sleep   |  399 |       | NULL | 399946.550 |     0 |         0 |    0.000 |       91896 |             0 | 653625317 |
    | 599156 | dbuser | server1:36480 | DB1  | Sleep   |  400 |       | NULL | 400178.841 |     0 |         0 |    0.000 |       59664 |             0 | 653625282 |
    | 599155 | dbuser | server1:36478 | DB1  | Sleep   |  400 |       | NULL | 400196.065 |     0 |         0 |    0.000 |      100032 |             0 | 653625241 |
    +--------+------+---------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    

    I am a little bit confused about those two conenctions at the end... While on the other server go runs the old version and commit:

    MariaDB [(none)]> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST where HOST like '%server2%';
    +--------+------+---------------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    | ID     | USER | HOST                | DB     | COMMAND | TIME | STATE | INFO | TIME_MS    | STAGE | MAX_STAGE | PROGRESS | MEMORY_USED | EXAMINED_ROWS | QUERY_ID  |
    +--------+------+---------------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    | 453236 | dbuser | server2:33138 | DB1  | Sleep   |    0 |       | NULL |    954.053 |     0 |         0 |    0.000 |       83672 |             0 | 653925859 |
    | 453235 | dbuser | server2:33136 | DB1  | Sleep   |    2 |       | NULL |   2311.532 |     0 |         0 |    0.000 |       83672 |             0 | 653925175 |
    | 453234 | dbuser | server2:33132 | DB1  | Sleep   |    0 |       | NULL |    792.861 |     0 |         0 |    0.000 |       83672 |             0 | 653925992 |
    | 453233 | dbuser | server2:33130 | DB1  | Sleep   |    2 |       | NULL |   2065.223 |     0 |         0 |    0.000 |       83672 |             0 | 653925349 |
    | 453232 | dbuser | server2:33126 | DB1  | Sleep   |    2 |       | NULL |   2812.222 |     0 |         0 |    0.000 |      100560 |             0 | 653924906 |
    | 453231 | dbuser | server2:33124 | DB1  | Sleep   |    1 |       | NULL |   1487.906 |     0 |         0 |    0.000 |       83672 |             0 | 653925637 |
    | 453230 | dbuser | server2:33120 | DB1  | Sleep   |    0 |       | NULL |    287.197 |     0 |         0 |    0.000 |       83672 |             0 | 653926457 |
    | 453229 | dbuser | server2:33118 | DB1  | Sleep   |    0 |       | NULL |     84.411 |     0 |         0 |    0.000 |       83672 |             0 | 653926656 |
    | 453226 | dbuser | server2:33114 | DB1  | Sleep   |    0 |       | NULL |    121.208 |     0 |         0 |    0.000 |      100544 |             0 | 653926612 |
    | 453225 | dbuser | server2:33112 | DB1  | Sleep   |    0 |       | NULL |    509.967 |     0 |         0 |    0.000 |       83672 |             0 | 653926103 |
    | 453222 | dbuser | server2:33106 | DB1  | Sleep   |    2 |       | NULL |   2904.463 |     0 |         0 |    0.000 |       83672 |             0 | 653924840 |
    | 453221 | dbuser | server2:33108 | DB1  | Sleep   |    0 |       | NULL |    363.417 |     0 |         0 |    0.000 |       83688 |             0 | 653926217 |
    | 436446 | dbuser | server2:45546 | DB2 | Sleep   |  175 |       | NULL | 175585.732 |     0 |         0 |    0.000 |       83680 |             0 | 653799233 |
    | 436445 | dbuser | server2:45544 | DB2 | Sleep   |   55 |       | NULL |  55673.248 |     0 |         0 |    0.000 |       83680 |             0 | 653885968 |
    | 436443 | dbuser | server2:45534 | DB2 | Sleep   |  115 |       | NULL | 115555.698 |     0 |         0 |    0.000 |       83680 |             0 | 653840992 |
    | 436442 | dbuser | server2:45532 | DB2 | Sleep   |  235 |       | NULL | 235540.642 |     0 |         0 |    0.000 |       83680 |             0 | 653751459 |
    | 436438 | dbuser | server2:45372 | DB1  | Sleep   |    0 |       | NULL |      7.290 |     0 |         0 |    0.000 |      124632 |             0 | 653926744 |
    | 436437 | dbuser | server2:45370 | DB1  | Sleep   |    0 |       | NULL |    314.409 |     0 |         0 |    0.000 |       83672 |             0 | 653926392 |
    | 436436 | dbuser | server2:45344 | DB1  | Sleep   |    1 |       | NULL |   1791.661 |     0 |         0 |    0.000 |       83680 |             0 | 653925459 |
    | 436435 | dbuser | server2:45342 | DB1  | Sleep   |    2 |       | NULL |   2208.515 |     0 |         0 |    0.000 |      116928 |             0 | 653925261 |
    | 436434 | dbuser | server2:45340 | DB1  | Sleep   |    1 |       | NULL |   1391.047 |     0 |         0 |    0.000 |      100056 |             0 | 653925725 |
    | 436433 | dbuser | server2:45338 | DB1  | Sleep   |    2 |       | NULL |   2441.613 |     0 |         0 |    0.000 |      100544 |             0 | 653925062 |
    | 436432 | dbuser | server2:45336 | DB1  | Sleep   |    1 |       | NULL |   1806.901 |     0 |         0 |    0.000 |       83672 |             0 | 653925436 |
    | 436431 | dbuser | server2:45334 | DB1  | Sleep   |    0 |       | NULL |    567.622 |     0 |         0 |    0.000 |       83672 |             0 | 653926059 |
    | 436430 | dbuser | server2:45332 | DB1  | Sleep   |    0 |       | NULL |    840.094 |     0 |         0 |    0.000 |      100056 |             0 | 653925948 |
    | 436429 | dbuser | server2:45330 | DB1  | Sleep   |    1 |       | NULL |   1152.405 |     0 |         0 |    0.000 |       83672 |             0 | 653925793 |
    | 436428 | dbuser | server2:45324 | DB1  | Sleep   |    2 |       | NULL |   2424.172 |     0 |         0 |    0.000 |       83672 |             0 | 653925084 |
    | 436427 | dbuser | server2:45322 | DB1  | Sleep   |    0 |       | NULL |    402.280 |     0 |         0 |    0.000 |       83672 |             0 | 653926193 |
    +--------+------+---------------------+--------+---------+------+-------+------+------------+-------+-----------+----------+-------------+---------------+-----------+
    

    The point why I've been paying attention to this is that all of my connections from server1 got stale after about 38 hours of running. The Connections were not interrupted (all 50 connections were stale) and new connections (i've started another instance of the same application) were able to create new connections to the database server. Maybe you have an idea how to debug such a situation...

    Example code

    all of the databases requests look like this, while the initial connection is only initiated once and then the pool is used.

    ////////////////////// DB Connection
    // establish database connection
    var dsn = appConfiguration.dbuser + ":" + appConfiguration.dbpass + "@tcp(" + appConfiguration.dbhostname + ":" + appConfiguration.dbport + ")/" + appConfiguration.dbNamename
    dbName, err := sql.Open("mysql", dsn)
    dbName.SetConnMaxLifetime(0)
    dbName.SetMaxIdleConns(50)
    dbName.SetMaxOpenConns(50)
    
    // if there is an error opening the connection, handle it
    if err != nil {
    	panic(err.Error())
    }
    
    ctxVCspstoredprocedure := context.Background()
    
    rowsResultsVCspstoredprocedure, err := dbName.QueryContext(ctxVCspstoredprocedure, "CALL storedprocedure((?),(?),(?),(?),(?),(?),(?),(?),(?));", "version", "xxx", "xxx", "p", "1", sql.NullString{}, sql.NullString{}, appConfiguration.identifier, 1)
    if err != nil {
    	log.Fatal(err)
    }
    defer rowsResultsVCspstoredprocedure.Close()
    
    for rowsResultsVCspstoredprocedure.Next() {
    	var spstoredprocedureVersion int
    	var spstoredprocedureVar1 int
    	var spstoredprocedureVar2 int
    	if err := rowsResultsVCspstoredprocedure.Scan(&spstoredprocedureVar1, &spstoredprocedureVar2, &spstoredprocedureVersion); err != nil {
    		log.Fatal(err)
    	}
    	if spstoredprocedureVersion != SPstoredprocedureVERSIONREQUIREMENT {
    		println(time.Now().Format(time.RFC3339) + " " + " - START - SPstoredprocedure VERSION check - ERROR: Version does not meet requirements by this version. Application requires: " + strconv.Itoa(SPstoredprocedureVERSIONREQUIREMENT) + " but DB seems to be: " + strconv.Itoa(spstoredprocedureVersion))
    		os.Exit(3)
    	} else {
    		println(time.Now().Format(time.RFC3339) + "  - START - SPstoredprocedure VERSION check - PASSED")
    	}
    }
    if err := rowsResultsVCspstoredprocedure.Err(); err != nil {
    	// print error when something went wrong
    	println(time.Now().Format(time.RFC3339)+"  - START - SPstoredprocedure VERSION check - GENERAL DB RESULTS ERROR:", err.Error())
    	println(time.Now().Format(time.RFC3339) + "  - START - SPstoredprocedure VERSION check - Stored Predure and/or Table Structure missing - EXIT")
    	os.Exit(3)
    }
    

    Configuration

    Server version: Maria.DB 10.0.38 Server OS: Debian 10 (buster) - latest updates applied, Go Applications running in Docker Container

  • Feature request: Fetch connection time_zone automatically.

    Feature request: Fetch connection time_zone automatically.

    Issue description

    Open dsn, if dsn's loc not set, the mysql timestamp field will parse error. just see the sample below.

    Example code

    mysql

    ```sql
    CREATE TABLE `Test1` (
      `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
      `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
    
    
    insert into Test1 values (1, '2022-01-01 00:00:00')
    
    show VARIABLES like '%time_zone%';
    

    the output: | Variable_name | Value | | :-- | :-- | | system_time_zone | CST | | time_zone | +08:00 |

    SELECT unix_timestamp(create_time) from Test1 where id = 1;
    

    the output

    | unix_timestamp(create_time) | | :--: | | 1640966400 |

    package main
    
    import (
    	"database/sql"
    	"fmt"
    	_ "github.com/go-sql-driver/mysql"
    	"time"
    )
    
    func main() {
      var user = "user"
      var pwd = "password"
      var dbName = "dbname"
      dsn := fmt.Sprintf("%s:%s@tcp(localhost:3306)/%s?timeout=100s&parseTime=true&interpolateParams=true", user, pwd, dbName)
      db, err := sql.Open("mysql", dsn)
      if err != nil {
        panic(err)
      }
      defer db.Close()
    
      rows, err := db.Query("select create_time from Test1 limit 1")
      if err != nil {
        panic(err)
      }
      for rows.Next() {
        t := time.Time{}
        rows.Scan(&t)
        fmt.Println(t)
        fmt.Println(t.Unix())
      }
    }
    

    Error log

    2022-01-01 00:00:00 +0000 UTC
    1640995200
    
    this is not equal the mysql create_time ->1640966400
    
    

    reason of the not equal

    the error is because, if the dsn's loc is not set, go-sql-driver will use the default loc1, loc2

    how does go-sql-driver parse the timestamp field:

    1. get the timestamp filed
    2. convert it to []byte
    3. use the timestamp pattern -> 0000-00-00 00:00:00.000000 to parse the []byte
    4. so get the year, moth, day, hour, min,sec
    5. finally, use call the time.Date(year, month, day, hour, min,sec, mc.Cfg.Loc) to get time.Time. but the mc.cfg.Loc get from the dsn.
    6. if dsn's loc not set , will use the default loc -> UTC.

    thus, client get the wrong timestamp.

    how to fix this

    I'm not sure wether it's a bug or design it like this.

    but I find java jdbc when connect to msyql server, will query SHOW VARIABLES to get the system_time_zone and time_zone. if user's dsn not set the loc, just replace user jdbc's loc with the mysql server's timezone

    go-sql-dirver's source code doesn't has this step, If I can add this feature ?

    Looking forward to your reply!

    Configuration

    Driver version (or git SHA): github.com/go-sql-driver/mysql v1.7.0

    Go version: run go version in your console go version go1.18.2 darwin/amd64

    Server version: E.g. MySQL 5.6, MariaDB 10.0.20

    MySQL 5.6

    Server OS: E.g. Debian 8.1 (Jessie), Windows 10

    macos

  • Master slave DSN connection string

    Master slave DSN connection string

    Issue description

    Does this driver support master,slave DSN string? I've tried below combinations of DSN strings, but couldn't get it to work. Is this supported? I did look at documentation & also here, couldn't find any string with multiple hosts.

    Example code

    #DSN connection string
    username:password@tcp(1.1.1.1:3306,2.2.2.2:3306)/photoprism?parseTime=true
    username:password@tcp(1.1.1.1:3306;2.2.2.2:3306)/photoprism?parseTime=true
    username:password@tcp(1.1.1.1:3306)@tcp(2.2.2.2:3306)/photoprism?parseTime=true
    username:password@tcp(1.1.1.1:3306);(2.2.2.2:3306)/photoprism?parseTime=true
    

    Error log

    If you have an error log, please paste it here.
    dial tcp: lookup 1.1.1.1:3306,2.2.2.2:3306: no such host
    

    Configuration

    Driver version (or git SHA): 1.6.0 Go version: run go version in your console 1.18 Server version: E.g. MySQL 5.6, MariaDB 10.0.20 10.6.9 (irrelevant) Server OS: E.g. Debian 8.1 (Jessie), Windows 10 Ubuntu 22.04 (irrelevant)

  • not think dsn is nil

    not think dsn is nil

    github.com/go-sql-driver/mysql/dsn.go line 358
    not think dsn is nil recommend this code if len(dsn) == 0 || ( !foundSlash && len(dsn) > 0 ) { return nil, errInvalidDSNNoSlash }

  • Parse multiple result sets will be block when use NextResultSet()

    Parse multiple result sets will be block when use NextResultSet()

    Issue description

    Parse multiple result sets will be block when use NextResultSet()

    if the procedure has no select , error will be return in Query(). but if it has select, error will be nil and NextResultSet() function will be block in the end

    Example mysql procedure

    -- first procedure
    CREATE DEFINER=`root`@`%` PROCEDURE `test_proc1`()
    BEGIN
    	SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error",  MYSQL_ERRNO = 10000;
    END;
    
    -- second procedure
    CREATE DEFINER=`root`@`%` PROCEDURE `test_proc2`()
    BEGIN
    	SELECT 1,2;
    	SELECT 3,4;
    	SIGNAL SQLSTATE '10000' SET MESSAGE_TEXT = "some error",  MYSQL_ERRNO = 10000;
    END;
    
    

    Example code

    	dsn := "usr:passwd@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True"
    	db, _ := sql.Open("mysql", dsn)
    
    	_, err := db.Query("CALL test_proc1()")
    	if err != nil { // err is not nil
    		log.Println(err.Error())
    	}
    
    	rows, err := db.Query("CALL test_proc2()")
    	if err != nil { // err is nil
    		panic(err.Error())
    	}
    	defer rows.Close()
    	for rows.Next() {
    		log.Println(rows.Columns())
    	}
    	for rows.NextResultSet() { // thread will be blocked when exec rs.Close()
    		for rows.Next() {
    			log.Println(rows.Columns())
    		}
    	}
    

    Error log

    2022/10/09 15:41:36 Error 10000: some error
    2022/10/09 15:41:38 [1 2] <nil>
    2022/10/09 15:41:38 [3 4] <nil>
    

    Configuration

    Driver version (or git SHA): 1.6.0

    Go version: 1.18

    Server version: MySQL 5.7

    Server OS: Windows 10

  • ErrPktTooLarge message may be incorrect

    ErrPktTooLarge message may be incorrect

    Issue description

    See: https://jira.percona.com/browse/DISTMYSQL-226 for context.

    An application, orchestrator, using the go-mysql-driver is reporting an error ErrPktTooLarge. The error message states "packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server" which I think may be incorrect or misleading.

    The application does not set maxAllowedPacket explicitly via the DSN in the go driver, so I assume that the default value is being used: https://github.com/zendesk/go-sql-driver-mysql/blob/master/const.go#L13 which is 4 MB.

    The MySQL server has a configuration setting of max_allowed_packet = 64MB.

    Error log

    Not really applicable but for context:

    2022-09-26T11:53:51.837501+02:00 orchestratorapp.example.com orchestrator[11887]: 2022-09-26 11:53:51 ERROR flushInstanceWriteBuffer: 2022-09-26 11:53:51 ERROR flushInstanceWriteBuffer last_seen: packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server
    2022-09-26T11:53:51.837569+02:00 orchestratorapp.example.com orchestrator[11887]: packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server
    2022-09-26T11:53:51.837645+02:00 orchestratorapp.example.com orchestrator[11887]: flushInstanceWriteBuffer: 2022-09-26 11:53:51 ERROR flushInstanceWriteBuffer last_seen: packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server
    

    Configuration

    Driver version (or git SHA):

    1.6 (part of orchestrator's vendor tree)

    Go version: run go version in your console

    not 100% sure but "recent".

    Server version: E.g. MySQL 5.6, MariaDB 10.0.20

    • MySQL 8.0.30

    Server OS: E.g. Debian 8.1 (Jessie), Windows 10

    • Linux / CentOS 8

    Expected behaviour

    In this case I expect the error is that the application has not set a large enough maxAllowedPacket value, the application is trying to send a SQL statement which is too large and the driver is correctly reporting an error.

    However, the error message is wrong: the problem here is that the default setting used by the client is too small, the server side setting is probably fine.

    The error should be:

    ErrPktTooLarge = errors.New("packet for query is too large. Try setting or increasing 'maxAllowedPacket' in the DSN or adjusting the 'max_allowed_packet' variable on the server")
    

    e.g. This is a trivial change to the constant message that is being given.

    I can provide a trivial PR for this if needed, but want to see if you agree that the current error message may incorrectly indicate the actual action to take.

  • IAM Authentication in AWS/GCP - dynamic passwords and connection pooling

    IAM Authentication in AWS/GCP - dynamic passwords and connection pooling

    Issue description

    Both aws and gcp allow use am IAM credentials to connect to the database. This is great as you don't have static passwords to manage, the password auth is delegated to IAM instead.

    Both GCP and AWS provide tooling for generating a password on the client, this password can then be used in the regular way in the connection string. Where this is a pain is for long lived processes, the password is only valid for a short period of time, which means a new password must be generated occasionally and the connection string updated. This breaks connection pooling as the password forms part of the connection string, and this the pool of connections.

    https://cloud.google.com/sql/docs/mysql/iam-logins https://docs.aws.amazon.com/cli/latest/reference/rds/generate-db-auth-token.html

    I have previously implemented support for a callback that supplies a password on demand which is executed when the pooled connection is being opened by the driver (rather than an already open pooled connection that is being supplied to the application) in postgres for .Net see https://github.com/npgsql/npgsql/issues/2500

    I'm new to Go and don't yet have the skills to contribute this change yet, but suggesting this would be a useful feature to add to this driver.

    Summary of feature:

    • Connection string is supplied without a password eg: user@protocol(host)
    • somehow we supply a callback/higher order function to generate the password, maybe to the open method?
    • when the driver needs to open a new connection the password func is called with necessary argument (host, db, user) and password is generated
    • the new connection is added to the pool identified by the original connection string - without password
    • connection pooling is not broken
Oracle driver for Go using database/sql

go-oci8 Description Golang Oracle database driver conforming to the Go database/sql interface Installation Install Oracle full client or Instant Clien

Dec 30, 2022
sqlite3 driver for go using database/sql

go-sqlite3 Latest stable version is v1.14 or later not v2. NOTE: The increase to v2 was an accident. There were no major changes or features. Descript

Jan 8, 2023
Go Sql Server database driver.

gofreetds Go FreeTDS wrapper. Native Sql Server database driver. Features: can be used as database/sql driver handles calling stored procedures handle

Dec 16, 2022
Pure Go Postgres driver for database/sql

pq - A pure Go postgres driver for Go's database/sql package Install go get github.com/lib/pq Features SSL Handles bad connections for database/sql S

Jan 2, 2023
Attach hooks to any database/sql driver

sqlhooks Attach hooks to any database/sql driver. The purpose of sqlhooks is to provide a way to instrument your sql statements, making really easy to

Dec 14, 2022
Firebird RDBMS sql driver for Go (golang)

firebirdsql (Go firebird sql driver) Firebird RDBMS http://firebirdsql.org SQL driver for Go Requirements Firebird 2.5 or higher Golang 1.13 or higher

Dec 20, 2022
Qmgo - The Go driver for MongoDB. It‘s based on official mongo-go-driver but easier to use like Mgo.

Qmgo English | 简体中文 Qmgo is a Go driver for MongoDB . It is based on MongoDB official driver, but easier to use like mgo (such as the chain call). Qmg

Dec 28, 2022
Go driver for PostgreSQL over SSH. This driver can connect to postgres on a server via SSH using the local ssh-agent, password, or private-key.

pqssh Go driver for PostgreSQL over SSH. This driver can connect to postgres on a server via SSH using the local ssh-agent, password, or private-key.

Nov 6, 2022
Golang MySQL driver

Install go get github.com/vczyh/go-mysql-driver Usage import _ "github.com/vczyh

Jan 27, 2022
Mirror of Apache Calcite - Avatica Go SQL Driver

Apache Avatica/Phoenix SQL Driver Apache Calcite's Avatica Go is a Go database/sql driver for the Avatica server. Avatica is a sub-project of Apache C

Nov 3, 2022
Microsoft SQL server driver written in go language

A pure Go MSSQL driver for Go's database/sql package Install Requires Go 1.8 or above. Install with go get github.com/denisenkom/go-mssqldb . Connecti

Dec 26, 2022
Lightweight Golang driver for ArangoDB

Arangolite Arangolite is a lightweight ArangoDB driver for Go. It focuses on pure AQL querying. See AranGO for a more ORM-like experience. IMPORTANT:

Sep 26, 2022
Golang driver for ClickHouse

ClickHouse Golang SQL database driver for Yandex ClickHouse Key features Uses native ClickHouse tcp client-server protocol Compatibility with database

Jan 8, 2023
GO DRiver for ORacle DB

Go DRiver for ORacle godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wra

Jan 5, 2023
PostgreSQL driver and toolkit for Go

pgx - PostgreSQL Driver and Toolkit pgx is a pure Go driver and toolkit for PostgreSQL. pgx aims to be low-level, fast, and performant, while also ena

Jan 4, 2023
Go language driver for RethinkDB
Go language driver for RethinkDB

RethinkDB-go - RethinkDB Driver for Go Go driver for RethinkDB Current version: v6.2.1 (RethinkDB v2.4) Please note that this version of the driver on

Dec 24, 2022
goriak - Go language driver for Riak KV
goriak - Go language driver for Riak KV

goriak Current version: v3.2.1. Riak KV version: 2.0 or higher, the latest version of Riak KV is always recommended. What is goriak? goriak is a wrapp

Nov 22, 2022
Mongo Go Models (mgm) is a fast and simple MongoDB ODM for Go (based on official Mongo Go Driver)
Mongo Go Models (mgm) is a fast and simple MongoDB ODM for Go (based on official Mongo Go Driver)

Mongo Go Models Important Note: We changed package name from github.com/Kamva/mgm/v3(uppercase Kamva) to github.com/kamva/mgm/v3(lowercase kamva) in v

Jan 2, 2023
The MongoDB driver for Go

The MongoDB driver for Go This fork has had a few improvements by ourselves as well as several PR's merged from the original mgo repo that are current

Jan 8, 2023