From c80c81163e0d31aefc82eafef2b4807cde6ab0b5 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Sat, 15 Feb 2025 17:48:53 +0100 Subject: [PATCH] [5.2.x] Refs #36181 -- Removed the obsolete SubqueryConstraint machinery. Adding proper support for subquery right-hand-sides to TupleIn made it obsolete. Backport of d386405e04dac50656af50d100a14efdf8c58e8f from main Co-authored-by: Simon Charette --- django/db/backends/mysql/compiler.py | 40 ++++++++-------------- django/db/models/fields/related_lookups.py | 13 ++----- django/db/models/sql/compiler.py | 14 -------- django/db/models/sql/where.py | 20 ----------- 4 files changed, 16 insertions(+), 71 deletions(-) diff --git a/django/db/backends/mysql/compiler.py b/django/db/backends/mysql/compiler.py index 2ec6bea2f1..0291b76c70 100644 --- a/django/db/backends/mysql/compiler.py +++ b/django/db/backends/mysql/compiler.py @@ -1,28 +1,20 @@ from django.core.exceptions import FieldError, FullResultSet from django.db.models.expressions import Col -from django.db.models.sql import compiler +from django.db.models.sql.compiler import SQLAggregateCompiler, SQLCompiler +from django.db.models.sql.compiler import SQLDeleteCompiler as BaseSQLDeleteCompiler +from django.db.models.sql.compiler import SQLInsertCompiler +from django.db.models.sql.compiler import SQLUpdateCompiler as BaseSQLUpdateCompiler + +__all__ = [ + "SQLAggregateCompiler", + "SQLCompiler", + "SQLDeleteCompiler", + "SQLInsertCompiler", + "SQLUpdateCompiler", +] -class SQLCompiler(compiler.SQLCompiler): - def as_subquery_condition(self, alias, columns, compiler): - qn = compiler.quote_name_unless_alias - qn2 = self.connection.ops.quote_name - sql, params = self.as_sql() - return ( - "(%s) IN (%s)" - % ( - ", ".join("%s.%s" % (qn(alias), qn2(column)) for column in columns), - sql, - ), - params, - ) - - -class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler): - pass - - -class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler): +class SQLDeleteCompiler(BaseSQLDeleteCompiler): def as_sql(self): # Prefer the non-standard DELETE FROM syntax over the SQL generated by # the SQLDeleteCompiler's default implementation when multiple tables @@ -52,7 +44,7 @@ class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler): return " ".join(result), tuple(params) -class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler): +class SQLUpdateCompiler(BaseSQLUpdateCompiler): def as_sql(self): update_query, update_params = super().as_sql() # MySQL and MariaDB support UPDATE ... ORDER BY syntax. @@ -78,7 +70,3 @@ class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler): # removed in .update() and cannot be resolved. pass return update_query, update_params - - -class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler): - pass diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py index 38d6308f53..9fc7db7c34 100644 --- a/django/db/models/fields/related_lookups.py +++ b/django/db/models/fields/related_lookups.py @@ -84,21 +84,12 @@ class RelatedIn(In): def as_sql(self, compiler, connection): if isinstance(self.lhs, ColPairs): - from django.db.models.sql.where import SubqueryConstraint - if self.rhs_is_direct_value(): values = [get_normalized_value(value, self.lhs) for value in self.rhs] lookup = TupleIn(self.lhs, values) - return compiler.compile(lookup) else: - return compiler.compile( - SubqueryConstraint( - self.lhs.alias, - [target.column for target in self.lhs.targets], - [source.name for source in self.lhs.sources], - self.rhs, - ), - ) + lookup = TupleIn(self.lhs, self.rhs) + return compiler.compile(lookup) return super().as_sql(compiler, connection) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 04372c509e..0b6cfbfc37 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -22,7 +22,6 @@ from django.db.models.sql.constants import ( SINGLE, ) from django.db.models.sql.query import Query, get_order_dir -from django.db.models.sql.where import AND from django.db.transaction import TransactionManagementError from django.utils.functional import cached_property from django.utils.hashable import make_hashable @@ -1661,19 +1660,6 @@ class SQLCompiler: return list(result) return result - def as_subquery_condition(self, alias, columns, compiler): - qn = compiler.quote_name_unless_alias - qn2 = self.connection.ops.quote_name - query = self.query.clone() - - for index, select_col in enumerate(query.select): - lhs_sql, lhs_params = self.compile(select_col) - rhs = "%s.%s" % (qn(alias), qn2(columns[index])) - query.where.add(RawSQL("%s = %s" % (lhs_sql, rhs), lhs_params), AND) - - sql, params = query.as_sql(compiler, self.connection) - return "EXISTS %s" % sql, params - def explain_query(self): result = list(self.execute_sql()) # Some backends return 1 item tuples with strings, and others return diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index 0fded5cce3..82f96aa6ec 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -343,23 +343,3 @@ class ExtraWhere: def as_sql(self, compiler=None, connection=None): sqls = ["(%s)" % sql for sql in self.sqls] return " AND ".join(sqls), list(self.params or ()) - - -class SubqueryConstraint: - # Even if aggregates or windows would be used in a subquery, - # the outer query isn't interested about those. - contains_aggregate = False - contains_over_clause = False - - def __init__(self, alias, columns, targets, query_object): - self.alias = alias - self.columns = columns - self.targets = targets - query_object.clear_ordering(clear_default=True) - self.query_object = query_object - - def as_sql(self, compiler, connection): - query = self.query_object - query.set_values(self.targets) - query_compiler = query.get_compiler(connection=connection) - return query_compiler.as_subquery_condition(self.alias, self.columns, compiler)