From: Mike Bayer Date: Wed, 19 Mar 2025 22:30:21 +0000 (-0400) Subject: skip FROM disambiguation for immediate alias of table X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ea3be0681dc09338e53b63cea4803de80ebcdc7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git skip FROM disambiguation for immediate alias of table Fixed regression caused by :ticket:`7471` leading to a SQL compilation issue where name disambiguation for two same-named FROM clauses with table aliasing in use at the same time would produce invalid SQL in the FROM clause with two "AS" clauses for the aliased table, due to double aliasing. Fixes: #12451 Change-Id: I981823f8f2cdf3992d65ace93a21fc20d1d74cda --- diff --git a/doc/build/changelog/unreleased_20/12451.rst b/doc/build/changelog/unreleased_20/12451.rst new file mode 100644 index 0000000000..71b6983ad3 --- /dev/null +++ b/doc/build/changelog/unreleased_20/12451.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, sql + :tickets: 12451 + + Fixed regression caused by :ticket:`7471` leading to a SQL compilation + issue where name disambiguation for two same-named FROM clauses with table + aliasing in use at the same time would produce invalid SQL in the FROM + clause with two "AS" clauses for the aliased table, due to double aliasing. diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 768a906d6a..79dd71ccf9 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -5260,6 +5260,7 @@ class SQLCompiler(Compiled): use_schema=True, from_linter=None, ambiguous_table_name_map=None, + enclosing_alias=None, **kwargs, ): if from_linter: @@ -5278,7 +5279,11 @@ class SQLCompiler(Compiled): ret = self.preparer.quote(table.name) if ( - not effective_schema + ( + enclosing_alias is None + or enclosing_alias.element is not table + ) + and not effective_schema and ambiguous_table_name_map and table.name in ambiguous_table_name_map ): diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index c167b627d8..5995c5848f 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -6901,65 +6901,59 @@ class SchemaTest(fixtures.TestBase, AssertsCompiledSQL): render_schema_translate=True, ) - def test_schema_non_schema_disambiguation(self): - """test #7471""" - - t1 = table("some_table", column("id"), column("q")) - t2 = table("some_table", column("id"), column("p"), schema="foo") - - self.assert_compile( - select(t1, t2), + @testing.combinations( + ( + lambda t1, t2: select(t1, t2), "SELECT some_table_1.id, some_table_1.q, " "foo.some_table.id AS id_1, foo.some_table.p " "FROM some_table AS some_table_1, foo.some_table", - ) - - self.assert_compile( - select(t1, t2).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL), + ), + ( + lambda t1, t2: select(t1, t2).set_label_style( + LABEL_STYLE_TABLENAME_PLUS_COL + ), # the original "tablename_colname" label is preserved despite # the alias of some_table "SELECT some_table_1.id AS some_table_id, some_table_1.q AS " "some_table_q, foo.some_table.id AS foo_some_table_id, " "foo.some_table.p AS foo_some_table_p " "FROM some_table AS some_table_1, foo.some_table", - ) - - self.assert_compile( - select(t1, t2).join_from(t1, t2, t1.c.id == t2.c.id), + ), + ( + lambda t1, t2: select(t1, t2).join_from( + t1, t2, t1.c.id == t2.c.id + ), "SELECT some_table_1.id, some_table_1.q, " "foo.some_table.id AS id_1, foo.some_table.p " "FROM some_table AS some_table_1 " "JOIN foo.some_table ON some_table_1.id = foo.some_table.id", - ) - - self.assert_compile( - select(t1, t2).where(t1.c.id == t2.c.id), + ), + ( + lambda t1, t2: select(t1, t2).where(t1.c.id == t2.c.id), "SELECT some_table_1.id, some_table_1.q, " "foo.some_table.id AS id_1, foo.some_table.p " "FROM some_table AS some_table_1, foo.some_table " "WHERE some_table_1.id = foo.some_table.id", - ) - - self.assert_compile( - select(t1).where(t1.c.id == t2.c.id), + ), + ( + lambda t1, t2: select(t1).where(t1.c.id == t2.c.id), "SELECT some_table_1.id, some_table_1.q " "FROM some_table AS some_table_1, foo.some_table " "WHERE some_table_1.id = foo.some_table.id", - ) - - subq = select(t1).where(t1.c.id == t2.c.id).subquery() - self.assert_compile( - select(t2).select_from(t2).join(subq, t2.c.id == subq.c.id), + ), + ( + lambda t2, subq: select(t2) + .select_from(t2) + .join(subq, t2.c.id == subq.c.id), "SELECT foo.some_table.id, foo.some_table.p " "FROM foo.some_table JOIN " "(SELECT some_table_1.id AS id, some_table_1.q AS q " "FROM some_table AS some_table_1, foo.some_table " "WHERE some_table_1.id = foo.some_table.id) AS anon_1 " "ON foo.some_table.id = anon_1.id", - ) - - self.assert_compile( - select(t1, subq.c.id) + ), + ( + lambda t1, subq: select(t1, subq.c.id) .select_from(t1) .join(subq, t1.c.id == subq.c.id), # some_table is only aliased inside the subquery. this is not @@ -6971,8 +6965,59 @@ class SchemaTest(fixtures.TestBase, AssertsCompiledSQL): "FROM some_table AS some_table_1, foo.some_table " "WHERE some_table_1.id = foo.some_table.id) AS anon_1 " "ON some_table.id = anon_1.id", + ), + ( + # issue #12451 + lambda t1alias, t2: select(t2, t1alias), + "SELECT foo.some_table.id, foo.some_table.p, " + "some_table_1.id AS id_1, some_table_1.q FROM foo.some_table, " + "some_table AS some_table_1", + ), + ( + # issue #12451 + lambda t1alias, t2: select(t2).join( + t1alias, t1alias.c.q == t2.c.p + ), + "SELECT foo.some_table.id, foo.some_table.p FROM foo.some_table " + "JOIN some_table AS some_table_1 " + "ON some_table_1.q = foo.some_table.p", + ), + ( + # issue #12451 + lambda t1alias, t2: select(t1alias).join( + t2, t1alias.c.q == t2.c.p + ), + "SELECT some_table_1.id, some_table_1.q " + "FROM some_table AS some_table_1 " + "JOIN foo.some_table ON some_table_1.q = foo.some_table.p", + ), + ( + # issue #12451 + lambda t1alias, t2alias: select(t1alias, t2alias).join( + t2alias, t1alias.c.q == t2alias.c.p + ), + "SELECT some_table_1.id, some_table_1.q, " + "some_table_2.id AS id_1, some_table_2.p " + "FROM some_table AS some_table_1 " + "JOIN foo.some_table AS some_table_2 " + "ON some_table_1.q = some_table_2.p", + ), + ) + def test_schema_non_schema_disambiguation(self, stmt, expected): + """test #7471, and its regression #12451""" + + t1 = table("some_table", column("id"), column("q")) + t2 = table("some_table", column("id"), column("p"), schema="foo") + t1alias = t1.alias() + t2alias = t2.alias() + subq = select(t1).where(t1.c.id == t2.c.id).subquery() + + stmt = testing.resolve_lambda( + stmt, t1=t1, t2=t2, subq=subq, t1alias=t1alias, t2alias=t2alias ) + self.assert_compile(stmt, expected) + def test_alias(self): a = alias(table4, "remtable") self.assert_compile(