Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/FirebirdSql.Data.FirebirdClient.Tests/FbDataReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -535,4 +535,60 @@ public async Task GetFieldValueTest()
await transaction.RollbackAsync();
}
}

[Test]
public async Task RecordsAffectedIsMinusOneForSelectTest()
{
// DbDataReader.RecordsAffected: "-1 for SELECT statements; 0 if no rows were affected or the statement failed."
await using (var command = new FbCommand("select INT_FIELD from TEST where 1 = 0", Connection))
{
var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{ }
await reader.CloseAsync();
Assert.AreEqual(-1, reader.RecordsAffected);
}
}

[Test]
public async Task RecordsAffectedForInsertReturningTest()
{
// INSERT ... RETURNING is classified by Firebird as a stored procedure execution, not as an INSERT.
await using (var transaction = await Connection.BeginTransactionAsync())
{
await using (var command = new FbCommand("insert into test (int_field) values (100001) returning int_field", Connection, transaction))
{
await using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{ }
Assert.AreEqual(1, reader.RecordsAffected);
}
}
await transaction.RollbackAsync();
}
}

[Test]
public async Task ExecuteNonQueryForStatementWithoutRowChangesIsMinusOneTest()
{
// Stored procedure execution that changes no rows keeps the -1 of "all other types of statements".
await using (var command = new FbCommand("execute block as begin end", Connection))
{
Assert.AreEqual(-1, await command.ExecuteNonQueryAsync());
}
}

[Test]
public async Task ExecuteNonQueryForInsertReturningTest()
{
await using (var transaction = await Connection.BeginTransactionAsync())
{
await using (var command = new FbCommand("insert into test (int_field) values (100002) returning int_field", Connection, transaction))
{
Assert.AreEqual(1, await command.ExecuteNonQueryAsync());
}
await transaction.RollbackAsync();
}
}
}
37 changes: 23 additions & 14 deletions src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,27 @@ internal int RecordsAffected
}
}

/// <summary>
/// The rows an INSERT, UPDATE or DELETE affected, or -1 for any other statement (DbCommand.ExecuteNonQuery: "For all
/// other types of statements, the return value is -1"; DbDataReader.RecordsAffected: "-1 for SELECT statements").
/// Firebird classifies INSERT ... RETURNING and DML inside an execute block as stored procedure execution; the server's
/// count is reported for those only when it is positive, so procedures that change no rows keep -1.
/// </summary>
internal int StatementRecordsAffected
{
get
{
return _statement?.StatementType switch
{
DbStatementType.Insert => RecordsAffected,
DbStatementType.Update => RecordsAffected,
DbStatementType.Delete => RecordsAffected,
DbStatementType.StoredProcedure when RecordsAffected > 0 => RecordsAffected,
_ => -1,
};
}
}

internal bool IsDisposed
{
get { return _disposed; }
Expand Down Expand Up @@ -529,13 +550,7 @@ public override int ExecuteNonQuery()
}
}

return _statement.StatementType switch
{
DbStatementType.Insert => RecordsAffected,
DbStatementType.Update => RecordsAffected,
DbStatementType.Delete => RecordsAffected,
_ => -1,
};
return StatementRecordsAffected;
}
public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -566,13 +581,7 @@ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellat
}
}

return _statement.StatementType switch
{
DbStatementType.Insert => RecordsAffected,
DbStatementType.Update => RecordsAffected,
DbStatementType.Delete => RecordsAffected,
_ => -1,
};
return StatementRecordsAffected;
}

public new FbDataReader ExecuteReader() => ExecuteReader(CommandBehavior.Default);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ internal FbDataReader(FbCommand command, FbConnection connection, CommandBehavio
_connection = connection;
_commandBehavior = commandBehavior;
_fields = _command.GetFieldsDescriptor();
_recordsAffected = -1;

UpdateRecordsAffected();
}
Expand Down Expand Up @@ -1016,10 +1017,11 @@ private void UpdateRecordsAffected()
{
if (_command != null && !_command.IsDisposed)
{
if (_command.RecordsAffected != -1)
var recordsAffected = _command.StatementRecordsAffected;
if (recordsAffected != -1)
{
_recordsAffected = _recordsAffected == -1 ? 0 : _recordsAffected;
_recordsAffected += _command.RecordsAffected;
_recordsAffected += recordsAffected;
}
}
}
Expand Down