Ticket #14298: cursor-close-patch.diff

File cursor-close-patch.diff, 2.8 KB (added by xoror, 5 years ago)
  • django/db/models/sql/compiler.py

     
    1313        self.connection = connection
    1414        self.using = using
    1515        self.quote_cache = {}
     16        self.iter_cursor_map = {}
    1617
    1718    def pre_sql_setup(self):
    1819        """
     
    677676        resolve_columns = hasattr(self, 'resolve_columns')
    678677        fields = None
    679678        has_aggregate_select = bool(self.query.aggregate_select)
    680         for rows in self.execute_sql(MULTI):
     679        cursor_iter = self.execute_sql(MULTI)
     680        for rows in cursor_iter:
    681681            for row in rows:
    682682                if resolve_columns:
    683683                    if fields is None:
     
    707707                    ]) + tuple(row[aggregate_end:])
    708708
    709709                yield row
     710        # iteration over cursor is completed.
     711        # it's now save to close the cursor and remove it from the lookup dict
     712        if cursor_iter in self.iter_cursor_map:
     713            self.iter_cursor_map[cursor_iter].close()
     714            del self.iter_cursor_map[cursor_iter]
    710715
    711716    def execute_sql(self, result_type=MULTI):
    712717        """
     
    734739        cursor = self.connection.cursor()
    735740        cursor.execute(sql, params)
    736741
     742        # close cursors for single results.
    737743        if not result_type:
    738744            return cursor
    739745        if result_type == SINGLE:
    740746            if self.query.ordering_aliases:
    741                 return cursor.fetchone()[:-len(self.query.ordering_aliases)]
    742             return cursor.fetchone()
     747                temp_result = cursor.fetchone()[:-len(self.query.ordering_aliases)]
     748                cursor.close()
     749                return temp_result
     750            temp_result = cursor.fetchone()
     751            cursor.close()
     752            return temp_result
    743753
    744754        # The MULTI case.
    745755        if self.query.ordering_aliases:
     
    748758        else:
    749759            result = iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)),
    750760                    self.connection.features.empty_fetchmany_value)
     761        # store iterator only if we use chunks
     762        if self.connection.features.can_use_chunked_reads:
     763            self.iter_cursor_map[result] = cursor
    751764        if not self.connection.features.can_use_chunked_reads:
    752765            # If we are using non-chunked reads, we return the same data
    753766            # structure as normally, but ensure it is all read into memory
    754767            # before going any further.
    755             return list(result)
     768            temp_ressult = list(result)
     769            cursor.close()
     770            return temp_result
    756771        return result
    757772
    758 
    759773class SQLInsertCompiler(SQLCompiler):
    760774    def placeholder(self, field, val):
    761775        if field is None:
Back to Top