unincremented version id counter on superclass

Issue #3996 resolved
Mike Bayer repo owner created an issue

from #3673

from sqlalchemy import *
from sqlalchemy import types
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base,  declared_attr
from sqlalchemy import event

from datetime import datetime

Base = declarative_base()

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(types.Integer, primary_key=True)
    type = Column(types.Unicode(64), nullable=False)
    bar = Column(types.DateTime(), nullable=False)
    other = Column(types.Integer)

    __mapper_args__ = {
        'polymorphic_on': u'type',
        'polymorphic_identity': u'Foo',
        'version_id_col': bar,
        'version_id_generator': False
    }

class FooDerived(Foo):
    __tablename__ = 'foo_derived'
    id = Column(types.Integer, ForeignKey(u'foo.id'), primary_key=True)
    other2 = Column(types.Integer)

    __mapper_args__ = {
        'polymorphic_identity': u'FooDerived'
    }


e = create_engine('sqlite:///:memory:', echo='debug')
Base.metadata.drop_all(e)
Base.metadata.create_all(e)

session = Session(e, autocommit=True, autoflush=False, expire_on_commit=False)

x = FooDerived()
x.bar = datetime(1970, 1, 1)
session.add(x)
session.flush()

x.other2 = 1
session.flush()

it tries to update the primary table:

#!

OperationalError: (sqlite3.OperationalError) near "WHERE": syntax error [SQL: u'UPDATE foo SET  WHERE foo.id = ? AND foo.bar = ?'] [parameters: (1, '1970-01-01 00:00:00.000000')]

docs:

#!


We can update our ``User`` object without incrementing the version counter
as well; the value of the counter will remain unchanged, and the UPDATE
statement will still check against the previous value.  This may be useful
for schemes where only certain classes of UPDATE are sensitive to concurrency
issues::

Comments (2)

  1. Mike Bayer reporter

    Detect no params w/ manual version_id counter and set to itself

    Fixed bug where programmatic version_id counter in conjunction with joined table inheritance would fail if the version_id counter were not actually incremented and no other values on the base table were modified, as the UPDATE would have an empty SET clause. Since programmatic version_id where version counter is not incremented is a documented use case, this specific condition is now detected and the UPDATE now sets the version_id value to itself, so that concurrency checks still take place.

    Change-Id: I80e385bffeed4851cc20131cbe983c173a46f655 Fixes: #3996

    → <<cset 0a67c1305266>>

  2. Log in to comment