summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorDavid Wobrock <david.wobrock@gmail.com>2021-09-29 00:00:50 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-09-29 20:53:16 +0200
commitb2a0978610413e4cd5ebb716b8bfa7803dff8d5b (patch)
tree4ffaefa0f303e51266852bb8251eef28a5f8da54 /django
parentaab76433ed585ebe997b94547e0d790605e01ad9 (diff)
[4.0.x] Fixed #33018 -- Fixed annotations with empty queryset.
Thanks Simon Charette for the review and implementation idea. Backport of dd1fa3a31b4680c0d3712e6ae122b878138580c7 from main
Diffstat (limited to 'django')
-rw-r--r--django/db/models/expressions.py9
-rw-r--r--django/db/models/sql/compiler.py8
-rw-r--r--django/db/models/sql/query.py1
3 files changed, 15 insertions, 3 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 100da26ee6..a3317bc28c 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -702,7 +702,13 @@ class Func(SQLiteNumericMixin, Expression):
sql_parts = []
params = []
for arg in self.source_expressions:
- arg_sql, arg_params = compiler.compile(arg)
+ try:
+ arg_sql, arg_params = compiler.compile(arg)
+ except EmptyResultSet:
+ empty_result_set_value = getattr(arg, 'empty_result_set_value', NotImplemented)
+ if empty_result_set_value is NotImplemented:
+ raise
+ arg_sql, arg_params = compiler.compile(Value(empty_result_set_value))
sql_parts.append(arg_sql)
params.extend(arg_params)
data = {**self.extra, **extra_context}
@@ -1114,6 +1120,7 @@ class Subquery(BaseExpression, Combinable):
"""
template = '(%(subquery)s)'
contains_aggregate = False
+ empty_result_set_value = None
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/compiler.py b/django/db/models/sql/compiler.py
index 97288c83d7..d1009847e7 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -266,8 +266,12 @@ class SQLCompiler:
try:
sql, params = self.compile(col)
except EmptyResultSet:
- # Select a predicate that's always False.
- sql, params = '0', ()
+ empty_result_set_value = getattr(col, 'empty_result_set_value', NotImplemented)
+ if empty_result_set_value is NotImplemented:
+ # Select a predicate that's always False.
+ sql, params = '0', ()
+ else:
+ sql, params = self.compile(Value(empty_result_set_value))
else:
sql, params = col.select_format(self, sql, params)
ret.append((col, (sql, params), alias))
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index d1c0c333f5..6436b25bae 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -143,6 +143,7 @@ class Query(BaseExpression):
"""A single SQL query."""
alias_prefix = 'T'
+ empty_result_set_value = None
subq_aliases = frozenset([alias_prefix])
compiler = 'SQLCompiler'