summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/orm/query.py36
-rw-r--r--lib/sqlalchemy/orm/strategies.py9
-rw-r--r--lib/sqlalchemy/testing/assertsql.py9
3 files changed, 39 insertions, 15 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py
index 617bba315..24d8975e4 100644
--- a/lib/sqlalchemy/orm/query.py
+++ b/lib/sqlalchemy/orm/query.py
@@ -3071,15 +3071,18 @@ class Query(Generative):
.. note::
- The :meth:`.distinct` call includes logic that will automatically
- add columns from the ORDER BY of the query to the columns
- clause of the SELECT statement, to satisfy the common need
- of the database backend that ORDER BY columns be part of the
- SELECT list when DISTINCT is used. These columns *are not*
- added to the list of columns actually fetched by the
- :class:`.Query`, however, so would not affect results.
- The columns are passed through when using the
- :attr:`.Query.statement` accessor, however.
+ The ORM-level :meth:`.distinct` call includes logic that will
+ automatically add columns from the ORDER BY of the query to the
+ columns clause of the SELECT statement, to satisfy the common need
+ of the database backend that ORDER BY columns be part of the SELECT
+ list when DISTINCT is used. These columns *are not* added to the
+ list of columns actually fetched by the :class:`.Query`, however,
+ so would not affect results. The columns are passed through when
+ using the :attr:`.Query.statement` accessor, however.
+
+ .. deprecated:: 2.0 This logic is deprecated and will be removed
+ in SQLAlchemy 2.0. See :ref:`migration_20_query_distinct`
+ for a description of this use case in 2.0.
:param \*expr: optional column expressions. When present,
the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)``
@@ -3994,9 +3997,18 @@ class Query(Generative):
context.order_by = None
if self._distinct is True and context.order_by:
- context.primary_columns += (
- sql_util.expand_column_list_from_order_by
- )(context.primary_columns, context.order_by)
+ to_add = sql_util.expand_column_list_from_order_by(
+ context.primary_columns, context.order_by
+ )
+ if to_add:
+ util.warn_deprecated_20(
+ "ORDER BY columns added implicitly due to "
+ "DISTINCT is deprecated and will be removed in "
+ "SQLAlchemy 2.0. SELECT statements with DISTINCT "
+ "should be written to explicitly include the appropriate "
+ "columns in the columns clause"
+ )
+ context.primary_columns += to_add
context.froms += tuple(context.eager_joins.values())
statement = sql.select(
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index 094637082..4da601530 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -1235,6 +1235,15 @@ class SubqueryLoader(PostLoader):
if q._limit is None and q._offset is None:
q._order_by = None
+ if q._distinct is True and q._order_by:
+ # the logic to automatically add the order by columns to the query
+ # when distinct is True is deprecated in the query
+ to_add = sql_util.expand_column_list_from_order_by(
+ target_cols, q._order_by
+ )
+ if to_add:
+ q._set_entities(target_cols + to_add)
+
# the original query now becomes a subquery
# which we'll join onto.
diff --git a/lib/sqlalchemy/testing/assertsql.py b/lib/sqlalchemy/testing/assertsql.py
index f0da69400..8876c2304 100644
--- a/lib/sqlalchemy/testing/assertsql.py
+++ b/lib/sqlalchemy/testing/assertsql.py
@@ -184,8 +184,8 @@ class CompiledSQL(SQLMatchRule):
def _failure_message(self, expected_params):
return (
- "Testing for compiled statement %r partial params %s, "
- "received %%(received_statement)r with params "
+ "Testing for compiled statement\n%r partial params %s, "
+ "received\n%%(received_statement)r with params "
"%%(received_parameters)r"
% (
self.statement.replace("%", "%%"),
@@ -343,6 +343,9 @@ class SQLExecuteObserved(object):
self.parameters = _distill_params(multiparams, params)
self.statements = []
+ def __repr__(self):
+ return str(self.statements)
+
class SQLCursorExecuteObserved(
collections.namedtuple(
@@ -373,7 +376,7 @@ class SQLAsserter(object):
elif rule.errormessage:
assert False, rule.errormessage
if observed:
- assert False, "Additional SQL statements remain"
+ assert False, "Additional SQL statements remain:\n%s" % observed
elif not rule.is_consumed:
rule.no_more_statements()