Skip to content

Commit

Permalink
Avoids SET NAMES commands if not needed
Browse files Browse the repository at this point in the history
for MariaDB since 15.1 (https://jira.mariadb.org/browse/MDEV-31609) followed session variables are sent in initial OK_Packet. This permits to avoids  initial query SET NAMES command, since charset is really know, defaulting to server corresponding default collation.

Signed-off-by: rusher <[email protected]>
  • Loading branch information
rusher committed Jul 15, 2024
1 parent 6794641 commit 06d1f8c
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public bool WriteQueryCommand(ref CommandListPosition commandListPosition, IDict

// 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.CommandAt(commandListPosition.CommandIndex).Connection!.Session.SupportsQueryAttributes)
if (commandListPosition.CommandAt(commandListPosition.CommandIndex).Connection!.Session.Context.SupportsQueryAttributes)
{
// attribute count
writer.WriteLengthEncodedInteger(0);
Expand Down
2 changes: 1 addition & 1 deletion src/MySqlConnector/Core/ConnectionPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public async ValueTask<ServerSession> GetSessionAsync(MySqlConnection connection
}
else
{
if (ConnectionSettings.ConnectionReset || session.DatabaseOverride is not null)
if (ConnectionSettings.ConnectionReset || !session.Context.IsInitialDatabase())
{
if (timeoutMilliseconds != 0)
session.SetTimeout(Math.Max(1, timeoutMilliseconds - Utility.GetElapsedMilliseconds(startingTimestamp)));
Expand Down
29 changes: 29 additions & 0 deletions src/MySqlConnector/Core/Context.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using MySqlConnector.Protocol;

namespace MySqlConnector.Core;

internal sealed class Context
{
public Context(ProtocolCapabilities protocolCapabilities, string? database, int connectionId)
{
SupportsDeprecateEof = (protocolCapabilities & ProtocolCapabilities.DeprecateEof) != 0;
SupportsCachedPreparedMetadata = (protocolCapabilities & ProtocolCapabilities.MariaDbCacheMetadata) != 0;
SupportsQueryAttributes = (protocolCapabilities & ProtocolCapabilities.QueryAttributes) != 0;
SupportsSessionTrack = (protocolCapabilities & ProtocolCapabilities.SessionTrack) != 0;
ConnectionId = connectionId;
Database = database;
m_initialDatabase = database;
}

public bool SupportsDeprecateEof { get; }
public bool SupportsQueryAttributes { get; }
public bool SupportsSessionTrack { get; }
public bool SupportsCachedPreparedMetadata { get; }
public string? ClientCharset { get; set; }

public string? Database { get; set; }
private readonly string? m_initialDatabase;
public bool IsInitialDatabase() => string.Equals(m_initialDatabase, Database, StringComparison.Ordinal);

public int ConnectionId { get; set; }
}
16 changes: 7 additions & 9 deletions src/MySqlConnector/Core/ResultSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
var firstByte = payload.HeaderByte;
if (firstByte == OkPayload.Signature)
{
var ok = OkPayload.Create(payload.Span, Session.SupportsDeprecateEof, Session.SupportsSessionTrack);
var ok = OkPayload.Create(payload.Span, Session.Context);

// if we've read a result set header then this is a SELECT statement, so we shouldn't overwrite RecordsAffected
// (which should be -1 for SELECT) unless the server reports a non-zero count
Expand All @@ -48,8 +48,6 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
if (ok.LastInsertId != 0)
Command?.SetLastInsertedId((long) ok.LastInsertId);
WarningCount = ok.WarningCount;
if (ok.NewSchema is not null)
Connection.Session.DatabaseOverride = ok.NewSchema;
m_columnDefinitions = default;
State = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0
? ResultSetState.NoMoreData
Expand Down Expand Up @@ -109,7 +107,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
}
else
{
var columnCountPacket = ColumnCountPayload.Create(payload.Span, Session.SupportsCachedPreparedMetadata);
var columnCountPacket = ColumnCountPayload.Create(payload.Span, Session.Context.SupportsCachedPreparedMetadata);
var columnCount = columnCountPacket.ColumnCount;
if (!columnCountPacket.MetadataFollows)
{
Expand All @@ -132,7 +130,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
m_columnDefinitions = m_columnDefinitionPayloadCache.AsMemory(0, columnCount);

// if the server supports metadata caching but has re-sent it, something has changed since last prepare/execution and we need to update the columns
var preparedColumns = Session.SupportsCachedPreparedMetadata ? DataReader.LastUsedPreparedStatement?.Columns : null;
var preparedColumns = Session.Context.SupportsCachedPreparedMetadata ? DataReader.LastUsedPreparedStatement?.Columns : null;

for (var column = 0; column < columnCount; column++)
{
Expand All @@ -156,7 +154,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
}
}

if (!Session.SupportsDeprecateEof)
if (!Session.Context.SupportsDeprecateEof)
{
payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
_ = EofPayload.Create(payload.Span);
Expand Down Expand Up @@ -252,13 +250,13 @@ public async Task<bool> ReadAsync(IOBehavior ioBehavior, CancellationToken cance

if (payload.HeaderByte == EofPayload.Signature)
{
if (Session.SupportsDeprecateEof && OkPayload.IsOk(payload.Span, Session.SupportsDeprecateEof))
if (Session.Context.SupportsDeprecateEof && OkPayload.IsOk(payload.Span, Session.Context))
{
var ok = OkPayload.Create(payload.Span, Session.SupportsDeprecateEof, Session.SupportsSessionTrack);
var ok = OkPayload.Create(payload.Span, Session.Context);
BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;
return null;
}
if (!Session.SupportsDeprecateEof && EofPayload.IsEof(payload))
if (!Session.Context.SupportsDeprecateEof && EofPayload.IsEof(payload))
{
var eof = EofPayload.Create(payload.Span);
BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;
Expand Down
Loading

0 comments on commit 06d1f8c

Please sign in to comment.