Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.6.x] Fixed #21553 -- Ensured unusable database connections get clo…

…sed.

Backport of 5f2f47f from master
  • Loading branch information...
commit 6fa7d7c594597ab7072ffa740da5b6f4a5a6cd26 1 parent 32529e6
Aymeric Augustin aaugustin authored
7 django/db/backends/__init__.py
View
@@ -442,9 +442,14 @@ def check_constraints(self, table_names=None):
def is_usable(self):
"""
Tests if the database connection is usable.
+
This function may assume that self.connection is not None.
+
+ Actual implementations should take care not to raise exceptions
+ as that may prevent Django from recycling unusable connections.
"""
- raise NotImplementedError
+ raise NotImplementedError(
+ "subclasses of BaseDatabaseWrapper may require an is_usable() method")
def close_if_unusable_or_obsolete(self):
"""
2  django/db/backends/mysql/base.py
View
@@ -517,7 +517,7 @@ def check_constraints(self, table_names=None):
def is_usable(self):
try:
self.connection.ping()
- except DatabaseError:
+ except Database.Error:
return False
else:
return True
2  django/db/backends/oracle/base.py
View
@@ -642,7 +642,7 @@ def is_usable(self):
else:
# Use a cx_Oracle cursor directly, bypassing Django's utilities.
self.connection.cursor().execute("SELECT 1 FROM DUAL")
- except DatabaseError:
+ except Database.Error:
return False
else:
return True
2  django/db/backends/postgresql_psycopg2/base.py
View
@@ -190,7 +190,7 @@ def is_usable(self):
try:
# Use a psycopg cursor directly, bypassing Django's utilities.
self.connection.cursor().execute("SELECT 1")
- except DatabaseError:
+ except Database.Error:
return False
else:
return True
31 tests/backends/tests.py
View
@@ -612,6 +612,37 @@ def test_duplicate_table_error(self):
cursor.execute(query)
+class IsUsableTests(TransactionTestCase):
+ # Avoid using a regular TestCase because Django really dislikes closing
+ # the database connection inside a transaction at this point (#21202).
+
+ available_apps = []
+
+ # Unfortunately with sqlite3 the in-memory test database cannot be closed.
+ @skipUnlessDBFeature('test_db_allows_multiple_connections')
+ def test_is_usable_after_database_disconnects(self):
+ """
+ Test that is_usable() doesn't crash when the database disconnects.
+
+ Regression for #21553.
+ """
+ # Open a connection to the database.
+ with connection.cursor():
+ pass
+ # Emulate a connection close by the database.
+ connection._close()
+ # Even then is_usable() should not raise an exception.
+ try:
+ self.assertFalse(connection.is_usable())
+ finally:
+ # Clean up the mess created by connection._close(). Since the
+ # connection is already closed, this crashes on some backends.
+ try:
+ connection.close()
+ except Exception:
+ pass
+
+
# We don't make these tests conditional because that means we would need to
# check and differentiate between:
# * MySQL+InnoDB, MySQL+MYISAM (something we currently can't do).
Please sign in to comment.
Something went wrong with that request. Please try again.