On Sep 8, 2014, at 12:27 PM, Marius van Niekerk <[email protected]> 
wrote:

> Using SQLAlchemy 0.9.7 against a PostgreSQL 9.2 database.  
> 
> with e as an Engine:
> 
> 
> i = 1
> with e.begin() as conn:
>     x = conn.execute('select * from test01')
>     print x.fetchall()
>     with conn.contextual_connect() as conn2:
>         with conn2.begin():
>             i += 1
>             conn2.execute('insert into marius.test01 values (%s)' % str(i))
>             x = conn2.execute('select * from test01')
>             print x.fetchall()
>     x = conn.execute('select * from test01')
>     print x.fetchall()
>     raise Exception("HELLO")
> 
> 
> This will actually commit a row to the table test, rather than commit nothing.
> 
> Should the transaction not be carried over to the branched connection?  This 
> is not PostgreSQL specific.

I observed this the other day when working on some refactoring of connection 
mechanics and apparently forgot to capture it, so that is here:

https://bitbucket.org/zzzeek/sqlalchemy/issue/3190/transactional-state-isnt-carried-over-with

This isn't a use case that comes up very often; usually people are binding the 
Connection to a Session within a test scenario which has an explicit check for 
the Connection being present already.    But I think I hit it when trying to 
work up an engine-level transactional test fixture.


> 
> Something like this solves this potential issue:
> 
> class Connection(sqlalchemy.engine.Connectable):
>     """Override of :class:`sqlalchemy.engine.Connection` to allow allow 
> "nested" connections (non-forking).
> 
>     This is achieved by using a stack increment decrement.
>     """
> 
>     def __init__(self, engine, connection=None, close_with_result=False, 
> _branch=False, _execution_options=None,
>                  _dispatch=None, _has_events=None, transaction=None):
>         ...
>         self.__transaction = transaction
>         ...
>         
>     def _branch(self):
>             """Return a new Connection which references this Connection's
>             engine and connection; but does not have close_with_result 
> enabled,
>             and also whose close() method does nothing.
> 
>             This is used to execute "sub" statements within a single 
> execution,
>             usually an INSERT statement.
>             """
> 
>         return self.engine._connection_cls(
>             self.engine,
>             self._Connection__connection,
>             _branch=True,
>             _has_events=self._has_events,
>             _dispatch=self.dispatch,
>             transaction=self.__transaction)

yup that's the easy part, the tedious part is new tests in 
test/engine/test_transaction.py.   If you have an interest in submitting 
patches...

> What is the standard way to deal with this case?  Subclassing Connection to 
> implement this?

for now you'd need to work around, probably doing isinstance(conn, Connection) 
and then not doing the connect() call, if you have to be in the transaction 
already.   Or forcing in the "__transaction" attribute into the new Connection 
(you'd have to hit it as _Connection__transaction).

For my engine-level fixture, I implemented a full wrapper for everything, see 
https://review.openstack.org/#/c/113153/12/oslo/db/sqlalchemy/utils.py.


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to