package  mysql 
 
import  ( 
	"bytes"  
	"crypto/tls"  
	"database/sql/driver"  
	"encoding/binary"  
	"encoding/json"  
	"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  
	} 
 
	 
 
 
 
 
 
	if  mc .reset  { 
		mc .reset  = false  
		conn  := mc .netConn  
		if  mc .rawConn  != nil  { 
			conn  = mc .rawConn  
		} 
		var  err  error  
		if  mc .cfg .CheckConnLiveness  { 
			if  mc .cfg .ReadTimeout  != 0  { 
				err  = conn .SetReadDeadline (time .Now ().Add (mc .cfg .ReadTimeout )) 
			} 
			if  err  == nil  { 
				err  = connCheck (conn ) 
			} 
		} 
		if  err  != nil  { 
			errLog .Print ("closing bad idle connection: " , err ) 
			mc .Close () 
			return  driver .ErrBadConn  
		} 
	} 
 
	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 ) readHandshakePacket () (data  []byte , plugin  string , err  error ) { 
	data , err  = mc .readPacket () 
	if  err  != nil  { 
		 
 
		if  err  == ErrInvalidConn  { 
			return  nil , "" , driver .ErrBadConn  
		} 
		return  
	} 
 
	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  
 
	 
	authData  := 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  { 
		if  mc .cfg .AllowFallbackToPlaintext  { 
			mc .cfg .TLS  = nil  
		} else  { 
			return  nil , "" , ErrNoTLS  
		} 
	} 
	pos  += 2  
 
	if  len (data ) > pos  { 
		 
 
 
 
 
		pos  += 1  + 2  + 2  + 1  + 10  
 
		 
 
 
 
 
 
 
 
 
 
 
 
		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 [:], authData ) 
		return  b [:], plugin , nil  
	} 
 
	 
	var  b  [8 ]byte  
	copy (b [:], authData ) 
	return  b [:], plugin , nil  
} 
 
 
 
func  (mc  *mysqlConn ) writeHandshakeResponsePacket (authResp  []byte , plugin  string ) 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  
	} 
 
	 
	var  authRespLEIBuf  [9 ]byte  
	authRespLen  := len (authResp ) 
	authRespLEI  := appendLengthEncodedInteger (authRespLEIBuf [:0 ], uint64 (authRespLen )) 
	if  len (authRespLEI ) > 1  { 
		 
 
		clientFlags  |= clientPluginAuthLenEncClientData  
	} 
 
	pktLen  := 4  + 4  + 1  + 23  + len (mc .cfg .User ) + 1  + len (authRespLEI ) + len (authResp ) + 21  + 1  
 
	 
	if  n  := len (mc .cfg .DBName ); n  > 0  { 
		clientFlags  |= clientConnectWithDB  
		pktLen  += n  + 1  
	} 
 
	 
	data , err  := mc .buf .takeSmallBuffer (pktLen  + 4 ) 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		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" ) 
	} 
 
	 
	pos  := 13  
	for  ; pos  < 13 +23 ; pos ++ { 
		data [pos ] = 0  
	} 
 
	 
 
	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 .rawConn  = mc .netConn  
		mc .netConn  = tlsConn  
		mc .buf .nc  = tlsConn  
	} 
 
	 
	if  len (mc .cfg .User ) > 0  { 
		pos  += copy (data [pos :], mc .cfg .User ) 
	} 
	data [pos ] = 0x00  
	pos ++ 
 
	 
	pos  += copy (data [pos :], authRespLEI ) 
	pos  += copy (data [pos :], authResp ) 
 
	 
	if  len (mc .cfg .DBName ) > 0  { 
		pos  += copy (data [pos :], mc .cfg .DBName ) 
		data [pos ] = 0x00  
		pos ++ 
	} 
 
	pos  += copy (data [pos :], plugin ) 
	data [pos ] = 0x00  
	pos ++ 
 
	 
	return  mc .writePacket (data [:pos ]) 
} 
 
 
func  (mc  *mysqlConn ) writeAuthSwitchPacket (authData  []byte ) error  { 
	pktLen  := 4  + len (authData ) 
	data , err  := mc .buf .takeSmallBuffer (pktLen ) 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		return  errBadConnNoWrite  
	} 
 
	 
	copy (data [4 :], authData ) 
	return  mc .writePacket (data ) 
} 
 
 
 
 
 
func  (mc  *mysqlConn ) writeCommandPacket (command  byte ) error  { 
	 
	mc .sequence  = 0  
 
	data , err  := mc .buf .takeSmallBuffer (4  + 1 ) 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		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 , err  := mc .buf .takeBuffer (pktLen  + 4 ) 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		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 , err  := mc .buf .takeSmallBuffer (4  + 1  + 4 ) 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		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 ) readAuthResult () ([]byte , string , error ) { 
	data , err  := mc .readPacket () 
	if  err  != nil  { 
		return  nil , "" , err  
	} 
 
	 
	switch  data [0 ] { 
 
	case  iOK : 
		return  nil , "" , mc .handleOkPacket (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 ) 
	} 
} 
 
 
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 ) 
} 
 
 
 
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  
	} 
 
	me  := &MySQLError {Number : errno } 
 
	pos  := 3  
 
	 
	if  data [3 ] == 0x23  { 
		copy (me .SQLState [:], data [4 :4 +5 ]) 
		pos  = 9  
	} 
 
	 
	me .Message  = string (data [pos :]) 
 
	return  me  
} 
 
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  
		isNull  bool  
		pos     int  = 0  
	) 
 
	for  i  := range  dest  { 
		 
		dest [i ], isNull , n , err  = readLengthEncodedString (data [pos :]) 
		pos  += n  
 
		if  err  != nil  { 
			return  err  
		} 
 
		if  isNull  { 
			dest [i ] = nil  
			continue  
		} 
 
		if  !mc .parseTime  { 
			continue  
		} 
 
		 
		switch  rows .rs .columns [i ].fieldType  { 
		case  fieldTypeTimestamp , 
			fieldTypeDateTime , 
			fieldTypeDate , 
			fieldTypeNewDate : 
			if  dest [i ], err  = parseDateTime (dest [i ].([]byte ), mc .cfg .Loc ); err  != nil  { 
				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  
} 
 
 
 
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  
	var  err  error  
 
	if  len (args ) == 0  { 
		data , err  = mc .buf .takeBuffer (minPktLen ) 
	} else  { 
		data , err  = mc .buf .takeCompleteBuffer () 
		 
	} 
	if  err  != nil  { 
		 
		errLog .Print (err ) 
		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  >= cap (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  := range  nullMask  { 
				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  
			} 
 
			if  v , ok  := arg .(json .RawMessage ); ok  { 
				arg  = []byte (v ) 
			} 
			 
			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  uint64 : 
				paramTypes [i +i ] = byte (fieldTypeLongLong ) 
				paramTypes [i +i +1 ] = 0x80   
 
				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 , err  = appendDateTime (b , v .In (mc .cfg .Loc )) 
					if  err  != nil  { 
						return  err  
					} 
				} 
 
				paramValues  = appendLengthEncodedInteger (paramValues , 
					uint64 (len (b )), 
				) 
				paramValues  = append (paramValues , b ...) 
 
			default : 
				return  fmt .Errorf ("cannot convert type: %T" , arg ) 
			} 
		} 
 
		 
 
		if  valuesCap  != cap (paramValues ) { 
			data  = append (data [:pos ], paramValues ...) 
			if  err  = mc .buf .store (data ); err  != nil  { 
				errLog .Print (err ) 
				return  errBadConnNoWrite  
			} 
		} 
 
		pos  += len (paramValues ) 
		data  = data [:pos ] 
	} 
 
	return  mc .writePacket (data ) 
} 
 
func  (mc  *mysqlConn ) discardResults () error  { 
	for  mc .status &statusMoreResultsExists  != 0  { 
		resLen , err  := mc .readResultSetHeaderPacket () 
		if  err  != nil  { 
			return  err  
		} 
		if  resLen  > 0  { 
			 
			if  err  := mc .readUntilEOF (); err  != nil  { 
				return  err  
			} 
			 
			if  err  := mc .readUntilEOF (); err  != nil  { 
				return  err  
			} 
		} 
	} 
	return  nil  
} 
 
 
func  (rows  *binaryRows ) readRow (dest  []driver .Value ) error  { 
	data , err  := rows .mc .readPacket () 
	if  err  != nil  { 
		return  err  
	} 
 
	 
	if  data [0 ] != iOK  { 
		 
		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  
		} 
		mc  := rows .mc  
		rows .mc  = nil  
 
		 
		return  mc .handleErrorPacket (data ) 
	} 
 
	 
	pos  := 1  + (len (dest )+7 +2 )>>3  
	nullMask  := data [1 :pos ] 
 
	for  i  := range  dest  { 
		 
 
		if  ((nullMask [(i +2 )>>3 ] >> uint ((i +2 )&7 )) & 1 ) == 1  { 
			dest [i ] = nil  
			continue  
		} 
 
		 
		switch  rows .rs .columns [i ].fieldType  { 
		case  fieldTypeNULL : 
			dest [i ] = nil  
			continue  
 
		 
		case  fieldTypeTiny : 
			if  rows .rs .columns [i ].flags &flagUnsigned  != 0  { 
				dest [i ] = int64 (data [pos ]) 
			} else  { 
				dest [i ] = int64 (int8 (data [pos ])) 
			} 
			pos ++ 
			continue  
 
		case  fieldTypeShort , fieldTypeYear : 
			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 ]))) 
			} 
			pos  += 2  
			continue  
 
		case  fieldTypeInt24 , fieldTypeLong : 
			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 ]))) 
			} 
			pos  += 4  
			continue  
 
		case  fieldTypeLongLong : 
			if  rows .rs .columns [i ].flags &flagUnsigned  != 0  { 
				val  := binary .LittleEndian .Uint64 (data [pos  : pos +8 ]) 
				if  val  > math .MaxInt64  { 
					dest [i ] = uint64ToString (val ) 
				} else  { 
					dest [i ] = int64 (val ) 
				} 
			} else  { 
				dest [i ] = int64 (binary .LittleEndian .Uint64 (data [pos  : pos +8 ])) 
			} 
			pos  += 8  
			continue  
 
		case  fieldTypeFloat : 
			dest [i ] = math .Float32frombits (binary .LittleEndian .Uint32 (data [pos  : pos +4 ])) 
			pos  += 4  
			continue  
 
		case  fieldTypeDouble : 
			dest [i ] = math .Float64frombits (binary .LittleEndian .Uint64 (data [pos  : pos +8 ])) 
			pos  += 8  
			continue  
 
		 
		case  fieldTypeDecimal , fieldTypeNewDecimal , fieldTypeVarChar , 
			fieldTypeBit , fieldTypeEnum , fieldTypeSet , fieldTypeTinyBLOB , 
			fieldTypeMediumBLOB , fieldTypeLongBLOB , fieldTypeBLOB , 
			fieldTypeVarString , fieldTypeString , fieldTypeGeometry , fieldTypeJSON : 
			var  isNull  bool  
			var  n  int  
			dest [i ], isNull , n , err  = readLengthEncodedString (data [pos :]) 
			pos  += n  
			if  err  == nil  { 
				if  !isNull  { 
					continue  
				} else  { 
					dest [i ] = nil  
					continue  
				} 
			} 
			return  err  
 
		case  
			fieldTypeDate , fieldTypeNewDate ,  
			fieldTypeTime ,                          
			fieldTypeTimestamp , fieldTypeDateTime :  
 
			num , isNull , n  := readLengthEncodedInteger (data [pos :]) 
			pos  += n  
 
			switch  { 
			case  isNull : 
				dest [i ] = nil  
				continue  
			case  rows .rs .columns [i ].fieldType  == fieldTypeTime : 
				 
				var  dstlen  uint8  
				switch  decimals  := rows .rs .columns [i ].decimals ; decimals  { 
				case  0x00 , 0x1f : 
					dstlen  = 8  
				case  1 , 2 , 3 , 4 , 5 , 6 : 
					dstlen  = 8  + 1  + decimals  
				default : 
					return  fmt .Errorf ( 
						"protocol error, illegal decimals value %d" , 
						rows .rs .columns [i ].decimals , 
					) 
				} 
				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 .rs .columns [i ].fieldType  == fieldTypeDate  { 
					dstlen  = 10  
				} else  { 
					switch  decimals  := rows .rs .columns [i ].decimals ; decimals  { 
					case  0x00 , 0x1f : 
						dstlen  = 19  
					case  1 , 2 , 3 , 4 , 5 , 6 : 
						dstlen  = 19  + 1  + decimals  
					default : 
						return  fmt .Errorf ( 
							"protocol error, illegal decimals value %d" , 
							rows .rs .columns [i ].decimals , 
						) 
					} 
				} 
				dest [i ], err  = formatBinaryDateTime (data [pos :pos +int (num )], dstlen ) 
			} 
 
			if  err  == nil  { 
				pos  += int (num ) 
				continue  
			} else  { 
				return  err  
			} 
 
		 
		default : 
			return  fmt .Errorf ("unknown field type %d" , rows .rs .columns [i ].fieldType ) 
		} 
	} 
 
	return  nil  
} 
  
The pages are generated with Golds   v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1  (reachable from the left QR code) to get the latest news of Golds .