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
This commit is contained in:
parent
ff6e529502
commit
ba010ec1c0
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue