From 5ad4cf3b09da78d9cbb28b4d01f104f3b49b20b0 Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Sun, 29 Oct 2023 12:56:58 -0700 Subject: [PATCH] Remove COM_MULTI implementation. Fixes #946 The only server that supported this capability bit was MariaDB prior to version 10.6. Additionally, this code is never regularly tested because CI only runs against MariaDB 10.6 and later. --- .../Core/BatchedCommandPayloadCreator.cs | 37 ------ src/MySqlConnector/Core/ServerSession.cs | 3 - src/MySqlConnector/MySqlBatch.cs | 3 +- src/MySqlConnector/Protocol/CommandKind.cs | 1 - .../Payloads/HandshakeResponse41Payload.cs | 1 - tests/IntegrationTests/BatchTests.cs | 23 ---- tests/IntegrationTests/CancelTests.cs | 112 ------------------ 7 files changed, 1 insertion(+), 179 deletions(-) delete mode 100644 src/MySqlConnector/Core/BatchedCommandPayloadCreator.cs diff --git a/src/MySqlConnector/Core/BatchedCommandPayloadCreator.cs b/src/MySqlConnector/Core/BatchedCommandPayloadCreator.cs deleted file mode 100644 index c17c53335..000000000 --- a/src/MySqlConnector/Core/BatchedCommandPayloadCreator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Buffers.Binary; -using MySqlConnector.Protocol; -using MySqlConnector.Protocol.Serialization; - -namespace MySqlConnector.Core; - -internal sealed class BatchedCommandPayloadCreator : ICommandPayloadCreator -{ - public static ICommandPayloadCreator Instance { get; } = new BatchedCommandPayloadCreator(); - - public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDictionary cachedProcedures, ByteBufferWriter writer, bool appendSemicolon) - { - writer.Write((byte) CommandKind.Multi); - bool? firstResult = default; - bool wroteCommand; - ReadOnlySpan padding = [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; - do - { - // save room for command length - var position = writer.Position; - writer.Write(padding); - - wroteCommand = SingleCommandPayloadCreator.Instance.WriteQueryCommand(ref commandListPosition, cachedProcedures, writer, appendSemicolon); - firstResult ??= wroteCommand; - - // write command length - var commandLength = writer.Position - position - padding.Length; - var span = writer.ArraySegment.AsSpan(position); - span[0] = 0xFE; - BinaryPrimitives.WriteUInt64LittleEndian(span[1..], (ulong) commandLength); - } while (wroteCommand); - - // remove the padding that was saved for the final command (which wasn't written) - writer.TrimEnd(padding.Length); - return firstResult.Value; - } -} diff --git a/src/MySqlConnector/Core/ServerSession.cs b/src/MySqlConnector/Core/ServerSession.cs index 351eda129..9ba24fd8c 100644 --- a/src/MySqlConnector/Core/ServerSession.cs +++ b/src/MySqlConnector/Core/ServerSession.cs @@ -62,7 +62,6 @@ public ServerSession(ILogger logger, ConnectionPool? pool, int poolGeneration, i public IPEndPoint? IPEndPoint => m_tcpClient?.Client.RemoteEndPoint as IPEndPoint; public string? UserID { get; private set; } public WeakReference? OwningConnection { get; set; } - public bool SupportsComMulti => m_supportsComMulti; public bool SupportsDeprecateEof => m_supportsDeprecateEof; public bool SupportsCachedPreparedMetadata { get; private set; } public bool SupportsQueryAttributes { get; private set; } @@ -485,7 +484,6 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella activity.SetTag(ActivitySourceHelper.DatabaseConnectionIdTagName, connectionId); } - m_supportsComMulti = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.MariaDbComMulti) != 0; m_supportsConnectionAttributes = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.ConnectionAttributes) != 0; m_supportsDeprecateEof = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.DeprecateEof) != 0; SupportsCachedPreparedMetadata = (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.MariaDbCacheMetadata) != 0; @@ -1933,7 +1931,6 @@ protected override void OnStatementBegin(int index) private IPayloadHandler? m_payloadHandler; private bool m_useCompression; private bool m_isSecureConnection; - private bool m_supportsComMulti; private bool m_supportsConnectionAttributes; private bool m_supportsDeprecateEof; private bool m_supportsSessionTrack; diff --git a/src/MySqlConnector/MySqlBatch.cs b/src/MySqlConnector/MySqlBatch.cs index 1aa0a1731..b3ed8d0cb 100644 --- a/src/MySqlConnector/MySqlBatch.cs +++ b/src/MySqlConnector/MySqlBatch.cs @@ -160,8 +160,7 @@ private ValueTask ExecuteReaderAsync(CommandBehavior behavior, foreach (MySqlBatchCommand batchCommand in BatchCommands) batchCommand.Batch = this; - var payloadCreator = Connection!.Session.SupportsComMulti ? BatchedCommandPayloadCreator.Instance : - IsPrepared ? SingleCommandPayloadCreator.Instance : + var payloadCreator = IsPrepared ? SingleCommandPayloadCreator.Instance : ConcatenatedCommandPayloadCreator.Instance; return CommandExecutor.ExecuteReaderAsync(new(BatchCommands!.Commands), payloadCreator, behavior, default, ioBehavior, cancellationToken); } diff --git a/src/MySqlConnector/Protocol/CommandKind.cs b/src/MySqlConnector/Protocol/CommandKind.cs index 8b232707f..6e384a733 100644 --- a/src/MySqlConnector/Protocol/CommandKind.cs +++ b/src/MySqlConnector/Protocol/CommandKind.cs @@ -10,5 +10,4 @@ internal enum CommandKind StatementPrepare = 22, StatementExecute = 23, ResetConnection = 31, - Multi = 254, } diff --git a/src/MySqlConnector/Protocol/Payloads/HandshakeResponse41Payload.cs b/src/MySqlConnector/Protocol/Payloads/HandshakeResponse41Payload.cs index cc8dce3af..bd048f0ee 100644 --- a/src/MySqlConnector/Protocol/Payloads/HandshakeResponse41Payload.cs +++ b/src/MySqlConnector/Protocol/Payloads/HandshakeResponse41Payload.cs @@ -28,7 +28,6 @@ private static ByteBufferWriter CreateCapabilitiesPayload(ProtocolCapabilities s ProtocolCapabilities.SessionTrack | ProtocolCapabilities.DeprecateEof | ProtocolCapabilities.QueryAttributes | - ProtocolCapabilities.MariaDbComMulti | ProtocolCapabilities.MariaDbCacheMetadata | additionalCapabilities) & serverCapabilities; diff --git a/tests/IntegrationTests/BatchTests.cs b/tests/IntegrationTests/BatchTests.cs index 04b5bb17c..dc0b5a947 100644 --- a/tests/IntegrationTests/BatchTests.cs +++ b/tests/IntegrationTests/BatchTests.cs @@ -223,29 +223,6 @@ public void ExecuteBatch(string suffix) Assert.Equal(16, total); } - [Fact(Skip = "COM_MULTI")] - public void ExecuteInvalidSqlBatch() - { - using var connection = new MySqlConnection(AppConfig.ConnectionString); - connection.Open(); - using var batch = new MySqlBatch(connection) - { - BatchCommands = - { - new MySqlBatchCommand("SELECT 1;"), - new MySqlBatchCommand("SELECT 2 /* incomplete"), - new MySqlBatchCommand("SELECT 3;"), - }, - }; - using var reader = batch.ExecuteReader(); - Assert.True(reader.Read()); - Assert.Equal(1, reader.GetInt32(0)); - Assert.False(reader.Read()); - - var ex = Assert.Throws(() => reader.NextResult()); - Assert.Equal(MySqlErrorCode.ParseError, ex.ErrorCode); - } - [Theory] [InlineData(false)] [InlineData(true)] diff --git a/tests/IntegrationTests/CancelTests.cs b/tests/IntegrationTests/CancelTests.cs index 6c37a310d..28f9d4e61 100644 --- a/tests/IntegrationTests/CancelTests.cs +++ b/tests/IntegrationTests/CancelTests.cs @@ -519,50 +519,6 @@ public void CancelBatchBeforeRead() Assert.InRange(rows, 0, 10000000); } - [SkippableFact(ServerFeatures.StreamingResults | ServerFeatures.Timeout, Skip = "COM_MULTI")] - public void CancelMultiCommandBatchReader() - { - using var barrier = new Barrier(2); - using var batch = new MySqlBatch(m_database.Connection) - { - BatchCommands = - { - new MySqlBatchCommand(c_hugeQuery), - new MySqlBatchCommand(c_hugeQuery), - new MySqlBatchCommand(c_hugeQuery), - }, - }; - var task = Task.Run(() => - { - barrier.SignalAndWait(); - batch.Cancel(); - }); - - int rows = 0; - using (var reader = batch.ExecuteReader()) - { - Assert.True(reader.Read()); - - barrier.SignalAndWait(); - try - { - while (reader.Read()) - rows++; - } - catch (MySqlException ex) - { - Assert.Equal(MySqlErrorCode.QueryInterrupted, ex.ErrorCode); - } - - // query returns 25 billion rows; we shouldn't have read many of them - Assert.InRange(rows, 0, 10000000); - - Assert.False(reader.NextResult()); - } - - task.Wait(); // shouldn't throw - } - [Fact] public async Task CancelBatchWithTokenBeforeExecuteScalar() { @@ -688,41 +644,6 @@ public async Task CancelHugeQueryBatchWithTokenAfterExecuteReader() Assert.False(reader.NextResult()); } - [SkippableFact(ServerFeatures.StreamingResults | ServerFeatures.Timeout, Skip = "COM_MULTI")] - public async Task CancelHugeQueryBatchWithTokenInNextResult() - { - using var batch = new MySqlBatch(m_database.Connection) - { - BatchCommands = - { - new MySqlBatchCommand(c_hugeQuery), - new MySqlBatchCommand("select 1, 2, 3;"), - }, - }; - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(0.5)); - using var reader = await batch.ExecuteReaderAsync(cts.Token); - - // read first result set - Assert.True(await reader.ReadAsync(cts.Token)); - - try - { - // skip to the next result set - Assert.True(await reader.NextResultAsync(cts.Token)); - - // shouldn't get here - Assert.True(false); - } - catch (OperationCanceledException ex) - { - Assert.Equal(cts.Token, ex.CancellationToken); - } - - // no more result sets - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); - } - [SkippableFact(ServerFeatures.Timeout)] public async Task CancelSlowQueryBatchWithTokenAfterExecuteReader() { @@ -796,39 +717,6 @@ public async Task CancelSlowQueryBatchWithTokenAfterNextResult() Assert.False(await reader.NextResultAsync()); } - - [SkippableFact(ServerFeatures.StreamingResults | ServerFeatures.Timeout, Skip = "COM_MULTI")] - public async Task CancelMultiStatementBatchInRead() - { - using var batch = new MySqlBatch(m_database.Connection) - { - BatchCommands = - { - new MySqlBatchCommand(c_hugeQuery), - new MySqlBatchCommand(c_hugeQuery), - new MySqlBatchCommand(c_hugeQuery), - }, - }; - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(0.5)); - using var reader = await batch.ExecuteReaderAsync(); - var rows = 0; - try - { - while (await reader.ReadAsync(cts.Token)) - rows++; - - Assert.True(false); - } - catch (OperationCanceledException ex) - { - Assert.Equal(cts.Token, ex.CancellationToken); - Assert.InRange(rows, 0, 10000000); - } - - // no more result sets; the whole command was cancelled - Assert.False(reader.Read()); - Assert.False(reader.NextResult()); - } #endif private static CancellationToken GetCanceledToken()