summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-04-28 11:51:52 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-04-28 11:51:52 +0000
commitba010ec1c04c4832d42b088b092df0969afdb7e6 (patch)
treed76c1ac9ad16b9bb220207fd58722488572a6b4c
parentff6e529502976b24906dd59636c3795218c6d708 (diff)
Made some types of nested update queries very slightly more efficient at the
database level. Also worked around the fact that MySQL (and maybe other backends we don't know about) cannot select from the table they're updating. Fixed #7095. git-svn-id: http://code.djangoproject.com/svn/django/trunk@7496 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-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