Skip to content

Commit e82f3ea

Browse files
alaricdclaude
andcommitted
Keep the server count for INSERT ... RETURNING
Firebird classifies INSERT ... RETURNING and DML inside an execute block as stored procedure execution, so the statement-type switch reported -1 for them and the reader stopped reporting the insert count it used to report. Count stored procedure execution only when the server reports a positive count, so procedures that change no rows keep -1. Also set RecordsAffected to -1 in the FbDataReader constructor instead of the field initializer, as requested in review. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
1 parent f4937b0 commit e82f3ea

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

‎src/FirebirdSql.Data.FirebirdClient.Tests/FbDataReaderTests.cs‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,46 @@ public async Task RecordsAffectedIsMinusOneForSelectTest()
549549
Assert.AreEqual(-1, reader.RecordsAffected);
550550
}
551551
}
552+
553+
[Test]
554+
public async Task RecordsAffectedForInsertReturningTest()
555+
{
556+
// INSERT ... RETURNING is classified by Firebird as a stored procedure execution, not as an INSERT.
557+
await using (var transaction = await Connection.BeginTransactionAsync())
558+
{
559+
await using (var command = new FbCommand("insert into test (int_field) values (100001) returning int_field", Connection, transaction))
560+
{
561+
await using (var reader = await command.ExecuteReaderAsync())
562+
{
563+
while (await reader.ReadAsync())
564+
{ }
565+
Assert.AreEqual(1, reader.RecordsAffected);
566+
}
567+
}
568+
await transaction.RollbackAsync();
569+
}
570+
}
571+
572+
[Test]
573+
public async Task ExecuteNonQueryForStatementWithoutRowChangesIsMinusOneTest()
574+
{
575+
// Stored procedure execution that changes no rows keeps the -1 of "all other types of statements".
576+
await using (var command = new FbCommand("execute block as begin end", Connection))
577+
{
578+
Assert.AreEqual(-1, await command.ExecuteNonQueryAsync());
579+
}
580+
}
581+
582+
[Test]
583+
public async Task ExecuteNonQueryForInsertReturningTest()
584+
{
585+
await using (var transaction = await Connection.BeginTransactionAsync())
586+
{
587+
await using (var command = new FbCommand("insert into test (int_field) values (100002) returning int_field", Connection, transaction))
588+
{
589+
Assert.AreEqual(1, await command.ExecuteNonQueryAsync());
590+
}
591+
await transaction.RollbackAsync();
592+
}
593+
}
552594
}

‎src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbCommand.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ internal int RecordsAffected
266266
/// <summary>
267267
/// The rows an INSERT, UPDATE or DELETE affected, or -1 for any other statement (DbCommand.ExecuteNonQuery: "For all
268268
/// other types of statements, the return value is -1"; DbDataReader.RecordsAffected: "-1 for SELECT statements").
269+
/// Firebird classifies INSERT ... RETURNING and DML inside an execute block as stored procedure execution; the server's
270+
/// count is reported for those only when it is positive, so procedures that change no rows keep -1.
269271
/// </summary>
270272
internal int StatementRecordsAffected
271273
{
@@ -276,6 +278,7 @@ internal int StatementRecordsAffected
276278
DbStatementType.Insert => RecordsAffected,
277279
DbStatementType.Update => RecordsAffected,
278280
DbStatementType.Delete => RecordsAffected,
281+
DbStatementType.StoredProcedure when RecordsAffected > 0 => RecordsAffected,
279282
_ => -1,
280283
};
281284
}

‎src/FirebirdSql.Data.FirebirdClient/FirebirdClient/FbDataReader.cs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public sealed class FbDataReader : DbDataReader
5151
private bool _eof;
5252
private bool _isClosed;
5353
private int _position;
54-
private int _recordsAffected = -1;
54+
private int _recordsAffected;
5555
private Dictionary<string, int> _columnsIndexesOrdinal;
5656
private Dictionary<string, int> _columnsIndexesOrdinalCI;
5757

@@ -84,6 +84,7 @@ internal FbDataReader(FbCommand command, FbConnection connection, CommandBehavio
8484
_connection = connection;
8585
_commandBehavior = commandBehavior;
8686
_fields = _command.GetFieldsDescriptor();
87+
_recordsAffected = -1;
8788

8889
UpdateRecordsAffected();
8990
}

0 commit comments

Comments
 (0)