]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
ensure implicit_returning is checked on a Table instance
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 16 Nov 2022 17:45:54 +0000 (12:45 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 22 Nov 2022 19:06:09 +0000 (14:06 -0500)
Fixed regression where flushing a mapped class that's mapped against a
subquery, such as a direct mapping or some forms of concrete table
inheritance, would fail if the :paramref:`_orm.Mapper.eager_defaults`
parameter were used.

mapper.local_table can still be a non-table instance.
correct the check first added in 466ed5b53a3.

Fixes: #8812
Change-Id: I1bb2b83c31b910fbd96fcd3ac43e789b657aebf7

doc/build/changelog/unreleased_20/8812.rst [new file with mode: 0644]
lib/sqlalchemy/orm/persistence.py
test/orm/test_unitofworkv2.py

diff --git a/doc/build/changelog/unreleased_20/8812.rst b/doc/build/changelog/unreleased_20/8812.rst
new file mode 100644 (file)
index 0000000..a354ce0
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 8812
+
+    Fixed regression where flushing a mapped class that's mapped against a
+    subquery, such as a direct mapping or some forms of concrete table
+    inheritance, would fail if the :paramref:`_orm.Mapper.eager_defaults`
+    parameter were used.
index dfb61c28ac2e95659773a709dc6b6d2558845456..7fddf7e69b3ac8e906a2e75cdd6fe8370ef5d800 100644 (file)
@@ -992,7 +992,7 @@ def _emit_insert_statements(
                 or (
                     has_all_defaults
                     or not base_mapper.eager_defaults
-                    or not base_mapper.local_table.implicit_returning
+                    or not table.implicit_returning
                     or not connection.dialect.insert_returning
                 )
             )
index 0fac7ccdad5803567d3fe24f495ddd0112749e00..f204e954cabec6b69647611d3880e7d5a647d6c1 100644 (file)
@@ -3046,6 +3046,70 @@ class EagerDefaultsTest(fixtures.MappedTest):
             ),
         )
 
+    @testing.fixture
+    def selectable_fixture(self, decl_base):
+
+        t1, t2 = self.tables("test", "test2")
+
+        stmt = (
+            select(t1.c.id, t1.c.foo, t2.c.id.label("id2"), t2.c.bar)
+            .join_from(t1, t2, t1.c.foo == t2.c.foo)
+            .subquery()
+        )
+
+        class MyClass(decl_base):
+            __table__ = stmt
+
+            __mapper_args__ = {"eager_defaults": True}
+
+        return MyClass
+
+    def test_against_selectable_insert(self, selectable_fixture):
+        """test #8812"""
+        MyClass = selectable_fixture
+
+        s = fixture_session()
+        obj = MyClass(id=1, id2=1, bar=5)
+        s.add(obj)
+
+        with self.sql_execution_asserter() as asserter:
+            s.flush()
+
+        asserter.assert_(
+            Conditional(
+                testing.db.dialect.insert_executemany_returning,
+                [
+                    CompiledSQL(
+                        "INSERT INTO test (id) VALUES (:id) "
+                        "RETURNING test.foo",
+                        [{"id": 1}],
+                    ),
+                    CompiledSQL(
+                        "INSERT INTO test2 (id, bar) VALUES (:id, :bar)",
+                        [{"id": 1, "bar": 5}],
+                    ),
+                ],
+                [
+                    CompiledSQL(
+                        "INSERT INTO test (id) VALUES (:id)",
+                        [{"id": 1}],
+                    ),
+                    CompiledSQL(
+                        "INSERT INTO test2 (id, bar) VALUES (:id, :bar)",
+                        [{"id": 1, "bar": 5}],
+                    ),
+                    CompiledSQL(
+                        "SELECT anon_1.foo AS anon_1_foo FROM "
+                        "(SELECT test.id AS id, test.foo AS foo, "
+                        "test2.id AS id2, test2.bar AS bar FROM test "
+                        "JOIN test2 ON test.foo = test2.foo) AS anon_1 "
+                        "WHERE anon_1.id = :pk_1 AND anon_1.id2 = :pk_2",
+                        [{"pk_1": 1, "pk_2": 1}],
+                    ),
+                ],
+            ),
+        )
+
 
 class TypeWoBoolTest(fixtures.MappedTest, testing.AssertsExecutionResults):
     """test support for custom datatypes that return a non-__bool__ value