Skip to content

Commit 84ef859

Browse files
committed
Add nullable annotations to Row and ResultSet.
1 parent f97f8ef commit 84ef859

File tree

4 files changed

+39
-49
lines changed

4 files changed

+39
-49
lines changed

src/MySqlConnector/Core/BinaryRow.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#nullable disable
21
using System;
32
using System.Buffers.Text;
43
using System.Runtime.InteropServices;
@@ -45,7 +44,7 @@ protected override void GetDataOffsets(ReadOnlySpan<byte> data, int[] dataOffset
4544
}
4645
else
4746
{
48-
var columnDefinition = ResultSet.ColumnDefinitions[column];
47+
var columnDefinition = ResultSet.ColumnDefinitions![column];
4948
int length;
5049
if (columnDefinition.ColumnType == ColumnType.Longlong || columnDefinition.ColumnType == ColumnType.Double)
5150
length = 8;

src/MySqlConnector/Core/ResultSet.cs

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#nullable disable
21
using System;
32
using System.Collections.Generic;
43
using System.Globalization;
@@ -35,7 +34,6 @@ public void Reset()
3534
m_columnDefinitionPayloadUsedBytes = 0;
3635
m_readBuffer?.Clear();
3736
m_row = null;
38-
m_rowBuffered = null;
3937
m_hasRows = false;
4038
ReadResultSetHeaderException = null;
4139
}
@@ -176,7 +174,7 @@ public bool Read()
176174
}
177175

178176
public Task<bool> ReadAsync(CancellationToken cancellationToken) =>
179-
ReadAsync(Command.Connection.AsyncIOBehavior, cancellationToken);
177+
ReadAsync(Connection.AsyncIOBehavior, cancellationToken);
180178

181179
public async Task<bool> ReadAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
182180
{
@@ -198,33 +196,32 @@ public async Task<bool> ReadAsync(IOBehavior ioBehavior, CancellationToken cance
198196
return true;
199197
}
200198

201-
public async Task<Row> BufferReadAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
199+
public async Task<Row?> BufferReadAsync(IOBehavior ioBehavior, CancellationToken cancellationToken)
202200
{
203-
m_rowBuffered = m_rowBuffered?.Clone();
204-
// ScanRowAsync sets m_rowBuffered to the next row if there is one
205-
if (await ScanRowAsync(ioBehavior, null, cancellationToken).ConfigureAwait(false) is null)
201+
var row = await ScanRowAsync(ioBehavior, null, cancellationToken).ConfigureAwait(false);
202+
if (row is null)
206203
return null;
207204
if (m_readBuffer is null)
208205
m_readBuffer = new Queue<Row>();
209-
m_readBuffer.Enqueue(m_rowBuffered);
210-
return m_rowBuffered;
206+
m_readBuffer.Enqueue(row);
207+
return row;
211208
}
212209

213-
private ValueTask<Row> ScanRowAsync(IOBehavior ioBehavior, Row row, CancellationToken cancellationToken)
210+
private ValueTask<Row?> ScanRowAsync(IOBehavior ioBehavior, Row? row, CancellationToken cancellationToken)
214211
{
215212
// if we've already read past the end of this resultset, Read returns false
216213
if (BufferState == ResultSetState.HasMoreData || BufferState == ResultSetState.NoMoreData || BufferState == ResultSetState.None)
217-
return new ValueTask<Row>((Row) null);
214+
return new ValueTask<Row?>(default(Row?));
218215

219216
using (Command.CancellableCommand.RegisterCancel(cancellationToken))
220217
{
221218
var payloadValueTask = Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None);
222219
return payloadValueTask.IsCompletedSuccessfully
223-
? new ValueTask<Row>(ScanRowAsyncRemainder(this, payloadValueTask.Result, row))
224-
: new ValueTask<Row>(ScanRowAsyncAwaited(this, payloadValueTask.AsTask(), row, cancellationToken));
220+
? new ValueTask<Row?>(ScanRowAsyncRemainder(this, payloadValueTask.Result, row))
221+
: new ValueTask<Row?>(ScanRowAsyncAwaited(this, payloadValueTask.AsTask(), row, cancellationToken));
225222
}
226223

227-
static async Task<Row> ScanRowAsyncAwaited(ResultSet this_, Task<PayloadData> payloadTask, Row row_, CancellationToken token)
224+
static async Task<Row?> ScanRowAsyncAwaited(ResultSet this_, Task<PayloadData> payloadTask, Row? row_, CancellationToken token)
228225
{
229226
PayloadData payloadData;
230227
try
@@ -241,7 +238,7 @@ static async Task<Row> ScanRowAsyncAwaited(ResultSet this_, Task<PayloadData> pa
241238
return ScanRowAsyncRemainder(this_, payloadData, row_);
242239
}
243240

244-
static Row ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row row_)
241+
static Row? ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row? row_)
245242
{
246243
if (payload.HeaderByte == EofPayload.Signature)
247244
{
@@ -250,14 +247,12 @@ static Row ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row row_)
250247
{
251248
var ok = OkPayload.Create(span, this_.Session.SupportsDeprecateEof, this_.Session.SupportsSessionTrack);
252249
this_.BufferState = (ok.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;
253-
this_.m_rowBuffered = null;
254250
return null;
255251
}
256252
if (!this_.Session.SupportsDeprecateEof && EofPayload.IsEof(payload))
257253
{
258254
var eof = EofPayload.Create(span);
259255
this_.BufferState = (eof.ServerStatus & ServerStatus.MoreResultsExist) == 0 ? ResultSetState.NoMoreData : ResultSetState.HasMoreData;
260-
this_.m_rowBuffered = null;
261256
return null;
262257
}
263258
}
@@ -318,7 +313,7 @@ static Row ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row row_)
318313
reader.Offset += length;
319314
columnCount++;
320315

321-
if (columnCount == this_.ColumnDefinitions.Length)
316+
if (columnCount == this_.ColumnDefinitions!.Length)
322317
{
323318
// if we used up all the bytes reading exactly 'ColumnDefinitions' length-encoded columns, then assume this is a text row
324319
if (reader.BytesRemaining == 0)
@@ -332,7 +327,6 @@ static Row ScanRowAsyncRemainder(ResultSet this_, PayloadData payload, Row row_)
332327
row_ = isBinaryRow ? (Row) new BinaryRow(this_) : new TextRow(this_);
333328
}
334329
row_.SetData(payload.Memory);
335-
this_.m_rowBuffered = row_;
336330
this_.m_hasRows = true;
337331
this_.BufferState = ResultSetState.ReadingRows;
338332
return row_;
@@ -357,7 +351,7 @@ public string GetDataTypeName(int ordinal)
357351
if (ordinal < 0 || ordinal >= ColumnDefinitions.Length)
358352
throw new IndexOutOfRangeException("value must be between 0 and {0}.".FormatInvariant(ColumnDefinitions.Length));
359353

360-
var mySqlDbType = ColumnTypes[ordinal];
354+
var mySqlDbType = ColumnTypes![ordinal];
361355
if (mySqlDbType == MySqlDbType.String)
362356
return string.Format(CultureInfo.InvariantCulture, "CHAR({0})", ColumnDefinitions[ordinal].ColumnLength / ProtocolUtility.GetBytesPerCharacter(ColumnDefinitions[ordinal].CharacterSet));
363357
return TypeMapper.Instance.GetColumnTypeMetadata(mySqlDbType).SimpleDataTypeName;
@@ -370,7 +364,7 @@ public Type GetFieldType(int ordinal)
370364
if (ordinal < 0 || ordinal >= ColumnDefinitions.Length)
371365
throw new IndexOutOfRangeException("value must be between 0 and {0}.".FormatInvariant(ColumnDefinitions.Length));
372366

373-
var type = TypeMapper.Instance.GetColumnTypeMetadata(ColumnTypes[ordinal]).DbTypeMapping.ClrType;
367+
var type = TypeMapper.Instance.GetColumnTypeMetadata(ColumnTypes![ordinal]).DbTypeMapping.ClrType;
374368
if (Connection.AllowZeroDateTime && type == typeof(DateTime))
375369
type = typeof(MySqlDateTime);
376370
return type;
@@ -412,25 +406,24 @@ public Row GetCurrentRow()
412406
}
413407

414408
public readonly MySqlDataReader DataReader;
415-
public Exception ReadResultSetHeaderException { get; private set; }
409+
public Exception? ReadResultSetHeaderException { get; private set; }
416410
public IMySqlCommand Command => DataReader.Command;
417411
public MySqlConnection Connection => DataReader.Connection;
418412
public ServerSession Session => DataReader.Session;
419413

420414
public ResultSetState BufferState { get; private set; }
421-
public ColumnDefinitionPayload[] ColumnDefinitions { get; private set; }
422-
public MySqlDbType[] ColumnTypes { get; private set; }
415+
public ColumnDefinitionPayload[]? ColumnDefinitions { get; private set; }
416+
public MySqlDbType[]? ColumnTypes { get; private set; }
423417
public long LastInsertId { get; private set; }
424418
public int? RecordsAffected { get; private set; }
425419
public int WarningCount { get; private set; }
426420
public ResultSetState State { get; private set; }
427421
public bool ContainsCommandParameters { get; private set; }
428422

429-
ResizableArray<byte> m_columnDefinitionPayloads;
423+
ResizableArray<byte>? m_columnDefinitionPayloads;
430424
int m_columnDefinitionPayloadUsedBytes;
431-
Queue<Row> m_readBuffer;
432-
Row m_row;
433-
Row m_rowBuffered;
425+
Queue<Row>? m_readBuffer;
426+
Row? m_row;
434427
bool m_hasRows;
435428
}
436429
}

src/MySqlConnector/Core/Row.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#nullable disable
21
using System;
32
using System.IO;
43
using System.Runtime.InteropServices;
@@ -15,12 +14,7 @@ internal abstract class Row
1514
public void SetData(ReadOnlyMemory<byte> data)
1615
{
1716
m_data = data;
18-
if (m_dataOffsets is null)
19-
{
20-
m_dataOffsets = new int[ResultSet.ColumnDefinitions.Length];
21-
m_dataLengths = new int[ResultSet.ColumnDefinitions.Length];
22-
}
23-
GetDataOffsets(m_data.Span, m_dataOffsets, m_dataLengths);
17+
GetDataOffsets(m_data.Span, m_dataOffsets, m_dataLengths!);
2418
}
2519

2620
public Row Clone()
@@ -34,8 +28,8 @@ public Row Clone()
3428

3529
public object GetValue(int ordinal)
3630
{
37-
if (ordinal < 0 || ordinal > ResultSet.ColumnDefinitions.Length)
38-
throw new ArgumentOutOfRangeException(nameof(ordinal), "value must be between 0 and {0}.".FormatInvariant(ResultSet.ColumnDefinitions.Length));
31+
if (ordinal < 0 || ordinal > ResultSet.ColumnDefinitions!.Length)
32+
throw new ArgumentOutOfRangeException(nameof(ordinal), "value must be between 0 and {0}.".FormatInvariant(ResultSet.ColumnDefinitions!.Length));
3933

4034
if (m_dataOffsets[ordinal] == -1)
4135
return DBNull.Value;
@@ -74,7 +68,7 @@ public bool GetBoolean(int ordinal)
7468

7569
public byte GetByte(int ordinal) => (byte) GetValue(ordinal);
7670

77-
public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
71+
public long GetBytes(int ordinal, long dataOffset, byte[]? buffer, int bufferOffset, int length)
7872
{
7973
CheckBinaryColumn(ordinal);
8074

@@ -100,7 +94,7 @@ public char GetChar(int ordinal)
10094
return stringValue.Length > 0 ? stringValue[0] : throw new InvalidCastException();
10195
}
10296

103-
public long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
97+
public long GetChars(int ordinal, long dataOffset, char[]? buffer, int bufferOffset, int length)
10498
{
10599
var value = GetString(ordinal);
106100
if (buffer is null)
@@ -294,7 +288,7 @@ public Stream GetStream(int ordinal)
294288
{
295289
CheckBinaryColumn(ordinal);
296290
return (MemoryMarshal.TryGetArray(m_data, out var arraySegment)) ?
297-
new MemoryStream(arraySegment.Array, arraySegment.Offset + m_dataOffsets[ordinal], m_dataLengths[ordinal], writable: false) :
291+
new MemoryStream(arraySegment.Array!, arraySegment.Offset + m_dataOffsets[ordinal], m_dataLengths[ordinal], writable: false) :
298292
throw new InvalidOperationException("Can't get underlying array.");
299293
}
300294

@@ -321,14 +315,14 @@ public MySqlDateTime GetMySqlDateTime(int ordinal)
321315
public MySqlGeometry GetMySqlGeometry(int ordinal)
322316
{
323317
var value = GetValue(ordinal);
324-
if (value is byte[] bytes && ResultSet.ColumnDefinitions[ordinal].ColumnType == ColumnType.Geometry)
318+
if (value is byte[] bytes && ResultSet.ColumnDefinitions![ordinal].ColumnType == ColumnType.Geometry)
325319
return new MySqlGeometry(bytes);
326-
throw new InvalidCastException("Can't convert {0} to MySqlGeometry.".FormatInvariant(ResultSet.ColumnDefinitions[ordinal].ColumnType));
320+
throw new InvalidCastException("Can't convert {0} to MySqlGeometry.".FormatInvariant(ResultSet.ColumnDefinitions![ordinal].ColumnType));
327321
}
328322

329323
public int GetValues(object[] values)
330324
{
331-
int count = Math.Min(values.Length, ResultSet.ColumnDefinitions.Length);
325+
int count = Math.Min((values ?? throw new ArgumentNullException(nameof(values))).Length, ResultSet.ColumnDefinitions!.Length);
332326
for (int i = 0; i < count; i++)
333327
values[i] = GetValue(i);
334328
return count;
@@ -340,7 +334,12 @@ public int GetValues(object[] values)
340334

341335
public object this[string name] => GetValue(ResultSet.GetOrdinal(name));
342336

343-
protected Row(ResultSet resultSet) => ResultSet = resultSet;
337+
protected Row(ResultSet resultSet)
338+
{
339+
ResultSet = resultSet;
340+
m_dataOffsets = new int[ResultSet.ColumnDefinitions!.Length];
341+
m_dataLengths = new int[ResultSet.ColumnDefinitions.Length];
342+
}
344343

345344
protected abstract Row CloneCore();
346345

@@ -382,7 +381,7 @@ private void CheckBinaryColumn(int ordinal)
382381
if (m_dataOffsets[ordinal] == -1)
383382
throw new InvalidCastException("Column is NULL.");
384383

385-
var column = ResultSet.ColumnDefinitions[ordinal];
384+
var column = ResultSet.ColumnDefinitions![ordinal];
386385
var columnType = column.ColumnType;
387386
if ((column.ColumnFlags & ColumnFlags.Binary) == 0 ||
388387
(columnType != ColumnType.String && columnType != ColumnType.VarString && columnType != ColumnType.TinyBlob &&

src/MySqlConnector/Core/TextRow.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#nullable disable
21
using System;
32
using System.Buffers.Text;
43
using System.Text;
@@ -135,7 +134,7 @@ private static ulong ParseUInt64(ReadOnlySpan<byte> data) =>
135134

136135
private object ParseDateTime(ReadOnlySpan<byte> value)
137136
{
138-
Exception exception = null;
137+
Exception? exception = null;
139138
if (!Utf8Parser.TryParse(value, out int year, out var bytesConsumed) || bytesConsumed != 4)
140139
goto InvalidDateTime;
141140
if (value.Length < 5 || value[4] != 45)

0 commit comments

Comments
 (0)