Skip to content

Commit 45228bd

Browse files
committed
fix buffering. fixes #244
1 parent 44d4957 commit 45228bd

File tree

2 files changed

+23
-26
lines changed

2 files changed

+23
-26
lines changed

src/MySqlConnector/MySqlClient/Results/ResultSet.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Row ScanRowAsyncRemainder(PayloadData payload)
205205

206206
if (row == null)
207207
row = new Row(this);
208-
row.SetData(m_dataLengths, m_dataOffsets, payload.ArraySegment.Array);
208+
row.SetData(m_dataLengths, m_dataOffsets, payload.ArraySegment);
209209
m_rowBuffered = row;
210210
return row;
211211
}

src/MySqlConnector/MySqlClient/Results/Row.cs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal class Row : IDisposable
1010
{
1111
public Row(ResultSet resultSet) => ResultSet = resultSet;
1212

13-
public void SetData(int[] dataLengths, int[] dataOffsets, byte[] payload)
13+
public void SetData(int[] dataLengths, int[] dataOffsets, ArraySegment<byte> payload)
1414
{
1515
m_dataLengths = dataLengths;
1616
m_dataOffsets = dataOffsets;
@@ -21,36 +21,35 @@ public void BufferData()
2121
{
2222
// by default, m_payload, m_dataLengths, and m_dataOffsets are re-used to save allocations
2323
// if the row is going to be buffered, we need to copy them
24+
// since m_payload can span multiple rows, offests must recalculated to include only this row
2425

25-
var bufferDataLengths = ArrayPool<int>.Shared.Rent(m_dataLengths.Length);
26+
var bufferDataLengths = new int[m_dataLengths.Length];
2627
Buffer.BlockCopy(m_dataLengths, 0, bufferDataLengths, 0, m_dataLengths.Length * sizeof(int));
2728
m_dataLengths = bufferDataLengths;
2829

29-
var bufferedDataOffsets = ArrayPool<int>.Shared.Rent(m_dataOffsets.Length);
30-
Buffer.BlockCopy(m_dataOffsets, 0, bufferedDataOffsets, 0, m_dataOffsets.Length * sizeof(int));
31-
m_dataOffsets = bufferedDataOffsets;
32-
33-
var bufferedPayload = ArrayPool<byte>.Shared.Rent(m_payload.Length);
34-
Buffer.BlockCopy(m_payload, 0, bufferedPayload, 0, m_payload.Length);
35-
m_payload = bufferedPayload;
30+
var bufferDataOffsets = new int[m_dataOffsets.Length];
31+
for (var i = 0; i < m_dataOffsets.Length; i++)
32+
{
33+
// a -1 offset denotes null, only adjust positive offsets
34+
if (m_dataOffsets[i] >= 0)
35+
bufferDataOffsets[i] = m_dataOffsets[i] - m_payload.Offset;
36+
else
37+
bufferDataOffsets[i] = m_dataOffsets[i];
38+
}
39+
m_dataOffsets = bufferDataOffsets;
3640

37-
m_buffered = true;
41+
var bufferedPayload = new byte[m_payload.Count];
42+
Buffer.BlockCopy(m_payload.Array, m_payload.Offset, bufferedPayload, 0, m_payload.Count);
43+
m_payload = new ArraySegment<byte>(bufferedPayload);
3844
}
3945

4046
public void Dispose() => ClearData();
4147

4248
public void ClearData()
4349
{
44-
if (m_buffered)
45-
{
46-
ArrayPool<int>.Shared.Return(m_dataLengths);
47-
ArrayPool<int>.Shared.Return(m_dataOffsets);
48-
ArrayPool<byte>.Shared.Return(m_payload);
49-
m_buffered = false;
50-
}
5150
m_dataLengths = null;
5251
m_dataOffsets = null;
53-
m_payload = null;
52+
m_payload = default(ArraySegment<byte>);
5453
}
5554

5655
public bool GetBoolean(int ordinal)
@@ -107,7 +106,7 @@ public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffs
107106
throw new ArgumentException("bufferOffset + length cannot exceed buffer.Length", nameof(length));
108107

109108
int lengthToCopy = Math.Min(m_dataLengths[ordinal] - (int) dataOffset, length);
110-
Buffer.BlockCopy(m_payload, checked((int) (m_dataOffsets[ordinal] + dataOffset)), buffer, bufferOffset, lengthToCopy);
109+
Buffer.BlockCopy(m_payload.Array, checked((int) (m_dataOffsets[ordinal] + dataOffset)), buffer, bufferOffset, lengthToCopy);
111110
return lengthToCopy;
112111
}
113112

@@ -255,7 +254,7 @@ public object GetValue(int ordinal)
255254
if (m_dataOffsets[ordinal] == -1)
256255
return DBNull.Value;
257256

258-
var data = new ArraySegment<byte>(m_payload, m_dataOffsets[ordinal], m_dataLengths[ordinal]);
257+
var data = new ArraySegment<byte>(m_payload.Array, m_dataOffsets[ordinal], m_dataLengths[ordinal]);
259258
var columnDefinition = ResultSet.ColumnDefinitions[ordinal];
260259
var isUnsigned = (columnDefinition.ColumnFlags & ColumnFlags.Unsigned) != 0;
261260
switch (columnDefinition.ColumnType)
@@ -279,7 +278,7 @@ public object GetValue(int ordinal)
279278
// BIT column is transmitted as MSB byte array
280279
ulong bitValue = 0;
281280
for (int i = 0; i < m_dataLengths[ordinal]; i++)
282-
bitValue = bitValue * 256 + m_payload[m_dataOffsets[ordinal] + i];
281+
bitValue = bitValue * 256 + m_payload.Array[m_dataOffsets[ordinal] + i];
283282
return bitValue;
284283

285284
case ColumnType.String:
@@ -296,7 +295,7 @@ public object GetValue(int ordinal)
296295
if (columnDefinition.CharacterSet == CharacterSet.Binary)
297296
{
298297
var result = new byte[m_dataLengths[ordinal]];
299-
Buffer.BlockCopy(m_payload, m_dataOffsets[ordinal], result, 0, result.Length);
298+
Buffer.BlockCopy(m_payload.Array, m_dataOffsets[ordinal], result, 0, result.Length);
300299
return Connection.OldGuids && columnDefinition.ColumnLength == 16 ? (object) new Guid(result) : result;
301300
}
302301
return Encoding.UTF8.GetString(data);
@@ -385,10 +384,8 @@ private static TimeSpan ParseTimeSpan(ArraySegment<byte> value)
385384
public readonly ResultSet ResultSet;
386385
public MySqlConnection Connection => ResultSet.Connection;
387386

388-
byte[] m_payload;
387+
ArraySegment<byte> m_payload;
389388
int[] m_dataLengths;
390389
int[] m_dataOffsets;
391-
bool m_buffered;
392-
393390
}
394391
}

0 commit comments

Comments
 (0)