@@ -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