|
@@ -25,26 +25,23 @@ import (
|
|
|
|
|
|
|
|
|
func (mc *mysqlConn) readPacket() ([]byte, error) {
|
|
|
- var payload []byte
|
|
|
+ var prevData []byte
|
|
|
for {
|
|
|
-
|
|
|
+
|
|
|
data, err := mc.buf.readNext(4)
|
|
|
if err != nil {
|
|
|
+ if cerr := mc.canceled.Value(); cerr != nil {
|
|
|
+ return nil, cerr
|
|
|
+ }
|
|
|
errLog.Print(err)
|
|
|
mc.Close()
|
|
|
- return nil, driver.ErrBadConn
|
|
|
+ return nil, ErrInvalidConn
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
|
|
|
|
|
|
- if pktLen < 1 {
|
|
|
- errLog.Print(ErrMalformPkt)
|
|
|
- mc.Close()
|
|
|
- return nil, driver.ErrBadConn
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
if data[3] != mc.sequence {
|
|
|
if data[3] > mc.sequence {
|
|
|
return nil, ErrPktSyncMul
|
|
@@ -53,26 +50,41 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
|
|
}
|
|
|
mc.sequence++
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ if pktLen == 0 {
|
|
|
+
|
|
|
+ if prevData == nil {
|
|
|
+ errLog.Print(ErrMalformPkt)
|
|
|
+ mc.Close()
|
|
|
+ return nil, ErrInvalidConn
|
|
|
+ }
|
|
|
+
|
|
|
+ return prevData, nil
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
data, err = mc.buf.readNext(pktLen)
|
|
|
if err != nil {
|
|
|
+ if cerr := mc.canceled.Value(); cerr != nil {
|
|
|
+ return nil, cerr
|
|
|
+ }
|
|
|
errLog.Print(err)
|
|
|
mc.Close()
|
|
|
- return nil, driver.ErrBadConn
|
|
|
+ return nil, ErrInvalidConn
|
|
|
}
|
|
|
|
|
|
- isLastPacket := (pktLen < maxPacketSize)
|
|
|
+
|
|
|
+ if pktLen < maxPacketSize {
|
|
|
+
|
|
|
+ if prevData == nil {
|
|
|
+ return data, nil
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- if isLastPacket && payload == nil {
|
|
|
- return data, nil
|
|
|
+ return append(prevData, data...), nil
|
|
|
}
|
|
|
|
|
|
- payload = append(payload, data...)
|
|
|
-
|
|
|
- if isLastPacket {
|
|
|
- return payload, nil
|
|
|
- }
|
|
|
+ prevData = append(prevData, data...)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -80,7 +92,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
|
|
|
func (mc *mysqlConn) writePacket(data []byte) error {
|
|
|
pktLen := len(data) - 4
|
|
|
|
|
|
- if pktLen > mc.maxPacketAllowed {
|
|
|
+ if pktLen > mc.maxAllowedPacket {
|
|
|
return ErrPktTooLarge
|
|
|
}
|
|
|
|
|
@@ -119,33 +131,47 @@ func (mc *mysqlConn) writePacket(data []byte) error {
|
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
+ mc.cleanup()
|
|
|
errLog.Print(ErrMalformPkt)
|
|
|
} else {
|
|
|
+ if cerr := mc.canceled.Value(); cerr != nil {
|
|
|
+ return cerr
|
|
|
+ }
|
|
|
+ if n == 0 && pktLen == len(data)-4 {
|
|
|
+
|
|
|
+ return errBadConnNoWrite
|
|
|
+ }
|
|
|
+ mc.cleanup()
|
|
|
errLog.Print(err)
|
|
|
}
|
|
|
- return driver.ErrBadConn
|
|
|
+ return ErrInvalidConn
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
-* Initialisation Process *
|
|
|
+* Initialization Process *
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
-func (mc *mysqlConn) readInitPacket() ([]byte, error) {
|
|
|
+func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
|
|
|
data, err := mc.readPacket()
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+
|
|
|
+
|
|
|
+ if err == ErrInvalidConn {
|
|
|
+ return nil, "", driver.ErrBadConn
|
|
|
+ }
|
|
|
+ return nil, "", err
|
|
|
}
|
|
|
|
|
|
if data[0] == iERR {
|
|
|
- return nil, mc.handleErrorPacket(data)
|
|
|
+ return nil, "", mc.handleErrorPacket(data)
|
|
|
}
|
|
|
|
|
|
|
|
|
if data[0] < minProtocolVersion {
|
|
|
- return nil, fmt.Errorf(
|
|
|
+ return nil, "", fmt.Errorf(
|
|
|
"unsupported protocol version %d. Version %d or higher is required",
|
|
|
data[0],
|
|
|
minProtocolVersion,
|
|
@@ -157,7 +183,7 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
|
|
|
pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4
|
|
|
|
|
|
|
|
|
- cipher := data[pos : pos+8]
|
|
|
+ authData := data[pos : pos+8]
|
|
|
|
|
|
|
|
|
pos += 8 + 1
|
|
@@ -165,13 +191,14 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
|
|
|
|
|
|
mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
|
|
|
if mc.flags&clientProtocol41 == 0 {
|
|
|
- return nil, ErrOldProtocol
|
|
|
+ return nil, "", ErrOldProtocol
|
|
|
}
|
|
|
if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
|
|
|
- return nil, ErrNoTLS
|
|
|
+ return nil, "", ErrNoTLS
|
|
|
}
|
|
|
pos += 2
|
|
|
|
|
|
+ plugin := ""
|
|
|
if len(data) > pos {
|
|
|
|
|
|
|
|
@@ -192,32 +219,34 @@ func (mc *mysqlConn) readInitPacket() ([]byte, error) {
|
|
|
|
|
|
|
|
|
|
|
|
- cipher = append(cipher, data[pos:pos+12]...)
|
|
|
+ authData = append(authData, data[pos:pos+12]...)
|
|
|
+ pos += 13
|
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ if end := bytes.IndexByte(data[pos:], 0x00); end != -1 {
|
|
|
+ plugin = string(data[pos : pos+end])
|
|
|
+ } else {
|
|
|
+ plugin = string(data[pos:])
|
|
|
+ }
|
|
|
|
|
|
|
|
|
var b [20]byte
|
|
|
- copy(b[:], cipher)
|
|
|
- return b[:], nil
|
|
|
+ copy(b[:], authData)
|
|
|
+ return b[:], plugin, nil
|
|
|
}
|
|
|
|
|
|
+ plugin = defaultAuthPlugin
|
|
|
+
|
|
|
|
|
|
var b [8]byte
|
|
|
- copy(b[:], cipher)
|
|
|
- return b[:], nil
|
|
|
+ copy(b[:], authData)
|
|
|
+ return b[:], plugin, nil
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
|
|
|
+func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error {
|
|
|
|
|
|
clientFlags := clientProtocol41 |
|
|
|
clientSecureConn |
|
|
@@ -241,10 +270,19 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
|
|
|
clientFlags |= clientMultiStatements
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))
|
|
|
+
|
|
|
+ var authRespLEIBuf [9]byte
|
|
|
+ authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp)))
|
|
|
+ if len(authRespLEI) > 1 {
|
|
|
+
|
|
|
+
|
|
|
+ clientFlags |= clientPluginAuthLenEncClientData
|
|
|
+ }
|
|
|
|
|
|
- pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + 1 + len(scrambleBuff) + 21 + 1
|
|
|
+ pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
|
|
|
+ if addNUL {
|
|
|
+ pktLen++
|
|
|
+ }
|
|
|
|
|
|
|
|
|
if n := len(mc.cfg.DBName); n > 0 {
|
|
@@ -255,9 +293,9 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
|
|
|
|
|
|
data := mc.buf.takeSmallBuffer(pktLen + 4)
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
|
|
@@ -312,9 +350,13 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
|
|
|
data[pos] = 0x00
|
|
|
pos++
|
|
|
|
|
|
-
|
|
|
- data[pos] = byte(len(scrambleBuff))
|
|
|
- pos += 1 + copy(data[pos+1:], scrambleBuff)
|
|
|
+
|
|
|
+ pos += copy(data[pos:], authRespLEI)
|
|
|
+ pos += copy(data[pos:], authResp)
|
|
|
+ if addNUL {
|
|
|
+ data[pos] = 0x00
|
|
|
+ pos++
|
|
|
+ }
|
|
|
|
|
|
|
|
|
if len(mc.cfg.DBName) > 0 {
|
|
@@ -323,51 +365,31 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
|
|
|
pos++
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- pos += copy(data[pos:], "mysql_native_password")
|
|
|
+ pos += copy(data[pos:], plugin)
|
|
|
data[pos] = 0x00
|
|
|
|
|
|
|
|
|
return mc.writePacket(data)
|
|
|
}
|
|
|
|
|
|
-
|
|
|
|
|
|
-func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
|
|
|
-
|
|
|
- scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.Passwd))
|
|
|
-
|
|
|
-
|
|
|
- pktLen := len(scrambleBuff) + 1
|
|
|
- data := mc.buf.takeSmallBuffer(4 + pktLen)
|
|
|
- if data == nil {
|
|
|
-
|
|
|
- errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error {
|
|
|
+ pktLen := 4 + len(authData)
|
|
|
+ if addNUL {
|
|
|
+ pktLen++
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- copy(data[4:], scrambleBuff)
|
|
|
- data[4+pktLen-1] = 0x00
|
|
|
-
|
|
|
- return mc.writePacket(data)
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-func (mc *mysqlConn) writeClearAuthPacket() error {
|
|
|
-
|
|
|
- pktLen := len(mc.cfg.Passwd) + 1
|
|
|
- data := mc.buf.takeSmallBuffer(4 + pktLen)
|
|
|
+ data := mc.buf.takeSmallBuffer(pktLen)
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- copy(data[4:], mc.cfg.Passwd)
|
|
|
- data[4+pktLen-1] = 0x00
|
|
|
+
|
|
|
+ copy(data[4:], authData)
|
|
|
+ if addNUL {
|
|
|
+ data[pktLen-1] = 0x00
|
|
|
+ }
|
|
|
|
|
|
return mc.writePacket(data)
|
|
|
}
|
|
@@ -382,9 +404,9 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
|
|
|
|
|
|
data := mc.buf.takeSmallBuffer(4 + 1)
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
|
|
@@ -401,9 +423,9 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
|
|
|
pktLen := 1 + len(arg)
|
|
|
data := mc.buf.takeBuffer(pktLen + 4)
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
|
|
@@ -422,9 +444,9 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
|
|
|
|
|
|
data := mc.buf.takeSmallBuffer(4 + 1 + 4)
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
|
|
@@ -444,37 +466,50 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
|
|
|
* Result Packets *
|
|
|
******************************************************************************/
|
|
|
|
|
|
-
|
|
|
-func (mc *mysqlConn) readResultOK() error {
|
|
|
+func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
|
|
|
data, err := mc.readPacket()
|
|
|
- if err == nil {
|
|
|
-
|
|
|
- switch data[0] {
|
|
|
+ if err != nil {
|
|
|
+ return nil, "", err
|
|
|
+ }
|
|
|
|
|
|
- case iOK:
|
|
|
- return mc.handleOkPacket(data)
|
|
|
+
|
|
|
+ switch data[0] {
|
|
|
|
|
|
- case iEOF:
|
|
|
- if len(data) > 1 {
|
|
|
- plugin := string(data[1:bytes.IndexByte(data, 0x00)])
|
|
|
- if plugin == "mysql_old_password" {
|
|
|
-
|
|
|
- return ErrOldPassword
|
|
|
- } else if plugin == "mysql_clear_password" {
|
|
|
-
|
|
|
- return ErrCleartextPassword
|
|
|
- } else {
|
|
|
- return ErrUnknownPlugin
|
|
|
- }
|
|
|
- } else {
|
|
|
- return ErrOldPassword
|
|
|
- }
|
|
|
+ case iOK:
|
|
|
+ return nil, "", mc.handleOkPacket(data)
|
|
|
|
|
|
- default:
|
|
|
- return mc.handleErrorPacket(data)
|
|
|
+ case iAuthMoreData:
|
|
|
+ return data[1:], "", err
|
|
|
+
|
|
|
+ case iEOF:
|
|
|
+ if len(data) < 1 {
|
|
|
+
|
|
|
+ return nil, "mysql_old_password", nil
|
|
|
}
|
|
|
+ pluginEndIndex := bytes.IndexByte(data, 0x00)
|
|
|
+ if pluginEndIndex < 0 {
|
|
|
+ return nil, "", ErrMalformPkt
|
|
|
+ }
|
|
|
+ plugin := string(data[1:pluginEndIndex])
|
|
|
+ authData := data[pluginEndIndex+1:]
|
|
|
+ return authData, plugin, nil
|
|
|
+
|
|
|
+ default:
|
|
|
+ return nil, "", mc.handleErrorPacket(data)
|
|
|
}
|
|
|
- return err
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (mc *mysqlConn) readResultOK() error {
|
|
|
+ data, err := mc.readPacket()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if data[0] == iOK {
|
|
|
+ return mc.handleOkPacket(data)
|
|
|
+ }
|
|
|
+ return mc.handleErrorPacket(data)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -517,6 +552,22 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
|
|
|
|
|
|
errno := binary.LittleEndian.Uint16(data[1:3])
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ mc.Close()
|
|
|
+ return driver.ErrBadConn
|
|
|
+ }
|
|
|
+
|
|
|
pos := 3
|
|
|
|
|
|
|
|
@@ -551,19 +602,12 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error {
|
|
|
|
|
|
|
|
|
mc.status = readStatus(data[1+n+m : 1+n+m+2])
|
|
|
- if err := mc.discardResults(); err != nil {
|
|
|
- return err
|
|
|
+ if mc.status&statusMoreResultsExists != 0 {
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
|
|
|
- if !mc.strict {
|
|
|
- return nil
|
|
|
- }
|
|
|
|
|
|
- pos := 1 + n + m + 2
|
|
|
- if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 {
|
|
|
- return mc.getWarnings()
|
|
|
- }
|
|
|
return nil
|
|
|
}
|
|
|
|
|
@@ -635,14 +679,21 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
+ pos += n
|
|
|
|
|
|
|
|
|
+ pos++
|
|
|
+
|
|
|
|
|
|
+ columns[i].charSet = data[pos]
|
|
|
+ pos += 2
|
|
|
+
|
|
|
|
|
|
- pos += n + 1 + 2 + 4
|
|
|
+ columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])
|
|
|
+ pos += 4
|
|
|
|
|
|
|
|
|
- columns[i].fieldType = data[pos]
|
|
|
+ columns[i].fieldType = fieldType(data[pos])
|
|
|
pos++
|
|
|
|
|
|
|
|
@@ -665,6 +716,10 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
|
|
|
func (rows *textRows) readRow(dest []driver.Value) error {
|
|
|
mc := rows.mc
|
|
|
|
|
|
+ if rows.rs.done {
|
|
|
+ return io.EOF
|
|
|
+ }
|
|
|
+
|
|
|
data, err := mc.readPacket()
|
|
|
if err != nil {
|
|
|
return err
|
|
@@ -674,10 +729,10 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
|
|
if data[0] == iEOF && len(data) == 5 {
|
|
|
|
|
|
rows.mc.status = readStatus(data[3:])
|
|
|
- if err := rows.mc.discardResults(); err != nil {
|
|
|
- return err
|
|
|
+ rows.rs.done = true
|
|
|
+ if !rows.HasNextResultSet() {
|
|
|
+ rows.mc = nil
|
|
|
}
|
|
|
- rows.mc = nil
|
|
|
return io.EOF
|
|
|
}
|
|
|
if data[0] == iERR {
|
|
@@ -699,7 +754,7 @@ func (rows *textRows) readRow(dest []driver.Value) error {
|
|
|
if !mc.parseTime {
|
|
|
continue
|
|
|
} else {
|
|
|
- switch rows.columns[i].fieldType {
|
|
|
+ switch rows.rs.columns[i].fieldType {
|
|
|
case fieldTypeTimestamp, fieldTypeDateTime,
|
|
|
fieldTypeDate, fieldTypeNewDate:
|
|
|
dest[i], err = parseDateTime(
|
|
@@ -771,14 +826,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
|
|
|
|
|
|
|
|
|
|
|
|
- if !stmt.mc.strict {
|
|
|
- return columnCount, nil
|
|
|
- }
|
|
|
|
|
|
-
|
|
|
- if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 {
|
|
|
- return columnCount, stmt.mc.getWarnings()
|
|
|
- }
|
|
|
return columnCount, nil
|
|
|
}
|
|
|
return 0, err
|
|
@@ -786,7 +834,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
|
|
|
|
|
|
|
|
|
func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
|
|
- maxLen := stmt.mc.maxPacketAllowed - 1
|
|
|
+ maxLen := stmt.mc.maxAllowedPacket - 1
|
|
|
pktLen := maxLen
|
|
|
|
|
|
|
|
@@ -795,7 +843,7 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
|
|
|
|
|
|
const dataOffset = 1 + 4 + 2
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
|
|
|
data := make([]byte, 4+1+4+2+len(arg))
|
|
@@ -850,6 +898,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
const minPktLen = 4 + 1 + 4 + 1 + 4
|
|
|
mc := stmt.mc
|
|
|
|
|
|
+
|
|
|
+ longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
|
|
|
+ if longDataSize < 64 {
|
|
|
+ longDataSize = 64
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
mc.sequence = 0
|
|
|
|
|
@@ -861,9 +915,9 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
data = mc.buf.takeCompleteBuffer()
|
|
|
}
|
|
|
if data == nil {
|
|
|
-
|
|
|
+
|
|
|
errLog.Print(ErrBusyBuffer)
|
|
|
- return driver.ErrBadConn
|
|
|
+ return errBadConnNoWrite
|
|
|
}
|
|
|
|
|
|
|
|
@@ -922,7 +976,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
|
|
|
if arg == nil {
|
|
|
nullMask[i/8] |= 1 << (uint(i) & 7)
|
|
|
- paramTypes[i+i] = fieldTypeNULL
|
|
|
+ paramTypes[i+i] = byte(fieldTypeNULL)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
continue
|
|
|
}
|
|
@@ -930,7 +984,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
|
|
|
switch v := arg.(type) {
|
|
|
case int64:
|
|
|
- paramTypes[i+i] = fieldTypeLongLong
|
|
|
+ paramTypes[i+i] = byte(fieldTypeLongLong)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
if cap(paramValues)-len(paramValues)-8 >= 0 {
|
|
@@ -946,7 +1000,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
}
|
|
|
|
|
|
case float64:
|
|
|
- paramTypes[i+i] = fieldTypeDouble
|
|
|
+ paramTypes[i+i] = byte(fieldTypeDouble)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
if cap(paramValues)-len(paramValues)-8 >= 0 {
|
|
@@ -962,7 +1016,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
}
|
|
|
|
|
|
case bool:
|
|
|
- paramTypes[i+i] = fieldTypeTiny
|
|
|
+ paramTypes[i+i] = byte(fieldTypeTiny)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
if v {
|
|
@@ -974,10 +1028,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
case []byte:
|
|
|
|
|
|
if v != nil {
|
|
|
- paramTypes[i+i] = fieldTypeString
|
|
|
+ paramTypes[i+i] = byte(fieldTypeString)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
- if len(v) < mc.maxPacketAllowed-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
|
|
+ if len(v) < longDataSize {
|
|
|
paramValues = appendLengthEncodedInteger(paramValues,
|
|
|
uint64(len(v)),
|
|
|
)
|
|
@@ -992,14 +1046,14 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
|
|
|
|
|
|
nullMask[i/8] |= 1 << (uint(i) & 7)
|
|
|
- paramTypes[i+i] = fieldTypeNULL
|
|
|
+ paramTypes[i+i] = byte(fieldTypeNULL)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
case string:
|
|
|
- paramTypes[i+i] = fieldTypeString
|
|
|
+ paramTypes[i+i] = byte(fieldTypeString)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
- if len(v) < mc.maxPacketAllowed-pos-len(paramValues)-(len(args)-(i+1))*64 {
|
|
|
+ if len(v) < longDataSize {
|
|
|
paramValues = appendLengthEncodedInteger(paramValues,
|
|
|
uint64(len(v)),
|
|
|
)
|
|
@@ -1011,23 +1065,25 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
|
|
|
}
|
|
|
|
|
|
case time.Time:
|
|
|
- paramTypes[i+i] = fieldTypeString
|
|
|
+ paramTypes[i+i] = byte(fieldTypeString)
|
|
|
paramTypes[i+i+1] = 0x00
|
|
|
|
|
|
- var val []byte
|
|
|
+ var a [64]byte
|
|
|
+ var b = a[:0]
|
|
|
+
|
|
|
if v.IsZero() {
|
|
|
- val = []byte("0000-00-00")
|
|
|
+ b = append(b, "0000-00-00"...)
|
|
|
} else {
|
|
|
- val = []byte(v.In(mc.cfg.Loc).Format(timeFormat))
|
|
|
+ b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
|
|
|
}
|
|
|
|
|
|
paramValues = appendLengthEncodedInteger(paramValues,
|
|
|
- uint64(len(val)),
|
|
|
+ uint64(len(b)),
|
|
|
)
|
|
|
- paramValues = append(paramValues, val...)
|
|
|
+ paramValues = append(paramValues, b...)
|
|
|
|
|
|
default:
|
|
|
- return fmt.Errorf("can not convert type: %T", arg)
|
|
|
+ return fmt.Errorf("cannot convert type: %T", arg)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1060,8 +1116,6 @@ func (mc *mysqlConn) discardResults() error {
|
|
|
if err := mc.readUntilEOF(); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- } else {
|
|
|
- mc.status &^= statusMoreResultsExists
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
@@ -1079,16 +1133,17 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
|
|
|
if data[0] == iEOF && len(data) == 5 {
|
|
|
rows.mc.status = readStatus(data[3:])
|
|
|
- if err := rows.mc.discardResults(); err != nil {
|
|
|
- return err
|
|
|
+ rows.rs.done = true
|
|
|
+ if !rows.HasNextResultSet() {
|
|
|
+ rows.mc = nil
|
|
|
}
|
|
|
- rows.mc = nil
|
|
|
return io.EOF
|
|
|
}
|
|
|
+ mc := rows.mc
|
|
|
rows.mc = nil
|
|
|
|
|
|
|
|
|
- return rows.mc.handleErrorPacket(data)
|
|
|
+ return mc.handleErrorPacket(data)
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1104,14 +1159,14 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
}
|
|
|
|
|
|
|
|
|
- switch rows.columns[i].fieldType {
|
|
|
+ switch rows.rs.columns[i].fieldType {
|
|
|
case fieldTypeNULL:
|
|
|
dest[i] = nil
|
|
|
continue
|
|
|
|
|
|
|
|
|
case fieldTypeTiny:
|
|
|
- if rows.columns[i].flags&flagUnsigned != 0 {
|
|
|
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
|
|
dest[i] = int64(data[pos])
|
|
|
} else {
|
|
|
dest[i] = int64(int8(data[pos]))
|
|
@@ -1120,7 +1175,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
continue
|
|
|
|
|
|
case fieldTypeShort, fieldTypeYear:
|
|
|
- if rows.columns[i].flags&flagUnsigned != 0 {
|
|
|
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
|
|
dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
|
|
|
} else {
|
|
|
dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
|
|
@@ -1129,7 +1184,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
continue
|
|
|
|
|
|
case fieldTypeInt24, fieldTypeLong:
|
|
|
- if rows.columns[i].flags&flagUnsigned != 0 {
|
|
|
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
|
|
dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
|
|
|
} else {
|
|
|
dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
|
|
@@ -1138,7 +1193,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
continue
|
|
|
|
|
|
case fieldTypeLongLong:
|
|
|
- if rows.columns[i].flags&flagUnsigned != 0 {
|
|
|
+ if rows.rs.columns[i].flags&flagUnsigned != 0 {
|
|
|
val := binary.LittleEndian.Uint64(data[pos : pos+8])
|
|
|
if val > math.MaxInt64 {
|
|
|
dest[i] = uint64ToString(val)
|
|
@@ -1152,7 +1207,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
continue
|
|
|
|
|
|
case fieldTypeFloat:
|
|
|
- dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])))
|
|
|
+ dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))
|
|
|
pos += 4
|
|
|
continue
|
|
|
|
|
@@ -1192,10 +1247,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
case isNull:
|
|
|
dest[i] = nil
|
|
|
continue
|
|
|
- case rows.columns[i].fieldType == fieldTypeTime:
|
|
|
+ case rows.rs.columns[i].fieldType == fieldTypeTime:
|
|
|
|
|
|
var dstlen uint8
|
|
|
- switch decimals := rows.columns[i].decimals; decimals {
|
|
|
+ switch decimals := rows.rs.columns[i].decimals; decimals {
|
|
|
case 0x00, 0x1f:
|
|
|
dstlen = 8
|
|
|
case 1, 2, 3, 4, 5, 6:
|
|
@@ -1203,18 +1258,18 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
default:
|
|
|
return fmt.Errorf(
|
|
|
"protocol error, illegal decimals value %d",
|
|
|
- rows.columns[i].decimals,
|
|
|
+ rows.rs.columns[i].decimals,
|
|
|
)
|
|
|
}
|
|
|
- dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
|
|
|
+ dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen)
|
|
|
case rows.mc.parseTime:
|
|
|
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
|
|
|
default:
|
|
|
var dstlen uint8
|
|
|
- if rows.columns[i].fieldType == fieldTypeDate {
|
|
|
+ if rows.rs.columns[i].fieldType == fieldTypeDate {
|
|
|
dstlen = 10
|
|
|
} else {
|
|
|
- switch decimals := rows.columns[i].decimals; decimals {
|
|
|
+ switch decimals := rows.rs.columns[i].decimals; decimals {
|
|
|
case 0x00, 0x1f:
|
|
|
dstlen = 19
|
|
|
case 1, 2, 3, 4, 5, 6:
|
|
@@ -1222,11 +1277,11 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
default:
|
|
|
return fmt.Errorf(
|
|
|
"protocol error, illegal decimals value %d",
|
|
|
- rows.columns[i].decimals,
|
|
|
+ rows.rs.columns[i].decimals,
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
- dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, false)
|
|
|
+ dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen)
|
|
|
}
|
|
|
|
|
|
if err == nil {
|
|
@@ -1238,7 +1293,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
|
|
|
|
|
|
|
|
default:
|
|
|
- return fmt.Errorf("unknown field type %d", rows.columns[i].fieldType)
|
|
|
+ return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType)
|
|
|
}
|
|
|
}
|
|
|
|