diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-04-09 11:09:16 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-04-09 11:55:43 -0400 |
| commit | 5ba31b5a8768e1ca1a08a82144ec0e726d8357c1 (patch) | |
| tree | f37a132eb427774685b7627c6b1997c084f2ca89 /lib/sqlalchemy | |
| parent | d868f7914cd0617d529a6067e8ec7843692f8937 (diff) | |
| download | sqlalchemy-5ba31b5a8768e1ca1a08a82144ec0e726d8357c1.tar.gz | |
Dont return outer transaction for _subtrans flag
Fixed critical regression where the :class:`_orm.Session` could fail to
"autobegin" a new transaction when a flush occurred without an existing
transaction in place, implicitly placing the :class:`_orm.Session` into
legacy autocommit mode which commit the transaction. The
:class:`_orm.Session` now has a check that will prevent this condition from
occurring, in addition to repairing the flush issue.
Additionally, scaled back part of the change made as part of :ticket:`5226`
which can run autoflush during an unexpire operation, to not actually
do this in the case of a :class:`_orm.Session` using legacy
:paramref:`_orm.Session.autocommit` mode, as this incurs a commit within
a refresh operation.
Fixes: #6233
Change-Id: Ia980e62a090e39e3e2a7fb77c95832ae784cc9a5
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/loading.py | 4 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 14 |
2 files changed, 14 insertions, 4 deletions
diff --git a/lib/sqlalchemy/orm/loading.py b/lib/sqlalchemy/orm/loading.py index 0dc92daf5..12acfc5b7 100644 --- a/lib/sqlalchemy/orm/loading.py +++ b/lib/sqlalchemy/orm/loading.py @@ -1343,7 +1343,9 @@ def load_scalar_attributes(mapper, state, attribute_names, passive): result = False - no_autoflush = bool(passive & attributes.NO_AUTOFLUSH) + no_autoflush = ( + bool(passive & attributes.NO_AUTOFLUSH) or state.session.autocommit + ) # in the case of inheritance, particularly concrete and abstract # concrete inheritance, the class manager might have some keys diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 0562569bf..d08abb788 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1140,8 +1140,7 @@ class Session(_SessionClassMethods): if autocommit: if future: raise sa_exc.ArgumentError( - "Cannot use autocommit mode with future=True. " - "use the autobegin flag." + "Cannot use autocommit mode with future=True." ) self.autocommit = True else: @@ -1308,7 +1307,7 @@ class Session(_SessionClassMethods): "Session objects." ) if self._autobegin(): - if not subtransactions and not nested: + if not subtransactions and not nested and not _subtrans: return self._transaction if self._transaction is not None: @@ -1321,9 +1320,18 @@ class Session(_SessionClassMethods): raise sa_exc.InvalidRequestError( "A transaction is already begun on this Session." ) + elif not self.autocommit: + # outermost transaction. must be a not nested and not + # a subtransaction + assert not nested and not _subtrans and not subtransactions + trans = SessionTransaction(self) + assert self._transaction is trans else: + # legacy autocommit mode + assert not self.future trans = SessionTransaction(self, nested=nested) assert self._transaction is trans + return self._transaction # needed for __enter__/__exit__ hook def begin_nested(self): |
