Skip to content

Commit 9813d46

Browse files
committed
fix: transaction status lost for captured commiting exception
1 parent f22710d commit 9813d46

3 files changed

Lines changed: 104 additions & 19 deletions

File tree

src/TagBites.DB/DB/DbLinkContext.cs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -813,30 +813,37 @@ internal void MarkTransaction(bool rollback, bool rollbackCalled = false)
813813
try
814814
{
815815
OnTransactionBeforeCommit();
816-
_batchQueue.Flush();
816+
817+
if (_transactionContext.Status != DbLinkTransactionStatus.RollingBack)
818+
_batchQueue.Flush();
819+
else
820+
_batchQueue.Cancel();
817821
}
818822
catch
819823
{
820824
_transactionContext.Status = DbLinkTransactionStatus.RollingBack;
821825
throw;
822826
}
823827

824-
if (_transactionContext.DbTransactionInternal != null)
825-
try
826-
{
827-
_transactionContext.DbTransactionInternal.Commit();
828-
}
829-
catch (Exception e)
830-
{
831-
_transactionContext.Status = DbLinkTransactionStatus.RollingBack;
828+
if (_transactionContext.Status != DbLinkTransactionStatus.RollingBack)
829+
{
830+
if (_transactionContext.DbTransactionInternal != null)
831+
try
832+
{
833+
_transactionContext.DbTransactionInternal.Commit();
834+
}
835+
catch (Exception e)
836+
{
837+
_transactionContext.Status = DbLinkTransactionStatus.RollingBack;
832838

833-
var ex = OnFormatException(e);
834-
if (e == ex)
835-
throw;
836-
throw ex;
837-
}
839+
var ex = OnFormatException(e);
840+
if (e == ex)
841+
throw;
842+
throw ex;
843+
}
838844

839-
_transactionContext.Status = DbLinkTransactionStatus.Committing;
845+
_transactionContext.Status = DbLinkTransactionStatus.Committing;
846+
}
840847
}
841848
}
842849
// Rollback
@@ -1267,7 +1274,18 @@ protected virtual Exception OnFormatException(Exception e)
12671274
}
12681275
protected virtual void OnTransactionBeforeCommit()
12691276
{
1270-
_transactionCommiting?.Invoke(this, EventArgs.Empty);
1277+
if (_transactionCommiting?.GetInvocationList() is { } events)
1278+
{
1279+
// ReSharper disable once ForCanBeConvertedToForeach
1280+
for (var i = 0; i < events.Length; i++)
1281+
{
1282+
var action = (EventHandler)events[i];
1283+
action(this, EventArgs.Empty);
1284+
1285+
if (_transactionContext.Status == DbLinkTransactionStatus.RollingBack)
1286+
break;
1287+
}
1288+
}
12711289
}
12721290

12731291
protected virtual void OnConnectionCreated() { }

src/TagBites.DB/DB/DbLinkTransactionContext.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Data.Common;
33

44
namespace TagBites.DB
@@ -219,7 +219,21 @@ protected void CheckDispose()
219219

220220
private void OnTransactionBeginning(object sender, EventArgs e) => _transactionBeginning?.Invoke(this, e);
221221
private void OnTransactionBegan(object sender, EventArgs e) => _transactionBegan?.Invoke(this, e);
222-
private void OnTransactionCommiting(object sender, EventArgs e) => _transactionCommiting?.Invoke(this, e);
222+
private void OnTransactionCommiting(object sender, EventArgs e)
223+
{
224+
if (_transactionCommiting?.GetInvocationList() is { } events)
225+
{
226+
// ReSharper disable once ForCanBeConvertedToForeach
227+
for (var i = 0; i < events.Length; i++)
228+
{
229+
var action = (EventHandler)events[i];
230+
action(this, EventArgs.Empty);
231+
232+
if (Status == DbLinkTransactionStatus.RollingBack)
233+
break;
234+
}
235+
}
236+
}
223237
private void OnTransactionClosed(object sender, DbLinkTransactionCloseEventArgs e) => _transactionClosed?.Invoke(this, e);
224238
private void OnTransactionContextClosed(object sender, DbLinkTransactionContextCloseEventArgs e) => _transactionContextClosed?.Invoke(this, e);
225239
}

tests/TagBites.DB.Tests/DB/TransactionTests.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ void OnConnectionContextOnTransactionContextClose(object s, DbLinkTransactionCon
126126
transaction2.Commit();
127127
}
128128
}
129-
};
129+
}
130+
;
130131

131132
Assert.Equal(1, count1);
132133
Assert.Equal(1, count2);
@@ -199,5 +200,57 @@ public void BeforeCommitTest()
199200
Assert.Equal(0, close);
200201
}
201202
}
203+
204+
[Fact]
205+
public void ErrorOnCommittingTest()
206+
{
207+
using var link = DefaultProvider.CreateLink();
208+
209+
using (var t = link.Begin())
210+
{
211+
link.Force();
212+
213+
link.TransactionContext.TransactionCommiting += (obj, args) =>
214+
{
215+
using var l = DefaultProvider.CreateLink();
216+
217+
Assert.Equal(DbLinkTransactionStatus.Open, l.TransactionStatus);
218+
219+
try
220+
{
221+
l.ExecuteNonQuery("DO $$ BEGIN RAISE EXCEPTION 'error'; END; $$;");
222+
}
223+
catch
224+
{
225+
// ignored
226+
}
227+
228+
Assert.Equal(DbLinkTransactionStatus.RollingBack, l.TransactionStatus);
229+
};
230+
231+
link.TransactionContext.TransactionClosed += (obj, args) =>
232+
{
233+
Assert.Equal(DbLinkTransactionCloseReason.Rollback, args.CloseReason);
234+
};
235+
link.TransactionContext.TransactionContextClosed += (obj, args) =>
236+
{
237+
Assert.Equal(DbLinkTransactionCloseReason.Rollback, args.CloseReason);
238+
};
239+
240+
try
241+
{
242+
t.Commit();
243+
}
244+
catch
245+
{
246+
// ignored
247+
}
248+
249+
Assert.Equal(DbLinkTransactionStatus.RollingBack, link.TransactionStatus);
250+
}
251+
252+
Assert.Equal(DbLinkTransactionStatus.None, link.TransactionStatus);
253+
link.ExecuteScalar("SELECT 1");
254+
}
202255
}
203256
}

0 commit comments

Comments
 (0)