Skip to content

Commit

Permalink
Allow RecordsAffected to be read after Close() in SingleStoreDataReader
Browse files Browse the repository at this point in the history
Summary: We've been getting InvalidOperationException if SingleStoreDataReader.RecordsAffected was read after calling Close() or Dispose().

Test Plan: https://app.circleci.com/pipelines/github/memsql/SingleStoreNETConnector/222/workflows/28d3fa1a-a3dd-45fc-8de4-4a3508d4af74

Reviewers: pmishchenko-ua

Reviewed By: pmishchenko-ua

Subscribers: engineering-list

JIRA Issues: PLAT-6281

Differential Revision: https://grizzly.internal.memcompute.com/D57828
  • Loading branch information
okramarenko committed Jul 27, 2022
1 parent d46f890 commit f63d2af
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 10 deletions.
3 changes: 1 addition & 2 deletions src/SingleStoreConnector/Core/ResultSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
// if we've read a result set header then this is a SELECT statement, so we shouldn't overwrite RecordsAffected
// (which should be -1 for SELECT) unless the server reports a non-zero count
if (State != ResultSetState.ReadResultSetHeader || ok.AffectedRowCount != 0)
RecordsAffected = (RecordsAffected ?? 0) + ok.AffectedRowCount;
DataReader.RealRecordsAffected = (DataReader.RealRecordsAffected ?? 0) + ok.AffectedRowCount;

if (ok.LastInsertId != 0)
Command?.SetLastInsertedId((long) ok.LastInsertId);
Expand Down Expand Up @@ -365,7 +365,6 @@ public Row GetCurrentRow()
public ResultSetState BufferState { get; private set; }
public ColumnDefinitionPayload[]? ColumnDefinitions { get; private set; }
public SingleStoreDbType[]? ColumnTypes { get; private set; }
public ulong? RecordsAffected { get; private set; }
public int WarningCount { get; private set; }
public ResultSetState State { get; private set; }
public bool ContainsCommandParameters { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions src/SingleStoreConnector/SingleStoreDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,7 @@ public override bool HasRows
}

public override bool IsClosed => Command is null;
public override int RecordsAffected => GetResultSet().RecordsAffected is ulong recordsAffected ? checked((int) recordsAffected) : -1;

public override int RecordsAffected => RealRecordsAffected is ulong recordsAffected ? checked((int) recordsAffected) : -1;
public override int GetOrdinal(string name) => GetResultSet().GetOrdinal(name);

public override bool GetBoolean(int ordinal) => GetResultSet().GetCurrentRow().GetBoolean(ordinal);
Expand Down Expand Up @@ -447,6 +446,7 @@ protected override void Dispose(bool disposing)
internal Activity? Activity { get; }
internal ISingleStoreCommand? Command { get; private set; }
internal SingleStoreConnection? Connection => Command?.Connection;
internal ulong? RealRecordsAffected { get; set; }
internal ServerSession? Session => Command?.Connection!.Session;

internal static async Task<SingleStoreDataReader> CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary<string, CachedProcedure?>? cachedProcedures, ISingleStoreCommand command, CommandBehavior behavior, Activity? activity, IOBehavior ioBehavior, CancellationToken cancellationToken)
Expand Down
20 changes: 14 additions & 6 deletions tests/SideBySide/UpdateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ public void Dispose()
}

[Theory]
[InlineData(1, 2)]
[InlineData(2, 1)]
[InlineData(3, 0)]
[InlineData(4, 1)]
public async Task UpdateRowsExecuteReader(int oldValue, int expectedRowsUpdated)
[MemberData(nameof(GetUpdateRowsExecuteReaderData))]
public async Task UpdateRowsExecuteReader(int oldValue, int expectedRowsUpdated, int closeDispose)
{
using (var cmd = m_database.Connection.CreateCommand())
{
Expand All @@ -43,11 +40,22 @@ public async Task UpdateRowsExecuteReader(int oldValue, int expectedRowsUpdated)

using var reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
Assert.False(await reader.ReadAsync().ConfigureAwait(false));

if (closeDispose == 1)
reader.Close();
else if (closeDispose == 2)
reader.Dispose();
Assert.Equal(expectedRowsUpdated, reader.RecordsAffected);
Assert.False(await reader.NextResultAsync().ConfigureAwait(false));

if (closeDispose == 0)
Assert.False(await reader.NextResultAsync().ConfigureAwait(false));
}
}

public static IEnumerable<object[]> GetUpdateRowsExecuteReaderData() =>
new[] { new KeyValuePair<int, int>(1, 2), new KeyValuePair<int, int>(2, 1), new KeyValuePair<int, int>(3, 0), new KeyValuePair<int, int>(4, 1) }
.SelectMany(x => new[] { 0, 1, 2 }.Select(y => new object[] { x.Key, x.Value, y }));

[Theory]
[InlineData(1, 2)]
[InlineData(2, 1)]
Expand Down

0 comments on commit f63d2af

Please sign in to comment.