Commit ba010ec1 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
Browse files

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
parent ff6e5295
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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):
    """
+1 −0
Original line number Diff line number Diff line
@@ -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):
+1 −0
Original line number Diff line number Diff line
@@ -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):
+20 −3
Original line number Diff line number Diff line
@@ -159,20 +159,37 @@ class UpdateQuery(Query):
        # from other tables.
        query = self.clone(klass=Query)
        query.bump_prefix()
        query.select = []
        query.extra_select = {}
        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