Commits

Mike Bayer committed 1973431

- 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.

Comments (0)

Files changed (3)

     - 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

lib/sqlalchemy/orm/mapper.py

                                 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:

test/orm/unitofwork.py

         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',)