summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-12-13 12:44:23 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-12-13 12:45:51 -0500
commitff471152b62f71accda62d9ede87e0107b8a8bcb (patch)
treedbfd6463e0b4a399ae28f0e58551e4676ac7eba0 /lib/sqlalchemy
parent926952c4afe0b2e16c4a74f05958bded7b932760 (diff)
downloadsqlalchemy-ff471152b62f71accda62d9ede87e0107b8a8bcb.tar.gz
Close connection if begin fails
Fixed issue where by if the "begin" of a transaction failed at the Core engine/connection level, such as due to network error or database is locked for some transactional recipes, within the context of the :class:`.Session` procuring that connection from the connection pool and then immediately returning it, the ORM :class:`.Session` would not close the connection despite this connection not being stored within the state of that :class:`.Session`. This would lead to the connection being cleaned out by the connection pool weakref handler within garbage collection which is an unpreferred codepath that in some special configurations can emit errors in standard error. Fixes: #5034 Change-Id: I6502a55791d86845f34bc10889c218f00765dfdc
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/session.py39
1 files changed, 24 insertions, 15 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index ac495f321..e331e2512 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -415,6 +415,7 @@ class SessionTransaction(object):
)
return self._connections[bind][0]
+ local_connect = False
if self._parent:
conn = self._parent._connection_for_bind(bind, execution_options)
if not self.nested:
@@ -429,24 +430,32 @@ class SessionTransaction(object):
)
else:
conn = bind.connect()
+ local_connect = True
- if execution_options:
- conn = conn.execution_options(**execution_options)
+ try:
+ if execution_options:
+ conn = conn.execution_options(**execution_options)
- if self.session.twophase and self._parent is None:
- transaction = conn.begin_twophase()
- elif self.nested:
- transaction = conn.begin_nested()
+ if self.session.twophase and self._parent is None:
+ transaction = conn.begin_twophase()
+ elif self.nested:
+ transaction = conn.begin_nested()
+ else:
+ transaction = conn.begin()
+ except:
+ # connection will not not be associated with this Session;
+ # close it immediately so that it isn't closed under GC
+ if local_connect:
+ conn.close()
+ raise
else:
- transaction = conn.begin()
-
- self._connections[conn] = self._connections[conn.engine] = (
- conn,
- transaction,
- conn is not bind,
- )
- self.session.dispatch.after_begin(self.session, self, conn)
- return conn
+ self._connections[conn] = self._connections[conn.engine] = (
+ conn,
+ transaction,
+ conn is not bind,
+ )
+ self.session.dispatch.after_begin(self.session, self, conn)
+ return conn
def prepare(self):
if self._parent is not None or not self.session.twophase: