diff options
| author | François Freitag <francois.freitag@polyconseil.fr> | 2016-09-28 22:39:50 -0700 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-10-04 10:46:29 -0400 |
| commit | 8ac115c730353dfc6bdbd03e0671a978dcc99e15 (patch) | |
| tree | f6a7aa9f5917de6f9d2bc529f6ba4da1f6b9c891 | |
| parent | 9e26a8331dd593c674ac94f2582093da01b070e8 (diff) | |
Fixed #27193 -- Preserved ordering in select_for_update subqueries.
| -rw-r--r-- | django/db/models/sql/compiler.py | 7 | ||||
| -rw-r--r-- | tests/select_for_update/tests.py | 9 |
2 files changed, 14 insertions, 2 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 1319b288aa..51c3d6e661 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -476,8 +476,11 @@ class SQLCompiler(object): Used when nesting this query inside another. """ obj = self.query.clone() - if obj.low_mark == 0 and obj.high_mark is None and not self.query.distinct_fields: - # If there is no slicing in use, then we can safely drop all ordering + # It's safe to drop ordering if the queryset isn't using slicing, + # distinct(*fields) or select_for_update(). + if (obj.low_mark == 0 and obj.high_mark is None and + not self.query.distinct_fields and + not self.query.select_for_update): obj.clear_ordering(True) nested_sql = obj.get_compiler(connection=self.connection).as_sql(subquery=True) if nested_sql == ('', ()): diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py index e6e1155ee2..4c30ff7179 100644 --- a/tests/select_for_update/tests.py +++ b/tests/select_for_update/tests.py @@ -300,3 +300,12 @@ class SelectForUpdateTests(TransactionTestCase): def test_nowait_and_skip_locked(self): with self.assertRaisesMessage(ValueError, 'The nowait option cannot be used with skip_locked.'): Person.objects.select_for_update(nowait=True, skip_locked=True) + + def test_ordered_select_for_update(self): + """ + Subqueries should respect ordering as an ORDER BY clause may be useful + to specify a row locking order to prevent deadlocks (#27193). + """ + with transaction.atomic(): + qs = Person.objects.filter(id__in=Person.objects.order_by('-id').select_for_update()) + self.assertIn('ORDER BY', str(qs.query)) |
