diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
a
|
b
|
|
263 | 263 | def max_name_length(self): |
264 | 264 | return 64 |
265 | 265 | |
| 266 | def savepoint_create_sql(self, sid): |
| 267 | return "SAVEPOINT %s" % sid |
| 268 | |
| 269 | def savepoint_commit_sql(self, sid): |
| 270 | return "RELEASE SAVEPOINT %s" % sid |
| 271 | |
| 272 | def savepoint_rollback_sql(self, sid): |
| 273 | return "ROLLBACK TO SAVEPOINT %s" % sid |
| 274 | |
266 | 275 | class DatabaseWrapper(BaseDatabaseWrapper): |
267 | 276 | vendor = 'mysql' |
268 | 277 | operators = { |
… |
… |
|
330 | 339 | self.connection = Database.connect(**kwargs) |
331 | 340 | self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode] |
332 | 341 | self.connection.encoders[SafeString] = self.connection.encoders[str] |
| 342 | self.features.uses_savepoints = \ |
| 343 | self.get_server_version() >= (5, 0, 3) |
333 | 344 | connection_created.send(sender=self.__class__, connection=self) |
334 | 345 | cursor = CursorWrapper(self.connection.cursor()) |
335 | 346 | return cursor |
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
a
|
b
|
|
238 | 238 | * It is now possible to load fixtures containing forward references when using |
239 | 239 | MySQL with the InnoDB database engine. |
240 | 240 | |
| 241 | * The MySQL database backend supports taking advantage of savepoint as featured |
| 242 | by MySQL version 5.0.3 or newer with the InnoDB storage engine. |
| 243 | |
241 | 244 | .. _backwards-incompatible-changes-1.4: |
242 | 245 | |
243 | 246 | Backwards incompatible changes in 1.4 |
diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
a
|
b
|
|
227 | 227 | |
228 | 228 | A savepoint is a marker within a transaction that enables you to roll back |
229 | 229 | part of a transaction, rather than the full transaction. Savepoints are |
230 | | available to the PostgreSQL 8 and Oracle backends. Other backends will |
231 | | provide the savepoint functions, but they are empty operations - they won't |
232 | | actually do anything. |
| 230 | available to the PostgreSQL 8, Oracle and MySQL (version 5.0.3 and newer, when |
| 231 | using the InnoDB storage bckend) backends. Other backends will provide the |
| 232 | savepoint functions, but they are empty operations - they won't actually do |
| 233 | anything. |
| 234 | |
| 235 | .. versionchanged:: 1.4 |
| 236 | Savepoint support when using the MySQL backend was added in Django 1.4 |
233 | 237 | |
234 | 238 | Savepoints aren't especially useful if you are using the default |
235 | 239 | ``autocommit`` behavior of Django. However, if you are using |
diff --git a/tests/regressiontests/transactions_regress/tests.py b/tests/regressiontests/transactions_regress/tests.py
a
|
b
|
|
162 | 162 | _ = User.objects.all()[0] |
163 | 163 | except: |
164 | 164 | self.fail("A transaction consisting of a failed operation was not closed.") |
| 165 | |
| 166 | |
| 167 | class SavepointTest(TransactionTestCase): |
| 168 | |
| 169 | @skipUnlessDBFeature('uses_savepoints') |
| 170 | def test_savepoint_commit(self): |
| 171 | @commit_manually |
| 172 | def work(): |
| 173 | mod = Mod.objects.create(fld=1) |
| 174 | pk = mod.pk |
| 175 | sid = transaction.savepoint() |
| 176 | mod1 = Mod.objects.filter(pk=pk).update(fld=10) |
| 177 | transaction.savepoint_commit(sid) |
| 178 | mod2 = Mod.objects.get(pk=pk) |
| 179 | transaction.commit() |
| 180 | self.assertEqual(mod2.fld, 10) |
| 181 | |
| 182 | work() |
| 183 | |
| 184 | @skipUnlessDBFeature('uses_savepoints') |
| 185 | def test_savepoint_rollback(self): |
| 186 | @commit_manually |
| 187 | def work(): |
| 188 | mod = Mod.objects.create(fld=1) |
| 189 | pk = mod.pk |
| 190 | sid = transaction.savepoint() |
| 191 | mod1 = Mod.objects.filter(pk=pk).update(fld=20) |
| 192 | transaction.savepoint_rollback(sid) |
| 193 | mod2 = Mod.objects.get(pk=pk) |
| 194 | transaction.commit() |
| 195 | self.assertEqual(mod2.fld, 1) |
| 196 | |
| 197 | work() |