#34798: Using Django 4.2 with MSSQL 2019 Aggregation Containing Subquery Fails
-------------------------------------+-------------------------------------
Reporter: Haldun Komsuoglu | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: MSSQL, Aggregation, | Triage Stage:
Subquery | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):
* cc: Simon Charette (added)
Comment:
As an example the following patch
{{{#!diff
diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py
index ad00afdcc1..63d446196e 100644
--- a/tests/aggregation/tests.py
+++ b/tests/aggregation/tests.py
@@ -2249,11 +2249,12 @@ def
test_referenced_subquery_requires_wrapping(self):
with self.assertNumQueries(1) as ctx:
aggregate = (
Author.objects.annotate(
- total_books=Subquery(total_books_qs.values("total"))
+ total_books=Subquery(total_books_qs.values("total")),
+ total_books_ref=F("total_books") / 1,
)
- .values("pk", "total_books")
+ .values("pk", "total_books_ref")
.aggregate(
- sum_total_books=Sum("total_books"),
+ sum_total_books=Sum("total_books_ref"),
)
)
sql = ctx.captured_queries[0]["sql"].lower()
}}}
Makes the
`aggregation.tests.AggregateAnnotationPruningTests.test_referenced_subquery_requires_wrapping`
test fail because the `total_books_ref` annotation doesn't have a
`.subquery` property. [https://forum.djangoproject.com/t/django-4-2
-behavior-change-when-using-arrayagg-on-unnested-arrayfield-postgresql-
specific/21547/2 What I think is required here] is an
`Expression.returns_set -> bool` method (better name welcome) that is
transitive in the sense that it behaves like `contains_aggregate` does
with regards to nested expressions.
This flag would also have [https://forum.djangoproject.com/t/proposal-add-
generate-series-support-to-contrib-postgres/21947/4 other possible use
cases] but I wonder if it'd be too invasive for a backport.
Here's what it a backportable solution could look like
{{{#!diff
diff --git a/django/db/models/expressions.py
b/django/db/models/expressions.py
index a3d08d4734..40a47c4873 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -256,6 +256,12 @@ def contains_column_references(self):
for expr in self.get_source_expressions()
)
+ @cached_property
+ def contains_subquery(self):
+ return (
+ expr and expr.contains_subquery for expr in
self.get_source_expressions()
+ )
+
def resolve_expression(
self, query=None, allow_joins=True, reuse=None, summarize=False,
for_save=False
):
@@ -1544,6 +1550,7 @@ class Subquery(BaseExpression, Combinable):
contains_aggregate = False
empty_result_set_value = None
subquery = True
+ contains_subquery = True
def __init__(self, queryset, output_field=None, **extra):
# Allow the usage of both QuerySet and sql.Query objects.
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 9853919482..8013fcefe6 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -189,6 +189,7 @@ class Query(BaseExpression):
filter_is_sticky = False
subquery = False
+ contains_subquery = True
# SQL-related attributes.
# Select and related select clauses are expressions to use in the
SELECT
@@ -420,7 +421,7 @@ def get_aggregation(self, using, aggregate_exprs):
# members of `aggregates` to resolve against each others.
self.append_annotation_mask([alias])
refs_subquery |= any(
- getattr(self.annotations[ref], "subquery", False)
+ getattr(self.annotations[ref], "contains_subquery",
False)
for ref in aggregate.get_refs()
)
refs_window |= any(
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34798#comment:4>
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/0107018a2e021524-21cd0e45-2036-4988-97fd-d45b6a598bdd-000000%40eu-central-1.amazonses.com.