bump reva and deps
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
+107
-74
@@ -13,10 +13,13 @@ import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,15 +28,17 @@ type mysqlConn struct {
|
||||
netConn net.Conn
|
||||
rawConn net.Conn // underlying connection when netConn is TLS connection.
|
||||
result mysqlResult // managed by clearResult() and handleOkPacket().
|
||||
compIO *compIO
|
||||
cfg *Config
|
||||
connector *connector
|
||||
maxAllowedPacket int
|
||||
maxWriteSize int
|
||||
writeTimeout time.Duration
|
||||
flags clientFlag
|
||||
status statusFlag
|
||||
sequence uint8
|
||||
compressSequence uint8
|
||||
parseTime bool
|
||||
compress bool
|
||||
|
||||
// for context support (Go 1.8+)
|
||||
watching bool
|
||||
@@ -41,71 +46,92 @@ type mysqlConn struct {
|
||||
closech chan struct{}
|
||||
finished chan<- struct{}
|
||||
canceled atomicError // set non-nil if conn is canceled
|
||||
closed atomicBool // set when conn is closed, before closech is closed
|
||||
closed atomic.Bool // set when conn is closed, before closech is closed
|
||||
}
|
||||
|
||||
// Helper function to call per-connection logger.
|
||||
func (mc *mysqlConn) log(v ...any) {
|
||||
_, filename, lineno, ok := runtime.Caller(1)
|
||||
if ok {
|
||||
pos := strings.LastIndexByte(filename, '/')
|
||||
if pos != -1 {
|
||||
filename = filename[pos+1:]
|
||||
}
|
||||
prefix := fmt.Sprintf("%s:%d ", filename, lineno)
|
||||
v = append([]any{prefix}, v...)
|
||||
}
|
||||
|
||||
mc.cfg.Logger.Print(v...)
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) readWithTimeout(b []byte) (int, error) {
|
||||
to := mc.cfg.ReadTimeout
|
||||
if to > 0 {
|
||||
if err := mc.netConn.SetReadDeadline(time.Now().Add(to)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return mc.netConn.Read(b)
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) writeWithTimeout(b []byte) (int, error) {
|
||||
to := mc.cfg.WriteTimeout
|
||||
if to > 0 {
|
||||
if err := mc.netConn.SetWriteDeadline(time.Now().Add(to)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return mc.netConn.Write(b)
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) resetSequence() {
|
||||
mc.sequence = 0
|
||||
mc.compressSequence = 0
|
||||
}
|
||||
|
||||
// syncSequence must be called when finished writing some packet and before start reading.
|
||||
func (mc *mysqlConn) syncSequence() {
|
||||
// Syncs compressionSequence to sequence.
|
||||
// This is not documented but done in `net_flush()` in MySQL and MariaDB.
|
||||
// https://github.com/mariadb-corporation/mariadb-connector-c/blob/8228164f850b12353da24df1b93a1e53cc5e85e9/libmariadb/ma_net.c#L170-L171
|
||||
// https://github.com/mysql/mysql-server/blob/824e2b4064053f7daf17d7f3f84b7a3ed92e5fb4/sql-common/net_serv.cc#L293
|
||||
if mc.compress {
|
||||
mc.sequence = mc.compressSequence
|
||||
mc.compIO.reset()
|
||||
}
|
||||
}
|
||||
|
||||
// Handles parameters set in DSN after the connection is established
|
||||
func (mc *mysqlConn) handleParams() (err error) {
|
||||
var cmdSet strings.Builder
|
||||
|
||||
for param, val := range mc.cfg.Params {
|
||||
switch param {
|
||||
// Charset: character_set_connection, character_set_client, character_set_results
|
||||
case "charset":
|
||||
charsets := strings.Split(val, ",")
|
||||
for _, cs := range charsets {
|
||||
// ignore errors here - a charset may not exist
|
||||
if mc.cfg.Collation != "" {
|
||||
err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation)
|
||||
} else {
|
||||
err = mc.exec("SET NAMES " + cs)
|
||||
}
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Other system vars accumulated in a single SET command
|
||||
default:
|
||||
if cmdSet.Len() == 0 {
|
||||
// Heuristic: 29 chars for each other key=value to reduce reallocations
|
||||
cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1))
|
||||
cmdSet.WriteString("SET ")
|
||||
} else {
|
||||
cmdSet.WriteString(", ")
|
||||
}
|
||||
cmdSet.WriteString(param)
|
||||
cmdSet.WriteString(" = ")
|
||||
cmdSet.WriteString(val)
|
||||
if cmdSet.Len() == 0 {
|
||||
// Heuristic: 29 chars for each other key=value to reduce reallocations
|
||||
cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1))
|
||||
cmdSet.WriteString("SET ")
|
||||
} else {
|
||||
cmdSet.WriteString(", ")
|
||||
}
|
||||
cmdSet.WriteString(param)
|
||||
cmdSet.WriteString(" = ")
|
||||
cmdSet.WriteString(val)
|
||||
}
|
||||
|
||||
if cmdSet.Len() > 0 {
|
||||
err = mc.exec(cmdSet.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// markBadConn replaces errBadConnNoWrite with driver.ErrBadConn.
|
||||
// This function is used to return driver.ErrBadConn only when safe to retry.
|
||||
func (mc *mysqlConn) markBadConn(err error) error {
|
||||
if mc == nil {
|
||||
return err
|
||||
if err == errBadConnNoWrite {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
if err != errBadConnNoWrite {
|
||||
return err
|
||||
}
|
||||
return driver.ErrBadConn
|
||||
return err
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Begin() (driver.Tx, error) {
|
||||
@@ -114,7 +140,6 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) {
|
||||
|
||||
func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
|
||||
if mc.closed.Load() {
|
||||
mc.log(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
var q string
|
||||
@@ -135,10 +160,14 @@ func (mc *mysqlConn) Close() (err error) {
|
||||
if !mc.closed.Load() {
|
||||
err = mc.writeCommandPacket(comQuit)
|
||||
}
|
||||
mc.close()
|
||||
return
|
||||
}
|
||||
|
||||
// close closes the network connection and clear results without sending COM_QUIT.
|
||||
func (mc *mysqlConn) close() {
|
||||
mc.cleanup()
|
||||
mc.clearResult()
|
||||
return
|
||||
}
|
||||
|
||||
// Closes the network connection and unsets internal variables. Do not call this
|
||||
@@ -157,7 +186,7 @@ func (mc *mysqlConn) cleanup() {
|
||||
return
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
mc.log(err)
|
||||
mc.log("closing connection:", err)
|
||||
}
|
||||
// This function can be called from multiple goroutines.
|
||||
// So we can not mc.clearResult() here.
|
||||
@@ -176,7 +205,6 @@ func (mc *mysqlConn) error() error {
|
||||
|
||||
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
|
||||
if mc.closed.Load() {
|
||||
mc.log(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
// Send command
|
||||
@@ -217,8 +245,10 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||
buf, err := mc.buf.takeCompleteBuffer()
|
||||
if err != nil {
|
||||
// can not take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return "", ErrInvalidConn
|
||||
mc.cleanup()
|
||||
// interpolateParams would be called before sending any query.
|
||||
// So its safe to retry.
|
||||
return "", driver.ErrBadConn
|
||||
}
|
||||
buf = buf[:0]
|
||||
argPos := 0
|
||||
@@ -309,7 +339,6 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
|
||||
|
||||
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
if mc.closed.Load() {
|
||||
mc.log(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
if len(args) != 0 {
|
||||
@@ -369,7 +398,6 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
|
||||
handleOk := mc.clearResult()
|
||||
|
||||
if mc.closed.Load() {
|
||||
mc.log(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
if len(args) != 0 {
|
||||
@@ -385,31 +413,34 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
|
||||
}
|
||||
// Send command
|
||||
err := mc.writeCommandPacketStr(comQuery, query)
|
||||
if err == nil {
|
||||
// Read Result
|
||||
var resLen int
|
||||
resLen, err = handleOk.readResultSetHeaderPacket()
|
||||
if err == nil {
|
||||
rows := new(textRows)
|
||||
rows.mc = mc
|
||||
if err != nil {
|
||||
return nil, mc.markBadConn(err)
|
||||
}
|
||||
|
||||
if resLen == 0 {
|
||||
rows.rs.done = true
|
||||
// Read Result
|
||||
var resLen int
|
||||
resLen, err = handleOk.readResultSetHeaderPacket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch err := rows.NextResultSet(); err {
|
||||
case nil, io.EOF:
|
||||
return rows, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
rows := new(textRows)
|
||||
rows.mc = mc
|
||||
|
||||
// Columns
|
||||
rows.rs.columns, err = mc.readColumns(resLen)
|
||||
return rows, err
|
||||
if resLen == 0 {
|
||||
rows.rs.done = true
|
||||
|
||||
switch err := rows.NextResultSet(); err {
|
||||
case nil, io.EOF:
|
||||
return rows, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, mc.markBadConn(err)
|
||||
|
||||
// Columns
|
||||
rows.rs.columns, err = mc.readColumns(resLen)
|
||||
return rows, err
|
||||
}
|
||||
|
||||
// Gets the value of the given MySQL System Variable
|
||||
@@ -443,7 +474,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// finish is called when the query has canceled.
|
||||
// cancel is called when the query has canceled.
|
||||
func (mc *mysqlConn) cancel(err error) {
|
||||
mc.canceled.Set(err)
|
||||
mc.cleanup()
|
||||
@@ -464,7 +495,6 @@ func (mc *mysqlConn) finish() {
|
||||
// Ping implements driver.Pinger interface
|
||||
func (mc *mysqlConn) Ping(ctx context.Context) (err error) {
|
||||
if mc.closed.Load() {
|
||||
mc.log(ErrInvalidConn)
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
|
||||
@@ -650,7 +680,7 @@ func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
|
||||
// ResetSession implements driver.SessionResetter.
|
||||
// (From Go 1.10)
|
||||
func (mc *mysqlConn) ResetSession(ctx context.Context) error {
|
||||
if mc.closed.Load() {
|
||||
if mc.closed.Load() || mc.buf.busy() {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
|
||||
@@ -684,5 +714,8 @@ func (mc *mysqlConn) ResetSession(ctx context.Context) error {
|
||||
// IsValid implements driver.Validator interface
|
||||
// (From Go 1.15)
|
||||
func (mc *mysqlConn) IsValid() bool {
|
||||
return !mc.closed.Load()
|
||||
return !mc.closed.Load() && !mc.buf.busy()
|
||||
}
|
||||
|
||||
var _ driver.SessionResetter = &mysqlConn{}
|
||||
var _ driver.Validator = &mysqlConn{}
|
||||
|
||||
Reference in New Issue
Block a user