Skip to content

Commit a04dac0

Browse files
committed
Optimise the fast path of PrepareAsync.
1 parent e0b99cd commit a04dac0

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

src/MySqlConnector/MySql.Data.MySqlClient/MySqlCommand.cs

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,30 +65,56 @@ public MySqlCommand(string commandText, MySqlConnection connection, MySqlTransac
6565

6666
public new MySqlDataReader ExecuteReader(CommandBehavior commandBehavior) => (MySqlDataReader) base.ExecuteReader(commandBehavior);
6767

68-
public override void Prepare() => PrepareAsync(IOBehavior.Synchronous, default).GetAwaiter().GetResult();
68+
public override void Prepare()
69+
{
70+
if (!NeedsPrepare(out var exception))
71+
{
72+
if (exception != null)
73+
throw exception;
74+
return;
75+
}
76+
77+
DoPrepareAsync(IOBehavior.Synchronous, default).GetAwaiter().GetResult();
78+
}
79+
6980
public Task PrepareAsync() => PrepareAsync(AsyncIOBehavior, default);
7081
public Task PrepareAsync(CancellationToken cancellationToken) => PrepareAsync(AsyncIOBehavior, cancellationToken);
71-
72-
private async Task PrepareAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
82+
83+
private Task PrepareAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
84+
{
85+
if (!NeedsPrepare(out var exception))
86+
return exception != null ? Utility.TaskFromException(exception) : Utility.CompletedTask;
87+
88+
return DoPrepareAsync(ioBehavior, cancellationToken);
89+
}
90+
91+
private bool NeedsPrepare(out Exception exception)
7392
{
93+
exception = null;
7494
if (Connection == null)
75-
throw new InvalidOperationException("Connection property must be non-null.");
76-
if (Connection.State != ConnectionState.Open)
77-
throw new InvalidOperationException("Connection must be Open; current state is {0}".FormatInvariant(Connection.State));
78-
if (string.IsNullOrWhiteSpace(CommandText))
79-
throw new InvalidOperationException("CommandText must be specified");
80-
if (m_connection?.HasActiveReader ?? false)
81-
throw new InvalidOperationException("Cannot call Prepare when there is an open DataReader for this command; it must be closed first.");
82-
if (Connection.IgnorePrepare)
83-
return;
95+
exception = new InvalidOperationException("Connection property must be non-null.");
96+
else if (Connection.State != ConnectionState.Open)
97+
exception = new InvalidOperationException("Connection must be Open; current state is {0}".FormatInvariant(Connection.State));
98+
else if (string.IsNullOrWhiteSpace(CommandText))
99+
exception = new InvalidOperationException("CommandText must be specified");
100+
else if (Connection?.HasActiveReader ?? false)
101+
exception = new InvalidOperationException("Cannot call Prepare when there is an open DataReader for this command; it must be closed first.");
102+
103+
if (exception != null || Connection.IgnorePrepare)
104+
return false;
84105

85106
if (CommandType != CommandType.Text)
86-
throw new NotSupportedException("Only CommandType.Text is currently supported by MySqlCommand.Prepare");
107+
{
108+
exception = new NotSupportedException("Only CommandType.Text is currently supported by MySqlCommand.Prepare");
109+
return false;
110+
}
87111

88112
// don't prepare the same SQL twice
89-
if (m_connection.Session.TryGetPreparedStatement(CommandText) != null)
90-
return;
113+
return Connection.Session.TryGetPreparedStatement(CommandText) == null;
114+
}
91115

116+
private async Task DoPrepareAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
117+
{
92118
var statementPreparer = new StatementPreparer(CommandText, Parameters, CreateStatementPreparerOptions());
93119
var parsedStatements = statementPreparer.SplitStatements();
94120

@@ -146,7 +172,7 @@ private async Task PrepareAsync(IOBehavior ioBehavior, CancellationToken cancell
146172
preparedStatements.Add(new PreparedStatement(response.StatementId, statement, columns, parameters));
147173
}
148174

149-
m_connection.Session.AddPreparedStatement(CommandText, new PreparedStatements(preparedStatements, parsedStatements));
175+
Connection.Session.AddPreparedStatement(CommandText, new PreparedStatements(preparedStatements, parsedStatements));
150176
}
151177

152178
public override string CommandText

src/MySqlConnector/Utilities/Utility.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,31 @@ public static TimeSpan ParseTimeSpan(ReadOnlySpan<byte> value)
301301
}
302302

303303
#if NET45
304+
public static Task CompletedTask
305+
{
306+
get
307+
{
308+
if (s_completedTask == null)
309+
{
310+
var tcs = new TaskCompletionSource<object>();
311+
tcs.SetResult(null);
312+
s_completedTask = tcs.Task;
313+
}
314+
return s_completedTask;
315+
}
316+
}
317+
static Task s_completedTask;
318+
319+
public static Task TaskFromException(Exception exception) => TaskFromException<object>(exception);
304320
public static Task<T> TaskFromException<T>(Exception exception)
305321
{
306322
var tcs = new TaskCompletionSource<T>();
307323
tcs.SetException(exception);
308324
return tcs.Task;
309325
}
310326
#else
327+
public static Task CompletedTask => Task.CompletedTask;
328+
public static Task TaskFromException(Exception exception) => Task.FromException(exception);
311329
public static Task<T> TaskFromException<T>(Exception exception) => Task.FromException<T>(exception);
312330
#endif
313331

0 commit comments

Comments
 (0)