mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-18 22:52:01 -04:00
Merge "Ensure ClauseAdapter treats FunctionElement as a ColumnElement"
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
||||
.. change::
|
||||
:tags: bug, regression, orm
|
||||
:tickets: 6086
|
||||
|
||||
Fixed regression where use of an unnamed SQL expression such as a SQL
|
||||
function would raise a column targeting error if the query itself were
|
||||
using joinedload for an entity and was also being wrapped in a subquery by
|
||||
the joinedload eager loading process.
|
||||
|
||||
@@ -2707,7 +2707,9 @@ class _ORMColumnEntity(_ColumnEntity):
|
||||
compile_state._entities.append(self)
|
||||
|
||||
compile_state._has_orm_entities = True
|
||||
|
||||
self.column = column
|
||||
|
||||
self._fetch_column = self._row_processor = None
|
||||
|
||||
self._extra_entities = (self.expr, self.column)
|
||||
|
||||
@@ -843,8 +843,13 @@ class ClauseAdapter(visitors.ReplacingExternalTraversal):
|
||||
newcol = self.selectable.exported_columns.get(col.name)
|
||||
return newcol
|
||||
|
||||
@util.preload_module("sqlalchemy.sql.functions")
|
||||
def replace(self, col):
|
||||
if isinstance(col, FromClause):
|
||||
functions = util.preloaded.sql_functions
|
||||
|
||||
if isinstance(col, FromClause) and not isinstance(
|
||||
col, functions.FunctionElement
|
||||
):
|
||||
if self.selectable.is_derived_from(col):
|
||||
return self.selectable
|
||||
elif isinstance(col, Alias) and isinstance(
|
||||
|
||||
@@ -488,6 +488,37 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL):
|
||||
|
||||
self.assert_sql_count(testing.db, go, 1)
|
||||
|
||||
def test_aliased_stmt_includes_unnamed_fn(self):
|
||||
User, Address = self.classes("User", "Address")
|
||||
users, addresses = self.tables("users", "addresses")
|
||||
mapper(
|
||||
User,
|
||||
users,
|
||||
properties={"addresses": relationship(Address, lazy="joined")},
|
||||
)
|
||||
mapper(Address, addresses)
|
||||
|
||||
s = fixture_session()
|
||||
|
||||
# issue #6086
|
||||
# statement wrapped in a subquery by limit() and group_by()
|
||||
# func.count() is unlabeled (in 1.3 the _ColumnEntity would label it,
|
||||
# in the ORM layer, hence there was no problem here).
|
||||
# the _ColumnEntity needs to adapt func.count(User.id) to the anon
|
||||
# count_1 label on the outside, corresponding_column can do it.
|
||||
# but ClauseAdapter has to treat the FunctionElement as a ColumnElement
|
||||
# whereas previously it was treating it as a FromClause (and
|
||||
# FunctionElement should really not even be a FromClause but there's
|
||||
# legacy baggage on that)
|
||||
q = (
|
||||
s.query(User, func.count(User.id))
|
||||
.order_by(User.id)
|
||||
.group_by(User.id)
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
eq_(q.first(), (User(id=7), 1))
|
||||
|
||||
def test_options_pathing(self):
|
||||
(
|
||||
users,
|
||||
|
||||
@@ -1338,6 +1338,40 @@ class ClauseAdapterTest(fixtures.TestBase, AssertsCompiledSQL):
|
||||
"AS anon_1 FROM table1 AS t1alias",
|
||||
)
|
||||
|
||||
def test_adapt_select_w_unlabeled_fn(self):
|
||||
|
||||
expr = func.count(t1.c.col1)
|
||||
stmt = select(t1, expr)
|
||||
|
||||
self.assert_compile(
|
||||
stmt,
|
||||
"SELECT table1.col1, table1.col2, table1.col3, "
|
||||
"count(table1.col1) AS count_1 FROM table1",
|
||||
)
|
||||
|
||||
stmt2 = select(stmt.subquery())
|
||||
|
||||
self.assert_compile(
|
||||
stmt2,
|
||||
"SELECT anon_1.col1, anon_1.col2, anon_1.col3, anon_1.count_1 "
|
||||
"FROM (SELECT table1.col1 AS col1, table1.col2 AS col2, "
|
||||
"table1.col3 AS col3, count(table1.col1) AS count_1 "
|
||||
"FROM table1) AS anon_1",
|
||||
)
|
||||
|
||||
is_(
|
||||
stmt2.selected_columns[3],
|
||||
stmt2.selected_columns.corresponding_column(expr),
|
||||
)
|
||||
|
||||
is_(
|
||||
sql_util.ClauseAdapter(stmt2).replace(expr),
|
||||
stmt2.selected_columns[3],
|
||||
)
|
||||
|
||||
column_adapter = sql_util.ColumnAdapter(stmt2)
|
||||
is_(column_adapter.columns[expr], stmt2.selected_columns[3])
|
||||
|
||||
def test_correlate_except_on_clone(self):
|
||||
# test [ticket:4537]'s issue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user