public static PacketHeader Write(MySqlStreamWriter writer, uint stmtId) { writer.ReserveHeader(); writer.WriteByte((byte)Command.STMT_RESET); writer.WriteUnsigned4(stmtId); var _header = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(_header); return _header; }
public static void Write(MySqlStreamWriter writer, uint stmtId, MyStructData[] _prepareValues) { //for those who don't want to alloc an new packet //just write it into a stream writer.ReserveHeader(); writer.WriteByte((byte)Command.STMT_EXECUTE); writer.WriteUnsignedNumber(4, stmtId); writer.WriteByte((byte)CursorFlags.CURSOR_TYPE_NO_CURSOR); writer.WriteUnsignedNumber(4, 1);//iteration-count, always 1 //write NULL-bitmap, length: (num-params+7)/8 MyStructData[] fillValues = _prepareValues; int paramNum = _prepareValues.Length; if (paramNum > 0) { uint bitmap = 0; uint bitValue = 1; for (int i = 0; i < paramNum; i++) { MySqlDataType dataType = _prepareValues[i].type; if (dataType == MySqlDataType.NULL) { bitmap += bitValue; } bitValue <<= 1; //shift to left 1 bit if (bitValue == 256) { //end of 8 bits //just store data writer.WriteUnsigned1(bitmap); bitmap = 0; bitValue = 1; } } if (bitValue != 1) { writer.WriteUnsigned1(bitmap); } } //new-params-bound - flag writer.WriteByte(1); //------------------------------------------------------- //data types for (int i = 0; i < paramNum; i++) { writer.WriteUnsignedNumber(2, (byte)_prepareValues[i].type); } //-------------------------------------- //actual data //-------------------------------------- //stream of data may large than 1 packet var tempSingleValueHolder = new TempSingleValueHolder(); tempSingleValueHolder.headerLenBuffer = new byte[9]; tempSingleValueHolder.generalContent = new byte[16]; for (int i = 0; i < paramNum; i++) { bool isComplete = WriteValueByType(writer, ref _prepareValues[i], ref tempSingleValueHolder); var header = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(header); //-------------------------------------------------------------------------------------------------- while (!isComplete) { //write until complete tempSingleValueHolder.round++; writer.ReserveHeader(); isComplete = WriteValueByType(writer, ref _prepareValues[i], ref tempSingleValueHolder); header = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(header); } //reset tempSingleValueHolder.Reset(); } //-------------------------------------- }
public static PacketHeader Write(MySqlStreamWriter writer, uint stmtId) { //for those who don't want to alloc an new packet //just write it into a stream writer.ReserveHeader(); writer.WriteByte((byte)Command.STMT_CLOSE); writer.WriteUnsigned4(stmtId); var h = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(h); return h; }
public static PacketHeader Write(MySqlStreamWriter writer, string sql) { //for those who don't want to alloc an new packet //just write it into a stream writer.ReserveHeader(); writer.WriteByte((byte)Command.STMT_PREPARE); writer.WriteString(sql); var h = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(h); return h; }
/// <summary> /// /// </summary> /// <param name="writer"></param> /// <param name="sql"></param> /// <returns></returns> public static void Write(MySqlStreamWriter writer, string sql) { //for those who don't want to alloc an new packet //just write it into a stream byte[] buffer = writer.GetEncodeBytes(sql.ToCharArray()); int totalLen = buffer.Length; int packetCount = (totalLen / Packet.MAX_PACKET_LENGTH) + 1; if (packetCount <= 1) { writer.ReserveHeader(); writer.WriteByte((byte)Command.QUERY); //check if we can write data in 1 packet or not writer.WriteBinaryString(buffer); var header = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(header); } else { //we need to split to multiple packet int currentPacketContentSize = Packet.MAX_PACKET_LENGTH; int pos = 0; for (int i = 0; i < packetCount; ++i) { //write each packet to stream writer.ReserveHeader(); if (i == 0) { //first packet writer.WriteByte((byte)Command.QUERY); writer.WriteBinaryString(buffer, pos, currentPacketContentSize - 1);//remove 1 query cmd pos += (currentPacketContentSize - 1); } else if (i == packetCount - 1) { //last packet currentPacketContentSize = totalLen - pos; writer.WriteBinaryString(buffer, pos, currentPacketContentSize); } else { writer.WriteBinaryString(buffer, pos, currentPacketContentSize); pos += (currentPacketContentSize); } //check if we can write data in 1 packet or not var header = new PacketHeader((uint)currentPacketContentSize, writer.IncrementPacketNumber()); writer.WriteHeader(header); } } }
public override void WritePacket(MySqlStreamWriter writer) { writer.ReserveHeader();//allocate header if (protocol41) { writer.WriteUnsigned4(clientFlags); writer.WriteUnsigned4(maxPacketSize); writer.WriteUnsigned1(charsetNumber); writer.WriteFiller(23); writer.WriteNullTerminatedString(user); writer.WriteLengthCodedBuffer(scrambleBuff); writer.WriteNullTerminatedString(database); } else { writer.WriteUnsigned2(clientFlags); writer.WriteUnsigned3(maxPacketSize); writer.WriteNullTerminatedString(user); writer.WriteBuffer(scrambleBuff); if (database != null && database.Length > 0) { writer.WriteFiller(1); writer.WriteBuffer(Encoding.ASCII.GetBytes(database)); } } _header = new PacketHeader(writer.OnlyPacketContentLength, writer.IncrementPacketNumber()); writer.WriteHeader(_header); }
void ExecuteNonPrepare_A(Action nextAction) { //abstract mysql packet //---------------------------------------- // (4 bytes header)| ( user content) //---------------------------------------- // 4 bytes header => 3 bytes for user content len (so max => (1 << 24) - 1 or 0xFF, 0xFF, 0xFF // => 1 byte for packet number, so this value is 0-255 _sqlParserMx.UseResultParser(); _writer.Reset();//*** packet number is reset to 0 //--------------- //https://dev.mysql.com/doc/internals/en/mysql-packet.html //If a MySQL client or server wants to send data, it: //Splits the data into packets of size (2^24)−1 bytes //Prepends to each chunk a packet header byte[] buffer = _writer.GetEncodeBytes(_sqlStrTemplate.BindValues(_cmdParams, false).ToCharArray()); //--------------- int totalLen = buffer.Length; //packet count int packetCount = ((totalLen + Connection.MAX_PACKET_CONTENT_LENGTH) / Connection.MAX_PACKET_CONTENT_LENGTH); #if DEBUG if (packetCount >= 255) { throw new NotSupportedException(); } #endif if (packetCount <= 1) { //-------------------------------------------- //check SendIO buffer is large enough or not //if not, handle this by asking for more buffer //or throw error back to user //-------------------------------------------- if (!_conn.EnsureSendIOBufferSize(totalLen)) { //how to handle exception //TODO: review here, //we should not throw exception on working thread throw new NotSupportedException(); } //-------------------------------------------- _writer.ReserveHeader(); _writer.WriteByte((byte)Command.QUERY); //check if we can write data in 1 packet or not _writer.WriteBinaryString(buffer); //var header = new PacketHeader(_writer.OnlyPacketContentLength, _writer.IncrementPacketNumber()); _writer.WriteHeader(_writer.OnlyPacketContentLength, _writer.IncrementPacketNumber()); // SendAndRecv_A(_writer.ToArray(), nextAction); } else { //we need to split to multiple packet //and we need max sendIO buffer //-------------------------------------------- //check SendIO buffer is large enough or not //if not, handle this by asking for more buffer //or throw error back to user //-------------------------------------------- if (!_conn.EnsureSendIOBufferSize(Connection.MAX_PACKET_CONTENT_LENGTH)) { //how to handle exception //TODO: review here, //we should not throw exception on working thread throw new NotSupportedException(); } //-------------------------------------------- int currentPacketContentSize = Connection.MAX_PACKET_CONTENT_LENGTH; int pos = 0; for (int packet_num = 0; packet_num < packetCount; ++packet_num) { //write each packet to stream _writer.ReserveHeader(); if (packet_num == 0) { //first packet _writer.WriteByte((byte)Command.QUERY); _writer.WriteBinaryString(buffer, pos, currentPacketContentSize - 1);//remove 1 query cmd pos += (currentPacketContentSize - 1); } else if (packet_num == packetCount - 1) { //last packet currentPacketContentSize = totalLen - pos; _writer.WriteBinaryString(buffer, pos, currentPacketContentSize); } else { //in between _writer.WriteBinaryString(buffer, pos, currentPacketContentSize); pos += (currentPacketContentSize); } //-------------- //check if we can write data in 1 packet or not //var header = new PacketHeader((uint)currentPacketContentSize, (byte)packet_num);//*** _writer.WriteHeader((uint)currentPacketContentSize, (byte)packet_num); //*** _conn.EnqueueOutputData(_writer.ToArray()); //enqueue output data _writer.Reset(); } _conn.StartSend(() => { //when send complete then start recv result RecvPacket_A(nextAction); }); } }
/// <summary> /// open connection, +/- blocking /// </summary> /// <param name="nextAction"></param> public void Connect(Action nextAction = null) { if (State == ConnectionState.Connected) { throw new NotSupportedException("already connected"); } _mysqlParserMx.UseConnectionParser(); this._workingState = WorkingState.Rest; //-------------- var endpoint = new IPEndPoint(IPAddress.Parse(config.host), config.port); socket.Connect(endpoint); this._workingState = WorkingState.Rest; //-------------- //**start listen after connect InitWait(); StartReceive(mysql_result => { //when complete1 //create handshake packet and send back var handshakeResult = mysql_result as MySqlHandshakeResult; if (handshakeResult == null) { //error throw new Exception("err1"); } HandshakePacket handshake_packet = handshakeResult.packet; this.threadId = handshake_packet.threadId; // https://dev.mysql.com/doc/internals/en/sha256.html byte[] token = string.IsNullOrEmpty(config.password) ? /*1*/ new byte[0] : //Empty passwords are not hashed, but sent as empty string. /* or 2*/ MakeToken(config.password, GetScrollbleBuffer( handshake_packet.scrambleBuff1, handshake_packet.scrambleBuff2)); _writer.IncrementPacketNumber(); //---------------------------- //send authen packet to the server var authPacket = new ClientAuthenticationPacket(new PacketHeader()); authPacket.SetValues(config.user, token, config.database, isProtocol41 = handshake_packet.protocol41); authPacket.WritePacket(_writer); byte[] sendBuff = _writer.ToArray(); _writer.Reset(); //------------------------------------ //switch to result packet parser _mysqlParserMx.SetProtocol41(isProtocol41); _mysqlParserMx.UseResultParser(); //------------------------------------ StartSend(sendBuff, 0, sendBuff.Length, () => { StartReceive(mysql_result2 => { var ok = mysql_result2 as MySqlOkResult; if (ok != null) { this._workingState = WorkingState.Rest; } else { //TODO: review here //error _workingState = WorkingState.Error; } //set max allow of the server *** //todo set max allow packet*** UnWait(); if (nextAction != null) { nextAction(); } }); }); }); if (nextAction == null) { //block .... Wait(); } else { UnWait(); } }