Skip to content

Commit 48b0cfc

Browse files
committed
Throw exception if not all rows were copied. Fixes #814
1 parent 6c49dc0 commit 48b0cfc

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBehavior, CancellationTo
128128
#endif
129129
{
130130
var tableName = DestinationTableName ?? throw new InvalidOperationException("DestinationTableName must be set before calling WriteToServer");
131+
m_wasAborted = false;
131132

132133
Log.Info("Starting bulk copy to {0}", tableName);
133134
var bulkLoader = new MySqlBulkLoader(m_connection)
@@ -215,13 +216,19 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBehavior, CancellationTo
215216
throw new InvalidOperationException("SourceOrdinal {0} is an invalid value".FormatInvariant(columnMapping.SourceOrdinal));
216217
}
217218

218-
await bulkLoader.LoadAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
219+
var rowsInserted = await bulkLoader.LoadAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
219220

220221
if (closeConnection)
221222
m_connection.Close();
222223

223224
Log.Info("Finished bulk copy to {0}", tableName);
224225

226+
if (!m_wasAborted && rowsInserted != RowsCopied)
227+
{
228+
Log.Error("Bulk copy to DestinationTableName={0} failed; RowsCopied={1}; RowsInserted={2}", tableName, RowsCopied, rowsInserted);
229+
throw new MySqlException(MySqlErrorCode.BulkCopyFailed, "{0} rows were copied to {1} but only {2} were inserted.".FormatInvariant(RowsCopied, tableName, rowsInserted));
230+
}
231+
225232
#if !NETSTANDARD2_1 && !NETCOREAPP3_0
226233
return default;
227234
#endif
@@ -330,6 +337,7 @@ await m_valuesEnumerator.MoveNextAsync().ConfigureAwait(false) :
330337
finally
331338
{
332339
ArrayPool<byte>.Shared.Return(buffer);
340+
m_wasAborted = eventArgs?.Abort ?? false;
333341
}
334342

335343
static bool WriteValue(MySqlConnection connection, object? value, Span<byte> output, out int bytesWritten)
@@ -558,5 +566,6 @@ static bool WriteBytes(ReadOnlySpan<byte> value, Span<byte> output, out int byte
558566
readonly MySqlConnection m_connection;
559567
readonly MySqlTransaction? m_transaction;
560568
IValuesEnumerator? m_valuesEnumerator;
569+
bool m_wasAborted;
561570
}
562571
}

src/MySqlConnector/MySql.Data.MySqlClient/MySqlErrorCode.g.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ namespace MySql.Data.MySqlClient
66
[System.CodeDom.Compiler.GeneratedCode("https://gist.github.com/bgrainger/791cecb647d514a9dd2f3d83b2387e49", "2")]
77
public enum MySqlErrorCode
88
{
9+
/// <summary>
10+
/// Not all rows from the source supplied to <see cref="MySqlBulkCopy"/> were copied to <see cref="MySqlBulkCopy.DestinationTableName"/>.
11+
/// </summary>
12+
BulkCopyFailed = -2,
13+
914
/// <summary>
1015
/// The timeout period specified by <see cref="MySqlCommand.CommandTimeout"/> elapsed before the operation completed.
1116
/// </summary>

tests/SideBySide/BulkLoaderSync.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,45 @@ public void BulkCopyColumnMappingsInvalidDestinationColumn()
918918

919919
Assert.Throws<InvalidOperationException>(() => bulkCopy.WriteToServer(dataTable));
920920
}
921+
922+
[Fact]
923+
public void BulkCopyDoesNotInsertAllRows()
924+
{
925+
using var connection = new MySqlConnection(GetLocalConnectionString());
926+
connection.Open();
927+
928+
connection.Execute(@"drop table if exists bulk_copy_duplicate_pk;
929+
create table bulk_copy_duplicate_pk(id integer primary key, value text not null);");
930+
931+
var bcp = new MySqlBulkCopy(connection)
932+
{
933+
DestinationTableName = "bulk_copy_duplicate_pk"
934+
};
935+
936+
var dataTable = new DataTable()
937+
{
938+
Columns =
939+
{
940+
new DataColumn("id", typeof(int)),
941+
new DataColumn("value", typeof(string)),
942+
},
943+
Rows =
944+
{
945+
new object[] { 1, "a" },
946+
new object[] { 1, "b" },
947+
new object[] { 3, "c" },
948+
}
949+
};
950+
951+
try
952+
{
953+
bcp.WriteToServer(dataTable);
954+
Assert.True(false, "Exception wasn't thrown");
955+
}
956+
catch (MySqlException ex) when (ex.Number == (int) MySqlErrorCode.BulkCopyFailed)
957+
{
958+
}
959+
}
921960
#endif
922961

923962
[Fact]

0 commit comments

Comments
 (0)