Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Ensured that thread-shareability gets validated when closing a Postgr…

…eSQL or SQLite connection. Refs #17258.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17206 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit a1d2f1f7b76d434072c35b55678ce8a3bbfb4649 1 parent 34e248e
@jphalip jphalip authored
View
2  django/db/backends/__init__.py
@@ -130,7 +130,7 @@ def validate_thread_sharing(self):
if (not self.allow_thread_sharing
and self._thread_ident != thread.get_ident()):
raise DatabaseError("DatabaseWrapper objects created in a "
- "thread can only be used in that same thread. The object"
+ "thread can only be used in that same thread. The object "
"with alias '%s' was created in thread id %s and this is "
"thread id %s."
% (self.alias, self._thread_ident, thread.get_ident()))
View
1  django/db/backends/postgresql_psycopg2/base.py
@@ -129,6 +129,7 @@ def check_constraints(self, table_names=None):
self.cursor().execute('SET CONSTRAINTS ALL DEFERRED')
def close(self):
+ self.validate_thread_sharing()
if self.connection is None:
return
View
1  django/db/backends/sqlite3/base.py
@@ -300,6 +300,7 @@ def check_constraints(self, table_names=None):
referenced_table_name, referenced_column_name))
def close(self):
+ self.validate_thread_sharing()
# If database is in memory, closing the connection destroys the
# database. To prevent accidental data loss, ignore close requests on
# an in-memory db.
View
45 tests/regressiontests/backends/tests.py
@@ -487,6 +487,9 @@ def test_connections_thread_local(self):
def runner():
from django.db import connections
for conn in connections.all():
+ # Allow thread sharing so the connection can be closed by the
+ # main thread.
+ conn.allow_thread_sharing = True
connections_set.add(conn)
for x in xrange(2):
t = threading.Thread(target=runner)
@@ -537,4 +540,46 @@ def runner(main_thread_connection):
exceptions = []
do_thread()
# All good
+ self.assertEqual(len(exceptions), 0)
+
+ def test_closing_non_shared_connections(self):
+ """
+ Ensure that a connection that is not explicitly shareable cannot be
+ closed by another thread.
+ Refs #17258.
+ """
+ # First, without explicitly enabling the connection for sharing.
+ exceptions = set()
+ def runner1():
+ def runner2(other_thread_connection):
+ try:
+ other_thread_connection.close()
+ except DatabaseError, e:
+ exceptions.add(e)
+ t2 = threading.Thread(target=runner2, args=[connections['default']])
+ t2.start()
+ t2.join()
+ t1 = threading.Thread(target=runner1)
+ t1.start()
+ t1.join()
+ # The exception was raised
+ self.assertEqual(len(exceptions), 1)
+
+ # Then, with explicitly enabling the connection for sharing.
+ exceptions = set()
+ def runner1():
+ def runner2(other_thread_connection):
+ try:
+ other_thread_connection.close()
+ except DatabaseError, e:
+ exceptions.add(e)
+ # Enable thread sharing
+ connections['default'].allow_thread_sharing = True
+ t2 = threading.Thread(target=runner2, args=[connections['default']])
+ t2.start()
+ t2.join()
+ t1 = threading.Thread(target=runner1)
+ t1.start()
+ t1.join()
+ # No exception was raised
self.assertEqual(len(exceptions), 0)
Please sign in to comment.
Something went wrong with that request. Please try again.