// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package mysql

import (
	
	
	
	
	
	
	
	
	
	
)

// Packets documentation:
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html

// Read packet to buffer 'data'
func ( *mysqlConn) () ([]byte, error) {
	var  []byte
	for {
		// read packet header
		,  := .buf.readNext(4)
		if  != nil {
			if  := .canceled.Value();  != nil {
				return nil, 
			}
			errLog.Print()
			.Close()
			return nil, ErrInvalidConn
		}

		// packet length [24 bit]
		 := int(uint32([0]) | uint32([1])<<8 | uint32([2])<<16)

		// check packet sync [8 bit]
		if [3] != .sequence {
			if [3] > .sequence {
				return nil, ErrPktSyncMul
			}
			return nil, ErrPktSync
		}
		.sequence++

		// packets with length 0 terminate a previous packet which is a
		// multiple of (2^24)-1 bytes long
		if  == 0 {
			// there was no previous packet
			if  == nil {
				errLog.Print(ErrMalformPkt)
				.Close()
				return nil, ErrInvalidConn
			}

			return , nil
		}

		// read packet body [pktLen bytes]
		,  = .buf.readNext()
		if  != nil {
			if  := .canceled.Value();  != nil {
				return nil, 
			}
			errLog.Print()
			.Close()
			return nil, ErrInvalidConn
		}

		// return data if this was the last packet
		if  < maxPacketSize {
			// zero allocations for non-split packets
			if  == nil {
				return , nil
			}

			return append(, ...), nil
		}

		 = append(, ...)
	}
}

// Write packet buffer 'data'
func ( *mysqlConn) ( []byte) error {
	 := len() - 4

	if  > .maxAllowedPacket {
		return ErrPktTooLarge
	}

	// Perform a stale connection check. We only perform this check for
	// the first query on a connection that has been checked out of the
	// connection pool: a fresh connection from the pool is more likely
	// to be stale, and it has not performed any previous writes that
	// could cause data corruption, so it's safe to return ErrBadConn
	// if the check fails.
	if .reset {
		.reset = false
		 := .netConn
		if .rawConn != nil {
			 = .rawConn
		}
		var  error
		if .cfg.CheckConnLiveness {
			if .cfg.ReadTimeout != 0 {
				 = .SetReadDeadline(time.Now().Add(.cfg.ReadTimeout))
			}
			if  == nil {
				 = connCheck()
			}
		}
		if  != nil {
			errLog.Print("closing bad idle connection: ", )
			.Close()
			return driver.ErrBadConn
		}
	}

	for {
		var  int
		if  >= maxPacketSize {
			[0] = 0xff
			[1] = 0xff
			[2] = 0xff
			 = maxPacketSize
		} else {
			[0] = byte()
			[1] = byte( >> 8)
			[2] = byte( >> 16)
			 = 
		}
		[3] = .sequence

		// Write packet
		if .writeTimeout > 0 {
			if  := .netConn.SetWriteDeadline(time.Now().Add(.writeTimeout));  != nil {
				return 
			}
		}

		,  := .netConn.Write([:4+])
		if  == nil &&  == 4+ {
			.sequence++
			if  != maxPacketSize {
				return nil
			}
			 -= 
			 = [:]
			continue
		}

		// Handle error
		if  == nil { // n != len(data)
			.cleanup()
			errLog.Print(ErrMalformPkt)
		} else {
			if  := .canceled.Value();  != nil {
				return 
			}
			if  == 0 &&  == len()-4 {
				// only for the first loop iteration when nothing was written yet
				return errBadConnNoWrite
			}
			.cleanup()
			errLog.Print()
		}
		return ErrInvalidConn
	}
}

/******************************************************************************
*                           Initialization Process                            *
******************************************************************************/

// Handshake Initialization Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
func ( *mysqlConn) () ( []byte,  string,  error) {
	,  = .readPacket()
	if  != 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  == ErrInvalidConn {
			return nil, "", driver.ErrBadConn
		}
		return
	}

	if [0] == iERR {
		return nil, "", .handleErrorPacket()
	}

	// protocol version [1 byte]
	if [0] < minProtocolVersion {
		return nil, "", fmt.Errorf(
			"unsupported protocol version %d. Version %d or higher is required",
			[0],
			minProtocolVersion,
		)
	}

	// server version [null terminated string]
	// connection id [4 bytes]
	 := 1 + bytes.IndexByte([1:], 0x00) + 1 + 4

	// first part of the password cipher [8 bytes]
	 := [ : +8]

	// (filler) always 0x00 [1 byte]
	 += 8 + 1

	// capability flags (lower 2 bytes) [2 bytes]
	.flags = clientFlag(binary.LittleEndian.Uint16([ : +2]))
	if .flags&clientProtocol41 == 0 {
		return nil, "", ErrOldProtocol
	}
	if .flags&clientSSL == 0 && .cfg.TLS != nil {
		if .cfg.AllowFallbackToPlaintext {
			.cfg.TLS = nil
		} else {
			return nil, "", ErrNoTLS
		}
	}
	 += 2

	if len() >  {
		// character set [1 byte]
		// status flags [2 bytes]
		// capability flags (upper 2 bytes) [2 bytes]
		// length of auth-plugin-data [1 byte]
		// reserved (all [00]) [10 bytes]
		 += 1 + 2 + 2 + 1 + 10

		// second part of the password cipher [mininum 13 bytes],
		// where len=MAX(13, length of auth-plugin-data - 8)
		//
		// The web documentation is ambiguous about the length. However,
		// according to mysql-5.7/sql/auth/sql_authentication.cc line 538,
		// the 13th byte is "\0 byte, terminating the second part of
		// a scramble". So the second part of the password cipher is
		// a NULL terminated string that's at least 13 bytes with the
		// last byte being NULL.
		//
		// The official Python library uses the fixed length 12
		// which seems to work but technically could have a hidden bug.
		 = append(, [:+12]...)
		 += 13

		// EOF if version (>= 5.5.7 and < 5.5.10) or (>= 5.6.0 and < 5.6.2)
		// \NUL otherwise
		if  := bytes.IndexByte([:], 0x00);  != -1 {
			 = string([ : +])
		} else {
			 = string([:])
		}

		// make a memory safe copy of the cipher slice
		var  [20]byte
		copy([:], )
		return [:], , nil
	}

	// make a memory safe copy of the cipher slice
	var  [8]byte
	copy([:], )
	return [:], , nil
}

// Client Authentication Packet
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
func ( *mysqlConn) ( []byte,  string) error {
	// Adjust client flags based on server support
	 := clientProtocol41 |
		clientSecureConn |
		clientLongPassword |
		clientTransactions |
		clientLocalFiles |
		clientPluginAuth |
		clientMultiResults |
		.flags&clientLongFlag

	if .cfg.ClientFoundRows {
		 |= clientFoundRows
	}

	// To enable TLS / SSL
	if .cfg.TLS != nil {
		 |= clientSSL
	}

	if .cfg.MultiStatements {
		 |= clientMultiStatements
	}

	// encode length of the auth plugin data
	var  [9]byte
	 := len()
	 := appendLengthEncodedInteger([:0], uint64())
	if len() > 1 {
		// if the length can not be written in 1 byte, it must be written as a
		// length encoded integer
		 |= clientPluginAuthLenEncClientData
	}

	 := 4 + 4 + 1 + 23 + len(.cfg.User) + 1 + len() + len() + 21 + 1

	// To specify a db name
	if  := len(.cfg.DBName);  > 0 {
		 |= clientConnectWithDB
		 +=  + 1
	}

	// Calculate packet length and get buffer with that size
	,  := .buf.takeSmallBuffer( + 4)
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// ClientFlags [32 bit]
	[4] = byte()
	[5] = byte( >> 8)
	[6] = byte( >> 16)
	[7] = byte( >> 24)

	// MaxPacketSize [32 bit] (none)
	[8] = 0x00
	[9] = 0x00
	[10] = 0x00
	[11] = 0x00

	// Charset [1 byte]
	var  bool
	[12],  = collations[.cfg.Collation]
	if ! {
		// 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 errors.New("unknown collation")
	}

	// Filler [23 bytes] (all 0x00)
	 := 13
	for ;  < 13+23; ++ {
		[] = 0
	}

	// SSL Connection Request Packet
	// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest
	if .cfg.TLS != nil {
		// Send TLS / SSL request packet
		if  := .writePacket([:(4+4+1+23)+4]);  != nil {
			return 
		}

		// Switch to TLS
		 := tls.Client(.netConn, .cfg.TLS)
		if  := .Handshake();  != nil {
			return 
		}
		.rawConn = .netConn
		.netConn = 
		.buf.nc = 
	}

	// User [null terminated string]
	if len(.cfg.User) > 0 {
		 += copy([:], .cfg.User)
	}
	[] = 0x00
	++

	// Auth Data [length encoded integer]
	 += copy([:], )
	 += copy([:], )

	// Databasename [null terminated string]
	if len(.cfg.DBName) > 0 {
		 += copy([:], .cfg.DBName)
		[] = 0x00
		++
	}

	 += copy([:], )
	[] = 0x00
	++

	// Send Auth packet
	return .writePacket([:])
}

// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
func ( *mysqlConn) ( []byte) error {
	 := 4 + len()
	,  := .buf.takeSmallBuffer()
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// Add the auth data [EOF]
	copy([4:], )
	return .writePacket()
}

/******************************************************************************
*                             Command Packets                                 *
******************************************************************************/

func ( *mysqlConn) ( byte) error {
	// Reset Packet Sequence
	.sequence = 0

	,  := .buf.takeSmallBuffer(4 + 1)
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// Add command byte
	[4] = 

	// Send CMD packet
	return .writePacket()
}

func ( *mysqlConn) ( byte,  string) error {
	// Reset Packet Sequence
	.sequence = 0

	 := 1 + len()
	,  := .buf.takeBuffer( + 4)
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// Add command byte
	[4] = 

	// Add arg
	copy([5:], )

	// Send CMD packet
	return .writePacket()
}

func ( *mysqlConn) ( byte,  uint32) error {
	// Reset Packet Sequence
	.sequence = 0

	,  := .buf.takeSmallBuffer(4 + 1 + 4)
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// Add command byte
	[4] = 

	// Add arg [32 bit]
	[5] = byte()
	[6] = byte( >> 8)
	[7] = byte( >> 16)
	[8] = byte( >> 24)

	// Send CMD packet
	return .writePacket()
}

/******************************************************************************
*                              Result Packets                                 *
******************************************************************************/

func ( *mysqlConn) () ([]byte, string, error) {
	,  := .readPacket()
	if  != nil {
		return nil, "", 
	}

	// packet indicator
	switch [0] {

	case iOK:
		return nil, "", .handleOkPacket()

	case iAuthMoreData:
		return [1:], "", 

	case iEOF:
		if len() == 1 {
			// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
			return nil, "mysql_old_password", nil
		}
		 := bytes.IndexByte(, 0x00)
		if  < 0 {
			return nil, "", ErrMalformPkt
		}
		 := string([1:])
		 := [+1:]
		return , , nil

	default: // Error otherwise
		return nil, "", .handleErrorPacket()
	}
}

// Returns error if Packet is not an 'Result OK'-Packet
func ( *mysqlConn) () error {
	,  := .readPacket()
	if  != nil {
		return 
	}

	if [0] == iOK {
		return .handleOkPacket()
	}
	return .handleErrorPacket()
}

// Result Set Header Packet
// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset
func ( *mysqlConn) () (int, error) {
	,  := .readPacket()
	if  == nil {
		switch [0] {

		case iOK:
			return 0, .handleOkPacket()

		case iERR:
			return 0, .handleErrorPacket()

		case iLocalInFile:
			return 0, .handleInFileRequest(string([1:]))
		}

		// column count
		, ,  := readLengthEncodedInteger()
		if -len() == 0 {
			return int(), nil
		}

		return 0, ErrMalformPkt
	}
	return 0, 
}

// Error Packet
// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet
func ( *mysqlConn) ( []byte) error {
	if [0] != iERR {
		return ErrMalformPkt
	}

	// 0xff [1 byte]

	// Error Number [16 bit uint]
	 := binary.LittleEndian.Uint16([1:3])

	// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
	// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
	if ( == 1792 ||  == 1290) && .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
		// permission. This is specifically for a possible race condition
		// during failover (e.g. on AWS Aurora). See README.md for more.
		//
		// We explicitly close the connection before returning
		// driver.ErrBadConn to ensure that `database/sql` purges this
		// connection and initiates a new one for next statement next time.
		.Close()
		return driver.ErrBadConn
	}

	 := &MySQLError{Number: }

	 := 3

	// SQL State [optional: # + 5bytes string]
	if [3] == 0x23 {
		copy(.SQLState[:], [4:4+5])
		 = 9
	}

	// Error Message [string]
	.Message = string([:])

	return 
}

func readStatus( []byte) statusFlag {
	return statusFlag([0]) | statusFlag([1])<<8
}

// Ok Packet
// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet
func ( *mysqlConn) ( []byte) error {
	var ,  int

	// 0x00 [1 byte]

	// Affected rows [Length Coded Binary]
	.affectedRows, _,  = readLengthEncodedInteger([1:])

	// Insert id [Length Coded Binary]
	.insertId, _,  = readLengthEncodedInteger([1+:])

	// server_status [2 bytes]
	.status = readStatus([1++ : 1+++2])
	if .status&statusMoreResultsExists != 0 {
		return nil
	}

	// warning count [2 bytes]

	return nil
}

// Read Packets as Field Packets until EOF-Packet or an Error appears
// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41
func ( *mysqlConn) ( int) ([]mysqlField, error) {
	 := make([]mysqlField, )

	for  := 0; ; ++ {
		,  := .readPacket()
		if  != nil {
			return nil, 
		}

		// EOF Packet
		if [0] == iEOF && (len() == 5 || len() == 1) {
			if  ==  {
				return , nil
			}
			return nil, fmt.Errorf("column count mismatch n:%d len:%d", , len())
		}

		// Catalog
		,  := skipLengthEncodedString()
		if  != nil {
			return nil, 
		}

		// Database [len coded string]
		,  := skipLengthEncodedString([:])
		if  != nil {
			return nil, 
		}
		 += 

		// Table [len coded string]
		if .cfg.ColumnsWithAlias {
			, , ,  := readLengthEncodedString([:])
			if  != nil {
				return nil, 
			}
			 += 
			[].tableName = string()
		} else {
			,  = skipLengthEncodedString([:])
			if  != nil {
				return nil, 
			}
			 += 
		}

		// Original table [len coded string]
		,  = skipLengthEncodedString([:])
		if  != nil {
			return nil, 
		}
		 += 

		// Name [len coded string]
		, , ,  := readLengthEncodedString([:])
		if  != nil {
			return nil, 
		}
		[].name = string()
		 += 

		// Original name [len coded string]
		,  = skipLengthEncodedString([:])
		if  != nil {
			return nil, 
		}
		 += 

		// Filler [uint8]
		++

		// Charset [charset, collation uint8]
		[].charSet = []
		 += 2

		// Length [uint32]
		[].length = binary.LittleEndian.Uint32([ : +4])
		 += 4

		// Field type [uint8]
		[].fieldType = fieldType([])
		++

		// Flags [uint16]
		[].flags = fieldFlag(binary.LittleEndian.Uint16([ : +2]))
		 += 2

		// Decimals [uint8]
		[].decimals = []
		//pos++

		// Default value [len coded binary]
		//if pos < len(data) {
		//	defaultVal, _, err = bytesToLengthCodedBinary(data[pos:])
		//}
	}
}

// Read Packets as Field Packets until EOF-Packet or an Error appears
// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow
func ( *textRows) ( []driver.Value) error {
	 := .mc

	if .rs.done {
		return io.EOF
	}

	,  := .readPacket()
	if  != nil {
		return 
	}

	// EOF Packet
	if [0] == iEOF && len() == 5 {
		// server_status [2 bytes]
		.mc.status = readStatus([3:])
		.rs.done = true
		if !.HasNextResultSet() {
			.mc = nil
		}
		return io.EOF
	}
	if [0] == iERR {
		.mc = nil
		return .handleErrorPacket()
	}

	// RowSet Packet
	var (
		      int
		 bool
		    int = 0
	)

	for  := range  {
		// Read bytes and convert to string
		[], , ,  = readLengthEncodedString([:])
		 += 

		if  != nil {
			return 
		}

		if  {
			[] = nil
			continue
		}

		if !.parseTime {
			continue
		}

		// Parse time field
		switch .rs.columns[].fieldType {
		case fieldTypeTimestamp,
			fieldTypeDateTime,
			fieldTypeDate,
			fieldTypeNewDate:
			if [],  = parseDateTime([].([]byte), .cfg.Loc);  != nil {
				return 
			}
		}
	}

	return nil
}

// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read
func ( *mysqlConn) () error {
	for {
		,  := .readPacket()
		if  != nil {
			return 
		}

		switch [0] {
		case iERR:
			return .handleErrorPacket()
		case iEOF:
			if len() == 5 {
				.status = readStatus([3:])
			}
			return nil
		}
	}
}

/******************************************************************************
*                           Prepared Statements                               *
******************************************************************************/

// Prepare Result Packets
// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html
func ( *mysqlStmt) () (uint16, error) {
	,  := .mc.readPacket()
	if  == nil {
		// packet indicator [1 byte]
		if [0] != iOK {
			return 0, .mc.handleErrorPacket()
		}

		// statement id [4 bytes]
		.id = binary.LittleEndian.Uint32([1:5])

		// Column count [16 bit uint]
		 := binary.LittleEndian.Uint16([5:7])

		// Param count [16 bit uint]
		.paramCount = int(binary.LittleEndian.Uint16([7:9]))

		// Reserved [8 bit]

		// Warning count [16 bit uint]

		return , nil
	}
	return 0, 
}

// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html
func ( *mysqlStmt) ( int,  []byte) error {
	 := .mc.maxAllowedPacket - 1
	 := 

	// After the header (bytes 0-3) follows before the data:
	// 1 byte command
	// 4 bytes stmtID
	// 2 bytes paramID
	const  = 1 + 4 + 2

	// Cannot use the write buffer since
	// a) the buffer is too small
	// b) it is in use
	 := make([]byte, 4+1+4+2+len())

	copy([4+:], )

	for  := len();  > 0;  -=  -  {
		if + <  {
			 =  + 
		}

		.mc.sequence = 0
		// Add command byte [1 byte]
		[4] = comStmtSendLongData

		// Add stmtID [32 bit]
		[5] = byte(.id)
		[6] = byte(.id >> 8)
		[7] = byte(.id >> 16)
		[8] = byte(.id >> 24)

		// Add paramID [16 bit]
		[9] = byte()
		[10] = byte( >> 8)

		// Send CMD packet
		 := .mc.writePacket([:4+])
		if  == nil {
			 = [-:]
			continue
		}
		return 

	}

	// Reset Packet Sequence
	.mc.sequence = 0
	return nil
}

// Execute Prepared Statement
// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html
func ( *mysqlStmt) ( []driver.Value) error {
	if len() != .paramCount {
		return fmt.Errorf(
			"argument count mismatch (got: %d; has: %d)",
			len(),
			.paramCount,
		)
	}

	const  = 4 + 1 + 4 + 1 + 4
	 := .mc

	// Determine threshold dynamically to avoid packet size shortage.
	 := .maxAllowedPacket / (.paramCount + 1)
	if  < 64 {
		 = 64
	}

	// Reset packet-sequence
	.sequence = 0

	var  []byte
	var  error

	if len() == 0 {
		,  = .buf.takeBuffer()
	} else {
		,  = .buf.takeCompleteBuffer()
		// In this case the len(data) == cap(data) which is used to optimise the flow below.
	}
	if  != nil {
		// cannot take the buffer. Something must be wrong with the connection
		errLog.Print()
		return errBadConnNoWrite
	}

	// command [1 byte]
	[4] = comStmtExecute

	// statement_id [4 bytes]
	[5] = byte(.id)
	[6] = byte(.id >> 8)
	[7] = byte(.id >> 16)
	[8] = byte(.id >> 24)

	// flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte]
	[9] = 0x00

	// iteration_count (uint32(1)) [4 bytes]
	[10] = 0x01
	[11] = 0x00
	[12] = 0x00
	[13] = 0x00

	if len() > 0 {
		 := 

		var  []byte
		if ,  := (len()+7)/8, 1+2*len(); ++ >= cap() {
			// buffer has to be extended but we don't know by how much so
			// we depend on append after all data with known sizes fit.
			// We stop at that because we deal with a lot of columns here
			// which makes the required allocation size hard to guess.
			 := make([]byte, ++)
			copy([:], [:])
			 = 
			 = [ : +]
			// No need to clean nullMask as make ensures that.
			 += 
		} else {
			 = [ : +]
			for  := range  {
				[] = 0
			}
			 += 
		}

		// newParameterBoundFlag 1 [1 byte]
		[] = 0x01
		++

		// type of each parameter [len(args)*2 bytes]
		 := [:]
		 += len() * 2

		// value of each parameter [n bytes]
		 := [:]
		 := cap()

		for ,  := range  {
			// build NULL-bitmap
			if  == nil {
				[/8] |= 1 << (uint() & 7)
				[+] = byte(fieldTypeNULL)
				[++1] = 0x00
				continue
			}

			if ,  := .(json.RawMessage);  {
				 = []byte()
			}
			// cache types and values
			switch v := .(type) {
			case int64:
				[+] = byte(fieldTypeLongLong)
				[++1] = 0x00

				if cap()-len()-8 >= 0 {
					 = [:len()+8]
					binary.LittleEndian.PutUint64(
						[len()-8:],
						uint64(),
					)
				} else {
					 = append(,
						uint64ToBytes(uint64())...,
					)
				}

			case uint64:
				[+] = byte(fieldTypeLongLong)
				[++1] = 0x80 // type is unsigned

				if cap()-len()-8 >= 0 {
					 = [:len()+8]
					binary.LittleEndian.PutUint64(
						[len()-8:],
						uint64(),
					)
				} else {
					 = append(,
						uint64ToBytes(uint64())...,
					)
				}

			case float64:
				[+] = byte(fieldTypeDouble)
				[++1] = 0x00

				if cap()-len()-8 >= 0 {
					 = [:len()+8]
					binary.LittleEndian.PutUint64(
						[len()-8:],
						math.Float64bits(),
					)
				} else {
					 = append(,
						uint64ToBytes(math.Float64bits())...,
					)
				}

			case bool:
				[+] = byte(fieldTypeTiny)
				[++1] = 0x00

				if  {
					 = append(, 0x01)
				} else {
					 = append(, 0x00)
				}

			case []byte:
				// Common case (non-nil value) first
				if  != nil {
					[+] = byte(fieldTypeString)
					[++1] = 0x00

					if len() <  {
						 = appendLengthEncodedInteger(,
							uint64(len()),
						)
						 = append(, ...)
					} else {
						if  := .writeCommandLongData(, );  != nil {
							return 
						}
					}
					continue
				}

				// Handle []byte(nil) as a NULL value
				[/8] |= 1 << (uint() & 7)
				[+] = byte(fieldTypeNULL)
				[++1] = 0x00

			case string:
				[+] = byte(fieldTypeString)
				[++1] = 0x00

				if len() <  {
					 = appendLengthEncodedInteger(,
						uint64(len()),
					)
					 = append(, ...)
				} else {
					if  := .writeCommandLongData(, []byte());  != nil {
						return 
					}
				}

			case time.Time:
				[+] = byte(fieldTypeString)
				[++1] = 0x00

				var  [64]byte
				var  = [:0]

				if .IsZero() {
					 = append(, "0000-00-00"...)
				} else {
					,  = appendDateTime(, .In(.cfg.Loc))
					if  != nil {
						return 
					}
				}

				 = appendLengthEncodedInteger(,
					uint64(len()),
				)
				 = append(, ...)

			default:
				return fmt.Errorf("cannot convert type: %T", )
			}
		}

		// Check if param values exceeded the available buffer
		// In that case we must build the data packet with the new values buffer
		if  != cap() {
			 = append([:], ...)
			if  = .buf.store();  != nil {
				errLog.Print()
				return errBadConnNoWrite
			}
		}

		 += len()
		 = [:]
	}

	return .writePacket()
}

func ( *mysqlConn) () error {
	for .status&statusMoreResultsExists != 0 {
		,  := .readResultSetHeaderPacket()
		if  != nil {
			return 
		}
		if  > 0 {
			// columns
			if  := .readUntilEOF();  != nil {
				return 
			}
			// rows
			if  := .readUntilEOF();  != nil {
				return 
			}
		}
	}
	return nil
}

// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html
func ( *binaryRows) ( []driver.Value) error {
	,  := .mc.readPacket()
	if  != nil {
		return 
	}

	// packet indicator [1 byte]
	if [0] != iOK {
		// EOF Packet
		if [0] == iEOF && len() == 5 {
			.mc.status = readStatus([3:])
			.rs.done = true
			if !.HasNextResultSet() {
				.mc = nil
			}
			return io.EOF
		}
		 := .mc
		.mc = nil

		// Error otherwise
		return .handleErrorPacket()
	}

	// NULL-bitmap,  [(column-count + 7 + 2) / 8 bytes]
	 := 1 + (len()+7+2)>>3
	 := [1:]

	for  := range  {
		// Field is NULL
		// (byte >> bit-pos) % 2 == 1
		if (([(+2)>>3] >> uint((+2)&7)) & 1) == 1 {
			[] = nil
			continue
		}

		// Convert to byte-coded string
		switch .rs.columns[].fieldType {
		case fieldTypeNULL:
			[] = nil
			continue

		// Numeric Types
		case fieldTypeTiny:
			if .rs.columns[].flags&flagUnsigned != 0 {
				[] = int64([])
			} else {
				[] = int64(int8([]))
			}
			++
			continue

		case fieldTypeShort, fieldTypeYear:
			if .rs.columns[].flags&flagUnsigned != 0 {
				[] = int64(binary.LittleEndian.Uint16([ : +2]))
			} else {
				[] = int64(int16(binary.LittleEndian.Uint16([ : +2])))
			}
			 += 2
			continue

		case fieldTypeInt24, fieldTypeLong:
			if .rs.columns[].flags&flagUnsigned != 0 {
				[] = int64(binary.LittleEndian.Uint32([ : +4]))
			} else {
				[] = int64(int32(binary.LittleEndian.Uint32([ : +4])))
			}
			 += 4
			continue

		case fieldTypeLongLong:
			if .rs.columns[].flags&flagUnsigned != 0 {
				 := binary.LittleEndian.Uint64([ : +8])
				if  > math.MaxInt64 {
					[] = uint64ToString()
				} else {
					[] = int64()
				}
			} else {
				[] = int64(binary.LittleEndian.Uint64([ : +8]))
			}
			 += 8
			continue

		case fieldTypeFloat:
			[] = math.Float32frombits(binary.LittleEndian.Uint32([ : +4]))
			 += 4
			continue

		case fieldTypeDouble:
			[] = math.Float64frombits(binary.LittleEndian.Uint64([ : +8]))
			 += 8
			continue

		// Length coded Binary Strings
		case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
			fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
			fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
			fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON:
			var  bool
			var  int
			[], , ,  = readLengthEncodedString([:])
			 += 
			if  == nil {
				if ! {
					continue
				} else {
					[] = nil
					continue
				}
			}
			return 

		case
			fieldTypeDate, fieldTypeNewDate, // Date YYYY-MM-DD
			fieldTypeTime,                         // Time [-][H]HH:MM:SS[.fractal]
			fieldTypeTimestamp, fieldTypeDateTime: // Timestamp YYYY-MM-DD HH:MM:SS[.fractal]

			, ,  := readLengthEncodedInteger([:])
			 += 

			switch {
			case :
				[] = nil
				continue
			case .rs.columns[].fieldType == fieldTypeTime:
				// database/sql does not support an equivalent to TIME, return a string
				var  uint8
				switch  := .rs.columns[].decimals;  {
				case 0x00, 0x1f:
					 = 8
				case 1, 2, 3, 4, 5, 6:
					 = 8 + 1 + 
				default:
					return fmt.Errorf(
						"protocol error, illegal decimals value %d",
						.rs.columns[].decimals,
					)
				}
				[],  = formatBinaryTime([:+int()], )
			case .mc.parseTime:
				[],  = parseBinaryDateTime(, [:], .mc.cfg.Loc)
			default:
				var  uint8
				if .rs.columns[].fieldType == fieldTypeDate {
					 = 10
				} else {
					switch  := .rs.columns[].decimals;  {
					case 0x00, 0x1f:
						 = 19
					case 1, 2, 3, 4, 5, 6:
						 = 19 + 1 + 
					default:
						return fmt.Errorf(
							"protocol error, illegal decimals value %d",
							.rs.columns[].decimals,
						)
					}
				}
				[],  = formatBinaryDateTime([:+int()], )
			}

			if  == nil {
				 += int()
				continue
			} else {
				return 
			}

		// Please report if this happens!
		default:
			return fmt.Errorf("unknown field type %d", .rs.columns[].fieldType)
		}
	}

	return nil
}