diff --git a/src/MySqlConnector/Core/CommandExecutor.cs b/src/MySqlConnector/Core/CommandExecutor.cs index 0434a8314..74b2b4e6a 100644 --- a/src/MySqlConnector/Core/CommandExecutor.cs +++ b/src/MySqlConnector/Core/CommandExecutor.cs @@ -8,22 +8,22 @@ namespace MySqlConnector.Core; internal static class CommandExecutor { - public static async ValueTask ExecuteReaderAsync(IReadOnlyList commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, Activity? activity, IOBehavior ioBehavior, CancellationToken cancellationToken) + public static async ValueTask ExecuteReaderAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, Activity? activity, IOBehavior ioBehavior, CancellationToken cancellationToken) { try { cancellationToken.ThrowIfCancellationRequested(); - var commandListPosition = new CommandListPosition(commands); - var command = commands[0]; + var command = commandListPosition.CommandAt(0); // pre-requisite: Connection is non-null must be checked before calling this method var connection = command.Connection!; - Log.CommandExecutorExecuteReader(command.Logger, connection.Session.Id, ioBehavior, commands.Count); + Log.CommandExecutorExecuteReader(command.Logger, connection.Session.Id, ioBehavior, commandListPosition.CommandCount); Dictionary? cachedProcedures = null; - foreach (var command2 in commands) + for (var commandIndex = 0; commandIndex < commandListPosition.CommandCount; commandIndex++) { + var command2 = commandListPosition.CommandAt(commandIndex); if (command2.CommandType == CommandType.StoredProcedure) { cachedProcedures ??= new(); diff --git a/src/MySqlConnector/Core/CommandListPosition.cs b/src/MySqlConnector/Core/CommandListPosition.cs index 24d9c0153..a54cb3766 100644 --- a/src/MySqlConnector/Core/CommandListPosition.cs +++ b/src/MySqlConnector/Core/CommandListPosition.cs @@ -5,18 +5,37 @@ namespace MySqlConnector.Core; /// internal struct CommandListPosition { - public CommandListPosition(IReadOnlyList commands) + public CommandListPosition(object commands) { - Commands = commands; + m_commands = commands; + CommandCount = commands switch + { + MySqlCommand _ => 1, + IReadOnlyList list => list.Count, + _ => 0, + }; PreparedStatements = null; CommandIndex = 0; PreparedStatementIndex = 0; } + public readonly IMySqlCommand CommandAt(int index) => + m_commands switch + { + MySqlCommand command when index is 0 => command, + IReadOnlyList list => list[index], + _ => throw new ArgumentOutOfRangeException(nameof(index)), + }; + + /// + /// The commands in this list; either a singular or a . + /// + private readonly object m_commands; + /// - /// The commands in the list. + /// The number of commands in the list. /// - public IReadOnlyList Commands { get; } + public readonly int CommandCount; /// /// Associated prepared statements of commands diff --git a/src/MySqlConnector/Core/ConcatenatedCommandPayloadCreator.cs b/src/MySqlConnector/Core/ConcatenatedCommandPayloadCreator.cs index 6cf0443be..20e0717f6 100644 --- a/src/MySqlConnector/Core/ConcatenatedCommandPayloadCreator.cs +++ b/src/MySqlConnector/Core/ConcatenatedCommandPayloadCreator.cs @@ -10,14 +10,14 @@ internal sealed class ConcatenatedCommandPayloadCreator : ICommandPayloadCreator public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDictionary cachedProcedures, ByteBufferWriter writer, bool appendSemicolon) { - if (commandListPosition.CommandIndex == commandListPosition.Commands.Count) + if (commandListPosition.CommandIndex == commandListPosition.CommandCount) return false; writer.Write((byte) CommandKind.Query); // ConcatenatedCommandPayloadCreator is only used by MySqlBatch, and MySqlBatchCommand doesn't expose attributes, // so just write an empty attribute set if the server needs it. - if (commandListPosition.Commands[commandListPosition.CommandIndex].Connection!.Session.SupportsQueryAttributes) + if (commandListPosition.CommandAt(commandListPosition.CommandIndex).Connection!.Session.SupportsQueryAttributes) { // attribute count writer.WriteLengthEncodedInteger(0); @@ -29,15 +29,15 @@ public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDict bool isComplete; do { - var command = commandListPosition.Commands[commandListPosition.CommandIndex]; + var command = commandListPosition.CommandAt(commandListPosition.CommandIndex); Log.PreparingCommandPayload(command.Logger, command.Connection!.Session.Id, command.CommandText!); isComplete = SingleCommandPayloadCreator.WriteQueryPayload(command, cachedProcedures, writer, - commandListPosition.CommandIndex < commandListPosition.Commands.Count - 1 || appendSemicolon, + commandListPosition.CommandIndex < commandListPosition.CommandCount - 1 || appendSemicolon, commandListPosition.CommandIndex == 0, - commandListPosition.CommandIndex == commandListPosition.Commands.Count - 1); + commandListPosition.CommandIndex == commandListPosition.CommandCount - 1); commandListPosition.CommandIndex++; - } while (commandListPosition.CommandIndex < commandListPosition.Commands.Count && isComplete); + } while (commandListPosition.CommandIndex < commandListPosition.CommandCount && isComplete); return true; } diff --git a/src/MySqlConnector/Core/SingleCommandPayloadCreator.cs b/src/MySqlConnector/Core/SingleCommandPayloadCreator.cs index b6e18ab95..0cd528877 100644 --- a/src/MySqlConnector/Core/SingleCommandPayloadCreator.cs +++ b/src/MySqlConnector/Core/SingleCommandPayloadCreator.cs @@ -14,10 +14,10 @@ internal sealed class SingleCommandPayloadCreator : ICommandPayloadCreator public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDictionary cachedProcedures, ByteBufferWriter writer, bool appendSemicolon) { - if (commandListPosition.CommandIndex == commandListPosition.Commands.Count) + if (commandListPosition.CommandIndex == commandListPosition.CommandCount) return false; - var command = commandListPosition.Commands[commandListPosition.CommandIndex]; + var command = commandListPosition.CommandAt(commandListPosition.CommandIndex); commandListPosition.PreparedStatements = command.TryGetPreparedStatements(); if (commandListPosition.PreparedStatements is null) { diff --git a/src/MySqlConnector/MySqlBatch.cs b/src/MySqlConnector/MySqlBatch.cs index 5ea46fd11..913eefdff 100644 --- a/src/MySqlConnector/MySqlBatch.cs +++ b/src/MySqlConnector/MySqlBatch.cs @@ -162,7 +162,7 @@ private ValueTask ExecuteReaderAsync(CommandBehavior behavior, var payloadCreator = Connection!.Session.SupportsComMulti ? BatchedCommandPayloadCreator.Instance : IsPrepared ? SingleCommandPayloadCreator.Instance : ConcatenatedCommandPayloadCreator.Instance; - return CommandExecutor.ExecuteReaderAsync(BatchCommands!.Commands, payloadCreator, behavior, default, ioBehavior, cancellationToken); + return CommandExecutor.ExecuteReaderAsync(new(BatchCommands!.Commands), payloadCreator, behavior, default, ioBehavior, cancellationToken); } #if NET6_0_OR_GREATER diff --git a/src/MySqlConnector/MySqlCommand.cs b/src/MySqlConnector/MySqlCommand.cs index 7de4a27d6..5cdf1082a 100644 --- a/src/MySqlConnector/MySqlCommand.cs +++ b/src/MySqlConnector/MySqlCommand.cs @@ -359,7 +359,7 @@ internal ValueTask ExecuteReaderNoResetTimeoutAsync(CommandBeha var activity = NoActivity ? null : Connection!.Session.StartActivity(ActivitySourceHelper.ExecuteActivityName, ActivitySourceHelper.DatabaseStatementTagName, CommandText); m_commandBehavior = behavior; - return CommandExecutor.ExecuteReaderAsync(new IMySqlCommand[] { this }, SingleCommandPayloadCreator.Instance, behavior, activity, ioBehavior, cancellationToken); + return CommandExecutor.ExecuteReaderAsync(new(this), SingleCommandPayloadCreator.Instance, behavior, activity, ioBehavior, cancellationToken); } public MySqlCommand Clone() => new(this); diff --git a/src/MySqlConnector/MySqlDataReader.cs b/src/MySqlConnector/MySqlDataReader.cs index 24337a1d7..e05db849e 100644 --- a/src/MySqlConnector/MySqlDataReader.cs +++ b/src/MySqlConnector/MySqlDataReader.cs @@ -68,9 +68,9 @@ internal async Task NextResultAsync(IOBehavior ioBehavior, CancellationTok if (!m_hasMoreResults) { - if (m_commandListPosition.CommandIndex < m_commandListPosition.Commands.Count) + if (m_commandListPosition.CommandIndex < m_commandListPosition.CommandCount) { - Command = m_commandListPosition.Commands[m_commandListPosition.CommandIndex]; + Command = m_commandListPosition.CommandAt(m_commandListPosition.CommandIndex); using (Command.CancellableCommand.RegisterCancel(cancellationToken)) { var writer = new ByteBufferWriter(); @@ -485,7 +485,7 @@ internal async Task InitAsync(CommandListPosition commandListPosition, ICommandP await ReadOutParametersAsync(command, m_resultSet, ioBehavior, cancellationToken).ConfigureAwait(false); // if the command list has multiple commands, keep reading until a result set is found - while (m_resultSet.State == ResultSetState.NoMoreData && commandListPosition.CommandIndex < commandListPosition.Commands.Count) + while (m_resultSet.State == ResultSetState.NoMoreData && commandListPosition.CommandIndex < commandListPosition.CommandCount) { await NextResultAsync(ioBehavior, cancellationToken).ConfigureAwait(false); }