:tags: bug, sql
:tickets: 12915
- Fixed issue where using :meth:`_sql.Select.params` to replace bound
- parameters in a query could fail for some cases where the parameters
- were embedded in subqueries or CTEs when ORM classes were involved,
- due to issues with internal query traversal for these cases.
+ Some improvements to the :meth:`_sql.ClauseElement.params` method to
+ replace bound parameters in a query were made, however the ultimate issue
+ in :ticket:`12915` involving ORM :func:`_orm.aliased` cannot be fixed fully
+ until 2.1, where the method is being rewritten to work without relying on
+ Core cloned traversal.
from sqlalchemy.orm import with_polymorphic
from sqlalchemy.sql import and_
from sqlalchemy.sql import sqltypes
-from sqlalchemy.sql import visitors
from sqlalchemy.sql.selectable import Join as core_join
from sqlalchemy.sql.selectable import LABEL_STYLE_DISAMBIGUATE_ONLY
from sqlalchemy.sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL
checkparams={"param_1": 6, "param_2": 5},
)
- @testing.variation("use_get_params", [True, False])
- def test_annotated_cte_params_traverse(self, use_get_params):
- """test #12915
-
- test that .params() applied to a statement that includes
- an annotated CTE will traverse into the CTE's internal structures
- to replace the bound parameters.
-
- """
- User = self.classes.User
-
- ids_param = bindparam("ids")
- cte = select(User).where(User.id == ids_param).cte("cte")
-
- ca = cte._annotate({"foo": "bar"})
-
- stmt = select(ca)
-
- if use_get_params:
- stmt = stmt.params(ids=17)
- else:
- # test without using params(), in case the implementation
- # for params() changes we still want to test cloned_traverse
- def visit_bindparam(bind):
- if bind.key == "ids":
- bind.value = 17
- bind.required = False
-
- stmt = visitors.cloned_traverse(
- stmt,
- {"maintain_key": True, "detect_subquery_cols": True},
- {"bindparam": visit_bindparam},
- )
-
- self.assert_compile(
- stmt,
- "WITH cte AS (SELECT users.id AS id, users.name AS name "
- "FROM users WHERE users.id = :ids) "
- "SELECT cte.id, cte.name FROM cte",
- checkparams={"ids": 17},
- )
-
class PropagateAttrsTest(QueryTest):
__backend__ = True
@testing.variation("use_get_params", [True, False])
def test_annotated_cte_params_traverse(self, use_get_params):
- """test #12915"""
+ """test #12915
+
+ this issue attempted to repair some traversal issues found using
+ params() but does not fix the full issue reported in #12915, which
+ is a "wontfix" in favor of #7066.
+
+ """
user = Table("user", MetaData(), Column("id", Integer))
ids_param = bindparam("ids")
if use_get_params:
stmt = stmt.params(ids=17)
else:
- # test without using params(), in case the implementation
- # for params() changes we still want to test cloned_traverse
+ # test without using params(), as the implementation
+ # for params() will be changing
def visit_bindparam(bind):
if bind.key == "ids":
bind.value = 17