#34523: Model.objects.update_or_create method sometimes raises
TransactionManagementError
-------------------------------------+-------------------------------------
     Reporter:  gatello-s            |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  4.2
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  update_or_create     |             Triage Stage:
  TransactionManagementError         |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Simon Charette):

 The changes in 331a460f8f2e4f447b68fba491464b68c9b21fd1 are semantically
 correct but they had the side effect of making
 `BaseDatabaseWrapper._savepoint_allowed` return `False` and thus
 `savepoint()` creation always return `None`.

 Since `update_or_create` uses nested `atomic` to handle possible integrity
 errors it was previously taking the savepoints created by MySQL as way to
 mark back the connection as usable. Now that savepoints are not returned
 anymore it assumes the outer atomic block is tainted as well and raise
 `TransactionManagementError`.

 I'm not sure why `Atomic.__enter__` and `__exit__` are not simply noops
 when transactions are determined to not be supported instead of trying to
 handle all kind of nesting and savepoint combinations.

 {{{#!diff
 diff --git a/django/db/transaction.py b/django/db/transaction.py
 index 4150cbcbbe..28229f8f3a 100644
 --- a/django/db/transaction.py
 +++ b/django/db/transaction.py
 @@ -181,6 +181,8 @@ def __init__(self, using, savepoint, durable):

      def __enter__(self):
          connection = get_connection(self.using)
 +        if not connection.features.supports_transactions:
 +            return

          if (
              self.durable
 @@ -223,6 +225,8 @@ def __enter__(self):

      def __exit__(self, exc_type, exc_value, traceback):
          connection = get_connection(self.using)
 +        if not connection.features.supports_transactions:
 +            return

          if connection.in_atomic_block:
              connection.atomic_blocks.pop()
 }}}

 As for the heuristics to determine if a backend supports transaction the
 situation is definitely weird on MySQL as supports is on a per-table basis
 and `default_storage_engine` is really just a guess at that.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34523#comment:13>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070187cb6d4824-f2855de3-694f-49f1-a603-4302f736fc96-000000%40eu-central-1.amazonses.com.

Reply via email to