Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
  • Loading branch information...
commit ba010ec1c04c4832d42b088b092df0969afdb7e6 1 parent ff6e529
Malcolm Tredinnick authored April 28, 2008
1  django/db/backends/__init__.py
@@ -51,6 +51,7 @@ class BaseDatabaseFeatures(object):
51 51
     uses_case_insensitive_names = False
52 52
     uses_custom_query_class = False
53 53
     empty_fetchmany_value = []
  54
+    update_can_self_select = True
54 55
 
55 56
 class BaseDatabaseOperations(object):
56 57
     """
1  django/db/backends/mysql/base.py
@@ -63,6 +63,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
63 63
     autoindexes_primary_keys = False
64 64
     inline_fk_references = False
65 65
     empty_fetchmany_value = ()
  66
+    update_can_self_select = False
66 67
 
67 68
 class DatabaseOperations(BaseDatabaseOperations):
68 69
     def date_extract_sql(self, lookup_type, field_name):
1  django/db/backends/mysql_old/base.py
@@ -67,6 +67,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
67 67
     autoindexes_primary_keys = False
68 68
     inline_fk_references = False
69 69
     empty_fetchmany_value = ()
  70
+    update_can_self_select = False
70 71
 
71 72
 class DatabaseOperations(BaseDatabaseOperations):
72 73
     def date_extract_sql(self, lookup_type, field_name):
23  django/db/models/sql/subqueries.py
@@ -159,20 +159,37 @@ def pre_sql_setup(self):
159 159
         # from other tables.
160 160
         query = self.clone(klass=Query)
161 161
         query.bump_prefix()
162  
-        query.select = []
163 162
         query.extra_select = {}
164  
-        query.add_fields([query.model._meta.pk.name])
  163
+        first_table = query.tables[0]
  164
+        if query.alias_refcount[first_table] == 1:
  165
+            # We can remove one table from the inner query.
  166
+            query.unref_alias(first_table)
  167
+            for i in xrange(1, len(query.tables)):
  168
+                table = query.tables[i]
  169
+                if query.alias_refcount[table]:
  170
+                    break
  171
+            join_info = query.alias_map[table]
  172
+            query.select = [(join_info[RHS_ALIAS], join_info[RHS_JOIN_COL])]
  173
+            must_pre_select = False
  174
+        else:
  175
+            query.select = []
  176
+            query.add_fields([query.model._meta.pk.name])
  177
+            must_pre_select = not self.connection.features.update_can_self_select
165 178
 
166 179
         # Now we adjust the current query: reset the where clause and get rid
167 180
         # of all the tables we don't need (since they're in the sub-select).
168 181
         self.where = self.where_class()
169  
-        if self.related_updates:
  182
+        if self.related_updates or must_pre_select:
  183
+            # Either we're using the idents in multiple update queries (so
  184
+            # don't want them to change), or the db backend doesn't support
  185
+            # selecting from the updating table (e.g. MySQL).
170 186
             idents = []
171 187
             for rows in query.execute_sql(MULTI):
172 188
                 idents.extend([r[0] for r in rows])
173 189
             self.add_filter(('pk__in', idents))
174 190
             self.related_ids = idents
175 191
         else:
  192
+            # The fast path. Filters and updates in one query.
176 193
             self.add_filter(('pk__in', query))
177 194
         for alias in self.tables[1:]:
178 195
             self.alias_refcount[alias] = 0

0 notes on commit ba010ec

Please sign in to comment.
Something went wrong with that request. Please try again.