Code

Ticket #17956: explicit_cursor_closing.patch

File explicit_cursor_closing.patch, 3.0 KB (added by nnseva, 2 years ago)

Patch for django 1.3.1.final to close opened cursors explicitly

  • django/db/models/sql/compiler.py

    old new  
    738738            return cursor 
    739739        if result_type == SINGLE: 
    740740            if self.query.ordering_aliases: 
    741                 return cursor.fetchone()[:-len(self.query.ordering_aliases)] 
    742             return cursor.fetchone() 
     741                r = cursor.fetchone()[:-len(self.query.ordering_aliases)] 
     742            else: 
     743                r = cursor.fetchone() 
     744            cursor.close() 
     745            return r 
    743746 
    744747        # The MULTI case. 
    745748        if self.query.ordering_aliases: 
    746749            result = order_modified_iter(cursor, len(self.query.ordering_aliases), 
    747750                    self.connection.features.empty_fetchmany_value) 
    748751        else: 
    749             result = iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)), 
     752            result = not_modified_iter(cursor, 
    750753                    self.connection.features.empty_fetchmany_value) 
     754 
    751755        if not self.connection.features.can_use_chunked_reads: 
    752756            # If we are using non-chunked reads, we return the same data 
    753757            # structure as normally, but ensure it is all read into memory 
     
    789793    def execute_sql(self, return_id=False): 
    790794        self.return_id = return_id 
    791795        cursor = super(SQLInsertCompiler, self).execute_sql(None) 
    792         if not (return_id and cursor): 
     796        if not cursor: 
    793797            return 
    794         if self.connection.features.can_return_id_from_insert: 
    795             return self.connection.ops.fetch_returned_insert_id(cursor) 
    796         return self.connection.ops.last_insert_id(cursor, 
    797                 self.query.model._meta.db_table, self.query.model._meta.pk.column) 
     798        r = None 
     799        if return_id: 
     800            if self.connection.features.can_return_id_from_insert: 
     801                r = self.connection.ops.fetch_returned_insert_id(cursor) 
     802            else: 
     803                r = self.connection.ops.last_insert_id(cursor, 
     804                    self.query.model._meta.db_table, self.query.model._meta.pk.column) 
     805        cursor.close() 
     806        return r 
    798807 
    799808 
    800809class SQLDeleteCompiler(SQLCompiler): 
     
    869878        cursor = super(SQLUpdateCompiler, self).execute_sql(result_type) 
    870879        rows = cursor and cursor.rowcount or 0 
    871880        is_empty = cursor is None 
     881        if cursor: 
     882            cursor.close() 
    872883        del cursor 
    873884        for query in self.query.get_related_updates(): 
    874885            aux_rows = query.get_compiler(self.using).execute_sql(result_type) 
     
    980991    for rows in iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)), 
    981992            sentinel): 
    982993        yield [r[:-trim] for r in rows] 
     994    cursor.close() 
     995 
     996def not_modified_iter(cursor, sentinel): 
     997    """ 
     998    Yields blocks of rows from a cursor. We use this iterator in usual 
     999    case - just to close the cursor at appropriate time. 
     1000    """ 
     1001    for rows in iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)), 
     1002            sentinel): 
     1003        yield [r[:] for r in rows] 
     1004    cursor.close()