Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9eab02a

Browse files
Support VECTOR in MySqlBulkCopy. Fixes #1604
1 parent 09be112 commit 9eab02a

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

‎src/MySqlConnector/MySqlBulkCopy.cs‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,17 @@ private async ValueTask<MySqlBulkCopyResult> WriteToServerAsync(IOBehavior ioBeh
234234
for (var i = 0; i < schema.Count; i++)
235235
{
236236
var destinationColumn = reader.GetName(i);
237-
if (schema[i].DataTypeName == "BIT")
237+
var dataTypeName = schema[i].DataTypeName;
238+
if (dataTypeName == "BIT")
238239
{
239240
AddColumnMapping(m_logger, columnMappings, addDefaultMappings, i, destinationColumn, $"@`\uE002\bcol{i}`", $"%COL% = CAST(%VAR% AS UNSIGNED)");
240241
}
241242
else
242243
{
243244
var type = schema[i].DataType;
244-
if (type == typeof(byte[]) || (type == typeof(Guid) && (m_connection.GuidFormat is MySqlGuidFormat.Binary16 or MySqlGuidFormat.LittleEndianBinary16 or MySqlGuidFormat.TimeSwapBinary16)))
245+
if (type == typeof(byte[]) ||
246+
dataTypeName == "VECTOR" ||
247+
(type == typeof(Guid) && (m_connection.GuidFormat is MySqlGuidFormat.Binary16 or MySqlGuidFormat.LittleEndianBinary16 or MySqlGuidFormat.TimeSwapBinary16)))
245248
{
246249
AddColumnMapping(m_logger, columnMappings, addDefaultMappings, i, destinationColumn, $"@`\uE002\bcol{i}`", $"%COL% = UNHEX(%VAR%)");
247250
}
@@ -471,14 +474,17 @@ static bool WriteValue(MySqlConnection connection, object value, ref int inputIn
471474
{
472475
return Utf8Formatter.TryFormat(decimalValue, output, out bytesWritten);
473476
}
474-
else if (value is byte[] or ReadOnlyMemory<byte> or Memory<byte> or ArraySegment<byte> or MySqlGeometry)
477+
else if (value is byte[] or ReadOnlyMemory<byte> or Memory<byte> or ArraySegment<byte> or MySqlGeometry or float[] or ReadOnlyMemory<float> or Memory<float>)
475478
{
476479
var inputSpan = value switch
477480
{
478481
byte[] byteArray => byteArray.AsSpan(),
479482
ArraySegment<byte> arraySegment => arraySegment.AsSpan(),
480483
Memory<byte> memory => memory.Span,
481484
MySqlGeometry geometry => geometry.ValueSpan,
485+
float[] floatArray => MySqlParameter.ConvertFloatsToBytes(floatArray.AsSpan()),
486+
Memory<float> memory => MySqlParameter.ConvertFloatsToBytes(memory.Span),
487+
ReadOnlyMemory<float> memory => MySqlParameter.ConvertFloatsToBytes(memory.Span),
482488
_ => ((ReadOnlyMemory<byte>) value).Span,
483489
};
484490

‎src/MySqlConnector/MySqlParameter.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ private static void WriteTime(ByteBufferWriter writer, TimeSpan timeSpan)
997997
}
998998
}
999999

1000-
private static ReadOnlySpan<byte> ConvertFloatsToBytes(ReadOnlySpan<float> floats)
1000+
internal static ReadOnlySpan<byte> ConvertFloatsToBytes(ReadOnlySpan<float> floats)
10011001
{
10021002
if (BitConverter.IsLittleEndian)
10031003
{

‎tests/IntegrationTests/BulkLoaderSync.cs‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Runtime.InteropServices;
12
using Xunit.Sdk;
23

34
namespace IntegrationTests;
@@ -588,6 +589,71 @@ public void BulkCopyDataTableWithMySqlDecimal()
588589
}
589590
}
590591

592+
[SkippableTheory(ServerFeatures.Vector)]
593+
[InlineData("byte[]")]
594+
[InlineData("float[]")]
595+
public void BulkCopyDataTableWithVector(string dataType)
596+
{
597+
var dataTable = new DataTable()
598+
{
599+
Columns =
600+
{
601+
new DataColumn("id", typeof(int)),
602+
new DataColumn("data",
603+
#pragma warning disable SA1118 // Parameter should not span multiple lines
604+
dataType switch
605+
{
606+
"byte[]" => typeof(byte[]),
607+
"float[]" => typeof(float[]),
608+
_ => throw new ArgumentOutOfRangeException(nameof(dataType)),
609+
}),
610+
#pragma warning restore SA1118 // Parameter should not span multiple lines
611+
},
612+
Rows =
613+
{
614+
new object[] { 1, GetDataRowValue([0, 0, 0], dataType) },
615+
new object[] { 2, GetDataRowValue([1f, 2f, 3f], dataType) },
616+
},
617+
};
618+
619+
using var connection = new MySqlConnection(GetLocalConnectionString());
620+
connection.Open();
621+
using (var cmd = new MySqlCommand(@"drop table if exists bulk_load_data_table;
622+
create table bulk_load_data_table(a int, b vector(3));", connection))
623+
{
624+
cmd.ExecuteNonQuery();
625+
}
626+
627+
var bulkCopy = new MySqlBulkCopy(connection)
628+
{
629+
DestinationTableName = "bulk_load_data_table",
630+
};
631+
var result = bulkCopy.WriteToServer(dataTable);
632+
Assert.Equal(2, result.RowsInserted);
633+
Assert.Empty(result.Warnings);
634+
635+
using (var cmd = new MySqlCommand(@"select b from bulk_load_data_table order by a;", connection))
636+
{
637+
using var reader = cmd.ExecuteReader();
638+
Assert.True(reader.Read());
639+
Assert.Equal(new float[3], GetFloatArray(reader, 0));
640+
Assert.True(reader.Read());
641+
Assert.Equal([1f, 2f, 3f], GetFloatArray(reader, 0));
642+
Assert.False(reader.Read());
643+
}
644+
645+
static object GetDataRowValue(float[] data, string dataType) =>
646+
dataType == "byte[]" ? MemoryMarshal.Cast<float, byte>(data).ToArray() : data;
647+
648+
static float[] GetFloatArray(MySqlDataReader reader, int ordinal) =>
649+
reader.GetValue(ordinal) switch
650+
{
651+
ReadOnlyMemory<float> romf => romf.ToArray(),
652+
byte[] b => MemoryMarshal.Cast<byte, float>(b).ToArray(),
653+
{ } x => throw new NotSupportedException(x.GetType().Name),
654+
};
655+
}
656+
591657
#if NET6_0_OR_GREATER
592658
[Fact]
593659
public void BulkCopyDataTableWithDateOnly()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /