Пример #1
0
        public void Test()
        {
            var sb = new StringBuilder("a");

            for (int i = 0; i < 50; i++)
            {
                sb.Append("😀");
            }


            var writer1 = new ByteBufferWriter();

            writer1.WriteLengthEncodedStringOld(sb);

            var realPayload = writer1.ToPayloadData().Memory.ToArray();


            var writer2 = new ByteBufferWriter();

            writer2.WriteLengthEncodedStringNew(sb);

            var payload = writer2.ToPayloadData();
            var data    = payload.Memory.ToArray();

            Assert.AreEqual(realPayload, data);
        }
        public void NewBehaviorShort()
        {
            var writer2 = new ByteBufferWriter();

            writer2.WriteLengthEncodedStringNew(_sbShort);

            var payload = writer2.ToPayloadData().Memory.ToArray();
        }
        public void SimpleBehaviorExLongSurrogates()
        {
            var writer2 = new ByteBufferWriter();

            writer2.WriteLengthEncodedStringSimple(_sbExLongSurrogates);

            var payload = writer2.ToPayloadData().Memory.ToArray();
        }
        public void OldBehaviorExLongSurrogates()
        {
            var writer1 = new ByteBufferWriter();

            writer1.WriteLengthEncodedStringOld(_sbExLongSurrogates);

            var payload = writer1.ToPayloadData().Memory.ToArray();
        }
        public void NewBehaviorMediumSurrogates()
        {
            var writer2 = new ByteBufferWriter();

            writer2.WriteLengthEncodedStringNew(_sbMediumSurrogates);

            var payload = writer2.ToPayloadData().Memory.ToArray();
        }
        public void SimpleBehaviorMedium()
        {
            var writer2 = new ByteBufferWriter();

            writer2.WriteLengthEncodedStringSimple(_sbMedium);

            var payload = writer2.ToPayloadData().Memory.ToArray();
        }
        public void OldBehaviorMedium()
        {
            var writer1 = new ByteBufferWriter();

            writer1.WriteLengthEncodedStringOld(_sbMedium);

            var payload = writer1.ToPayloadData().Memory.ToArray();
        }
        private PayloadData CreateQueryPayload(PreparedStatement preparedStatement, MySqlParameterCollection parameterCollection, MySqlGuidFormat guidFormat)
        {
            var writer = new ByteBufferWriter();

            writer.Write((byte)CommandKind.StatementExecute);
            writer.Write(preparedStatement.StatementId);
            writer.Write((byte)0);
            writer.Write(1);
            if (preparedStatement.Parameters?.Length > 0)
            {
                // TODO: How to handle incorrect number of parameters?

                // build subset of parameters for this statement
                var parameters = new MySqlParameter[preparedStatement.Statement.ParameterNames.Count];
                for (var i = 0; i < preparedStatement.Statement.ParameterNames.Count; i++)
                {
                    var parameterName  = preparedStatement.Statement.ParameterNames[i];
                    var parameterIndex = parameterName != null?parameterCollection.NormalizedIndexOf(parameterName) : preparedStatement.Statement.ParameterIndexes[i];

                    parameters[i] = parameterCollection[parameterIndex];
                }

                // write null bitmap
                byte nullBitmap = 0;
                for (var i = 0; i < parameters.Length; i++)
                {
                    var parameter = parameters[i];
                    if (parameter.Value == null || parameter.Value == DBNull.Value)
                    {
                        if (i > 0 && i % 8 == 0)
                        {
                            writer.Write(nullBitmap);
                            nullBitmap = 0;
                        }

                        nullBitmap |= (byte)(1 << (i % 8));
                    }
                }
                writer.Write(nullBitmap);

                // write "new parameters bound" flag
                writer.Write((byte)1);

                foreach (var parameter in parameters)
                {
                    writer.Write(TypeMapper.ConvertToColumnTypeAndFlags(parameter.MySqlDbType, guidFormat));
                }

                var options = m_command.CreateStatementPreparerOptions();
                foreach (var parameter in parameters)
                {
                    parameter.AppendBinary(writer, options);
                }
            }

            return(writer.ToPayloadData());
        }
Пример #9
0
        public static PayloadData Create(string databaseName)
        {
            var writer = new ByteBufferWriter();

            writer.Write((byte)CommandKind.InitDatabase);
            writer.Write(databaseName);

            return(writer.ToPayloadData());
        }
Пример #10
0
        public ParsedStatements SplitStatements()
        {
            var statements = new List <ParsedStatement>();
            var statementStartEndIndexes = new List <int>();
            var writer = new ByteBufferWriter(m_commandText.Length + 1);
            var parser = new PreparedCommandSqlParser(this, statements, statementStartEndIndexes, writer);

            parser.Parse(m_commandText);
            for (var i = 0; i < statements.Count; i++)
            {
                statements[i].StatementBytes = writer.ArraySegment.Slice(statementStartEndIndexes[i * 2], statementStartEndIndexes[i * 2 + 1] - statementStartEndIndexes[i * 2]);
            }
            return(new ParsedStatements(statements, writer.ToPayloadData()));
        }
Пример #11
0
        public static PayloadData Create(string filename)
        {
            var writer   = new ByteBufferWriter();
            var position = 4;
            var flags    = (ushort)BinlogFlags.NonBlock;
            var serverId = 10;

            writer.Write((byte)CommandKind.BinlogDump);
            writer.Write(position);
            writer.Write(flags);
            writer.Write(serverId);
            writer.Write(filename);

            return(writer.ToPayloadData());
        }
Пример #12
0
        public static PayloadData Create(string user, byte[] authResponse, string schemaName, byte[] connectionAttributes)
        {
            var writer = new ByteBufferWriter();

            writer.Write((byte)CommandKind.ChangeUser);
            writer.WriteNullTerminatedString(user);
            writer.Write(checked ((byte)authResponse.Length));
            writer.Write(authResponse);
            writer.WriteNullTerminatedString(schemaName ?? "");
            writer.Write((byte)CharacterSet.Utf8Mb4Binary);
            writer.Write((byte)0);
            writer.WriteNullTerminatedString("mysql_native_password");
            if (connectionAttributes != null)
            {
                writer.Write(connectionAttributes);
            }

            return(writer.ToPayloadData());
        }
Пример #13
0
        public static PayloadData Create(string user, ReadOnlySpan <byte> authResponse, string?schemaName, CharacterSet characterSet, byte[]?connectionAttributes)
        {
            var writer = new ByteBufferWriter();

            writer.Write((byte)CommandKind.ChangeUser);
            writer.WriteNullTerminatedString(user);
            writer.Write(checked ((byte)authResponse.Length));
            writer.Write(authResponse);
            writer.WriteNullTerminatedString(schemaName ?? "");
            writer.Write((byte)characterSet);
            writer.Write((byte)0);
            writer.WriteNullTerminatedString("mysql_native_password");
            if (connectionAttributes is not null)
            {
                writer.Write(connectionAttributes);
            }

            return(writer.ToPayloadData());
        }
Пример #14
0
        public static async Task <DbDataReader> ExecuteReaderAsync(IReadOnlyList <IMySqlCommand> commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var commandListPosition = new CommandListPosition(commands);
            var command             = commands[0];

            // pre-requisite: Connection is non-null must be checked before calling this method
            var connection = command.Connection !;

            if (Log.IsDebugEnabled())
            {
                Log.Debug("Session{0} ExecuteReader {1} CommandCount: {2}", connection.Session.Id, ioBehavior, commands.Count);
            }

            Dictionary <string, CachedProcedure?>?cachedProcedures = null;

            foreach (var command2 in commands)
            {
                if (command2.CommandType == CommandType.StoredProcedure)
                {
                    cachedProcedures ??= new Dictionary <string, CachedProcedure?>();
                    var commandText = command2.CommandText !;
                    if (!cachedProcedures.ContainsKey(commandText))
                    {
                        cachedProcedures.Add(commandText, await connection.GetCachedProcedure(ioBehavior, commandText, cancellationToken).ConfigureAwait(false));

                        // because the connection was used to execute a MySqlDataReader with the connection's DefaultCommandTimeout,
                        // we need to reapply the command's CommandTimeout (even if some of the time has elapsed)
                        command.CancellableCommand.ResetCommandTimeout();
                    }
                }
            }

            var writer = new ByteBufferWriter();

            // cachedProcedures will be non-null if there is a stored procedure, which is also the only time it will be read
            if (!payloadCreator.WriteQueryCommand(ref commandListPosition, cachedProcedures !, writer))
            {
                throw new InvalidOperationException("ICommandPayloadCreator failed to write query payload");
            }

            cancellationToken.ThrowIfCancellationRequested();

            using var payload      = writer.ToPayloadData();
            using var registration = command.CancellableCommand.RegisterCancel(cancellationToken);
            connection.Session.StartQuerying(command.CancellableCommand);
            command.SetLastInsertedId(-1);
            try
            {
                await connection.Session.SendAsync(payload, ioBehavior, CancellationToken.None).ConfigureAwait(false);

                return(await MySqlDataReader.CreateAsync(commandListPosition, payloadCreator, cachedProcedures, command, behavior, ioBehavior, cancellationToken).ConfigureAwait(false));
            }
            catch (MySqlException ex) when(ex.Number == (int)MySqlErrorCode.QueryInterrupted && cancellationToken.IsCancellationRequested)
            {
                Log.Warn("Session{0} query was interrupted", connection.Session.Id);
                throw new OperationCanceledException(cancellationToken);
            }
            catch (Exception ex) when(payload.Span.Length > 4_194_304 && (ex is SocketException || ex is IOException || ex is MySqlProtocolException))
            {
                // the default MySQL Server value for max_allowed_packet (in MySQL 5.7) is 4MiB: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet
                // use "decimal megabytes" (to round up) when creating the exception message
                int megabytes = payload.Span.Length / 1_000_000;

                throw new MySqlException("Error submitting {0}MB packet; ensure 'max_allowed_packet' is greater than {0}MB.".FormatInvariant(megabytes), ex);
            }
        }
Пример #15
0
        internal async Task <bool> NextResultAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            VerifyNotDisposed();
            try
            {
                do
                {
                    while (true)
                    {
                        await m_resultSet !.ReadEntireAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
                        await ScanResultSetAsync(ioBehavior, m_resultSet, cancellationToken).ConfigureAwait(false);

                        if (m_hasMoreResults && m_resultSet.ContainsCommandParameters)
                        {
                            await ReadOutParametersAsync(Command !, m_resultSet, ioBehavior, cancellationToken).ConfigureAwait(false);
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (!m_hasMoreResults)
                    {
                        if (m_commandListPosition.CommandIndex < m_commandListPosition.Commands.Count)
                        {
                            Command = m_commandListPosition.Commands[m_commandListPosition.CommandIndex];
                            using (Command.CancellableCommand.RegisterCancel(cancellationToken))
                            {
                                var writer = new ByteBufferWriter();
                                if (!Command.Connection !.Session.IsCancelingQuery && m_payloadCreator.WriteQueryCommand(ref m_commandListPosition, m_cachedProcedures !, writer))
                                {
                                    using var payload = writer.ToPayloadData();
                                    await Command.Connection.Session.SendAsync(payload, ioBehavior, cancellationToken).ConfigureAwait(false);

                                    await m_resultSet.ReadResultSetHeaderAsync(ioBehavior).ConfigureAwait(false);

                                    ActivateResultSet();
                                    m_hasMoreResults = true;
                                }
                            }
                        }
                    }
                    else
                    {
                        ActivateResultSet();
                    }
                }while (m_hasMoreResults && (Command !.CommandBehavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0);

                if (!m_hasMoreResults)
                {
                    m_resultSet.Reset();
                }
#if !NETSTANDARD1_3
                m_schemaTable = null;
#endif
                return(m_hasMoreResults);
            }
            catch (MySqlException)
            {
                m_resultSet !.Reset();
                m_hasMoreResults = false;
#if !NETSTANDARD1_3
                m_schemaTable = null;
#endif
                throw;
            }
        }
Пример #16
0
        private PayloadData CreateQueryPayload(PreparedStatement preparedStatement, MySqlParameterCollection parameterCollection, MySqlGuidFormat guidFormat)
        {
            var writer = new ByteBufferWriter();

            writer.Write((byte)CommandKind.StatementExecute);
            writer.Write(preparedStatement.StatementId);
            writer.Write((byte)0);
            writer.Write(1);
            if (preparedStatement.Parameters?.Length > 0)
            {
                // TODO: How to handle incorrect number of parameters?

                // build subset of parameters for this statement
                var parameters = new MySqlParameter[preparedStatement.Statement.ParameterNames.Count];
                for (var i = 0; i < preparedStatement.Statement.ParameterNames.Count; i++)
                {
                    var parameterName  = preparedStatement.Statement.ParameterNames[i];
                    var parameterIndex = parameterName != null ? (parameterCollection?.NormalizedIndexOf(parameterName) ?? -1) : preparedStatement.Statement.ParameterIndexes[i];
                    if (parameterIndex == -1 && parameterName != null)
                    {
                        throw new MySqlException("Parameter '{0}' must be defined.".FormatInvariant(parameterName));
                    }
                    else if (parameterIndex < 0 || parameterIndex >= (parameterCollection?.Count ?? 0))
                    {
                        throw new MySqlException("Parameter index {0} is invalid when only {1} parameter{2} defined.".FormatInvariant(parameterIndex, parameterCollection?.Count ?? 0, parameterCollection?.Count == 1 ? " is" : "s are"));
                    }
                    parameters[i] = parameterCollection[parameterIndex];
                }

                // write null bitmap
                byte nullBitmap = 0;
                for (var i = 0; i < parameters.Length; i++)
                {
                    var parameter = parameters[i];
                    if (parameter.Value == null || parameter.Value == DBNull.Value)
                    {
                        if (i > 0 && i % 8 == 0)
                        {
                            writer.Write(nullBitmap);
                            nullBitmap = 0;
                        }

                        nullBitmap |= (byte)(1 << (i % 8));
                    }
                }
                writer.Write(nullBitmap);

                // write "new parameters bound" flag
                writer.Write((byte)1);

                foreach (var parameter in parameters)
                {
                    writer.Write(TypeMapper.ConvertToColumnTypeAndFlags(parameter.MySqlDbType, guidFormat));
                }

                var options = m_command.CreateStatementPreparerOptions();
                foreach (var parameter in parameters)
                {
                    parameter.AppendBinary(writer, options);
                }
            }

            return(writer.ToPayloadData());
        }
Пример #17
0
        public static async Task <DbDataReader> ExecuteReaderAsync(IReadOnlyList <IMySqlCommand> commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var commandListPosition = new CommandListPosition(commands);
            var command             = commands[0];

            if (Log.IsDebugEnabled())
            {
                Log.Debug("Session{0} ExecuteReader {1} CommandCount: {2}", command.Connection.Session.Id, ioBehavior, commands.Count);
            }

            Dictionary <string, CachedProcedure> cachedProcedures = null;

            foreach (var command2 in commands)
            {
                if (command2.CommandType == CommandType.StoredProcedure)
                {
                    if (cachedProcedures is null)
                    {
                        cachedProcedures = new Dictionary <string, CachedProcedure>();
                    }
                    if (!cachedProcedures.ContainsKey(command2.CommandText))
                    {
                        cachedProcedures.Add(command2.CommandText, await command2.Connection.GetCachedProcedure(ioBehavior, command2.CommandText, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            var writer = new ByteBufferWriter();

            if (!payloadCreator.WriteQueryCommand(ref commandListPosition, cachedProcedures, writer))
            {
                throw new InvalidOperationException("ICommandPayloadCreator failed to write query payload");
            }

            cancellationToken.ThrowIfCancellationRequested();

            using (var payload = writer.ToPayloadData())
                using (command.CancellableCommand.RegisterCancel(cancellationToken))
                {
                    command.Connection.Session.StartQuerying(command.CancellableCommand);
                    command.SetLastInsertedId(-1);
                    try
                    {
                        await command.Connection.Session.SendAsync(payload, ioBehavior, CancellationToken.None).ConfigureAwait(false);

                        return(await MySqlDataReader.CreateAsync(commandListPosition, payloadCreator, cachedProcedures, command, behavior, ioBehavior, cancellationToken).ConfigureAwait(false));
                    }
                    catch (MySqlException ex) when(ex.Number == (int)MySqlErrorCode.QueryInterrupted && cancellationToken.IsCancellationRequested)
                    {
                        Log.Warn("Session{0} query was interrupted", command.Connection.Session.Id);
                        throw new OperationCanceledException(cancellationToken);
                    }
                    catch (Exception ex) when(payload.ArraySegment.Count > 4_194_304 && (ex is SocketException || ex is IOException || ex is MySqlProtocolException))
                    {
                        // the default MySQL Server value for max_allowed_packet (in MySQL 5.7) is 4MiB: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet
                        // use "decimal megabytes" (to round up) when creating the exception message
                        int megabytes = payload.ArraySegment.Count / 1_000_000;

                        throw new MySqlException("Error submitting {0}MB packet; ensure 'max_allowed_packet' is greater than {0}MB.".FormatInvariant(megabytes), ex);
                    }
                }
        }