error when use two-phase transactions and pass connection to session.bind_mapper after session.commit()

Issue #1603 resolved
Former user created an issue

Steps to reproduce[BR] 1) I create new two-phase session and bind with bind_mapper(mapper, connectionObject)[BR] 2) session.commit() throws exception[BR]

The problem was in commit function, when it decides to set _ _transaction to None, next piece of code tried to make rollback() and _ _transaction is not instance of TwoPhaseTransaction.[BR]

I've fixed it by ugly hack in sqlalchemy.engine.base

from sqlalchemy.engine.base import Transaction
def close(self):
    if not self._parent.is_active or self.connection._Connection__transaction is None:
        return
    if self._parent is self:
        self.rollback()

Transaction.close = close

When I use engine instead of connection all works

Comments (6)

  1. Mike Bayer repo owner

    can you add some detail about the "error" ? is the rollback() somehow disallowed on the connection ? what backend ?

  2. Former user Account Deleted

    Rollback is allowed in this transaction.[BR] I think problem is in sqlalchemy.engine.base.Transaction.close method[BR] [BR] 1. In session.py after two phase transaction committed {{{t1.commit() #session.py:382}}} in base.Connection {{{self.__transaction}}} became None (base.py:_commit_twophase_impl():790)[BR] 2. session.py call {{{self.close():#session.py:390}}}[BR] 3. In {{{Session.close() # session.py:426}}} will be called {{{transaction.close()}}}, because I use connection instead of engine and autoclose is False[BR] 4. For two phase transactions in close method {{{self._parent is self}}}, so called rollback[BR] 5. Rollback in {{{Connection._rollback_twophase_impl #base.py:780}}} require

    But it set None in commit and transaction not started yet
    
  3. Mike Bayer repo owner

    if you could illustrate with a small sample script that reproduces the error, it would greatly increase the chances of this fix being committed today or tomorrow, otherwise I'll have to find time to reproduce the issue.

  4. Former user Account Deleted
    from sqlalchemy import create_engine, MetaData, Table
    from sqlalchemy.orm import sessionmaker, mapper
    import vr.config as config
    
    engine = create_engine("mysql://%(user)s:%(passwd)s@%(host)s/%(db)s" % config.db.COMMON, pool_size=20)
    
    meta = MetaData(engine)
    structure = Table("someTable", meta, autoload=True)
    
    class MyTable(object):
        """ Table class """
    
    mapper(MyTable, structure)
    
    connection = engine.connect()
    
    session = sessionmaker(autoflush=True, autocommit=False, expire_on_commit=False, twophase=True)()
    
    session.bind_mapper(MyTable, connection)
    
    t = MyTable()
    session.add(t)
    
    session.prepare()
    session.commit()
    
  5. Log in to comment