1
1
using System ;
2
+ using System . Buffers . Text ;
2
3
using System . Data ;
3
4
using System . Data . Common ;
4
- using System . IO ;
5
+ using System . Diagnostics ;
5
6
using MySqlConnector . Core ;
7
+ using MySqlConnector . Protocol . Serialization ;
6
8
using MySqlConnector . Utilities ;
7
9
8
10
namespace MySql . Data . MySqlClient
@@ -175,16 +177,16 @@ private MySqlParameter(MySqlParameter other, string parameterName)
175
177
176
178
internal string NormalizedParameterName { get ; private set ; }
177
179
178
- internal void AppendSqlString ( BinaryWriter writer , StatementPreparerOptions options , string parameterName )
180
+ internal void AppendSqlString ( ByteBufferWriter writer , StatementPreparerOptions options , string parameterName )
179
181
{
180
182
if ( Value == null || Value == DBNull . Value )
181
183
{
182
- writer . WriteUtf8 ( "NULL" ) ;
184
+ writer . Write ( s_nullBytes ) ;
183
185
}
184
186
else if ( Value is string stringValue )
185
187
{
186
188
writer . Write ( ( byte ) '\' ' ) ;
187
- writer . WriteUtf8 ( stringValue . Replace ( "\\ " , "\\ \\ " ) . Replace ( "'" , "\\ '" ) ) ;
189
+ writer . Write ( stringValue . Replace ( "\\ " , "\\ \\ " ) . Replace ( "'" , "\\ '" ) ) ;
188
190
writer . Write ( ( byte ) '\' ' ) ;
189
191
}
190
192
else if ( Value is char charValue )
@@ -199,44 +201,70 @@ internal void AppendSqlString(BinaryWriter writer, StatementPreparerOptions opti
199
201
break ;
200
202
201
203
default :
202
- writer . WriteUtf8 ( charValue . ToString ( ) ) ;
204
+ writer . Write ( charValue . ToString ( ) ) ;
203
205
break ;
204
206
}
205
207
writer . Write ( ( byte ) '\' ' ) ;
206
208
}
207
- else if ( Value is byte || Value is sbyte || Value is short || Value is int || Value is long || Value is ushort || Value is uint || Value is ulong || Value is decimal )
209
+ else if ( Value is byte || Value is sbyte || Value is decimal )
208
210
{
209
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( Value ) ) ;
211
+ writer . Write ( "{0}" . FormatInvariant ( Value ) ) ;
212
+ }
213
+ else if ( Value is short shortValue )
214
+ {
215
+ writer . WriteString ( shortValue ) ;
216
+ }
217
+ else if ( Value is ushort ushortValue )
218
+ {
219
+ writer . WriteString ( ushortValue ) ;
220
+ }
221
+ else if ( Value is int intValue )
222
+ {
223
+ writer . WriteString ( intValue ) ;
224
+ }
225
+ else if ( Value is uint uintValue )
226
+ {
227
+ writer . WriteString ( uintValue ) ;
228
+ }
229
+ else if ( Value is long longValue )
230
+ {
231
+ writer . WriteString ( longValue ) ;
232
+ }
233
+ else if ( Value is ulong ulongValue )
234
+ {
235
+ writer . WriteString ( ulongValue ) ;
210
236
}
211
237
else if ( Value is byte [ ] byteArrayValue )
212
238
{
213
239
// determine the number of bytes to be written
214
- const string c_prefix = "_binary'" ;
215
- var length = byteArrayValue . Length + c_prefix . Length + 1 ;
240
+ var length = byteArrayValue . Length + s_binaryBytes . Length + 1 ;
216
241
foreach ( var by in byteArrayValue )
217
242
{
218
243
if ( by == 0x27 || by == 0x5C )
219
244
length ++ ;
220
245
}
221
246
222
- ( ( MemoryStream ) writer . BaseStream ) . Capacity = ( int ) writer . BaseStream . Length + length ;
223
-
224
- writer . WriteUtf8 ( c_prefix ) ;
247
+ var span = writer . GetSpan ( length ) ;
248
+ s_binaryBytes . CopyTo ( span ) ;
249
+ var index = s_binaryBytes . Length ;
225
250
foreach ( var by in byteArrayValue )
226
251
{
227
252
if ( by == 0x27 || by == 0x5C )
228
- writer . Write ( ( byte ) 0x5C ) ;
229
- writer . Write ( by ) ;
253
+ span [ index ++ ] = 0x5C ;
254
+ span [ index ++ ] = by ;
230
255
}
231
- writer . Write ( ( byte ) '\' ' ) ;
256
+ span [ index ++ ] = 0x27 ;
257
+ Debug . Assert ( index == length , "index == length" ) ;
258
+ writer . Advance ( index ) ;
232
259
}
233
260
else if ( Value is bool boolValue )
234
261
{
235
- writer . WriteUtf8 ( boolValue ? "true" : "false" ) ;
262
+ writer . Write ( boolValue ? s_trueBytes : s_falseBytes ) ;
236
263
}
237
264
else if ( Value is float || Value is double )
238
265
{
239
- writer . WriteUtf8 ( "{0:R}" . FormatInvariant ( Value ) ) ;
266
+ // NOTE: Utf8Formatter doesn't support "R"
267
+ writer . Write ( "{0:R}" . FormatInvariant ( Value ) ) ;
240
268
}
241
269
else if ( Value is DateTime dateTimeValue )
242
270
{
@@ -245,22 +273,22 @@ internal void AppendSqlString(BinaryWriter writer, StatementPreparerOptions opti
245
273
else if ( ( options & StatementPreparerOptions . DateTimeLocal ) != 0 && dateTimeValue . Kind == DateTimeKind . Utc )
246
274
throw new MySqlException ( "DateTime.Kind must not be Utc when DateTimeKind setting is Local (parameter name: {0})" . FormatInvariant ( parameterName ) ) ;
247
275
248
- writer . WriteUtf8 ( "timestamp('{0:yyyy'-'MM'-'dd' 'HH':'mm':'ss'.'ffffff}')" . FormatInvariant ( dateTimeValue ) ) ;
276
+ writer . Write ( "timestamp('{0:yyyy'-'MM'-'dd' 'HH':'mm':'ss'.'ffffff}')" . FormatInvariant ( dateTimeValue ) ) ;
249
277
}
250
278
else if ( Value is DateTimeOffset dateTimeOffsetValue )
251
279
{
252
280
// store as UTC as it will be read as such when deserialized from a timespan column
253
- writer . WriteUtf8 ( "timestamp('{0:yyyy'-'MM'-'dd' 'HH':'mm':'ss'.'ffffff}')" . FormatInvariant ( dateTimeOffsetValue . UtcDateTime ) ) ;
281
+ writer . Write ( "timestamp('{0:yyyy'-'MM'-'dd' 'HH':'mm':'ss'.'ffffff}')" . FormatInvariant ( dateTimeOffsetValue . UtcDateTime ) ) ;
254
282
}
255
283
else if ( Value is TimeSpan ts )
256
284
{
257
- writer . WriteUtf8 ( "time '" ) ;
285
+ writer . Write ( "time '" ) ;
258
286
if ( ts . Ticks < 0 )
259
287
{
260
288
writer . Write ( ( byte ) '-' ) ;
261
289
ts = TimeSpan . FromTicks ( - ts . Ticks ) ;
262
290
}
263
- writer . WriteUtf8 ( "{0}:{1:mm':'ss'.'ffffff}'" . FormatInvariant ( ts . Days * 24 + ts . Hours , ts ) ) ;
291
+ writer . Write ( "{0}:{1:mm':'ss'.'ffffff}'" . FormatInvariant ( ts . Days * 24 + ts . Hours , ts ) ) ;
264
292
}
265
293
else if ( Value is Guid guidValue )
266
294
{
@@ -287,7 +315,7 @@ internal void AppendSqlString(BinaryWriter writer, StatementPreparerOptions opti
287
315
Utility . SwapBytes ( bytes , 1 , 3 ) ;
288
316
}
289
317
}
290
- writer . WriteUtf8 ( "_binary'" ) ;
318
+ writer . Write ( s_binaryBytes ) ;
291
319
foreach ( var by in bytes )
292
320
{
293
321
if ( by == 0x27 || by == 0x5C )
@@ -296,46 +324,48 @@ internal void AppendSqlString(BinaryWriter writer, StatementPreparerOptions opti
296
324
}
297
325
writer . Write ( ( byte ) '\' ' ) ;
298
326
}
299
- else if ( guidOptions == StatementPreparerOptions . GuidFormatChar32 )
300
- {
301
- writer . WriteUtf8 ( "'{0:N}'" . FormatInvariant ( guidValue ) ) ;
302
- }
303
327
else
304
328
{
305
- writer . WriteUtf8 ( "'{0:D}'" . FormatInvariant ( guidValue ) ) ;
329
+ var is32Characters = guidOptions == StatementPreparerOptions . GuidFormatChar32 ;
330
+ var guidLength = is32Characters ? 34 : 38 ;
331
+ var span = writer . GetSpan ( guidLength ) ;
332
+ span [ 0 ] = 0x27 ;
333
+ Utf8Formatter . TryFormat ( guidValue , span . Slice ( 1 ) , out _ , is32Characters ? 'N' : 'D' ) ;
334
+ span [ guidLength - 1 ] = 0x27 ;
335
+ writer . Advance ( guidLength ) ;
306
336
}
307
337
}
308
338
else if ( MySqlDbType == MySqlDbType . Int16 )
309
339
{
310
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( short ) Value ) ) ;
340
+ writer . WriteString ( ( short ) Value ) ;
311
341
}
312
342
else if ( MySqlDbType == MySqlDbType . UInt16 )
313
343
{
314
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( ushort ) Value ) ) ;
344
+ writer . WriteString ( ( ushort ) Value ) ;
315
345
}
316
346
else if ( MySqlDbType == MySqlDbType . Int32 )
317
347
{
318
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( int ) Value ) ) ;
348
+ writer . WriteString ( ( int ) Value ) ;
319
349
}
320
350
else if ( MySqlDbType == MySqlDbType . UInt32 )
321
351
{
322
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( uint ) Value ) ) ;
352
+ writer . WriteString ( ( uint ) Value ) ;
323
353
}
324
354
else if ( MySqlDbType == MySqlDbType . Int64 )
325
355
{
326
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( long ) Value ) ) ;
356
+ writer . WriteString ( ( long ) Value ) ;
327
357
}
328
358
else if ( MySqlDbType == MySqlDbType . UInt64 )
329
359
{
330
- writer . WriteUtf8 ( "{0}" . FormatInvariant ( ( ulong ) Value ) ) ;
360
+ writer . WriteString ( ( ulong ) Value ) ;
331
361
}
332
362
else if ( ( MySqlDbType == MySqlDbType . String || MySqlDbType == MySqlDbType . VarChar ) && HasSetDbType && Value is Enum )
333
363
{
334
- writer . WriteUtf8 ( "'{0:G}'" . FormatInvariant ( Value ) ) ;
364
+ writer . Write ( "'{0:G}'" . FormatInvariant ( Value ) ) ;
335
365
}
336
366
else if ( Value is Enum )
337
367
{
338
- writer . WriteUtf8 ( "{0:d}" . FormatInvariant ( Value ) ) ;
368
+ writer . Write ( "{0:d}" . FormatInvariant ( Value ) ) ;
339
369
}
340
370
else
341
371
{
@@ -357,6 +387,11 @@ internal static string NormalizeParameterName(string name)
357
387
return name . StartsWith ( "@" , StringComparison . Ordinal ) || name . StartsWith ( "?" , StringComparison . Ordinal ) ? name . Substring ( 1 ) : name ;
358
388
}
359
389
390
+ static readonly byte [ ] s_nullBytes = { 0x4E , 0x55 , 0x4C , 0x4C } ; // NULL
391
+ static readonly byte [ ] s_trueBytes = { 0x74 , 0x72 , 0x75 , 0x65 } ; // true
392
+ static readonly byte [ ] s_falseBytes = { 0x66 , 0x61 , 0x6C , 0x73 , 0x65 } ; // false
393
+ static readonly byte [ ] s_binaryBytes = { 0x5F , 0x62 , 0x69 , 0x6E , 0x61 , 0x72 , 0x79 , 0x27 } ; // _binary'
394
+
360
395
DbType m_dbType ;
361
396
MySqlDbType m_mySqlDbType ;
362
397
string m_name ;
0 commit comments