Skip to content

Commit 63fda81

Browse files
committed
Optimise GetInt32.
Signed-off-by: Bradley Grainger <[email protected]>
1 parent 7a399c6 commit 63fda81

File tree

4 files changed

+90
-29
lines changed

4 files changed

+90
-29
lines changed

src/MySqlConnector/Core/BinaryRow.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,39 @@ protected override void GetDataOffsets(ReadOnlySpan<byte> data, int[] dataOffset
6969
}
7070
}
7171

72+
protected override int GetInt32Core(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition)
73+
{
74+
var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0;
75+
switch (columnDefinition.ColumnType)
76+
{
77+
case ColumnType.Bit:
78+
return checked((int) ReadBit(data, columnDefinition));
79+
80+
case ColumnType.Tiny:
81+
return isUnsigned ? (int) data[0] : (sbyte) data[0];
82+
83+
case ColumnType.Decimal:
84+
case ColumnType.NewDecimal:
85+
return Utf8Parser.TryParse(data, out decimal decimalValue, out int bytesConsumed) && bytesConsumed == data.Length ? checked((int) decimalValue) : throw new FormatException();
86+
87+
case ColumnType.Int24:
88+
case ColumnType.Long:
89+
return isUnsigned ? checked((int) MemoryMarshal.Read<uint>(data)) : MemoryMarshal.Read<int>(data);
90+
91+
case ColumnType.Longlong:
92+
return isUnsigned ? checked((int) MemoryMarshal.Read<ulong>(data)) : checked((int) MemoryMarshal.Read<long>(data));
93+
94+
case ColumnType.Short:
95+
return isUnsigned ? (int) MemoryMarshal.Read<ushort>(data) : MemoryMarshal.Read<short>(data);
96+
97+
case ColumnType.Year:
98+
return (int) MemoryMarshal.Read<short>(data);
99+
100+
default:
101+
throw new FormatException();
102+
}
103+
}
104+
72105
protected override object GetValueCore(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition)
73106
{
74107
var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0;

src/MySqlConnector/Core/Row.cs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -200,29 +200,38 @@ public short GetInt16(int ordinal)
200200

201201
public int GetInt32(int ordinal)
202202
{
203-
var value = GetValue(ordinal);
204-
if (value is int)
205-
return (int) value;
203+
if (ordinal < 0 || ordinal > ResultSet.ColumnDefinitions!.Length)
204+
throw new ArgumentOutOfRangeException(nameof(ordinal), "value must be between 0 and {0}.".FormatInvariant(ResultSet.ColumnDefinitions!.Length));
206205

207-
if (value is sbyte)
208-
return (sbyte) value;
209-
if (value is byte)
210-
return (byte) value;
211-
if (value is short)
212-
return (short) value;
213-
if (value is ushort)
214-
return (ushort) value;
215-
if (value is uint)
216-
return checked((int) (uint) value);
217-
if (value is long)
218-
return checked((int) (long) value);
219-
if (value is ulong)
220-
return checked((int) (ulong) value);
221-
if (value is decimal)
222-
return (int) (decimal) value;
223-
return (int) value;
206+
if (m_dataOffsets[ordinal] == -1)
207+
throw new InvalidCastException();
208+
209+
var columnDefinition = ResultSet.ColumnDefinitions[ordinal];
210+
if ((columnDefinition.ColumnType != ColumnType.Tiny &&
211+
columnDefinition.ColumnType != ColumnType.Short &&
212+
columnDefinition.ColumnType != ColumnType.Int24 &&
213+
columnDefinition.ColumnType != ColumnType.Long &&
214+
columnDefinition.ColumnType != ColumnType.Longlong &&
215+
columnDefinition.ColumnType != ColumnType.Bit &&
216+
columnDefinition.ColumnType != ColumnType.Year &&
217+
columnDefinition.ColumnType != ColumnType.Decimal &&
218+
columnDefinition.ColumnType != ColumnType.NewDecimal) ||
219+
(columnDefinition.ColumnType == ColumnType.Tiny && Connection.TreatTinyAsBoolean && columnDefinition.ColumnLength == 1 && (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) == 0))
220+
{
221+
throw new InvalidCastException("Can't convert {0} to Int32".FormatInvariant(ResultSet.ColumnTypes![ordinal]));
222+
}
223+
224+
var data = m_data.Slice(m_dataOffsets[ordinal], m_dataLengths[ordinal]).Span;
225+
226+
if (columnDefinition.ColumnType == ColumnType.Bit)
227+
return checked((int) ReadBit(data, columnDefinition));
228+
else if (columnDefinition.ColumnType == ColumnType.Decimal)
229+
return (int) (decimal) GetValue(ordinal);
230+
return GetInt32Core(data, columnDefinition);
224231
}
225232

233+
protected abstract int GetInt32Core(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition);
234+
226235
public long GetInt64(int ordinal)
227236
{
228237
var value = GetValue(ordinal);
@@ -427,7 +436,7 @@ protected unsafe static Guid CreateGuidFromBytes(MySqlGuidFormat guidFormat, Rea
427436
#endif
428437
};
429438

430-
protected static object ReadBit(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition)
439+
protected static ulong ReadBit(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition)
431440
{
432441
if ((columnDefinition.ColumnFlags & ColumnFlags.Binary) == 0)
433442
{

src/MySqlConnector/Core/TextRow.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ protected override void GetDataOffsets(ReadOnlySpan<byte> data, int[] dataOffset
3131
}
3232
}
3333

34+
protected override int GetInt32Core(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition) =>
35+
!Utf8Parser.TryParse(data, out int value, out var bytesConsumed) || bytesConsumed != data.Length ? throw new OverflowException() : value;
36+
3437
protected override object GetValueCore(ReadOnlySpan<byte> data, ColumnDefinitionPayload columnDefinition)
3538
{
3639
var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0;

tests/SideBySide/QueryTests.cs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -603,15 +603,23 @@ public void SumBytes()
603603
Assert.Equal(512, reader.GetInt32(0));
604604
}
605605

606-
[Fact]
607-
public void SumShorts()
606+
[Theory]
607+
[InlineData(false)]
608+
[InlineData(true)]
609+
public void SumShorts(bool prepareCommand)
608610
{
609-
m_database.Connection.Execute(@"drop table if exists sum_shorts;
611+
var csb = AppConfig.CreateConnectionStringBuilder();
612+
csb.IgnorePrepare = !prepareCommand;
613+
using var connection = new MySqlConnection(csb.ConnectionString);
614+
connection.Open();
615+
616+
connection.Execute(@"drop table if exists sum_shorts;
610617
create table sum_shorts(value smallint unsigned not null);
611618
insert into sum_shorts(value) values(0), (1), (2), (32766), (32767);");
612619

613-
using var cmd = m_database.Connection.CreateCommand();
620+
using var cmd = connection.CreateCommand();
614621
cmd.CommandText = "select sum(value) from sum_shorts";
622+
cmd.Prepare();
615623
Assert.Equal(65536m, cmd.ExecuteScalar());
616624

617625
using var reader = cmd.ExecuteReader();
@@ -622,15 +630,23 @@ public void SumShorts()
622630
Assert.Equal(65536L, reader.GetInt64(0));
623631
}
624632

625-
[Fact]
626-
public void SumInts()
633+
[Theory]
634+
[InlineData(false)]
635+
[InlineData(true)]
636+
public void SumInts(bool prepareCommand)
627637
{
628-
m_database.Connection.Execute(@"drop table if exists sum_ints;
638+
var csb = AppConfig.CreateConnectionStringBuilder();
639+
csb.IgnorePrepare = !prepareCommand;
640+
using var connection = new MySqlConnection(csb.ConnectionString);
641+
connection.Open();
642+
643+
connection.Execute(@"drop table if exists sum_ints;
629644
create table sum_ints(value int unsigned not null);
630645
insert into sum_ints(value) values(0), (1), (2), (2147483646), (2147483647);");
631646

632-
using var cmd = m_database.Connection.CreateCommand();
647+
using var cmd = connection.CreateCommand();
633648
cmd.CommandText = "select sum(value) from sum_ints";
649+
cmd.Prepare();
634650
Assert.Equal(4294967296m, cmd.ExecuteScalar());
635651

636652
using var reader = cmd.ExecuteReader();

0 commit comments

Comments
 (0)