Skip to content

Commit 3f50c14

Browse files
committed
Ensure all server variables specify the right character set.
Signed-off-by: Bradley Grainger <[email protected]>
1 parent 3326a0e commit 3f50c14

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
538538
if (m_useCompression)
539539
m_payloadHandler = new CompressedPayloadHandler(m_payloadHandler.ByteHandler);
540540

541-
if (ok.ClientCharacterSet != (ServerVersion.Version >= ServerVersions.SupportsUtf8Mb4 ? "utf8mb4" : "utf8"))
541+
// send 'SET NAMES' to set the character set and collation unless the server reports that it's already using the desired character set (e.g., MariaDB >= 11.5)
542+
if (ok.NewCharacterSet != (ServerVersion.Version >= ServerVersions.SupportsUtf8Mb4 ? CharacterSet.Utf8Mb4Binary : CharacterSet.Utf8Mb3Binary))
542543
{
543544
// set 'collation_connection' to the server default
544545
await SendAsync(m_setNamesPayload, ioBehavior, cancellationToken).ConfigureAwait(false);
@@ -550,7 +551,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
550551
{
551552
await GetRealServerDetailsAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
552553
}
553-
else if (ok.ConnectionId is int newConnectionId && newConnectionId != ConnectionId)
554+
else if (ok.NewConnectionId is int newConnectionId && newConnectionId != ConnectionId)
554555
{
555556
Log.ChangingConnectionId(m_logger, Id, ConnectionId, newConnectionId, ServerVersion.OriginalString, ServerVersion.OriginalString);
556557
ConnectionId = newConnectionId;

src/MySqlConnector/Protocol/Payloads/OkPayload.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ internal sealed class OkPayload
1414
public int WarningCount { get; }
1515
public string? StatusInfo { get; }
1616
public string? NewSchema { get; }
17-
public string? ClientCharacterSet { get; }
18-
public int? ConnectionId { get; }
17+
public CharacterSet? NewCharacterSet { get; }
18+
public int? NewConnectionId { get; }
1919

2020
public const byte Signature = 0x00;
2121

@@ -61,7 +61,9 @@ public static void Verify(ReadOnlySpan<byte> span, IServerCapabilities serverCap
6161
var serverStatus = (ServerStatus) reader.ReadUInt16();
6262
var warningCount = (int) reader.ReadUInt16();
6363
string? newSchema = null;
64-
string? clientCharacterSet = null;
64+
CharacterSet clientCharacterSet = default;
65+
CharacterSet connectionCharacterSet = default;
66+
CharacterSet resultsCharacterSet = default;
6567
int? connectionId = null;
6668
ReadOnlySpan<byte> statusBytes;
6769

@@ -93,7 +95,21 @@ public static void Verify(ReadOnlySpan<byte> span, IServerCapabilities serverCap
9395
var systemVariableValue = systemVariableValueLength == -1 ? default : reader.ReadByteString(systemVariableValueLength);
9496
if (systemVariableName.SequenceEqual("character_set_client"u8) && systemVariableValueLength != 0)
9597
{
96-
clientCharacterSet = Encoding.ASCII.GetString(systemVariableValue);
98+
clientCharacterSet = systemVariableValue.SequenceEqual("utf8mb4"u8) ? CharacterSet.Utf8Mb4Binary :
99+
systemVariableValue.SequenceEqual("utf8"u8) ? CharacterSet.Utf8Mb3Binary :
100+
CharacterSet.None;
101+
}
102+
else if (systemVariableName.SequenceEqual("character_set_connection"u8) && systemVariableValueLength != 0)
103+
{
104+
connectionCharacterSet = systemVariableValue.SequenceEqual("utf8mb4"u8) ? CharacterSet.Utf8Mb4Binary :
105+
systemVariableValue.SequenceEqual("utf8"u8) ? CharacterSet.Utf8Mb3Binary :
106+
CharacterSet.None;
107+
}
108+
else if (systemVariableName.SequenceEqual("character_set_results"u8) && systemVariableValueLength != 0)
109+
{
110+
resultsCharacterSet = systemVariableValue.SequenceEqual("utf8mb4"u8) ? CharacterSet.Utf8Mb4Binary :
111+
systemVariableValue.SequenceEqual("utf8"u8) ? CharacterSet.Utf8Mb3Binary :
112+
CharacterSet.None;
97113
}
98114
else if (systemVariableName.SequenceEqual("connection_id"u8))
99115
{
@@ -129,32 +145,37 @@ public static void Verify(ReadOnlySpan<byte> span, IServerCapabilities serverCap
129145
{
130146
var statusInfo = statusBytes.Length == 0 ? null : Encoding.UTF8.GetString(statusBytes);
131147

132-
if (affectedRowCount == 0 && lastInsertId == 0 && warningCount == 0 && statusInfo is null && newSchema is null && clientCharacterSet is null && connectionId is null)
148+
// detect the connection character set as utf8mb4 (or utf8) if all three system variables are set to the same value
149+
var characterSet = clientCharacterSet == CharacterSet.Utf8Mb4Binary && connectionCharacterSet == CharacterSet.Utf8Mb4Binary && resultsCharacterSet == CharacterSet.Utf8Mb4Binary ? CharacterSet.Utf8Mb4Binary :
150+
clientCharacterSet == CharacterSet.Utf8Mb3Binary && connectionCharacterSet == CharacterSet.Utf8Mb3Binary && resultsCharacterSet == CharacterSet.Utf8Mb3Binary ? CharacterSet.Utf8Mb3Binary :
151+
CharacterSet.None;
152+
153+
if (affectedRowCount == 0 && lastInsertId == 0 && warningCount == 0 && statusInfo is null && newSchema is null && clientCharacterSet is CharacterSet.None && connectionId is null)
133154
{
134155
if (serverStatus == ServerStatus.AutoCommit)
135156
return s_autoCommitOk;
136157
if (serverStatus == (ServerStatus.AutoCommit | ServerStatus.SessionStateChanged))
137158
return s_autoCommitSessionStateChangedOk;
138159
}
139160

140-
return new OkPayload(affectedRowCount, lastInsertId, serverStatus, warningCount, statusInfo, newSchema, clientCharacterSet, connectionId);
161+
return new OkPayload(affectedRowCount, lastInsertId, serverStatus, warningCount, statusInfo, newSchema, characterSet, connectionId);
141162
}
142163
else
143164
{
144165
return null;
145166
}
146167
}
147168

148-
private OkPayload(ulong affectedRowCount, ulong lastInsertId, ServerStatus serverStatus, int warningCount, string? statusInfo, string? newSchema, string? clientCharacterSet, int? connectionId)
169+
private OkPayload(ulong affectedRowCount, ulong lastInsertId, ServerStatus serverStatus, int warningCount, string? statusInfo, string? newSchema, CharacterSet newCharacterSet, int? connectionId)
149170
{
150171
AffectedRowCount = affectedRowCount;
151172
LastInsertId = lastInsertId;
152173
ServerStatus = serverStatus;
153174
WarningCount = warningCount;
154175
StatusInfo = statusInfo;
155176
NewSchema = newSchema;
156-
ClientCharacterSet = clientCharacterSet;
157-
ConnectionId = connectionId;
177+
NewCharacterSet = newCharacterSet;
178+
NewConnectionId = connectionId;
158179
}
159180

160181
private static readonly OkPayload s_autoCommitOk = new(0, 0, ServerStatus.AutoCommit, 0, default, default, default, default);

0 commit comments

Comments
 (0)