]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- add some UPDATE..FROM tests and also some new reqs
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 12 Oct 2012 17:20:56 +0000 (13:20 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 12 Oct 2012 17:20:56 +0000 (13:20 -0400)
lib/sqlalchemy/testing/requirements.py
test/orm/test_update_delete.py
test/requirements.py

index 9681750b21fa075330bd2cc3686fd17eaff04241..ae285afa4b50c32b3239e6aea5f9018f3051ddc3 100644 (file)
@@ -183,3 +183,24 @@ class SuiteRequirements(Requirements):
         """target database can persist/return an empty string."""
 
         return exclusions.open()
+
+
+    @property
+    def update_from(self):
+        """Target must support UPDATE..FROM syntax"""
+        return exclusions.closed()
+
+    @property
+    def update_where_target_in_subquery(self):
+        """Target must support UPDATE where the same table is present in a
+        subquery in the WHERE clause.
+
+        This is an ANSI-standard syntax that apparently MySQL can't handle,
+        such as:
+
+        UPDATE documents SET flag=1 WHERE documents.title IN
+            (SELECT max(documents.title) AS title
+                FROM documents GROUP BY documents.user_id
+            )
+        """
+        return exclusions.open()
index 3d4d2559ca2e0c3f161b470de462614efeeec5d0..4da07458e11a418568b3dab883165b22eb31f6b2 100644 (file)
@@ -1,7 +1,7 @@
 from sqlalchemy.testing import eq_, assert_raises, assert_raises_message
 from sqlalchemy.testing import fixtures
 from sqlalchemy import Integer, String, ForeignKey, or_, and_, exc, \
-    select, func, Boolean
+    select, func, Boolean, case
 from sqlalchemy.orm import mapper, relationship, backref, Session, \
     joinedload, aliased
 from sqlalchemy import testing
@@ -541,7 +541,7 @@ class UpdateDeleteFromTest(fixtures.MappedTest):
               Column('id', Integer, primary_key=True),
               Column('user_id', None, ForeignKey('users.id')),
               Column('title', String(32)),
-              Column('flag', Boolean, default=False)
+              Column('flag', Boolean)
         )
 
     @classmethod
@@ -597,6 +597,50 @@ class UpdateDeleteFromTest(fixtures.MappedTest):
         s.query(Document).filter(Document.title == subq.c.title).\
                 update({'flag': True}, synchronize_session=False)
 
+        eq_(
+            set(s.query(Document.id, Document.flag)),
+            set([
+                    (1, True), (2, None),
+                    (3, None), (4, True),
+                    (5, True), (6, None),
+                ])
+        )
+
+    @testing.requires.update_where_target_in_subquery
+    def test_update_using_in(self):
+        Document = self.classes.Document
+        s = Session()
+
+        subq = s.query(func.max(Document.title).label('title')).\
+                group_by(Document.user_id).subquery()
+
+        s.query(Document).filter(Document.title.in_(subq)).\
+                update({'flag': True}, synchronize_session=False)
+
+        eq_(
+            set(s.query(Document.id, Document.flag)),
+            set([
+                    (1, True), (2, None),
+                    (3, None), (4, True),
+                    (5, True), (6, None),
+                ])
+        )
+
+    @testing.requires.update_where_target_in_subquery
+    @testing.requires.standalone_binds
+    def test_update_using_case(self):
+        Document = self.classes.Document
+        s = Session()
+
+
+        subq = s.query(func.max(Document.title).label('title')).\
+                group_by(Document.user_id).subquery()
+
+        # this would work with Firebird if you do literal_column('1')
+        # instead
+        case_stmt = case([(Document.title.in_(subq), True)], else_=False)
+        s.query(Document).update({'flag': case_stmt}, synchronize_session=False)
+
         eq_(
             set(s.query(Document.id, Document.flag)),
             set([
@@ -606,8 +650,6 @@ class UpdateDeleteFromTest(fixtures.MappedTest):
                 ])
         )
 
-
-
 class ExpressionUpdateTest(fixtures.MappedTest):
     @classmethod
     def define_tables(cls, metadata):
index 3e9f5ee0f5cc3c30165f2dc8a9c359ad86ad05e2..ca245eb3077d9a29996dfb80adefea4c10342f1c 100644 (file)
@@ -183,6 +183,22 @@ class DefaultRequirements(SuiteRequirements):
                 "Backend does not support UPDATE..FROM")
 
 
+    @property
+    def update_where_target_in_subquery(self):
+        """Target must support UPDATE where the same table is present in a
+        subquery in the WHERE clause.
+
+        This is an ANSI-standard syntax that apparently MySQL can't handle,
+        such as:
+
+        UPDATE documents SET flag=1 WHERE documents.title IN
+            (SELECT max(documents.title) AS title
+                FROM documents GROUP BY documents.user_id
+            )
+        """
+        return fails_if('mysql', 'MySQL error 1093 "Cant specify target table '
+                                        'for update in FROM clause"')
+
     @property
     def savepoints(self):
         """Target database must support savepoints."""