From: Mike Bayer Date: Wed, 19 Mar 2025 22:30:21 +0000 (-0400) Subject: skip FROM disambiguation for immediate alias of table X-Git-Tag: rel_2_0_40~10^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a20334aa7d556003ae936015c44df5b090240d21;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 (cherry picked from commit 9ea3be0681dc09338e53b63cea4803de80ebcdc7) --- 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 f55f0d96bb..9130cdb2c3 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -5263,6 +5263,7 @@ class SQLCompiler(Compiled): use_schema=True, from_linter=None, ambiguous_table_name_map=None, + enclosing_alias=None, **kwargs, ): if from_linter: @@ -5281,7 +5282,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 4d546b57b3..12ba24e170 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -6905,65 +6905,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 @@ -6975,8 +6969,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(