From: Mike Bayer Date: Wed, 16 Nov 2022 17:45:54 +0000 (-0500) Subject: ensure implicit_returning is checked on a Table instance X-Git-Tag: rel_2_0_0b4~41^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab84559ca0f4cce1638a00f48295085e18ecaf45;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git ensure implicit_returning is checked on a Table instance 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 --- diff --git a/doc/build/changelog/unreleased_20/8812.rst b/doc/build/changelog/unreleased_20/8812.rst new file mode 100644 index 0000000000..a354ce0f9a --- /dev/null +++ b/doc/build/changelog/unreleased_20/8812.rst @@ -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. diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py index dfb61c28ac..7fddf7e69b 100644 --- a/lib/sqlalchemy/orm/persistence.py +++ b/lib/sqlalchemy/orm/persistence.py @@ -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 ) ) diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py index 0fac7ccdad..f204e954ca 100644 --- a/test/orm/test_unitofworkv2.py +++ b/test/orm/test_unitofworkv2.py @@ -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