From 62dc2e4829fe0b947b88f14fb9098935d05c5475 Mon Sep 17 00:00:00 2001
From: Tay Ray Chuan <rctay89@gmail.com>
Date: Sat, 12 Jun 2010 00:00:34 +0800
Subject: [PATCH] implement savepoints for sqlite3
---
django/db/backends/sqlite3/base.py | 39 ++++++++++++++++++++++++++++++++++++
1 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index bc97f5c..c57df14 100644
a
|
b
|
if Database.version_info >= (2,4,1):
|
54 | 54 | Database.register_adapter(str, lambda s:s.decode('utf-8')) |
55 | 55 | Database.register_adapter(SafeString, lambda s:s.decode('utf-8')) |
56 | 56 | |
| 57 | uses_savepoints = False |
| 58 | if Database.sqlite_version_info >= (3,6,8): |
| 59 | uses_savepoints = True |
| 60 | |
57 | 61 | class DatabaseFeatures(BaseDatabaseFeatures): |
58 | 62 | # SQLite cannot handle us only partially reading from a cursor's result set |
59 | 63 | # and then writing the same rows to the database in another cursor. This |
60 | 64 | # setting ensures we always read result sets fully into memory all in one |
61 | 65 | # go. |
62 | 66 | can_use_chunked_reads = False |
| 67 | uses_savepoints = uses_savepoints |
63 | 68 | |
64 | 69 | class DatabaseOperations(BaseDatabaseOperations): |
65 | 70 | def date_extract_sql(self, lookup_type, field_name): |
… |
… |
class DatabaseOperations(BaseDatabaseOperations):
|
90 | 95 | def no_limit_value(self): |
91 | 96 | return -1 |
92 | 97 | |
| 98 | def savepoint_create_sql(self, sid): |
| 99 | return "SAVEPOINT " + self.quote_name(sid) |
| 100 | |
| 101 | def savepoint_rollback_sql(self, sid): |
| 102 | return "ROLLBACK TO SAVEPOINT " + self.quote_name(sid) |
| 103 | |
| 104 | def savepoint_commit_sql(self, sid): |
| 105 | return "RELEASE SAVEPOINT " + self.quote_name(sid) |
| 106 | |
93 | 107 | def sql_flush(self, style, tables, sequences): |
94 | 108 | # NB: The generated SQL below is specific to SQLite |
95 | 109 | # Note: The DELETE FROM... SQL generated below works for SQLite databases |
… |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
160 | 174 | self.introspection = DatabaseIntrospection(self) |
161 | 175 | self.validation = BaseDatabaseValidation(self) |
162 | 176 | |
| 177 | if Database.sqlite_version_info >= (3,6,8): |
| 178 | self.features.uses_savepoints = True |
| 179 | self._default_isolation_level = None |
| 180 | |
163 | 181 | def _cursor(self): |
164 | 182 | if self.connection is None: |
165 | 183 | settings_dict = self.settings_dict |
… |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
172 | 190 | } |
173 | 191 | kwargs.update(settings_dict['OPTIONS']) |
174 | 192 | self.connection = Database.connect(**kwargs) |
| 193 | self._default_isolation_level = self.connection.isolation_level |
175 | 194 | # Register extract, date_trunc, and regexp functions. |
176 | 195 | self.connection.create_function("django_extract", 2, _sqlite_extract) |
177 | 196 | self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc) |
… |
… |
class DatabaseWrapper(BaseDatabaseWrapper):
|
179 | 198 | connection_created.send(sender=self.__class__) |
180 | 199 | return self.connection.cursor(factory=SQLiteCursorWrapper) |
181 | 200 | |
| 201 | def _enter_transaction_management(self, managed): |
| 202 | """ |
| 203 | If savepoints are allowed, switch the isolation_level to None. |
| 204 | |
| 205 | However, this implies autocommits, so begin a transaction explicitly - |
| 206 | django assumes non-autocommits. |
| 207 | """ |
| 208 | if managed and self.features.uses_savepoints: |
| 209 | cursor = self._cursor() |
| 210 | cursor.connection.isolation_level = None |
| 211 | cursor.execute('BEGIN TRANSACTION') |
| 212 | |
| 213 | def _leave_transaction_management(self, managed): |
| 214 | """ |
| 215 | If savepoints are allowed, we're now in autocommit mode - switch the |
| 216 | isolation_level back to the default one. |
| 217 | """ |
| 218 | if managed and self.features.uses_savepoints and self.connection.isolation_level is None: |
| 219 | self.connection.isolation_level = self._default_isolation_level |
| 220 | |
182 | 221 | def close(self): |
183 | 222 | # If database is in memory, closing the connection destroys the |
184 | 223 | # database. To prevent accidental data loss, ignore close requests on |