summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/backends/__init__.py1
-rw-r--r--django/db/backends/mysql/base.py1
-rw-r--r--django/db/backends/mysql_old/base.py1
-rw-r--r--django/db/models/sql/subqueries.py23
4 files changed, 23 insertions, 3 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
index 8917fc3b23..063c0ae411 100644
--- a/django/db/backends/__init__.py
+++ b/django/db/backends/__init__.py
@@ -51,6 +51,7 @@ class BaseDatabaseFeatures(object):
uses_case_insensitive_names = False
uses_custom_query_class = False
empty_fetchmany_value = []
+ update_can_self_select = True
class BaseDatabaseOperations(object):
"""
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 17aa6f13bf..da57ecbe47 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -63,6 +63,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
autoindexes_primary_keys = False
inline_fk_references = False
empty_fetchmany_value = ()
+ update_can_self_select = False
class DatabaseOperations(BaseDatabaseOperations):
def date_extract_sql(self, lookup_type, field_name):
diff --git a/django/db/backends/mysql_old/base.py b/django/db/backends/mysql_old/base.py
index efbfeeafc5..0ae114d176 100644
--- a/django/db/backends/mysql_old/base.py
+++ b/django/db/backends/mysql_old/base.py
@@ -67,6 +67,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
autoindexes_primary_keys = False
inline_fk_references = False
empty_fetchmany_value = ()
+ update_can_self_select = False
class DatabaseOperations(BaseDatabaseOperations):
def date_extract_sql(self, lookup_type, field_name):
diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py
index 1f9a13ecdc..7385cd00e1 100644
--- a/django/db/models/sql/subqueries.py
+++ b/django/db/models/sql/subqueries.py
@@ -159,20 +159,37 @@ class UpdateQuery(Query):
# from other tables.
query = self.clone(klass=Query)
query.bump_prefix()
- query.select = []
query.extra_select = {}
- query.add_fields([query.model._meta.pk.name])
+ first_table = query.tables[0]
+ if query.alias_refcount[first_table] == 1:
+ # We can remove one table from the inner query.
+ query.unref_alias(first_table)
+ for i in xrange(1, len(query.tables)):
+ table = query.tables[i]
+ if query.alias_refcount[table]:
+ break
+ join_info = query.alias_map[table]
+ query.select = [(join_info[RHS_ALIAS], join_info[RHS_JOIN_COL])]
+ must_pre_select = False
+ else:
+ query.select = []
+ query.add_fields([query.model._meta.pk.name])
+ must_pre_select = not self.connection.features.update_can_self_select
# Now we adjust the current query: reset the where clause and get rid
# of all the tables we don't need (since they're in the sub-select).
self.where = self.where_class()
- if self.related_updates:
+ if self.related_updates or must_pre_select:
+ # Either we're using the idents in multiple update queries (so
+ # don't want them to change), or the db backend doesn't support
+ # selecting from the updating table (e.g. MySQL).
idents = []
for rows in query.execute_sql(MULTI):
idents.extend([r[0] for r in rows])
self.add_filter(('pk__in', idents))
self.related_ids = idents
else:
+ # The fast path. Filters and updates in one query.
self.add_filter(('pk__in', query))
for alias in self.tables[1:]:
self.alias_refcount[alias] = 0