summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2018-12-02 22:17:32 +0000
committerTim Graham <timograham@gmail.com>2018-12-06 15:31:33 -0500
commitf9a33e3c3f4cfbff60522cd54455e78c96a9d2a4 (patch)
treec34c82c910be73980f7ed03bdb19bd6e75bb9588
parentae180fa4b7f927a4aeae772975927c9888bb0cb0 (diff)
Fixed #29932 -- Fixed combining compound queries with sub-compound queries on SQLite and Oracle.
-rw-r--r--django/db/backends/base/features.py1
-rw-r--r--django/db/backends/sqlite3/features.py1
-rw-r--r--django/db/models/sql/compiler.py12
-rw-r--r--tests/queries/test_qs_combinators.py6
4 files changed, 19 insertions, 1 deletions
diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index 56f7d4fb6a..9787901b07 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -226,6 +226,7 @@ class BaseDatabaseFeatures:
supports_select_intersection = True
supports_select_difference = True
supports_slicing_ordering_in_compound = False
+ supports_parentheses_in_compound = True
# Does the database support SQL 2003 FILTER (WHERE ...) in aggregate
# expressions?
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index d9ee9c85b8..aa24024f91 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -37,6 +37,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_partial_indexes = Database.version_info >= (3, 8, 0)
# Is "ALTER TABLE ... RENAME COLUMN" supported?
can_alter_table_rename_column = Database.sqlite_version_info >= (3, 25, 0)
+ supports_parentheses_in_compound = False
@cached_property
def supports_stddev(self):
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index aa9ffc7b0e..30fb1418ab 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -429,7 +429,17 @@ class SQLCompiler:
*self.query.values_select,
*self.query.annotation_select,
))
- parts += (compiler.as_sql(),)
+ part_sql, part_args = compiler.as_sql()
+ if compiler.query.combinator:
+ # Wrap in a subquery if wrapping in parentheses isn't
+ # supported.
+ if not features.supports_parentheses_in_compound:
+ part_sql = 'SELECT * FROM ({})'.format(part_sql)
+ # Add parentheses when combining with compound query if not
+ # already added for all compound queries.
+ elif not 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
# first queryset is nonempty.
diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py
index f1785dd783..8a928ba91f 100644
--- a/tests/queries/test_qs_combinators.py
+++ b/tests/queries/test_qs_combinators.py
@@ -214,3 +214,9 @@ class QuerySetSetOperationTests(TestCase):
list(qs1.union(qs2).order_by('num'))
# switched order, now 'exists' again:
list(qs2.union(qs1).order_by('num'))
+
+ @skipUnlessDBFeature('supports_select_difference', 'supports_select_intersection')
+ def test_qs_with_subcompound_qs(self):
+ qs1 = Number.objects.all()
+ qs2 = Number.objects.intersection(Number.objects.filter(num__gt=1))
+ self.assertEqual(qs1.difference(qs2).count(), 2)