From 84927e110e813c3bea6a600e4474eb577e15f2b9 Mon Sep 17 00:00:00 2001 From: Francesco Panico Date: Wed, 18 Jan 2023 22:42:53 +0000 Subject: [PATCH] [4.2.x] Fixed #34267 -- Fixed sliced QuerySet.union() crash. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression in 3d734c09ff0138441dfe0a59010435871d17950f. Thanks Raphaƫl Stefanini for the report. Backport of cc8aa6bf9c127a493e6dd005012b9e6397b3f319 from main --- django/db/models/sql/compiler.py | 3 --- tests/queries/test_qs_combinators.py | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 97ecd58bdd..7c433b3f06 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -532,15 +532,12 @@ class SQLCompiler: "ORDER BY not allowed in subqueries of compound statements." ) elif self.query.is_sliced and combinator == "union": - limit = (self.query.low_mark, self.query.high_mark) for compiler in compilers: # A sliced union cannot have its parts elided as some of them # might be sliced as well and in the event where only a single # part produces a non-empty resultset it might be impossible to # generate valid SQL. compiler.elide_empty = False - if not compiler.query.is_sliced: - compiler.query.set_limits(*limit) parts = () for compiler in compilers: try: diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py index 6358e537ae..96a5b24cc1 100644 --- a/tests/queries/test_qs_combinators.py +++ b/tests/queries/test_qs_combinators.py @@ -87,6 +87,15 @@ class QuerySetSetOperationTests(TestCase): qs3 = qs1.union(qs2) self.assertNumbersEqual(qs3.order_by("num")[2:3], [2]) + def test_union_slice_index(self): + Celebrity.objects.create(name="Famous") + c1 = Celebrity.objects.create(name="Very famous") + + qs1 = Celebrity.objects.filter(name="nonexistent") + qs2 = Celebrity.objects.all() + combined_qs = qs1.union(qs2).order_by("name") + self.assertEqual(combined_qs[1], c1) + def test_union_order_with_null_first_last(self): Number.objects.filter(other_num=5).update(other_num=None) qs1 = Number.objects.filter(num__lte=1) @@ -319,10 +328,10 @@ class QuerySetSetOperationTests(TestCase): e1 = ExtraInfo.objects.create(value=7, info="e1") a1 = Author.objects.create(name="a1", num=1, extra=e1) Author.objects.create(name="a2", num=3, extra=e1) - base_qs = Author.objects.select_related("extra") + base_qs = Author.objects.select_related("extra").order_by() qs1 = base_qs.filter(name="a1") qs2 = base_qs.filter(name="a2") - self.assertEqual(qs1.union(qs2).first(), a1) + self.assertEqual(qs1.union(qs2).order_by("name").first(), a1) def test_union_with_first(self): e1 = ExtraInfo.objects.create(value=7, info="e1") @@ -455,8 +464,7 @@ class QuerySetSetOperationTests(TestCase): captured_sql, ) self.assertEqual( - captured_sql.count(connection.ops.limit_offset_sql(None, 1)), - 3 if connection.features.supports_slicing_ordering_in_compound else 1, + captured_sql.count(connection.ops.limit_offset_sql(None, 1)), 1 ) def test_exists_union_empty_result(self):