[4.1.x] Fixed #33796 -- Fixed ordered combined queryset crash when used in subquery on PostgreSQL and MySQL.

Thanks Shai Berger for the report.

Regression in 30a0144134.

Backport of 44ffd8d06f from main
This commit is contained in:
Mariusz Felisiak 2022-06-24 07:29:58 +02:00
parent 2026314b20
commit d38cd2677e
4 changed files with 51 additions and 0 deletions

View File

@ -171,6 +171,25 @@ class DatabaseFeatures(BaseDatabaseFeatures):
},
}
)
if (
self.connection.mysql_is_mariadb and self.connection.mysql_version < (10, 4)
) or (
not self.connection.mysql_is_mariadb
and self.connection.mysql_version < (8,)
):
skips.update(
{
"Parenthesized combined queries are not supported on MySQL < 8 and "
"MariaDB < 10.4": {
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_subquery",
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_subquery_related_outerref",
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_with_ordering",
}
}
)
if not self.supports_explain_analyze:
skips.update(
{

View File

@ -109,6 +109,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
"migrations.test_operations.OperationTests."
"test_alter_field_pk_fk_db_collation",
},
"Oracle raises an error when a subquery contains unnecessary ORDER BY "
"clause (#32786).": {
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_with_ordering",
},
}
django_test_expected_failures = {
# A bug in Django/cx_Oracle with respect to string handling (#23843).

View File

@ -548,6 +548,11 @@ class SQLCompiler:
or not features.supports_slicing_ordering_in_compound
):
part_sql = "({})".format(part_sql)
elif (
self.query.subquery
and features.supports_slicing_ordering_in_compound
):
part_sql = "({})".format(part_sql)
parts += ((part_sql, part_args),)
except EmptyResultSet:
# Omit the empty queryset with UNION and with DIFFERENCE if the

View File

@ -321,6 +321,28 @@ class QuerySetSetOperationTests(TestCase):
# Combined queries don't mutate.
self.assertCountEqual(qs, ["a1", "a2"])
@skipUnlessDBFeature("supports_slicing_ordering_in_compound")
def test_union_in_with_ordering(self):
qs1 = Number.objects.filter(num__gt=7).order_by("num")
qs2 = Number.objects.filter(num__lt=2).order_by("num")
self.assertNumbersEqual(
Number.objects.exclude(id__in=qs1.union(qs2).values("id")),
[2, 3, 4, 5, 6, 7],
ordered=False,
)
@skipUnlessDBFeature(
"supports_slicing_ordering_in_compound", "allow_sliced_subqueries_with_in"
)
def test_union_in_with_ordering_and_slice(self):
qs1 = Number.objects.filter(num__gt=7).order_by("num")[:1]
qs2 = Number.objects.filter(num__lt=2).order_by("-num")[:1]
self.assertNumbersEqual(
Number.objects.exclude(id__in=qs1.union(qs2).values("id")),
[0, 2, 3, 4, 5, 6, 7, 9],
ordered=False,
)
def test_count_union(self):
qs1 = Number.objects.filter(num__lte=1).values("num")
qs2 = Number.objects.filter(num__gte=2, num__lte=3).values("num")