From: Mike Bayer Date: Mon, 31 Jul 2023 15:17:20 +0000 (-0400) Subject: pass along independent CTE attributes in ORM context X-Git-Tag: rel_2_0_20~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a8b37e8802a754c39999024d00f5acf6ba5bffa6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git pass along independent CTE attributes in ORM context Fixed issue where an ORM-enabled :func:`_sql.select` construct would not render any CTEs added only via the :meth:`_sql.Select.add_cte` method that were not otherwise referenced in the statement. Fixes: #10167 Change-Id: Ib13f478607628b02742e6026e94bce54b089627d --- diff --git a/doc/build/changelog/unreleased_20/10167.rst b/doc/build/changelog/unreleased_20/10167.rst new file mode 100644 index 0000000000..ac054016bd --- /dev/null +++ b/doc/build/changelog/unreleased_20/10167.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, orm + :tickets: 10167 + + Fixed issue where an ORM-enabled :func:`_sql.select` construct would not + render any CTEs added only via the :meth:`_sql.Select.add_cte` method that + were not otherwise referenced in the statement. diff --git a/lib/sqlalchemy/orm/context.py b/lib/sqlalchemy/orm/context.py index dfb7b3ef62..e961e59347 100644 --- a/lib/sqlalchemy/orm/context.py +++ b/lib/sqlalchemy/orm/context.py @@ -1604,6 +1604,8 @@ class ORMSelectCompileState(ORMCompileState, SelectState): prefixes, suffixes, group_by, + independent_ctes, + independent_ctes_opts, ): statement = Select._create_raw_select( _raw_columns=raw_columns, @@ -1631,6 +1633,8 @@ class ORMSelectCompileState(ORMCompileState, SelectState): statement._offset_clause = offset_clause statement._fetch_clause = fetch_clause statement._fetch_clause_options = fetch_clause_options + statement._independent_ctes = independent_ctes + statement._independent_ctes_opts = independent_ctes_opts if prefixes: statement._prefixes = prefixes @@ -2296,6 +2300,10 @@ class ORMSelectCompileState(ORMCompileState, SelectState): "fetch_clause_options": ( self.select_statement._fetch_clause_options ), + "independent_ctes": self.select_statement._independent_ctes, + "independent_ctes_opts": ( + self.select_statement._independent_ctes_opts + ), } @property diff --git a/test/orm/test_core_compilation.py b/test/orm/test_core_compilation.py index fe47bcd856..328460fe39 100644 --- a/test/orm/test_core_compilation.py +++ b/test/orm/test_core_compilation.py @@ -519,6 +519,33 @@ class DMLTest(QueryTest, AssertsCompiledSQL): else: stmt_type.fail() + @testing.variation("stmt_type", ["core", "orm"]) + def test_add_cte(self, stmt_type: testing.Variation): + """test #10167""" + + if stmt_type.orm: + User = self.classes.User + cte_select = select(User.name).limit(1).cte() + cte_insert = insert(User).from_select(["name"], cte_select).cte() + elif stmt_type.core: + user_table = self.tables.users + cte_select = select(user_table.c.name).limit(1).cte() + cte_insert = ( + insert(user_table).from_select(["name"], cte_select).cte() + ) + else: + stmt_type.fail() + + select_stmt = select(cte_select).add_cte(cte_insert) + + self.assert_compile( + select_stmt, + "WITH anon_2 AS (SELECT users.name AS name FROM users LIMIT " + ":param_1), anon_1 AS (INSERT INTO users (name) " + "SELECT anon_2.name AS name FROM anon_2) " + "SELECT anon_2.name FROM anon_2", + ) + class ColumnsClauseFromsTest(QueryTest, AssertsCompiledSQL): __dialect__ = "default"