From 52879e68e5067b2261a06ff08baa8e609cb89d2f Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Wed, 1 Oct 2025 04:38:17 -0700 Subject: [PATCH 1/2] Fix mappings for extra columns in schema. Fixes #1568 This creates/updates column mappings for columns in the DB schema that have a higher ordinal number than columns in the source data. Signed-off-by: Bradley Grainger --- src/MySqlConnector/MySqlBulkCopy.cs | 4 +- tests/IntegrationTests/BulkLoaderAsync.cs | 39 +++++++++++++++++++ tests/IntegrationTests/BulkLoaderSync.cs | 39 +++++++++++++++++++ .../IntegrationTests/IntegrationTests.csproj | 2 +- 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/MySqlConnector/MySqlBulkCopy.cs b/src/MySqlConnector/MySqlBulkCopy.cs index de4ccb8e5..7aea3fbe4 100644 --- a/src/MySqlConnector/MySqlBulkCopy.cs +++ b/src/MySqlConnector/MySqlBulkCopy.cs @@ -266,7 +266,7 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBeh using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SchemaOnly, ioBehavior, cancellationToken).ConfigureAwait(false)) { var schema = reader.GetColumnSchema(); - for (var i = 0; i < Math.Min(m_valuesEnumerator!.FieldCount, schema.Count); i++) + for (var i = 0; i < schema.Count; i++) { var destinationColumn = reader.GetName(i); if (schema[i].DataTypeName == "BIT") @@ -295,7 +295,7 @@ private async ValueTask WriteToServerAsync(IOBehavior ioBeh } // set columns and expressions from the column mappings - for (var i = 0; i < m_valuesEnumerator.FieldCount; i++) + for (var i = 0; i < m_valuesEnumerator!.FieldCount; i++) { var columnMapping = columnMappings.FirstOrDefault(x => x.SourceOrdinal == i); if (columnMapping is null) diff --git a/tests/IntegrationTests/BulkLoaderAsync.cs b/tests/IntegrationTests/BulkLoaderAsync.cs index ddd11c4a4..78fc127ba 100644 --- a/tests/IntegrationTests/BulkLoaderAsync.cs +++ b/tests/IntegrationTests/BulkLoaderAsync.cs @@ -635,6 +635,45 @@ public async Task BulkCopyNullDataReader() var bulkCopy = new MySqlBulkCopy(connection); await Assert.ThrowsAsync(async () => await bulkCopy.WriteToServerAsync(default(DbDataReader))); } + + [Fact] + public async Task BulkCopyGeometryAsync() + { + var dataTable = new DataTable() + { + Columns = + { + new DataColumn("geo_data", typeof(MySqlGeometry)), + }, + Rows = + { + new object[] { MySqlGeometry.FromWkb(4326, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, + }, + }; + + using var connection = new MySqlConnection(GetLocalConnectionString()); + await connection.OpenAsync(); + using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table; +create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY SRID 4326 NOT NULL);", connection)) + { + await cmd.ExecuteNonQueryAsync(); + } + + var bc = new MySqlBulkCopy(connection) + { + DestinationTableName = "bulk_load_data_table", + ColumnMappings = + { + new() + { + SourceOrdinal = 0, + DestinationColumn = "geo_data", + }, + }, + }; + + await bc.WriteToServerAsync(dataTable); + } #endif private static string GetConnectionString() => BulkLoaderSync.GetConnectionString(); diff --git a/tests/IntegrationTests/BulkLoaderSync.cs b/tests/IntegrationTests/BulkLoaderSync.cs index ddcb849cc..3c4fdae5d 100644 --- a/tests/IntegrationTests/BulkLoaderSync.cs +++ b/tests/IntegrationTests/BulkLoaderSync.cs @@ -1284,6 +1284,45 @@ public void BulkCopyDataTableConflictOption(MySqlBulkLoaderConflictOption confli using (var cmd = new MySqlCommand("select b from bulk_load_data_table;", connection)) Assert.Equal(expected, cmd.ExecuteScalar()); } + + [Fact] + public void BulkCopyGeometry() + { + var dataTable = new DataTable() + { + Columns = + { + new DataColumn("geo_data", typeof(MySqlGeometry)), + }, + Rows = + { + new object[] { MySqlGeometry.FromWkb(4326, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, + }, + }; + + using var connection = new MySqlConnection(GetLocalConnectionString()); + connection.Open(); + using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table; +create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY SRID 4326 NOT NULL);", connection)) + { + cmd.ExecuteNonQuery(); + } + + var bc = new MySqlBulkCopy(connection) + { + DestinationTableName = "bulk_load_data_table", + ColumnMappings = + { + new() + { + SourceOrdinal = 0, + DestinationColumn = "geo_data", + }, + }, + }; + + bc.WriteToServer(dataTable); + } #endif internal static string GetConnectionString() => AppConfig.ConnectionString; diff --git a/tests/IntegrationTests/IntegrationTests.csproj b/tests/IntegrationTests/IntegrationTests.csproj index bb388f662..df7f1706a 100644 --- a/tests/IntegrationTests/IntegrationTests.csproj +++ b/tests/IntegrationTests/IntegrationTests.csproj @@ -23,7 +23,7 @@ true true 64 - 11.0 + 12.0 enable $(NoWarn);SA0001;SA1021;SA1133;xUnit1030 From 37d01d646f09411170ef4e742b6b64f7066495a3 Mon Sep 17 00:00:00 2001 From: Bradley Grainger Date: Wed, 1 Oct 2025 04:58:43 -0700 Subject: [PATCH 2/2] Delete SRID in tests. This improves compatibility with other MySQL servers and doesn't materially affect the test case. Signed-off-by: Bradley Grainger --- tests/IntegrationTests/BulkLoaderAsync.cs | 4 ++-- tests/IntegrationTests/BulkLoaderSync.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/IntegrationTests/BulkLoaderAsync.cs b/tests/IntegrationTests/BulkLoaderAsync.cs index 78fc127ba..dae9362e5 100644 --- a/tests/IntegrationTests/BulkLoaderAsync.cs +++ b/tests/IntegrationTests/BulkLoaderAsync.cs @@ -647,14 +647,14 @@ public async Task BulkCopyGeometryAsync() }, Rows = { - new object[] { MySqlGeometry.FromWkb(4326, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, + new object[] { MySqlGeometry.FromWkb(0, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, }, }; using var connection = new MySqlConnection(GetLocalConnectionString()); await connection.OpenAsync(); using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table; -create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY SRID 4326 NOT NULL);", connection)) +create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY NOT NULL);", connection)) { await cmd.ExecuteNonQueryAsync(); } diff --git a/tests/IntegrationTests/BulkLoaderSync.cs b/tests/IntegrationTests/BulkLoaderSync.cs index 3c4fdae5d..89e553361 100644 --- a/tests/IntegrationTests/BulkLoaderSync.cs +++ b/tests/IntegrationTests/BulkLoaderSync.cs @@ -1296,14 +1296,14 @@ public void BulkCopyGeometry() }, Rows = { - new object[] { MySqlGeometry.FromWkb(4326, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, + new object[] { MySqlGeometry.FromWkb(0, [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 240, 63]) }, }, }; using var connection = new MySqlConnection(GetLocalConnectionString()); connection.Open(); using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table; -create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY SRID 4326 NOT NULL);", connection)) +create table bulk_load_data_table(id BIGINT UNIQUE NOT NULL AUTO_INCREMENT, geo_data GEOMETRY NOT NULL);", connection)) { cmd.ExecuteNonQuery(); }