Skip to content

Commit f4cf70f

Browse files
committed
Fix bugs escaping characters in MySqlBulkCopy.
1 parent 8762229 commit f4cf70f

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ static bool WriteString(string value, Span<byte> output, out int bytesWritten)
356356
bytesWritten = 0;
357357
while (index < value.Length)
358358
{
359-
if (value[index] == '\t' || value[index] == '\\')
359+
if (Array.IndexOf(s_specialCharacters, value[index]) != -1)
360360
{
361361
if (output.Length < 2)
362362
{
@@ -365,13 +365,14 @@ static bool WriteString(string value, Span<byte> output, out int bytesWritten)
365365
}
366366

367367
output[0] = (byte) '\\';
368-
output[1] = value[index] == '\t' ? (byte) 't' : (byte) '\\';
368+
output[1] = (byte) value[index];
369369
output = output.Slice(2);
370370
bytesWritten += 2;
371+
index++;
371372
}
372373
else
373374
{
374-
var nextIndex = value.IndexOfAny(new char[] { '\t', '\\' }, index);
375+
var nextIndex = value.IndexOfAny(s_specialCharacters, index);
375376
if (nextIndex == -1)
376377
nextIndex = value.Length;
377378
var encodedBytesWritten = Encoding.UTF8.GetBytes(value.AsSpan(index, nextIndex - index), output);
@@ -414,6 +415,7 @@ static bool WriteBytes(ReadOnlySpan<byte> value, Span<byte> output, out int byte
414415
}
415416

416417
private static ReadOnlySpan<byte> EscapedNull => new byte[] { 0x5C, 0x4E };
418+
private static readonly char[] s_specialCharacters = new char[] { '\t', '\\', '\n' };
417419

418420
readonly MySqlConnection m_connection;
419421
readonly MySqlTransaction? m_transaction;

tests/SideBySide/BulkLoaderSync.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,49 @@ public void BulkLoadDataTableWithLongData()
525525
bulkCopy.WriteToServer(dataTable);
526526
}
527527

528+
[Fact]
529+
public void BulkLoadDataTableWithSpecialCharacters()
530+
{
531+
var dataTable = new DataTable()
532+
{
533+
Columns =
534+
{
535+
new DataColumn("id", typeof(int)),
536+
new DataColumn("data", typeof(string)),
537+
},
538+
};
539+
540+
var strings = new[] { " ", "\t", ",", "\n", "\r", "\\", "ab\t", "\tcd", "ab\tcd", "\tab\ncd\t" };
541+
for (var i = 0; i < strings.Length; i++)
542+
dataTable.Rows.Add(i, strings[i]);
543+
544+
using var connection = new MySqlConnection(GetLocalConnectionString());
545+
connection.Open();
546+
using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table;
547+
create table bulk_load_data_table(a int, b text);", connection))
548+
{
549+
cmd.ExecuteNonQuery();
550+
}
551+
552+
var bulkCopy = new MySqlBulkCopy(connection)
553+
{
554+
DestinationTableName = "bulk_load_data_table",
555+
};
556+
bulkCopy.WriteToServer(dataTable);
557+
558+
using (var cmd = new MySqlCommand("select * from bulk_load_data_table order by a;", connection))
559+
using (var reader = cmd.ExecuteReader())
560+
{
561+
for (int i = 0; i < strings.Length; i++)
562+
{
563+
Assert.True(reader.Read());
564+
Assert.Equal(i, reader.GetInt32(0));
565+
Assert.Equal(strings[i], reader.GetString(1));
566+
}
567+
Assert.False(reader.Read());
568+
}
569+
}
570+
528571
[Fact]
529572
public void BulkLoadDataTableWithTooLongData()
530573
{

0 commit comments

Comments
 (0)