bump reva and deps
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
+165
-196
@@ -21,36 +21,56 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Packets documentation:
|
||||
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html
|
||||
// MySQL client/server protocol documentations.
|
||||
// https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html
|
||||
// https://mariadb.com/kb/en/clientserver-protocol/
|
||||
|
||||
// Read packet to buffer 'data'
|
||||
func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
var prevData []byte
|
||||
invalidSequence := false
|
||||
|
||||
readNext := mc.buf.readNext
|
||||
if mc.compress {
|
||||
readNext = mc.compIO.readNext
|
||||
}
|
||||
|
||||
for {
|
||||
// read packet header
|
||||
data, err := mc.buf.readNext(4)
|
||||
data, err := readNext(4, mc.readWithTimeout)
|
||||
if err != nil {
|
||||
mc.close()
|
||||
if cerr := mc.canceled.Value(); cerr != nil {
|
||||
return nil, cerr
|
||||
}
|
||||
mc.log(err)
|
||||
mc.Close()
|
||||
return nil, ErrInvalidConn
|
||||
}
|
||||
|
||||
// packet length [24 bit]
|
||||
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
|
||||
pktLen := getUint24(data[:3])
|
||||
seq := data[3]
|
||||
|
||||
// check packet sync [8 bit]
|
||||
if data[3] != mc.sequence {
|
||||
mc.Close()
|
||||
if data[3] > mc.sequence {
|
||||
return nil, ErrPktSyncMul
|
||||
if mc.compress {
|
||||
// MySQL and MariaDB doesn't check packet nr in compressed packet.
|
||||
if debug && seq != mc.compressSequence {
|
||||
fmt.Printf("[debug] mismatched compression sequence nr: expected: %v, got %v",
|
||||
mc.compressSequence, seq)
|
||||
}
|
||||
return nil, ErrPktSync
|
||||
mc.compressSequence = seq + 1
|
||||
} else {
|
||||
// check packet sync [8 bit]
|
||||
if seq != mc.sequence {
|
||||
mc.log(fmt.Sprintf("[warn] unexpected seq nr: expected %v, got %v", mc.sequence, seq))
|
||||
// For large packets, we stop reading as soon as sync error.
|
||||
if len(prevData) > 0 {
|
||||
mc.close()
|
||||
return nil, ErrPktSyncMul
|
||||
}
|
||||
invalidSequence = true
|
||||
}
|
||||
mc.sequence++
|
||||
}
|
||||
mc.sequence++
|
||||
|
||||
// packets with length 0 terminate a previous packet which is a
|
||||
// multiple of (2^24)-1 bytes long
|
||||
@@ -58,32 +78,38 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
// there was no previous packet
|
||||
if prevData == nil {
|
||||
mc.log(ErrMalformPkt)
|
||||
mc.Close()
|
||||
mc.close()
|
||||
return nil, ErrInvalidConn
|
||||
}
|
||||
|
||||
return prevData, nil
|
||||
}
|
||||
|
||||
// read packet body [pktLen bytes]
|
||||
data, err = mc.buf.readNext(pktLen)
|
||||
data, err = readNext(pktLen, mc.readWithTimeout)
|
||||
if err != nil {
|
||||
mc.close()
|
||||
if cerr := mc.canceled.Value(); cerr != nil {
|
||||
return nil, cerr
|
||||
}
|
||||
mc.log(err)
|
||||
mc.Close()
|
||||
return nil, ErrInvalidConn
|
||||
}
|
||||
|
||||
// return data if this was the last packet
|
||||
if pktLen < maxPacketSize {
|
||||
// zero allocations for non-split packets
|
||||
if prevData == nil {
|
||||
return data, nil
|
||||
if prevData != nil {
|
||||
data = append(prevData, data...)
|
||||
}
|
||||
|
||||
return append(prevData, data...), nil
|
||||
if invalidSequence {
|
||||
mc.close()
|
||||
// return sync error only for regular packet.
|
||||
// error packets may have wrong sequence number.
|
||||
if data[0] != iERR {
|
||||
return nil, ErrPktSync
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
prevData = append(prevData, data...)
|
||||
@@ -93,60 +119,52 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
||||
// Write packet buffer 'data'
|
||||
func (mc *mysqlConn) writePacket(data []byte) error {
|
||||
pktLen := len(data) - 4
|
||||
|
||||
if pktLen > mc.maxAllowedPacket {
|
||||
return ErrPktTooLarge
|
||||
}
|
||||
|
||||
writeFunc := mc.writeWithTimeout
|
||||
if mc.compress {
|
||||
writeFunc = mc.compIO.writePackets
|
||||
}
|
||||
|
||||
for {
|
||||
var size int
|
||||
if pktLen >= maxPacketSize {
|
||||
data[0] = 0xff
|
||||
data[1] = 0xff
|
||||
data[2] = 0xff
|
||||
size = maxPacketSize
|
||||
} else {
|
||||
data[0] = byte(pktLen)
|
||||
data[1] = byte(pktLen >> 8)
|
||||
data[2] = byte(pktLen >> 16)
|
||||
size = pktLen
|
||||
}
|
||||
size := min(maxPacketSize, pktLen)
|
||||
putUint24(data[:3], size)
|
||||
data[3] = mc.sequence
|
||||
|
||||
// Write packet
|
||||
if mc.writeTimeout > 0 {
|
||||
if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("writePacket: size=%v seq=%v", size, mc.sequence)
|
||||
}
|
||||
|
||||
n, err := mc.netConn.Write(data[:4+size])
|
||||
if err == nil && n == 4+size {
|
||||
mc.sequence++
|
||||
if size != maxPacketSize {
|
||||
return nil
|
||||
}
|
||||
pktLen -= size
|
||||
data = data[size:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Handle error
|
||||
if err == nil { // n != len(data)
|
||||
n, err := writeFunc(data[:4+size])
|
||||
if err != nil {
|
||||
mc.cleanup()
|
||||
mc.log(ErrMalformPkt)
|
||||
} else {
|
||||
if cerr := mc.canceled.Value(); cerr != nil {
|
||||
return cerr
|
||||
}
|
||||
if n == 0 && pktLen == len(data)-4 {
|
||||
// only for the first loop iteration when nothing was written yet
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
mc.cleanup()
|
||||
mc.log(err)
|
||||
}
|
||||
return ErrInvalidConn
|
||||
if n != 4+size {
|
||||
// io.Writer(b) must return a non-nil error if it cannot write len(b) bytes.
|
||||
// The io.ErrShortWrite error is used to indicate that this rule has not been followed.
|
||||
mc.cleanup()
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
|
||||
mc.sequence++
|
||||
if size != maxPacketSize {
|
||||
return nil
|
||||
}
|
||||
pktLen -= size
|
||||
data = data[size:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,11 +177,6 @@ func (mc *mysqlConn) writePacket(data []byte) error {
|
||||
func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) {
|
||||
data, err = mc.readPacket()
|
||||
if err != nil {
|
||||
// for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
|
||||
// in connection initialization we don't risk retrying non-idempotent actions.
|
||||
if err == ErrInvalidConn {
|
||||
return nil, "", driver.ErrBadConn
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -207,10 +220,13 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro
|
||||
if len(data) > pos {
|
||||
// character set [1 byte]
|
||||
// status flags [2 bytes]
|
||||
pos += 3
|
||||
// capability flags (upper 2 bytes) [2 bytes]
|
||||
mc.flags |= clientFlag(binary.LittleEndian.Uint16(data[pos:pos+2])) << 16
|
||||
pos += 2
|
||||
// length of auth-plugin-data [1 byte]
|
||||
// reserved (all [00]) [10 bytes]
|
||||
pos += 1 + 2 + 2 + 1 + 10
|
||||
pos += 11
|
||||
|
||||
// second part of the password cipher [minimum 13 bytes],
|
||||
// where len=MAX(13, length of auth-plugin-data - 8)
|
||||
@@ -258,13 +274,17 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
clientLocalFiles |
|
||||
clientPluginAuth |
|
||||
clientMultiResults |
|
||||
clientConnectAttrs |
|
||||
mc.flags&clientConnectAttrs |
|
||||
mc.flags&clientLongFlag
|
||||
|
||||
sendConnectAttrs := mc.flags&clientConnectAttrs != 0
|
||||
|
||||
if mc.cfg.ClientFoundRows {
|
||||
clientFlags |= clientFoundRows
|
||||
}
|
||||
|
||||
if mc.cfg.compress && mc.flags&clientCompress == clientCompress {
|
||||
clientFlags |= clientCompress
|
||||
}
|
||||
// To enable TLS / SSL
|
||||
if mc.cfg.TLS != nil {
|
||||
clientFlags |= clientSSL
|
||||
@@ -293,43 +313,37 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
}
|
||||
|
||||
// encode length of the connection attributes
|
||||
var connAttrsLEIBuf [9]byte
|
||||
connAttrsLen := len(mc.connector.encodedAttributes)
|
||||
connAttrsLEI := appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen))
|
||||
pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes)
|
||||
var connAttrsLEI []byte
|
||||
if sendConnectAttrs {
|
||||
var connAttrsLEIBuf [9]byte
|
||||
connAttrsLen := len(mc.connector.encodedAttributes)
|
||||
connAttrsLEI = appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen))
|
||||
pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes)
|
||||
}
|
||||
|
||||
// Calculate packet length and get buffer with that size
|
||||
data, err := mc.buf.takeBuffer(pktLen + 4)
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
mc.cleanup()
|
||||
return err
|
||||
}
|
||||
|
||||
// ClientFlags [32 bit]
|
||||
data[4] = byte(clientFlags)
|
||||
data[5] = byte(clientFlags >> 8)
|
||||
data[6] = byte(clientFlags >> 16)
|
||||
data[7] = byte(clientFlags >> 24)
|
||||
binary.LittleEndian.PutUint32(data[4:], uint32(clientFlags))
|
||||
|
||||
// MaxPacketSize [32 bit] (none)
|
||||
data[8] = 0x00
|
||||
data[9] = 0x00
|
||||
data[10] = 0x00
|
||||
data[11] = 0x00
|
||||
binary.LittleEndian.PutUint32(data[8:], 0)
|
||||
|
||||
// Collation ID [1 byte]
|
||||
cname := mc.cfg.Collation
|
||||
if cname == "" {
|
||||
cname = defaultCollation
|
||||
}
|
||||
var found bool
|
||||
data[12], found = collations[cname]
|
||||
if !found {
|
||||
// Note possibility for false negatives:
|
||||
// could be triggered although the collation is valid if the
|
||||
// collations map does not contain entries the server supports.
|
||||
return fmt.Errorf("unknown collation: %q", cname)
|
||||
data[12] = defaultCollationID
|
||||
if cname := mc.cfg.Collation; cname != "" {
|
||||
colID, ok := collations[cname]
|
||||
if ok {
|
||||
data[12] = colID
|
||||
} else if len(mc.cfg.charsets) > 0 {
|
||||
// When cfg.charset is set, the collation is set by `SET NAMES <charset> COLLATE <collation>`.
|
||||
return fmt.Errorf("unknown collation: %q", cname)
|
||||
}
|
||||
}
|
||||
|
||||
// Filler [23 bytes] (all 0x00)
|
||||
@@ -349,10 +363,12 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
// Switch to TLS
|
||||
tlsConn := tls.Client(mc.netConn, mc.cfg.TLS)
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
if cerr := mc.canceled.Value(); cerr != nil {
|
||||
return cerr
|
||||
}
|
||||
return err
|
||||
}
|
||||
mc.netConn = tlsConn
|
||||
mc.buf.nc = tlsConn
|
||||
}
|
||||
|
||||
// User [null terminated string]
|
||||
@@ -378,8 +394,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
pos++
|
||||
|
||||
// Connection Attributes
|
||||
pos += copy(data[pos:], connAttrsLEI)
|
||||
pos += copy(data[pos:], []byte(mc.connector.encodedAttributes))
|
||||
if sendConnectAttrs {
|
||||
pos += copy(data[pos:], connAttrsLEI)
|
||||
pos += copy(data[pos:], []byte(mc.connector.encodedAttributes))
|
||||
}
|
||||
|
||||
// Send Auth packet
|
||||
return mc.writePacket(data[:pos])
|
||||
@@ -388,11 +406,10 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
|
||||
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
|
||||
pktLen := 4 + len(authData)
|
||||
data, err := mc.buf.takeSmallBuffer(pktLen)
|
||||
data, err := mc.buf.takeBuffer(pktLen)
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
mc.cleanup()
|
||||
return err
|
||||
}
|
||||
|
||||
// Add the auth data [EOF]
|
||||
@@ -406,13 +423,11 @@ func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
|
||||
|
||||
func (mc *mysqlConn) writeCommandPacket(command byte) error {
|
||||
// Reset Packet Sequence
|
||||
mc.sequence = 0
|
||||
mc.resetSequence()
|
||||
|
||||
data, err := mc.buf.takeSmallBuffer(4 + 1)
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
return err
|
||||
}
|
||||
|
||||
// Add command byte
|
||||
@@ -424,14 +439,12 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
|
||||
|
||||
func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
|
||||
// Reset Packet Sequence
|
||||
mc.sequence = 0
|
||||
mc.resetSequence()
|
||||
|
||||
pktLen := 1 + len(arg)
|
||||
data, err := mc.buf.takeBuffer(pktLen + 4)
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
return err
|
||||
}
|
||||
|
||||
// Add command byte
|
||||
@@ -441,28 +454,25 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
|
||||
copy(data[5:], arg)
|
||||
|
||||
// Send CMD packet
|
||||
return mc.writePacket(data)
|
||||
err = mc.writePacket(data)
|
||||
mc.syncSequence()
|
||||
return err
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
|
||||
// Reset Packet Sequence
|
||||
mc.sequence = 0
|
||||
mc.resetSequence()
|
||||
|
||||
data, err := mc.buf.takeSmallBuffer(4 + 1 + 4)
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
return err
|
||||
}
|
||||
|
||||
// Add command byte
|
||||
data[4] = command
|
||||
|
||||
// Add arg [32 bit]
|
||||
data[5] = byte(arg)
|
||||
data[6] = byte(arg >> 8)
|
||||
data[7] = byte(arg >> 16)
|
||||
data[8] = byte(arg >> 24)
|
||||
binary.LittleEndian.PutUint32(data[5:], arg)
|
||||
|
||||
// Send CMD packet
|
||||
return mc.writePacket(data)
|
||||
@@ -500,6 +510,9 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
|
||||
}
|
||||
plugin := string(data[1:pluginEndIndex])
|
||||
authData := data[pluginEndIndex+1:]
|
||||
if len(authData) > 0 && authData[len(authData)-1] == 0 {
|
||||
authData = authData[:len(authData)-1]
|
||||
}
|
||||
return authData, plugin, nil
|
||||
|
||||
default: // Error otherwise
|
||||
@@ -521,32 +534,33 @@ func (mc *okHandler) readResultOK() error {
|
||||
}
|
||||
|
||||
// Result Set Header Packet
|
||||
// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset
|
||||
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response.html
|
||||
func (mc *okHandler) readResultSetHeaderPacket() (int, error) {
|
||||
// handleOkPacket replaces both values; other cases leave the values unchanged.
|
||||
mc.result.affectedRows = append(mc.result.affectedRows, 0)
|
||||
mc.result.insertIds = append(mc.result.insertIds, 0)
|
||||
|
||||
data, err := mc.conn().readPacket()
|
||||
if err == nil {
|
||||
switch data[0] {
|
||||
|
||||
case iOK:
|
||||
return 0, mc.handleOkPacket(data)
|
||||
|
||||
case iERR:
|
||||
return 0, mc.conn().handleErrorPacket(data)
|
||||
|
||||
case iLocalInFile:
|
||||
return 0, mc.handleInFileRequest(string(data[1:]))
|
||||
}
|
||||
|
||||
// column count
|
||||
num, _, _ := readLengthEncodedInteger(data)
|
||||
// ignore remaining data in the packet. see #1478.
|
||||
return int(num), nil
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, err
|
||||
|
||||
switch data[0] {
|
||||
case iOK:
|
||||
return 0, mc.handleOkPacket(data)
|
||||
|
||||
case iERR:
|
||||
return 0, mc.conn().handleErrorPacket(data)
|
||||
|
||||
case iLocalInFile:
|
||||
return 0, mc.handleInFileRequest(string(data[1:]))
|
||||
}
|
||||
|
||||
// column count
|
||||
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset.html
|
||||
num, _, _ := readLengthEncodedInteger(data)
|
||||
// ignore remaining data in the packet. see #1478.
|
||||
return int(num), nil
|
||||
}
|
||||
|
||||
// Error Packet
|
||||
@@ -563,7 +577,8 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
|
||||
|
||||
// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
|
||||
// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
|
||||
if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
|
||||
// 1836: ER_READ_ONLY_MODE
|
||||
if (errno == 1792 || errno == 1290 || errno == 1836) && mc.cfg.RejectReadOnly {
|
||||
// Oops; we are connected to a read-only connection, and won't be able
|
||||
// to issue any write statements. Since RejectReadOnly is configured,
|
||||
// we throw away this connection hoping this one would have write
|
||||
@@ -930,19 +945,15 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
||||
pktLen = dataOffset + argLen
|
||||
}
|
||||
|
||||
stmt.mc.sequence = 0
|
||||
stmt.mc.resetSequence()
|
||||
// Add command byte [1 byte]
|
||||
data[4] = comStmtSendLongData
|
||||
|
||||
// Add stmtID [32 bit]
|
||||
data[5] = byte(stmt.id)
|
||||
data[6] = byte(stmt.id >> 8)
|
||||
data[7] = byte(stmt.id >> 16)
|
||||
data[8] = byte(stmt.id >> 24)
|
||||
binary.LittleEndian.PutUint32(data[5:], stmt.id)
|
||||
|
||||
// Add paramID [16 bit]
|
||||
data[9] = byte(paramID)
|
||||
data[10] = byte(paramID >> 8)
|
||||
binary.LittleEndian.PutUint16(data[9:], uint16(paramID))
|
||||
|
||||
// Send CMD packet
|
||||
err := stmt.mc.writePacket(data[:4+pktLen])
|
||||
@@ -951,11 +962,10 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
// Reset Packet Sequence
|
||||
stmt.mc.sequence = 0
|
||||
stmt.mc.resetSequence()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -980,7 +990,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
}
|
||||
|
||||
// Reset packet-sequence
|
||||
mc.sequence = 0
|
||||
mc.resetSequence()
|
||||
|
||||
var data []byte
|
||||
var err error
|
||||
@@ -992,28 +1002,20 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
// In this case the len(data) == cap(data) which is used to optimise the flow below.
|
||||
}
|
||||
if err != nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
return err
|
||||
}
|
||||
|
||||
// command [1 byte]
|
||||
data[4] = comStmtExecute
|
||||
|
||||
// statement_id [4 bytes]
|
||||
data[5] = byte(stmt.id)
|
||||
data[6] = byte(stmt.id >> 8)
|
||||
data[7] = byte(stmt.id >> 16)
|
||||
data[8] = byte(stmt.id >> 24)
|
||||
binary.LittleEndian.PutUint32(data[5:], stmt.id)
|
||||
|
||||
// flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
|
||||
data[9] = 0x00
|
||||
|
||||
// iteration_count (uint32(1)) [4 bytes]
|
||||
data[10] = 0x01
|
||||
data[11] = 0x00
|
||||
data[12] = 0x00
|
||||
data[13] = 0x00
|
||||
binary.LittleEndian.PutUint32(data[10:], 1)
|
||||
|
||||
if len(args) > 0 {
|
||||
pos := minPktLen
|
||||
@@ -1067,50 +1069,17 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
case int64:
|
||||
paramTypes[i+i] = byte(fieldTypeLongLong)
|
||||
paramTypes[i+i+1] = 0x00
|
||||
|
||||
if cap(paramValues)-len(paramValues)-8 >= 0 {
|
||||
paramValues = paramValues[:len(paramValues)+8]
|
||||
binary.LittleEndian.PutUint64(
|
||||
paramValues[len(paramValues)-8:],
|
||||
uint64(v),
|
||||
)
|
||||
} else {
|
||||
paramValues = append(paramValues,
|
||||
uint64ToBytes(uint64(v))...,
|
||||
)
|
||||
}
|
||||
paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v))
|
||||
|
||||
case uint64:
|
||||
paramTypes[i+i] = byte(fieldTypeLongLong)
|
||||
paramTypes[i+i+1] = 0x80 // type is unsigned
|
||||
|
||||
if cap(paramValues)-len(paramValues)-8 >= 0 {
|
||||
paramValues = paramValues[:len(paramValues)+8]
|
||||
binary.LittleEndian.PutUint64(
|
||||
paramValues[len(paramValues)-8:],
|
||||
uint64(v),
|
||||
)
|
||||
} else {
|
||||
paramValues = append(paramValues,
|
||||
uint64ToBytes(uint64(v))...,
|
||||
)
|
||||
}
|
||||
paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v))
|
||||
|
||||
case float64:
|
||||
paramTypes[i+i] = byte(fieldTypeDouble)
|
||||
paramTypes[i+i+1] = 0x00
|
||||
|
||||
if cap(paramValues)-len(paramValues)-8 >= 0 {
|
||||
paramValues = paramValues[:len(paramValues)+8]
|
||||
binary.LittleEndian.PutUint64(
|
||||
paramValues[len(paramValues)-8:],
|
||||
math.Float64bits(v),
|
||||
)
|
||||
} else {
|
||||
paramValues = append(paramValues,
|
||||
uint64ToBytes(math.Float64bits(v))...,
|
||||
)
|
||||
}
|
||||
paramValues = binary.LittleEndian.AppendUint64(paramValues, math.Float64bits(v))
|
||||
|
||||
case bool:
|
||||
paramTypes[i+i] = byte(fieldTypeTiny)
|
||||
@@ -1191,17 +1160,16 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
||||
// In that case we must build the data packet with the new values buffer
|
||||
if valuesCap != cap(paramValues) {
|
||||
data = append(data[:pos], paramValues...)
|
||||
if err = mc.buf.store(data); err != nil {
|
||||
mc.log(err)
|
||||
return errBadConnNoWrite
|
||||
}
|
||||
mc.buf.store(data) // allow this buffer to be reused
|
||||
}
|
||||
|
||||
pos += len(paramValues)
|
||||
data = data[:pos]
|
||||
}
|
||||
|
||||
return mc.writePacket(data)
|
||||
err = mc.writePacket(data)
|
||||
mc.syncSequence()
|
||||
return err
|
||||
}
|
||||
|
||||
// For each remaining resultset in the stream, discards its rows and updates
|
||||
@@ -1325,7 +1293,8 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
|
||||
fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
|
||||
fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
|
||||
fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON:
|
||||
fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,
|
||||
fieldTypeVector:
|
||||
var isNull bool
|
||||
var n int
|
||||
dest[i], isNull, n, err = readLengthEncodedString(data[pos:])
|
||||
|
||||
Reference in New Issue
Block a user