]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Set IDENTITY_INSERT for insert.values({column: expr})
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 13 Feb 2019 16:26:54 +0000 (11:26 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 13 Feb 2019 16:28:10 +0000 (11:28 -0500)
Fixed bug where the SQL Server "IDENTITY_INSERT" logic that allows an INSERT
to proceed with an explicit value on an IDENTITY column was not detecting
the case where :meth:`.Insert.values` were used with a dictionary that
contained a :class:`.Column` as key and a SQL expression as a value.

Fixes: #4499
Change-Id: Ia61cd6524b030b40a665db9c20771f0c5aa5fcd7
(cherry picked from commit 71d642711d26ee8e1e7e8b19d70be8be1eca22eb)

doc/build/changelog/unreleased_12/4499.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
test/dialect/mssql/test_query.py
test/orm/test_unitofwork.py

diff --git a/doc/build/changelog/unreleased_12/4499.rst b/doc/build/changelog/unreleased_12/4499.rst
new file mode 100644 (file)
index 0000000..ca6be04
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+   :tags: bug, mssql
+   :tickets: 4499
+
+   Fixed bug where the SQL Server "IDENTITY_INSERT" logic that allows an INSERT
+   to proceed with an explicit value on an IDENTITY column was not detecting
+   the case where :meth:`.Insert.values` were used with a dictionary that
+   contained a :class:`.Column` as key and a SQL expression as a value.
index 9d70c70c53d4b4878eb6a11ee9ead218249acd2b..3e8dcd9b1c03aa597724079de59830f0926ec1f5 100644 (file)
@@ -1322,13 +1322,21 @@ class MSExecutionContext(default.DefaultExecutionContext):
                     and (
                         (
                             self.compiled.statement._has_multi_parameters
-                            and seq_column.key
-                            in self.compiled.statement.parameters[0]
+                            and (
+                                seq_column.key
+                                in self.compiled.statement.parameters[0]
+                                or seq_column
+                                in self.compiled.statement.parameters[0]
+                            )
                         )
                         or (
                             not self.compiled.statement._has_multi_parameters
-                            and seq_column.key
-                            in self.compiled.statement.parameters
+                            and (
+                                seq_column.key
+                                in self.compiled.statement.parameters
+                                or seq_column
+                                in self.compiled.statement.parameters
+                            )
                         )
                     )
                 )
index d70adffab608f4b3a85617375bf94af192430f11..63ca26981ba3ffe67bba3e79b37480c9c04621ee 100644 (file)
@@ -7,6 +7,7 @@ from sqlalchemy import event
 from sqlalchemy import ForeignKey
 from sqlalchemy import func
 from sqlalchemy import Integer
+from sqlalchemy import literal
 from sqlalchemy import MetaData
 from sqlalchemy import or_
 from sqlalchemy import PrimaryKeyConstraint
@@ -172,36 +173,68 @@ class IdentityInsertTest(fixtures.TestBase, AssertsCompiledSQL):
         )
 
     def test_execute(self):
-        cattable.insert().values(id=9, description="Python").execute()
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert().values(id=9, description="Python"))
 
-        cats = cattable.select().order_by(cattable.c.id).execute()
-        eq_([(9, "Python")], list(cats))
+            cats = conn.execute(cattable.select().order_by(cattable.c.id))
+            eq_([(9, "Python")], list(cats))
 
-        result = cattable.insert().values(description="PHP").execute()
-        eq_([10], result.inserted_primary_key)
-        lastcat = cattable.select().order_by(desc(cattable.c.id)).execute()
-        eq_((10, "PHP"), lastcat.first())
+            result = conn.execute(cattable.insert().values(description="PHP"))
+            eq_([10], result.inserted_primary_key)
+            lastcat = conn.execute(
+                cattable.select().order_by(desc(cattable.c.id))
+            )
+            eq_((10, "PHP"), lastcat.first())
 
     def test_executemany(self):
-        cattable.insert().execute(
-            [
-                {"id": 89, "description": "Python"},
-                {"id": 8, "description": "Ruby"},
-                {"id": 3, "description": "Perl"},
-                {"id": 1, "description": "Java"},
-            ]
-        )
-        cats = cattable.select().order_by(cattable.c.id).execute()
-        eq_(
-            [(1, "Java"), (3, "Perl"), (8, "Ruby"), (89, "Python")], list(cats)
-        )
-        cattable.insert().execute(
-            [{"description": "PHP"}, {"description": "Smalltalk"}]
-        )
-        lastcats = (
-            cattable.select().order_by(desc(cattable.c.id)).limit(2).execute()
-        )
-        eq_([(91, "Smalltalk"), (90, "PHP")], list(lastcats))
+        with testing.db.connect() as conn:
+            conn.execute(
+                cattable.insert(),
+                [
+                    {"id": 89, "description": "Python"},
+                    {"id": 8, "description": "Ruby"},
+                    {"id": 3, "description": "Perl"},
+                    {"id": 1, "description": "Java"},
+                ],
+            )
+            cats = conn.execute(cattable.select().order_by(cattable.c.id))
+            eq_(
+                [(1, "Java"), (3, "Perl"), (8, "Ruby"), (89, "Python")],
+                list(cats),
+            )
+            conn.execute(
+                cattable.insert(),
+                [{"description": "PHP"}, {"description": "Smalltalk"}],
+            )
+            lastcats = conn.execute(
+                cattable.select().order_by(desc(cattable.c.id)).limit(2)
+            )
+            eq_([(91, "Smalltalk"), (90, "PHP")], list(lastcats))
+
+    def test_insert_plain_param(self):
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert(), id=5)
+            eq_(conn.scalar(select([cattable.c.id])), 5)
+
+    def test_insert_values_key_plain(self):
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert().values(id=5))
+            eq_(conn.scalar(select([cattable.c.id])), 5)
+
+    def test_insert_values_key_expression(self):
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert().values(id=literal(5)))
+            eq_(conn.scalar(select([cattable.c.id])), 5)
+
+    def test_insert_values_col_plain(self):
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert().values({cattable.c.id: 5}))
+            eq_(conn.scalar(select([cattable.c.id])), 5)
+
+    def test_insert_values_col_expression(self):
+        with testing.db.connect() as conn:
+            conn.execute(cattable.insert().values({cattable.c.id: literal(5)}))
+            eq_(conn.scalar(select([cattable.c.id])), 5)
 
 
 class QueryUnicodeTest(fixtures.TestBase):
index 32b73994ae13790e1c598ceff5c9dd19994e62a7..26fc0c855089a3e2e863f258f8bf77df532eb59c 100644 (file)
@@ -476,6 +476,8 @@ class ForeignPKTest(fixtures.MappedTest):
 
 
 class ClauseAttributesTest(fixtures.MappedTest):
+    __backend__ = True
+
     @classmethod
     def define_tables(cls, metadata):
         Table(