Code

Ticket #14298: cursor-close-patch.diff

File cursor-close-patch.diff, 2.8 KB (added by xoror, 3 years ago)
Line 
1Index: django/db/models/sql/compiler.py
2===================================================================
3--- django/db/models/sql/compiler.py    (revision 15147)
4+++ django/db/models/sql/compiler.py    (working copy)
5@@ -13,6 +13,7 @@
6         self.connection = connection
7         self.using = using
8         self.quote_cache = {}
9+        self.iter_cursor_map = {}
10 
11     def pre_sql_setup(self):
12         """
13@@ -677,7 +676,8 @@
14         resolve_columns = hasattr(self, 'resolve_columns')
15         fields = None
16         has_aggregate_select = bool(self.query.aggregate_select)
17-        for rows in self.execute_sql(MULTI):
18+        cursor_iter = self.execute_sql(MULTI)
19+        for rows in cursor_iter:
20             for row in rows:
21                 if resolve_columns:
22                     if fields is None:
23@@ -707,6 +707,11 @@
24                     ]) + tuple(row[aggregate_end:])
25 
26                 yield row
27+        # iteration over cursor is completed.
28+        # it's now save to close the cursor and remove it from the lookup dict
29+        if cursor_iter in self.iter_cursor_map:
30+            self.iter_cursor_map[cursor_iter].close()
31+            del self.iter_cursor_map[cursor_iter]
32 
33     def execute_sql(self, result_type=MULTI):
34         """
35@@ -734,12 +739,17 @@
36         cursor = self.connection.cursor()
37         cursor.execute(sql, params)
38 
39+        # close cursors for single results.
40         if not result_type:
41             return cursor
42         if result_type == SINGLE:
43             if self.query.ordering_aliases:
44-                return cursor.fetchone()[:-len(self.query.ordering_aliases)]
45-            return cursor.fetchone()
46+                temp_result = cursor.fetchone()[:-len(self.query.ordering_aliases)]
47+                cursor.close()
48+                return temp_result
49+            temp_result = cursor.fetchone()
50+            cursor.close()
51+            return temp_result
52 
53         # The MULTI case.
54         if self.query.ordering_aliases:
55@@ -748,14 +758,18 @@
56         else:
57             result = iter((lambda: cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE)),
58                     self.connection.features.empty_fetchmany_value)
59+        # store iterator only if we use chunks
60+        if self.connection.features.can_use_chunked_reads:
61+            self.iter_cursor_map[result] = cursor
62         if not self.connection.features.can_use_chunked_reads:
63             # If we are using non-chunked reads, we return the same data
64             # structure as normally, but ensure it is all read into memory
65             # before going any further.
66-            return list(result)
67+            temp_ressult = list(result)
68+            cursor.close()
69+            return temp_result
70         return result
71 
72-
73 class SQLInsertCompiler(SQLCompiler):
74     def placeholder(self, field, val):
75         if field is None: