From dd9c6bc359a799fcbed647055b596239956a472a Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Sun, 30 Jun 2013 15:57:00 +0200 Subject: [PATCH] Introduced getters for connection.autocommit and .needs_rollback. They ensure that the attributes aren't accessed in conditions where they don't contain a valid value. Fixed #20666. --- django/db/backends/__init__.py | 34 +++++++++++++++++++++++----------- django/db/transaction.py | 12 ++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 9abb9a9637..a1fd923faf 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -204,7 +204,7 @@ class BaseDatabaseWrapper(object): def _savepoint_allowed(self): # Savepoints cannot be created outside a transaction - return self.features.uses_savepoints and not self.autocommit + return self.features.uses_savepoints and not self.get_autocommit() ##### Generic savepoint management methods ##### @@ -279,15 +279,13 @@ class BaseDatabaseWrapper(object): """ self.validate_no_atomic_block() - self.ensure_connection() - self.transaction_state.append(managed) if not managed and self.is_dirty() and not forced: self.commit() self.set_clean() - if managed == self.autocommit: + if managed == self.get_autocommit(): self.set_autocommit(not managed) def leave_transaction_management(self): @@ -298,8 +296,6 @@ class BaseDatabaseWrapper(object): """ self.validate_no_atomic_block() - self.ensure_connection() - if self.transaction_state: del self.transaction_state[-1] else: @@ -313,14 +309,21 @@ class BaseDatabaseWrapper(object): if self._dirty: self.rollback() - if managed == self.autocommit: + if managed == self.get_autocommit(): self.set_autocommit(not managed) raise TransactionManagementError( "Transaction managed block ended with pending COMMIT/ROLLBACK") - if managed == self.autocommit: + if managed == self.get_autocommit(): self.set_autocommit(not managed) + def get_autocommit(self): + """ + Check the autocommit state. + """ + self.ensure_connection() + return self.autocommit + def set_autocommit(self, autocommit): """ Enable or disable autocommit. @@ -330,13 +333,22 @@ class BaseDatabaseWrapper(object): self._set_autocommit(autocommit) self.autocommit = autocommit + def get_rollback(self): + """ + Get the "needs rollback" flag -- for *advanced use* only. + """ + if not self.in_atomic_block: + raise TransactionManagementError( + "The rollback flag doesn't work outside of an 'atomic' block.") + return self.needs_rollback + def set_rollback(self, rollback): """ Set or unset the "needs rollback" flag -- for *advanced use* only. """ if not self.in_atomic_block: raise TransactionManagementError( - "needs_rollback doesn't work outside of an 'atomic' block.") + "The rollback flag doesn't work outside of an 'atomic' block.") self.needs_rollback = rollback def validate_no_atomic_block(self): @@ -370,7 +382,7 @@ class BaseDatabaseWrapper(object): to decide in a managed block of code to decide whether there are open changes waiting for commit. """ - if not self.autocommit: + if not self.get_autocommit(): self._dirty = True def set_clean(self): @@ -436,7 +448,7 @@ class BaseDatabaseWrapper(object): if self.connection is not None: # If the application didn't restore the original autocommit setting, # don't take chances, drop the connection. - if self.autocommit != self.settings_dict['AUTOCOMMIT']: + if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']: self.close() return diff --git a/django/db/transaction.py b/django/db/transaction.py index 6031ce96c8..96be981e7b 100644 --- a/django/db/transaction.py +++ b/django/db/transaction.py @@ -123,7 +123,7 @@ def get_autocommit(using=None): """ Get the autocommit status of the connection. """ - return get_connection(using).autocommit + return get_connection(using).get_autocommit() def set_autocommit(autocommit, using=None): """ @@ -175,7 +175,7 @@ def get_rollback(using=None): """ Gets the "needs rollback" flag -- for *advanced use* only. """ - return get_connection(using).needs_rollback + return get_connection(using).get_rollback() def set_rollback(rollback, using=None): """ @@ -229,15 +229,11 @@ class Atomic(object): def __enter__(self): connection = get_connection(self.using) - # Ensure we have a connection to the database before testing - # autocommit status. - connection.ensure_connection() - if not connection.in_atomic_block: # Reset state when entering an outermost atomic block. connection.commit_on_exit = True connection.needs_rollback = False - if not connection.autocommit: + if not connection.get_autocommit(): # Some database adapters (namely sqlite3) don't handle # transactions and savepoints properly when autocommit is off. # Turning autocommit back on isn't an option; it would trigger @@ -500,7 +496,7 @@ def commit_on_success_unless_managed(using=None, savepoint=False): legacy behavior. """ connection = get_connection(using) - if connection.autocommit or connection.in_atomic_block: + if connection.get_autocommit() or connection.in_atomic_block: return atomic(using, savepoint) else: def entering(using):