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()); }
public static PayloadData Create(string databaseName) { var writer = new ByteBufferWriter(); writer.Write((byte)CommandKind.InitDatabase); writer.Write(databaseName); return(writer.ToPayloadData()); }
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())); }
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()); }
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()); }
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()); }
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); } }
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; } }
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()); }
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); } } }