+- engines
+ - connections can be detached from their pool, closing on dereference
+ instead of returning to the pool for reuse
- sql
- _Label class overrides compare_self to return its ultimate object.
meaning, if you say someexpr.label('foo') == 5, it produces
def invalidate(self, e=None):
if self.connection is None:
raise exceptions.InvalidRequestError("This connection is closed")
- self._connection_record.invalidate(e=e)
+ if self._connection_record is not None:
+ self._connection_record.invalidate(e=e)
self.connection = None
self._cursors = None
self._close()
self.__counter +=1
return self
+ def detach(self):
+ if self._connection_record is not None:
+ self._connection_record.connection = None
+ self._pool.do_return_conn(self._connection_record)
+ self._connection_record = None
+
def close_open_cursors(self):
if self._cursors is not None:
for c in list(self._cursors):
if self.connection is not None:
try:
self.connection.rollback()
+ # Immediately close detached instances
+ if self._connection_record is None:
+ self.connection.close()
except Exception, e:
if self._connection_record is not None:
self._connection_record.invalidate(e=e)
def __init__(self):
global mcid
self.id = mcid
+ self.closed = False
mcid += 1
def close(self):
- pass
+ self.closed = True
def rollback(self):
pass
def cursor(self):
c1 = p.connect()
assert c1.connection.id != c_id
+
+ def test_detach(self):
+ dbapi = MockDBAPI()
+ p = pool.QueuePool(creator = lambda: dbapi.connect('foo.db'), pool_size = 1, max_overflow = 0, use_threadlocal = False)
+
+ c1 = p.connect()
+ c1.detach()
+ c_id = c1.connection.id
+
+ c2 = p.connect()
+ assert c2.connection.id != c1.connection.id
+ dbapi.raise_error = True
+
+ c2.invalidate()
+ c2 = None
+
+ c2 = p.connect()
+ assert c2.connection.id != c1.connection.id
+
+ con = c1.connection
+
+ assert not con.closed
+ c1.close()
+ assert con.closed
def testthreadlocal_del(self):
self._do_testthreadlocal(useclose=False)