@@ -65,26 +65,56 @@ public MySqlCommand(string commandText, MySqlConnection connection, MySqlTransac
65
65
66
66
public new MySqlDataReader ExecuteReader ( CommandBehavior commandBehavior ) => ( MySqlDataReader ) base . ExecuteReader ( commandBehavior ) ;
67
67
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
+
69
80
public Task PrepareAsync ( ) => PrepareAsync ( AsyncIOBehavior , default ) ;
70
81
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 )
73
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 )
92
+ {
93
+ exception = null ;
74
94
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 ;
84
105
85
106
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
+ }
111
+
112
+ // don't prepare the same SQL twice
113
+ return Connection . Session . TryGetPreparedStatement ( CommandText ) == null ;
114
+ }
87
115
116
+ private async Task DoPrepareAsync ( IOBehavior ioBehavior , CancellationToken cancellationToken )
117
+ {
88
118
var statementPreparer = new StatementPreparer ( CommandText , Parameters , CreateStatementPreparerOptions ( ) ) ;
89
119
var parsedStatements = statementPreparer . SplitStatements ( ) ;
90
120
@@ -142,8 +172,7 @@ private async Task PrepareAsync(IOBehavior ioBehavior, CancellationToken cancell
142
172
preparedStatements . Add ( new PreparedStatement ( response . StatementId , statement , columns , parameters ) ) ;
143
173
}
144
174
145
- m_parsedStatements = parsedStatements ;
146
- m_statements = preparedStatements ;
175
+ Connection . Session . AddPreparedStatement ( CommandText , new PreparedStatements ( preparedStatements , parsedStatements ) ) ;
147
176
}
148
177
149
178
public override string CommandText
@@ -154,11 +183,10 @@ public override string CommandText
154
183
if ( m_connection ? . HasActiveReader ?? false )
155
184
throw new InvalidOperationException ( "Cannot set MySqlCommand.CommandText when there is an open DataReader for this command; it must be closed first." ) ;
156
185
m_commandText = value ;
157
- ClearPreparedStatements ( ) ;
158
186
}
159
187
}
160
188
161
- public bool IsPrepared => m_statements != null ;
189
+ public bool IsPrepared => TryGetPreparedStatement ( ) != null ;
162
190
163
191
public new MySqlTransaction Transaction { get ; set ; }
164
192
@@ -170,7 +198,6 @@ public override string CommandText
170
198
if ( m_connection ? . HasActiveReader ?? false )
171
199
throw new InvalidOperationException ( "Cannot set MySqlCommand.Connection when there is an open DataReader for this command; it must be closed first." ) ;
172
200
m_connection = value ;
173
- ClearPreparedStatements ( ) ;
174
201
}
175
202
}
176
203
@@ -188,7 +215,6 @@ public override CommandType CommandType
188
215
if ( value != CommandType . Text && value != CommandType . StoredProcedure )
189
216
throw new ArgumentException ( "CommandType must be Text or StoredProcedure." , nameof ( value ) ) ;
190
217
m_commandType = value ;
191
- ClearPreparedStatements ( ) ;
192
218
}
193
219
}
194
220
@@ -277,8 +303,9 @@ internal Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior, IOBehav
277
303
if ( ! IsValid ( out var exception ) )
278
304
return Utility . TaskFromException < DbDataReader > ( exception ) ;
279
305
280
- if ( m_statements != null )
281
- m_commandExecutor = new PreparedStatementCommandExecutor ( this ) ;
306
+ var preparedStatements = TryGetPreparedStatement ( ) ;
307
+ if ( preparedStatements != null )
308
+ m_commandExecutor = new PreparedStatementCommandExecutor ( this , preparedStatements ) ;
282
309
else if ( m_commandType == CommandType . Text )
283
310
m_commandExecutor = new TextCommandExecutor ( this ) ;
284
311
else if ( m_commandType == CommandType . StoredProcedure )
@@ -292,10 +319,7 @@ protected override void Dispose(bool disposing)
292
319
try
293
320
{
294
321
if ( disposing )
295
- {
296
322
m_parameterCollection = null ;
297
- ClearPreparedStatements ( ) ;
298
- }
299
323
}
300
324
finally
301
325
{
@@ -324,8 +348,6 @@ internal IDisposable RegisterCancel(CancellationToken token)
324
348
325
349
internal int CancelAttemptCount { get ; set ; }
326
350
327
- internal IReadOnlyList < PreparedStatement > PreparedStatements => m_statements ;
328
-
329
351
/// <summary>
330
352
/// Causes the effective command timeout to be reset back to the value specified by <see cref="CommandTimeout"/>.
331
353
/// </summary>
@@ -400,12 +422,7 @@ private bool IsValid(out Exception exception)
400
422
return exception == null ;
401
423
}
402
424
403
- private void ClearPreparedStatements ( )
404
- {
405
- m_parsedStatements ? . Dispose ( ) ;
406
- m_parsedStatements = null ;
407
- m_statements = null ;
408
- }
425
+ private PreparedStatements TryGetPreparedStatement ( ) => CommandType == CommandType . Text && ! string . IsNullOrWhiteSpace ( CommandText ) ? m_connection . Session . TryGetPreparedStatement ( CommandText ) : null ;
409
426
410
427
internal void ReaderClosed ( ) => ( m_commandExecutor as StoredProcedureCommandExecutor ) ? . SetParams ( ) ;
411
428
@@ -414,8 +431,6 @@ private void ClearPreparedStatements()
414
431
MySqlConnection m_connection ;
415
432
string m_commandText ;
416
433
MySqlParameterCollection m_parameterCollection ;
417
- ParsedStatements m_parsedStatements ;
418
- IReadOnlyList < PreparedStatement > m_statements ;
419
434
int ? m_commandTimeout ;
420
435
CommandType m_commandType ;
421
436
ICommandExecutor m_commandExecutor ;
0 commit comments