[1.6.x] 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.

Backport of dd9c6bc359 from master.
This commit is contained in:
Aymeric Augustin 2013-06-30 15:57:00 +02:00
parent d255004289
commit 02976a46c9
2 changed files with 27 additions and 19 deletions

View File

@ -204,7 +204,7 @@ class BaseDatabaseWrapper(object):
def _savepoint_allowed(self): def _savepoint_allowed(self):
# Savepoints cannot be created outside a transaction # 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 ##### ##### Generic savepoint management methods #####
@ -279,15 +279,13 @@ class BaseDatabaseWrapper(object):
""" """
self.validate_no_atomic_block() self.validate_no_atomic_block()
self.ensure_connection()
self.transaction_state.append(managed) self.transaction_state.append(managed)
if not managed and self.is_dirty() and not forced: if not managed and self.is_dirty() and not forced:
self.commit() self.commit()
self.set_clean() self.set_clean()
if managed == self.autocommit: if managed == self.get_autocommit():
self.set_autocommit(not managed) self.set_autocommit(not managed)
def leave_transaction_management(self): def leave_transaction_management(self):
@ -298,8 +296,6 @@ class BaseDatabaseWrapper(object):
""" """
self.validate_no_atomic_block() self.validate_no_atomic_block()
self.ensure_connection()
if self.transaction_state: if self.transaction_state:
del self.transaction_state[-1] del self.transaction_state[-1]
else: else:
@ -313,14 +309,21 @@ class BaseDatabaseWrapper(object):
if self._dirty: if self._dirty:
self.rollback() self.rollback()
if managed == self.autocommit: if managed == self.get_autocommit():
self.set_autocommit(not managed) self.set_autocommit(not managed)
raise TransactionManagementError( raise TransactionManagementError(
"Transaction managed block ended with pending COMMIT/ROLLBACK") "Transaction managed block ended with pending COMMIT/ROLLBACK")
if managed == self.autocommit: if managed == self.get_autocommit():
self.set_autocommit(not managed) self.set_autocommit(not managed)
def get_autocommit(self):
"""
Check the autocommit state.
"""
self.ensure_connection()
return self.autocommit
def set_autocommit(self, autocommit): def set_autocommit(self, autocommit):
""" """
Enable or disable autocommit. Enable or disable autocommit.
@ -330,13 +333,22 @@ class BaseDatabaseWrapper(object):
self._set_autocommit(autocommit) self._set_autocommit(autocommit)
self.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): def set_rollback(self, rollback):
""" """
Set or unset the "needs rollback" flag -- for *advanced use* only. Set or unset the "needs rollback" flag -- for *advanced use* only.
""" """
if not self.in_atomic_block: if not self.in_atomic_block:
raise TransactionManagementError( 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 self.needs_rollback = rollback
def validate_no_atomic_block(self): 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 to decide in a managed block of code to decide whether there are open
changes waiting for commit. changes waiting for commit.
""" """
if not self.autocommit: if not self.get_autocommit():
self._dirty = True self._dirty = True
def set_clean(self): def set_clean(self):
@ -436,7 +448,7 @@ class BaseDatabaseWrapper(object):
if self.connection is not None: if self.connection is not None:
# If the application didn't restore the original autocommit setting, # If the application didn't restore the original autocommit setting,
# don't take chances, drop the connection. # don't take chances, drop the connection.
if self.autocommit != self.settings_dict['AUTOCOMMIT']: if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:
self.close() self.close()
return return

View File

@ -123,7 +123,7 @@ def get_autocommit(using=None):
""" """
Get the autocommit status of the connection. Get the autocommit status of the connection.
""" """
return get_connection(using).autocommit return get_connection(using).get_autocommit()
def set_autocommit(autocommit, using=None): def set_autocommit(autocommit, using=None):
""" """
@ -175,7 +175,7 @@ def get_rollback(using=None):
""" """
Gets the "needs rollback" flag -- for *advanced use* only. 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): def set_rollback(rollback, using=None):
""" """
@ -229,15 +229,11 @@ class Atomic(object):
def __enter__(self): def __enter__(self):
connection = get_connection(self.using) 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: if not connection.in_atomic_block:
# Reset state when entering an outermost atomic block. # Reset state when entering an outermost atomic block.
connection.commit_on_exit = True connection.commit_on_exit = True
connection.needs_rollback = False connection.needs_rollback = False
if not connection.autocommit: if not connection.get_autocommit():
# Some database adapters (namely sqlite3) don't handle # Some database adapters (namely sqlite3) don't handle
# transactions and savepoints properly when autocommit is off. # transactions and savepoints properly when autocommit is off.
# Turning autocommit back on isn't an option; it would trigger # 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. legacy behavior.
""" """
connection = get_connection(using) 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) return atomic(using, savepoint)
else: else:
def entering(using): def entering(using):