Skip to content

Commit a42c809

Browse files
committed
Avoid creating substrings when parsing server version.
1 parent 3fcd9f8 commit a42c809

File tree

3 files changed

+21
-23
lines changed

3 files changed

+21
-23
lines changed

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public async Task ConnectAsync(ConnectionSettings cs, ILoadBalancer loadBalancer
304304
throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
305305
}
306306

307-
ServerVersion = new ServerVersion(Encoding.ASCII.GetString(initialHandshake.ServerVersion));
307+
ServerVersion = new ServerVersion(initialHandshake.ServerVersion);
308308
ConnectionId = initialHandshake.ConnectionId;
309309
AuthPluginData = initialHandshake.AuthPluginData;
310310
m_useCompression = cs.UseCompression && (initialHandshake.ProtocolCapabilities & ProtocolCapabilities.Compress) != 0;
@@ -1152,13 +1152,13 @@ private async Task GetRealServerDetailsAsync(IOBehavior ioBehavior, Cancellation
11521152

11531153
// first (and only) row
11541154
payload = await ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
1155-
void ReadRow(ReadOnlySpan<byte> span, out int? connectionId_, out string serverVersion_)
1155+
void ReadRow(ReadOnlySpan<byte> span, out int? connectionId_, out byte[] serverVersion_)
11561156
{
11571157
var reader = new ByteArrayReader(span);
11581158
var length = reader.ReadLengthEncodedIntegerOrNull();
11591159
connectionId_ = (length != -1 && Utf8Parser.TryParse(reader.ReadByteString(length), out int id, out _)) ? id : default(int?);
11601160
length = reader.ReadLengthEncodedIntegerOrNull();
1161-
serverVersion_ = length != -1 ? Encoding.UTF8.GetString(reader.ReadByteString(length)) : null;
1161+
serverVersion_ = length != -1 ? reader.ReadByteString(length).ToArray() : null;
11621162
}
11631163
ReadRow(payload.AsSpan(), out var connectionId, out var serverVersion);
11641164

@@ -1171,9 +1171,10 @@ void ReadRow(ReadOnlySpan<byte> span, out int? connectionId_, out string serverV
11711171

11721172
if (connectionId.HasValue && serverVersion != null)
11731173
{
1174-
Log.Info("Session{0} changing ConnectionIdOld {1} to ConnectionId {2} and ServerVersionOld {3} to ServerVersion {4}", m_logArguments[0], ConnectionId, connectionId.Value, ServerVersion.OriginalString, serverVersion);
1174+
var newServerVersion = new ServerVersion(serverVersion);
1175+
Log.Info("Session{0} changing ConnectionIdOld {1} to ConnectionId {2} and ServerVersionOld {3} to ServerVersion {4}", m_logArguments[0], ConnectionId, connectionId.Value, ServerVersion.OriginalString, newServerVersion.OriginalString);
11751176
ConnectionId = connectionId.Value;
1176-
ServerVersion = new ServerVersion(serverVersion);
1177+
ServerVersion = newServerVersion;
11771178
}
11781179
}
11791180
catch (MySqlException ex)

src/MySqlConnector/Core/ServerVersion.cs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
using System;
2-
using System.Globalization;
2+
using System.Buffers.Text;
3+
using System.Text;
4+
using MySqlConnector.Utilities;
35

46
namespace MySqlConnector.Core
57
{
68
internal sealed class ServerVersion
79
{
8-
public ServerVersion(string versionString)
10+
public ServerVersion(ReadOnlySpan<byte> versionString)
911
{
10-
OriginalString = versionString;
12+
OriginalString = Encoding.ASCII.GetString(versionString);
1113

12-
var last = 0;
13-
var index = versionString.IndexOf('.', last);
14-
var major = int.Parse(versionString.Substring(last, index - last), CultureInfo.InvariantCulture);
15-
last = index + 1;
16-
17-
index = versionString.IndexOf('.', last);
18-
var minor = int.Parse(versionString.Substring(last, index - last), CultureInfo.InvariantCulture);
19-
last = index + 1;
20-
21-
do
22-
{
23-
index++;
24-
} while (index < versionString.Length && versionString[index] >= '0' && versionString[index] <= '9');
25-
var build = int.Parse(versionString.Substring(last, index - last), CultureInfo.InvariantCulture);
14+
if (!Utf8Parser.TryParse(versionString, out int major, out var bytesConsumed) || versionString[bytesConsumed] != 0x2E)
15+
throw new InvalidOperationException("Error parsing " + OriginalString);
16+
versionString = versionString.Slice(bytesConsumed + 1);
17+
if (!Utf8Parser.TryParse(versionString, out int minor, out bytesConsumed) || versionString[bytesConsumed] != 0x2E)
18+
throw new InvalidOperationException("Error parsing " + OriginalString);
19+
versionString = versionString.Slice(bytesConsumed + 1);
20+
if (!Utf8Parser.TryParse(versionString, out int build, out bytesConsumed))
21+
throw new InvalidOperationException("Error parsing " + OriginalString);
2622

2723
Version = new Version(major, minor, build);
2824
}

tests/MySqlConnector.Tests/ServerVersionTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Text;
23
using MySqlConnector.Core;
34
using Xunit;
45

@@ -16,7 +17,7 @@ public class ServerVersionTests
1617
public void ParseServerVersion(string serverVersion, string expectedString)
1718
{
1819
var expected = Version.Parse(expectedString);
19-
Assert.Equal(expected, new ServerVersion(serverVersion).Version);
20+
Assert.Equal(expected, new ServerVersion(Encoding.UTF8.GetBytes(serverVersion)).Version);
2021
}
2122
}
2223
}

0 commit comments

Comments
 (0)