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);
 }
示例#7
0
        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();
            }
        }