Commits

Mike Bayer committed 65b05cb

- MySQL's update does work. add some logic to compiler to convert from ORM column to Table column

Comments (0)

Files changed (3)

     and if the parent table is referenced in the
     WHERE clause, the compiler will call upon
     UPDATE..FROM syntax as allowed by the dialect
-    to satisfy the WHERE clause.  Target columns
-    must still be in the target table i.e.
-    does not support MySQL's multi-table update
-    feature (even though this is in Core).
+    to satisfy the WHERE clause.  MySQL's multi-table
+    update feature is also supported if columns
+    are specified by object in the "values" dicitionary.
     PG's DELETE..USING is also not available
     in Core yet.
 

lib/sqlalchemy/sql/compiler.py

         # special logic that only occurs for multi-table UPDATE
         # statements
         if extra_tables and stmt.parameters:
+            normalized_params = dict(
+                (sql._clause_element_as_expr(c), param)
+                for c, param in stmt.parameters.items()
+            )
             assert self.isupdate
             affected_tables = set()
             for t in extra_tables:
                 for c in t.c:
-                    if c in stmt.parameters:
+                    if c in normalized_params:
                         affected_tables.add(t)
                         check_columns[c.key] = c
-                        value = stmt.parameters[c]
+                        value = normalized_params[c]
                         if sql._is_literal(value):
                             value = self._create_crud_bind_param(
                                             c, value, required=value is required)
             # server_onupdate for these
             for t in affected_tables:
                 for c in t.c:
-                    if c in stmt.parameters:
+                    if c in normalized_params:
                         continue
                     elif c.onupdate is not None and not c.onupdate.is_sequence:
                         if c.onupdate.is_clause_element:

test/orm/test_update_delete.py

             set([('e1', 'e1', ), ('e2', 'e5')])
         )
 
+    @testing.only_on('mysql', 'Multi table update')
+    def test_update_from_multitable(self):
+        Engineer = self.classes.Engineer
+        Person = self.classes.Person
+        s = Session(testing.db)
+        s.query(Engineer).filter(Engineer.id == Person.id).\
+            filter(Person.name == 'e2').update({Person.name: 'e22',
+                                Engineer.engineer_name: 'e55'})
+
+        eq_(
+            set(s.query(Person.name, Engineer.engineer_name)),
+            set([('e1', 'e1', ), ('e22', 'e55')])
+        )