Fixed #36318 -- Fixed incorrect rollback exception attribution in nested atomic blocks.

Signed-off-by: saJaeHyukc <wogur981208@gmail.com>
This commit is contained in:
saJaeHyukc 2025-04-18 11:32:30 +09:00
parent de1117ea8e
commit 9bfb250b1b
2 changed files with 26 additions and 0 deletions

View file

@ -195,6 +195,7 @@ class Atomic(ContextDecorator):
# Reset state when entering an outermost atomic block.
connection.commit_on_exit = True
connection.needs_rollback = False
connection.rollback_exc = None
if not connection.get_autocommit():
# Pretend we're already in an atomic block to bypass the code
# that disables autocommit to enter a transaction, and make a
@ -278,6 +279,9 @@ class Atomic(ContextDecorator):
# otherwise.
if sid is None:
connection.needs_rollback = True
# Avoid shadowing an already assigned rollback exc.
if connection.rollback_exc is None:
connection.rollback_exc = exc_value
else:
try:
connection.savepoint_rollback(sid)

View file

@ -359,6 +359,28 @@ class AtomicErrorsTests(TransactionTestCase):
self.assertIsInstance(cm.exception.__cause__, IntegrityError)
self.assertEqual(Reporter.objects.get(pk=r1.pk).last_name, "Haddock")
def test_atomic_prevents_queries_in_broken_transaction_cause_attribution(self):
# Trigger a previous atomic rollback to populate cause.
with self.assertRaises(Exception), transaction.atomic():
raise Exception("First failure")
with (
self.assertRaises(transaction.TransactionManagementError) as ctx,
transaction.atomic(),
):
try:
with transaction.atomic(savepoint=False):
raise Exception("Second failure")
except Exception:
pass
try:
with transaction.atomic(savepoint=False):
raise Exception("Third failure")
except Exception:
pass
Reporter.objects.count()
self.assertEqual(str(ctx.exception.__cause__), "Second failure")
@skipIfDBFeature("atomic_transactions")
def test_atomic_allows_queries_after_fixing_transaction(self):
r1 = Reporter.objects.create(first_name="Archibald", last_name="Haddock")