From: Mike Bayer Date: Tue, 13 Jan 2009 06:11:17 +0000 (+0000) Subject: - Fixed a bug with the unitofwork's "row switch" mechanism, X-Git-Tag: rel_0_5_1~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b23f8c0f2efea544954e1f6cfcdf4931b2f57213;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed a bug with the unitofwork's "row switch" mechanism, i.e. the conversion of INSERT/DELETE into an UPDATE, when combined with joined-table inheritance and an object which contained no defined values for the child table where an UPDATE with no SET clause would be rendered. --- diff --git a/CHANGES b/CHANGES index 35c0032f27..409e25340f 100644 --- a/CHANGES +++ b/CHANGES @@ -40,6 +40,12 @@ CHANGES - ColumnProperty (and front-end helpers such as ``deferred``) no longer ignores unknown **keyword arguments. + - Fixed a bug with the unitofwork's "row switch" mechanism, + i.e. the conversion of INSERT/DELETE into an UPDATE, when + combined with joined-table inheritance and an object + which contained no defined values for the child table where + an UPDATE with no SET clause would be rendered. + - schema - Index now accepts column-oriented InstrumentedAttributes (i.e. column-based mapped class attributes) as column diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 04fc9d0ef1..6bcc89b3c2 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1305,13 +1305,15 @@ class Mapper(object): if col in pks: if history.deleted: params[col._label] = prop.get_col_value(col, history.deleted[0]) + hasdata = True else: # row switch logic can reach us here # remove the pk from the update params so the update doesn't # attempt to include the pk in the update statement del params[col.key] params[col._label] = prop.get_col_value(col, history.added[0]) - hasdata = True + else: + hasdata = True elif col in pks: params[col._label] = mapper._get_state_attr_by_column(state, col) if hasdata: diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py index a4363b5e5f..553713da53 100644 --- a/test/orm/unitofwork.py +++ b/test/orm/unitofwork.py @@ -2216,6 +2216,49 @@ class RowSwitchTest(_base.MappedTest): assert list(sess.execute(t5.select(), mapper=T5)) == [(2, 'some other t5')] assert list(sess.execute(t6.select(), mapper=T5)) == [(1, 'some other t6', 2)] +class InheritingRowSwitchTest(_base.MappedTest): + def define_tables(self, metadata): + Table('parent', metadata, + Column('id', Integer, primary_key=True), + Column('pdata', String(30)) + ) + Table('child', metadata, + Column('id', Integer, primary_key=True), + Column('pid', Integer, ForeignKey('parent.id')), + Column('cdata', String(30)) + ) + + def setup_classes(self): + class P(_base.ComparableEntity): + pass + + class C(P): + pass + + @testing.resolve_artifact_names + def test_row_switch_no_child_table(self): + mapper(P, parent) + mapper(C, child, inherits=P) + + sess = create_session() + c1 = C(id=1, pdata='c1', cdata='c1') + sess.add(c1) + sess.flush() + + # establish a row switch between c1 and c2. + # c2 has no value for the "child" table + c2 = C(id=1, pdata='c2') + sess.add(c2) + sess.delete(c1) + + self.assert_sql_execution(testing.db, sess.flush, + CompiledSQL("UPDATE parent SET pdata=:pdata WHERE parent.id = :parent_id", + {'pdata':'c2', 'parent_id':1} + ) + ) + + + class TransactionTest(_base.MappedTest): __requires__ = ('deferrable_constraints',)