Fixed #33796 -- Fixed ordered combined queryset crash when used in subquery on PostgreSQL and MySQL.
Thanks Shai Berger for the report.
Regression in 30a0144134
.
This commit is contained in:
parent
6f63e0ce8e
commit
44ffd8d06f
|
@ -175,6 +175,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:
|
if not self.supports_explain_analyze:
|
||||||
skips.update(
|
skips.update(
|
||||||
{
|
{
|
||||||
|
|
|
@ -116,6 +116,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
"migrations.test_operations.OperationTests."
|
"migrations.test_operations.OperationTests."
|
||||||
"test_alter_field_pk_fk_db_collation",
|
"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 = {
|
django_test_expected_failures = {
|
||||||
# A bug in Django/cx_Oracle with respect to string handling (#23843).
|
# A bug in Django/cx_Oracle with respect to string handling (#23843).
|
||||||
|
|
|
@ -548,6 +548,11 @@ class SQLCompiler:
|
||||||
or not features.supports_slicing_ordering_in_compound
|
or not features.supports_slicing_ordering_in_compound
|
||||||
):
|
):
|
||||||
part_sql = "({})".format(part_sql)
|
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),)
|
parts += ((part_sql, part_args),)
|
||||||
except EmptyResultSet:
|
except EmptyResultSet:
|
||||||
# Omit the empty queryset with UNION and with DIFFERENCE if the
|
# Omit the empty queryset with UNION and with DIFFERENCE if the
|
||||||
|
|
|
@ -321,6 +321,28 @@ class QuerySetSetOperationTests(TestCase):
|
||||||
# Combined queries don't mutate.
|
# Combined queries don't mutate.
|
||||||
self.assertCountEqual(qs, ["a1", "a2"])
|
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):
|
def test_count_union(self):
|
||||||
qs1 = Number.objects.filter(num__lte=1).values("num")
|
qs1 = Number.objects.filter(num__lte=1).values("num")
|
||||||
qs2 = Number.objects.filter(num__gte=2, num__lte=3).values("num")
|
qs2 = Number.objects.filter(num__gte=2, num__lte=3).values("num")
|
||||||
|
|
Loading…
Reference in New Issue