Loading django/db/backends/sqlite3/base.py +10 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,10 @@ class DatabaseFeatures(BaseDatabaseFeatures): has_bulk_insert = True can_combine_inserts_with_and_without_auto_increment_pk = False @cached_property def uses_savepoints(self): return Database.sqlite_version_info >= (3, 6, 8) @cached_property def supports_stddev(self): """Confirm support for STDDEV and related stats functions Loading Loading @@ -355,6 +359,12 @@ class DatabaseWrapper(BaseDatabaseWrapper): if self.settings_dict['NAME'] != ":memory:": BaseDatabaseWrapper.close(self) def _savepoint_allowed(self): # When 'isolation_level' is None, Django doesn't provide a way to # create a transaction (yet) so savepoints can't be created. When it # isn't, sqlite3 commits before each savepoint -- it's a bug. return False def _set_autocommit(self, autocommit): if autocommit: level = None Loading docs/ref/databases.txt +1 −2 Original line number Diff line number Diff line Loading @@ -424,8 +424,7 @@ Savepoints Both the Django ORM and MySQL (when using the InnoDB :ref:`storage engine <mysql-storage-engines>`) support database :ref:`savepoints <topics-db-transactions-savepoints>`, but this feature wasn't available in Django until version 1.4 when such support was added. <topics-db-transactions-savepoints>`. If you use the MyISAM storage engine please be aware of the fact that you will receive database-generated errors if you try to use the :ref:`savepoint-related Loading docs/topics/db/transactions.txt +25 −10 Original line number Diff line number Diff line Loading @@ -251,11 +251,11 @@ the transaction middleware, and only modify selected functions as needed. Savepoints ========== A savepoint is a marker within a transaction that enables you to roll back part of a transaction, rather than the full transaction. Savepoints are available with the PostgreSQL 8, Oracle and MySQL (when using the InnoDB storage engine) backends. Other backends provide the savepoint functions, but they're empty operations -- they don't actually do anything. A savepoint is a marker within a transaction that enables you to roll back part of a transaction, rather than the full transaction. Savepoints are available with the SQLite (≥ 3.6.8), PostgreSQL, Oracle and MySQL (when using the InnoDB storage engine) backends. Other backends provide the savepoint functions, but they're empty operations -- they don't actually do anything. Savepoints aren't especially useful if you are using the default ``autocommit`` behavior of Django. However, if you are using Loading Loading @@ -314,6 +314,21 @@ The following example demonstrates the use of savepoints:: Database-specific notes ======================= Savepoints in SQLite -------------------- While SQLite ≥ 3.6.8 supports savepoints, a flaw in the design of the :mod:`sqlite3` makes them hardly usable. When autocommit is enabled, savepoints don't make sense. When it's disabled, :mod:`sqlite3` commits implicitly before savepoint-related statement. (It commits before any statement other than ``SELECT``, ``INSERT``, ``UPDATE``, ``DELETE`` and ``REPLACE``.) As a consequence, savepoints are only usable if you start a transaction manually while in autocommit mode, and Django doesn't provide an API to achieve that. Transactions in MySQL --------------------- Loading Loading @@ -363,11 +378,11 @@ itself. Savepoint rollback ~~~~~~~~~~~~~~~~~~ If you are using PostgreSQL 8 or later, you can use :ref:`savepoints <topics-db-transactions-savepoints>` to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction. For example:: You can use :ref:`savepoints <topics-db-transactions-savepoints>` to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction. For example:: a.save() # Succeeds, and never undone by savepoint rollback try: Loading tests/transactions_regress/tests.py +4 −0 Original line number Diff line number Diff line Loading @@ -309,6 +309,8 @@ class TestManyToManyAddTransaction(TransactionTestCase): class SavepointTest(TransactionTestCase): @skipIf(connection.vendor == 'sqlite', "SQLite doesn't support savepoints in managed mode") @skipUnlessDBFeature('uses_savepoints') def test_savepoint_commit(self): @commit_manually Loading @@ -324,6 +326,8 @@ class SavepointTest(TransactionTestCase): work() @skipIf(connection.vendor == 'sqlite', "SQLite doesn't support savepoints in managed mode") @skipIf(connection.vendor == 'mysql' and connection.features._mysql_storage_engine == 'MyISAM', "MyISAM MySQL storage engine doesn't support savepoints") Loading Loading
django/db/backends/sqlite3/base.py +10 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,10 @@ class DatabaseFeatures(BaseDatabaseFeatures): has_bulk_insert = True can_combine_inserts_with_and_without_auto_increment_pk = False @cached_property def uses_savepoints(self): return Database.sqlite_version_info >= (3, 6, 8) @cached_property def supports_stddev(self): """Confirm support for STDDEV and related stats functions Loading Loading @@ -355,6 +359,12 @@ class DatabaseWrapper(BaseDatabaseWrapper): if self.settings_dict['NAME'] != ":memory:": BaseDatabaseWrapper.close(self) def _savepoint_allowed(self): # When 'isolation_level' is None, Django doesn't provide a way to # create a transaction (yet) so savepoints can't be created. When it # isn't, sqlite3 commits before each savepoint -- it's a bug. return False def _set_autocommit(self, autocommit): if autocommit: level = None Loading
docs/ref/databases.txt +1 −2 Original line number Diff line number Diff line Loading @@ -424,8 +424,7 @@ Savepoints Both the Django ORM and MySQL (when using the InnoDB :ref:`storage engine <mysql-storage-engines>`) support database :ref:`savepoints <topics-db-transactions-savepoints>`, but this feature wasn't available in Django until version 1.4 when such support was added. <topics-db-transactions-savepoints>`. If you use the MyISAM storage engine please be aware of the fact that you will receive database-generated errors if you try to use the :ref:`savepoint-related Loading
docs/topics/db/transactions.txt +25 −10 Original line number Diff line number Diff line Loading @@ -251,11 +251,11 @@ the transaction middleware, and only modify selected functions as needed. Savepoints ========== A savepoint is a marker within a transaction that enables you to roll back part of a transaction, rather than the full transaction. Savepoints are available with the PostgreSQL 8, Oracle and MySQL (when using the InnoDB storage engine) backends. Other backends provide the savepoint functions, but they're empty operations -- they don't actually do anything. A savepoint is a marker within a transaction that enables you to roll back part of a transaction, rather than the full transaction. Savepoints are available with the SQLite (≥ 3.6.8), PostgreSQL, Oracle and MySQL (when using the InnoDB storage engine) backends. Other backends provide the savepoint functions, but they're empty operations -- they don't actually do anything. Savepoints aren't especially useful if you are using the default ``autocommit`` behavior of Django. However, if you are using Loading Loading @@ -314,6 +314,21 @@ The following example demonstrates the use of savepoints:: Database-specific notes ======================= Savepoints in SQLite -------------------- While SQLite ≥ 3.6.8 supports savepoints, a flaw in the design of the :mod:`sqlite3` makes them hardly usable. When autocommit is enabled, savepoints don't make sense. When it's disabled, :mod:`sqlite3` commits implicitly before savepoint-related statement. (It commits before any statement other than ``SELECT``, ``INSERT``, ``UPDATE``, ``DELETE`` and ``REPLACE``.) As a consequence, savepoints are only usable if you start a transaction manually while in autocommit mode, and Django doesn't provide an API to achieve that. Transactions in MySQL --------------------- Loading Loading @@ -363,11 +378,11 @@ itself. Savepoint rollback ~~~~~~~~~~~~~~~~~~ If you are using PostgreSQL 8 or later, you can use :ref:`savepoints <topics-db-transactions-savepoints>` to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction. For example:: You can use :ref:`savepoints <topics-db-transactions-savepoints>` to control the extent of a rollback. Before performing a database operation that could fail, you can set or update the savepoint; that way, if the operation fails, you can roll back the single offending operation, rather than the entire transaction. For example:: a.save() # Succeeds, and never undone by savepoint rollback try: Loading
tests/transactions_regress/tests.py +4 −0 Original line number Diff line number Diff line Loading @@ -309,6 +309,8 @@ class TestManyToManyAddTransaction(TransactionTestCase): class SavepointTest(TransactionTestCase): @skipIf(connection.vendor == 'sqlite', "SQLite doesn't support savepoints in managed mode") @skipUnlessDBFeature('uses_savepoints') def test_savepoint_commit(self): @commit_manually Loading @@ -324,6 +326,8 @@ class SavepointTest(TransactionTestCase): work() @skipIf(connection.vendor == 'sqlite', "SQLite doesn't support savepoints in managed mode") @skipIf(connection.vendor == 'mysql' and connection.features._mysql_storage_engine == 'MyISAM', "MyISAM MySQL storage engine doesn't support savepoints") Loading