func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
	if len(args) != stmt.paramCount {
		return fmt.Errorf(
			"argument count mismatch (got: %d; has: %d)",
			len(args),
			stmt.paramCount,
		)
	}
	const minPktLen = 4 + 1 + 4 + 1 + 4
	mc := stmt.mc
	longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1)
	if longDataSize < 64 {
		longDataSize = 64
	}
	mc.sequence = 0
	var data []byte
	if len(args) == 0 {
		data = mc.buf.takeBuffer(minPktLen)
	} else {
		data = mc.buf.takeCompleteBuffer()
	}
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	data[4] = comStmtExecute
	data[5] = byte(stmt.id)
	data[6] = byte(stmt.id >> 8)
	data[7] = byte(stmt.id >> 16)
	data[8] = byte(stmt.id >> 24)
	data[9] = 0x00
	data[10] = 0x01
	data[11] = 0x00
	data[12] = 0x00
	data[13] = 0x00
	if len(args) > 0 {
		pos := minPktLen
		var nullMask []byte
		if maskLen, typesLen := (len(args)+7)/8, 1+2*len(args); pos+maskLen+typesLen >= len(data) {
			tmp := make([]byte, pos+maskLen+typesLen)
			copy(tmp[:pos], data[:pos])
			data = tmp
			nullMask = data[pos : pos+maskLen]
			pos += maskLen
		} else {
			nullMask = data[pos : pos+maskLen]
			for i := 0; i < maskLen; i++ {
				nullMask[i] = 0
			}
			pos += maskLen
		}
		data[pos] = 0x01
		pos++
		paramTypes := data[pos:]
		pos += len(args) * 2
		paramValues := data[pos:pos]
		valuesCap := cap(paramValues)
		for i, arg := range args {
			if arg == nil {
				nullMask[i/8] |= 1 << (uint(i) & 7)
				paramTypes[i+i] = byte(fieldTypeNULL)
				paramTypes[i+i+1] = 0x00
				continue
			}
			switch v := arg.(type) {
			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))...,
					)
				}
			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))...,
					)
				}
			case bool:
				paramTypes[i+i] = byte(fieldTypeTiny)
				paramTypes[i+i+1] = 0x00
				if v {
					paramValues = append(paramValues, 0x01)
				} else {
					paramValues = append(paramValues, 0x00)
				}
			case []byte:
				if v != nil {
					paramTypes[i+i] = byte(fieldTypeString)
					paramTypes[i+i+1] = 0x00
					if len(v) < longDataSize {
						paramValues = appendLengthEncodedInteger(paramValues,
							uint64(len(v)),
						)
						paramValues = append(paramValues, v...)
					} else {
						if err := stmt.writeCommandLongData(i, v); err != nil {
							return err
						}
					}
					continue
				}
				nullMask[i/8] |= 1 << (uint(i) & 7)
				paramTypes[i+i] = byte(fieldTypeNULL)
				paramTypes[i+i+1] = 0x00
			case string:
				paramTypes[i+i] = byte(fieldTypeString)
				paramTypes[i+i+1] = 0x00
				if len(v) < longDataSize {
					paramValues = appendLengthEncodedInteger(paramValues,
						uint64(len(v)),
					)
					paramValues = append(paramValues, v...)
				} else {
					if err := stmt.writeCommandLongData(i, []byte(v)); err != nil {
						return err
					}
				}
			case time.Time:
				paramTypes[i+i] = byte(fieldTypeString)
				paramTypes[i+i+1] = 0x00
				var a [64]byte
				var b = a[:0]
				if v.IsZero() {
					b = append(b, "0000-00-00"...)
				} else {
					b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
				}
				paramValues = appendLengthEncodedInteger(paramValues,
					uint64(len(b)),
				)
				paramValues = append(paramValues, b...)
			default:
				return fmt.Errorf("can not convert type: %T", arg)
			}
		}
		if valuesCap != cap(paramValues) {
			data = append(data[:pos], paramValues...)
			mc.buf.buf = data
		}
		pos += len(paramValues)
		data = data[:pos]
	}
	return mc.writePacket(data)
}
Execute Prepared Statement
http://dev.mysql.com/doc/internals/en/com-stmt-execute.html
package mysql
import (
	"bytes"
	"crypto/tls"
	"database/sql/driver"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math"
	"time"
)
func (mc *mysqlConn) readPacket() ([]byte, error) {
	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, ErrInvalidConn
		}
		pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16)
		if data[3] != mc.sequence {
			if data[3] > mc.sequence {
				return nil, ErrPktSyncMul
			}
			return nil, ErrPktSync
		}
		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, ErrInvalidConn
		}
		if pktLen < maxPacketSize {
			if prevData == nil {
				return data, nil
			}
			return append(prevData, data...), nil
		}
		prevData = append(prevData, data...)
	}
}
func (mc *mysqlConn) writePacket(data []byte) error {
	pktLen := len(data) - 4
	if pktLen > mc.maxAllowedPacket {
		return ErrPktTooLarge
	}
	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
		}
		data[3] = mc.sequence
		if mc.writeTimeout > 0 {
			if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil {
				return err
			}
		}
		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
		}
		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 ErrInvalidConn
	}
}
func (mc *mysqlConn) readInitPacket() ([]byte, error) {
	data, err := mc.readPacket()
	if err != nil {
		return nil, err
	}
	if data[0] == iERR {
		return nil, mc.handleErrorPacket(data)
	}
	if data[0] < minProtocolVersion {
		return nil, fmt.Errorf(
			"unsupported protocol version %d. Version %d or higher is required",
			data[0],
			minProtocolVersion,
		)
	}
	pos := 1 + bytes.IndexByte(data[1:], 0x00) + 1 + 4
	cipher := data[pos : pos+8]
	pos += 8 + 1
	mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
	if mc.flags&clientProtocol41 == 0 {
		return nil, ErrOldProtocol
	}
	if mc.flags&clientSSL == 0 && mc.cfg.tls != nil {
		return nil, ErrNoTLS
	}
	pos += 2
	if len(data) > pos {
		pos += 1 + 2 + 2 + 1 + 10
		cipher = append(cipher, data[pos:pos+12]...)
		var b [20]byte
		copy(b[:], cipher)
		return b[:], nil
	}
	var b [8]byte
	copy(b[:], cipher)
	return b[:], nil
}
func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
	clientFlags := clientProtocol41 |
		clientSecureConn |
		clientLongPassword |
		clientTransactions |
		clientLocalFiles |
		clientPluginAuth |
		clientMultiResults |
		mc.flags&clientLongFlag
	if mc.cfg.ClientFoundRows {
		clientFlags |= clientFoundRows
	}
	if mc.cfg.tls != nil {
		clientFlags |= clientSSL
	}
	if mc.cfg.MultiStatements {
		clientFlags |= clientMultiStatements
	}
	scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))
	pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + 1 + len(scrambleBuff) + 21 + 1
	if n := len(mc.cfg.DBName); n > 0 {
		clientFlags |= clientConnectWithDB
		pktLen += n + 1
	}
	data := mc.buf.takeSmallBuffer(pktLen + 4)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	data[4] = byte(clientFlags)
	data[5] = byte(clientFlags >> 8)
	data[6] = byte(clientFlags >> 16)
	data[7] = byte(clientFlags >> 24)
	data[8] = 0x00
	data[9] = 0x00
	data[10] = 0x00
	data[11] = 0x00
	var found bool
	data[12], found = collations[mc.cfg.Collation]
	if !found {
		return errors.New("unknown collation")
	}
	if mc.cfg.tls != nil {
		if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil {
			return err
		}
		tlsConn := tls.Client(mc.netConn, mc.cfg.tls)
		if err := tlsConn.Handshake(); err != nil {
			return err
		}
		mc.netConn = tlsConn
		mc.buf.nc = tlsConn
	}
	pos := 13
	for ; pos < 13+23; pos++ {
		data[pos] = 0
	}
	if len(mc.cfg.User) > 0 {
		pos += copy(data[pos:], mc.cfg.User)
	}
	data[pos] = 0x00
	pos++
	data[pos] = byte(len(scrambleBuff))
	pos += 1 + copy(data[pos+1:], scrambleBuff)
	if len(mc.cfg.DBName) > 0 {
		pos += copy(data[pos:], mc.cfg.DBName)
		data[pos] = 0x00
		pos++
	}
	pos += copy(data[pos:], "mysql_native_password")
	data[pos] = 0x00
	return mc.writePacket(data)
}
func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
	scrambleBuff := scrambleOldPassword(cipher[:8], []byte(mc.cfg.Passwd))
	pktLen := len(scrambleBuff) + 1
	data := mc.buf.takeSmallBuffer(4 + pktLen)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	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)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	copy(data[4:], mc.cfg.Passwd)
	data[4+pktLen-1] = 0x00
	return mc.writePacket(data)
}
func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
	scrambleBuff := scramblePassword(cipher[0:20], []byte(mc.cfg.Passwd))
	pktLen := len(scrambleBuff)
	data := mc.buf.takeSmallBuffer(4 + pktLen)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	copy(data[4:], scrambleBuff)
	return mc.writePacket(data)
}
func (mc *mysqlConn) writeCommandPacket(command byte) error {
	mc.sequence = 0
	data := mc.buf.takeSmallBuffer(4 + 1)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	data[4] = command
	return mc.writePacket(data)
}
func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
	mc.sequence = 0
	pktLen := 1 + len(arg)
	data := mc.buf.takeBuffer(pktLen + 4)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	data[4] = command
	copy(data[5:], arg)
	return mc.writePacket(data)
}
func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
	mc.sequence = 0
	data := mc.buf.takeSmallBuffer(4 + 1 + 4)
	if data == nil {
		errLog.Print(ErrBusyBuffer)
		return errBadConnNoWrite
	}
	data[4] = command
	data[5] = byte(arg)
	data[6] = byte(arg >> 8)
	data[7] = byte(arg >> 16)
	data[8] = byte(arg >> 24)
	return mc.writePacket(data)
}
func (mc *mysqlConn) readResultOK() ([]byte, error) {
	data, err := mc.readPacket()
	if err == nil {
		switch data[0] {
		case iOK:
			return nil, mc.handleOkPacket(data)
		case iEOF:
			if len(data) > 1 {
				pluginEndIndex := bytes.IndexByte(data, 0x00)
				plugin := string(data[1:pluginEndIndex])
				cipher := data[pluginEndIndex+1:]
				switch plugin {
				case "mysql_old_password":
					return cipher, ErrOldPassword
				case "mysql_clear_password":
					return cipher, ErrCleartextPassword
				case "mysql_native_password":
					return cipher, ErrNativePassword
				default:
					return cipher, ErrUnknownPlugin
				}
			}
			return nil, ErrOldPassword
		default:  
			return nil, mc.handleErrorPacket(data)
		}
	}
	return nil, err
}
func (mc *mysqlConn) readResultSetHeaderPacket() (int, error) {
	data, err := mc.readPacket()
	if err == nil {
		switch data[0] {
		case iOK:
			return 0, mc.handleOkPacket(data)
		case iERR:
			return 0, mc.handleErrorPacket(data)
		case iLocalInFile:
			return 0, mc.handleInFileRequest(string(data[1:]))
		}
		num, _, n := readLengthEncodedInteger(data)
		if n-len(data) == 0 {
			return int(num), nil
		}
		return 0, ErrMalformPkt
	}
	return 0, err
}
func (mc *mysqlConn) handleErrorPacket(data []byte) error {
	if data[0] != iERR {
		return ErrMalformPkt
	}
	errno := binary.LittleEndian.Uint16(data[1:3])
	if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
		mc.Close()
		return driver.ErrBadConn
	}
	pos := 3
	if data[3] == 0x23 {
		pos = 9
	}
	return &MySQLError{
		Number:  errno,
		Message: string(data[pos:]),
	}
}
func readStatus(b []byte) statusFlag {
	return statusFlag(b[0]) | statusFlag(b[1])<<8
}
func (mc *mysqlConn) handleOkPacket(data []byte) error {
	var n, m int
	mc.affectedRows, _, n = readLengthEncodedInteger(data[1:])
	mc.insertId, _, m = readLengthEncodedInteger(data[1+n:])
	mc.status = readStatus(data[1+n+m : 1+n+m+2])
	if mc.status&statusMoreResultsExists != 0 {
		return nil
	}
	return nil
}
func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
	columns := make([]mysqlField, count)
	for i := 0; ; i++ {
		data, err := mc.readPacket()
		if err != nil {
			return nil, err
		}
		if data[0] == iEOF && (len(data) == 5 || len(data) == 1) {
			if i == count {
				return columns, nil
			}
			return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns))
		}
		pos, err := skipLengthEncodedString(data)
		if err != nil {
			return nil, err
		}
		n, err := skipLengthEncodedString(data[pos:])
		if err != nil {
			return nil, err
		}
		pos += n
		if mc.cfg.ColumnsWithAlias {
			tableName, _, n, err := readLengthEncodedString(data[pos:])
			if err != nil {
				return nil, err
			}
			pos += n
			columns[i].tableName = string(tableName)
		} else {
			n, err = skipLengthEncodedString(data[pos:])
			if err != nil {
				return nil, err
			}
			pos += n
		}
		n, err = skipLengthEncodedString(data[pos:])
		if err != nil {
			return nil, err
		}
		pos += n
		name, _, n, err := readLengthEncodedString(data[pos:])
		if err != nil {
			return nil, err
		}
		columns[i].name = string(name)
		pos += n
		n, err = skipLengthEncodedString(data[pos:])
		if err != nil {
			return nil, err
		}
		pos += n
		pos++
		columns[i].charSet = data[pos]
		pos += 2
		columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])
		pos += 4
		columns[i].fieldType = fieldType(data[pos])
		pos++
		columns[i].flags = fieldFlag(binary.LittleEndian.Uint16(data[pos : pos+2]))
		pos += 2
		columns[i].decimals = data[pos]
	}
}
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
	}
	if data[0] == iEOF && len(data) == 5 {
		rows.mc.status = readStatus(data[3:])
		rows.rs.done = true
		if !rows.HasNextResultSet() {
			rows.mc = nil
		}
		return io.EOF
	}
	if data[0] == iERR {
		rows.mc = nil
		return mc.handleErrorPacket(data)
	}
	var n int
	var isNull bool
	pos := 0
	for i := range dest {
		dest[i], isNull, n, err = readLengthEncodedString(data[pos:])
		pos += n
		if err == nil {
			if !isNull {
				if !mc.parseTime {
					continue
				} else {
					switch rows.rs.columns[i].fieldType {
					case fieldTypeTimestamp, fieldTypeDateTime,
						fieldTypeDate, fieldTypeNewDate:
						dest[i], err = parseDateTime(
							string(dest[i].([]byte)),
							mc.cfg.Loc,
						)
						if err == nil {
							continue
						}
					default:
						continue
					}
				}
			} else {
				dest[i] = nil
				continue
			}
		}
		return err  
	}
	return nil
}
func (mc *mysqlConn) readUntilEOF() error {
	for {
		data, err := mc.readPacket()
		if err != nil {
			return err
		}
		switch data[0] {
		case iERR:
			return mc.handleErrorPacket(data)
		case iEOF:
			if len(data) == 5 {
				mc.status = readStatus(data[3:])
			}
			return nil
		}
	}
}
func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
	data, err := stmt.mc.readPacket()
	if err == nil {
		if data[0] != iOK {
			return 0, stmt.mc.handleErrorPacket(data)
		}
		stmt.id = binary.LittleEndian.Uint32(data[1:5])
		columnCount := binary.LittleEndian.Uint16(data[5:7])
		stmt.paramCount = int(binary.LittleEndian.Uint16(data[7:9]))
		return columnCount, nil
	}
	return 0, err
}
func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error {
	maxLen := stmt.mc.maxAllowedPacket - 1
	pktLen := maxLen
	const dataOffset = 1 + 4 + 2
	data := make([]byte, 4+1+4+2+len(arg))
	copy(data[4+dataOffset:], arg)
	for argLen := len(arg); argLen > 0; argLen -= pktLen - dataOffset {
		if dataOffset+argLen < maxLen {
			pktLen = dataOffset + argLen
		}
		stmt.mc.sequence = 0
		data[4] = comStmtSendLongData
		data[5] = byte(stmt.id)
		data[6] = byte(stmt.id >> 8)
		data[7] = byte(stmt.id >> 16)
		data[8] = byte(stmt.id >> 24)
		data[9] = byte(paramID)
		data[10] = byte(paramID >> 8)
		err := stmt.mc.writePacket(data[:4+pktLen])
		if err == nil {
			data = data[pktLen-dataOffset:]
			continue
		}
		return err
	}
	stmt.mc.sequence = 0
	return nil
}