#34523: update_or_create not work in parallel insertion
-------------------------------------+-------------------------------------
     Reporter:  gatello-s            |                    Owner:  nobody
         Type:  Bug                  |                   Status:  closed
    Component:  Database layer       |                  Version:  4.2
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:  needsinfo
     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 gatello-s):

 code from db/models/query.py

 {{{
 return self.create(**params), True
 }}}
 **  # test generate IntegrityError, this ok**

 {{{
 return self.get(**kwargs), False
 }}}
 **  # this must work fine, but raise
 django.db.transaction.TransactionManagementError**

 {{{
     def get_or_create(self, defaults=None, **kwargs):
         """
         Look up an object with the given kwargs, creating one if
 necessary.
         Return a tuple of (object, created), where created is a boolean
         specifying whether an object was created.
         """
         # The get() needs to be targeted at the write database in order
         # to avoid potential transaction consistency problems.
         self._for_write = True
         try:
             return self.get(**kwargs), False
         except self.model.DoesNotExist:
             params = self._extract_model_params(defaults, **kwargs)
             # Try to create an object using passed params.
             try:
                 with transaction.atomic(using=self.db):
                     params = dict(resolve_callables(params))
                     return self.create(**params), True  # test generate
 IntegrityError, this ok
             except IntegrityError:
                 try:
                     return self.get(**kwargs), False  # this must work
 fine, but raise django.db.transaction.TransactionManagementError
                 except self.model.DoesNotExist:
                     pass
                 raise
 }}}

 ----

 {{{
 ERROR: test_update_or_create (polls.tests.TransactionManagementErrorTest)
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 916, in get_or_create
     return self.get(**kwargs), False
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 637, in get
     raise self.model.DoesNotExist(
 polls.tests.TransactionManagementErrorTest.TestModel.DoesNotExist:
 TestModel matching query does not exist.

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 89, in _execute
     return self.cursor.execute(sql, params)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/mysql/base.py", line 75, in execute
     return self.cursor.execute(query, args)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 206, in execute
     res = self._query(query)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 320, in _query
     self._do_get_result(db)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 145, in _do_get_result
     self._result = result = self._get_result()
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 352, in _get_result
     return self._get_db().store_result()
 MySQLdb.IntegrityError: (1062, "Duplicate entry '1' for key 'PRIMARY'")

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 923, in get_or_create
     return self.create(**params), True
   File
 "/home/alex/workspace/test_TransactionManagementError/mysite/polls/tests.py",
 line 19, in create
     return super().create(**kwargs)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 658, in create
     obj.save(force_insert=True, using=self.db)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/base.py", line 814, in save
     self.save_base(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/base.py", line 877, in save_base
     updated = self._save_table(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/base.py", line 1020, in _save_table
     results = self._do_insert(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/base.py", line 1061, in _do_insert
     return manager._insert(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/manager.py", line 87, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 1805, in _insert
     return query.get_compiler(using=using).execute_sql(returning_fields)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/sql/compiler.py", line 1820, in
 execute_sql
     cursor.execute(sql, params)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 67, in execute
     return self._execute_with_wrappers(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 80, in
 _execute_with_wrappers
     return executor(sql, params, many, context)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 89, in _execute
     return self.cursor.execute(sql, params)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/utils.py", line 91, in __exit__
     raise dj_exc_value.with_traceback(traceback) from exc_value
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 89, in _execute
     return self.cursor.execute(sql, params)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/mysql/base.py", line 75, in execute
     return self.cursor.execute(query, args)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 206, in execute
     res = self._query(query)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 320, in _query
     self._do_get_result(db)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 145, in _do_get_result
     self._result = result = self._get_result()
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/MySQLdb/cursors.py", line 352, in _get_result
     return self._get_db().store_result()
 django.db.utils.IntegrityError: (1062, "Duplicate entry '1' for key
 'PRIMARY'")

 The above exception was the direct cause of the following exception:

 Traceback (most recent call last):
   File
 "/home/alex/workspace/test_TransactionManagementError/mysite/polls/tests.py",
 line 47, in test_update_or_create
     self.TestModel.objects.update_or_create(id=1, defaults={'field': 2})
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/manager.py", line 87, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 949, in update_or_create
     obj, created = self.select_for_update().get_or_create(defaults,
 **kwargs)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 926, in get_or_create
     return self.get(**kwargs), False
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 633, in get
     num = len(clone)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 380, in __len__
     self._fetch_all()
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 1881, in _fetch_all
     self._result_cache = list(self._iterable_class(self))
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/query.py", line 91, in __iter__
     results = compiler.execute_sql(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/models/sql/compiler.py", line 1560, in
 execute_sql
     cursor.execute(sql, params)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 67, in execute
     return self._execute_with_wrappers(
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 80, in
 _execute_with_wrappers
     return executor(sql, params, many, context)
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/utils.py", line 83, in _execute
     self.db.validate_no_broken_transaction()
   File
 "/home/alex/workspace/test_TransactionManagementError/.venv/lib/python3.9
 /site-packages/django/db/backends/base/base.py", line 531, in
 validate_no_broken_transaction
     raise TransactionManagementError(
 django.db.transaction.TransactionManagementError: An error occurred in the
 current transaction. You can't execute queries until the end of the
 'atomic' block.

 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34523#comment:7>
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/01070187c31fac50-26e7d888-7fa1-48e0-bf25-0baf33cf27e1-000000%40eu-central-1.amazonses.com.

Reply via email to