summaryrefslogtreecommitdiff
path: root/django/db/models/sql/query.py
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2022-11-09 21:55:47 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-11-11 08:46:08 +0100
commita9d2d8d1c36a4338758a792c475965180629a59f (patch)
treef9265a79d0a80b83e12dafd6bba39d0c85cab07e /django/db/models/sql/query.py
parent99b4f90ec6b96e8c2a9f22b360d4eb5589763034 (diff)
downloaddjango-a9d2d8d1c36a4338758a792c475965180629a59f.tar.gz
Refs #28477 -- Reduced complexity of aggregation over qualify queries.
Diffstat (limited to 'django/db/models/sql/query.py')
-rw-r--r--django/db/models/sql/query.py34
1 files changed, 20 insertions, 14 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index c9e2960012..775e2668b0 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -447,13 +447,15 @@ class Query(BaseExpression):
if alias not in added_aggregate_names
}
# Existing usage of aggregation can be determined by the presence of
- # selected aggregate and window annotations but also by filters against
- # aliased aggregate and windows via HAVING / QUALIFY.
- has_existing_aggregation = any(
- getattr(annotation, "contains_aggregate", True)
- or getattr(annotation, "contains_over_clause", True)
- for annotation in existing_annotations.values()
- ) or any(self.where.split_having_qualify()[1:])
+ # selected aggregates but also by filters against aliased aggregates.
+ _, having, qualify = self.where.split_having_qualify()
+ has_existing_aggregation = (
+ any(
+ getattr(annotation, "contains_aggregate", True)
+ for annotation in existing_annotations.values()
+ )
+ or having
+ )
# Decide if we need to use a subquery.
#
# Existing aggregations would cause incorrect results as
@@ -468,6 +470,7 @@ class Query(BaseExpression):
isinstance(self.group_by, tuple)
or self.is_sliced
or has_existing_aggregation
+ or qualify
or self.distinct
or self.combinator
):
@@ -494,13 +497,16 @@ class Query(BaseExpression):
self.model._meta.pk.get_col(inner_query.get_initial_alias()),
)
inner_query.default_cols = False
- # Mask existing annotations that are not referenced by
- # aggregates to be pushed to the outer query.
- annotation_mask = set()
- for name in added_aggregate_names:
- annotation_mask.add(name)
- annotation_mask |= inner_query.annotations[name].get_refs()
- inner_query.set_annotation_mask(annotation_mask)
+ if not qualify:
+ # Mask existing annotations that are not referenced by
+ # aggregates to be pushed to the outer query unless
+ # filtering against window functions is involved as it
+ # requires complex realising.
+ annotation_mask = set()
+ for name in added_aggregate_names:
+ annotation_mask.add(name)
+ annotation_mask |= inner_query.annotations[name].get_refs()
+ inner_query.set_annotation_mask(annotation_mask)
relabels = {t: "subquery" for t in inner_query.alias_map}
relabels[None] = "subquery"