diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-02-09 17:49:38 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-02-09 17:49:38 -0500 |
| commit | ff3be95620b6505943b2d7e4688abc29dca3e493 (patch) | |
| tree | 1d90206b004c30bc296d709d5d169bf8a1f2a16a /lib/sqlalchemy | |
| parent | 7d2bed69abb6ab545cfa5ca967141338387417c2 (diff) | |
| download | sqlalchemy-ff3be95620b6505943b2d7e4688abc29dca3e493.tar.gz | |
- A refinement to the logic which adds columns to the resulting SQL when
:meth:`.Query.distinct` is combined with :meth:`.Query.order_by` such
that columns which are already present will not be added
a second time, even if they are labeled with a different name.
Regardless of this change, the extra columns added to the SQL have
never been returned in the final result, so this change only impacts
the string form of the statement as well as its behavior when used in
a Core execution context. Additionally, columns are no longer added
when the DISTINCT ON format is used, provided the query is not
wrapped inside a subquery due to joined eager loading.
fixes #3641
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/query.py | 26 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 22 |
2 files changed, 33 insertions, 15 deletions
diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 08600c357..8a25f570a 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -3254,12 +3254,11 @@ class Query(object): # then append eager joins onto that if context.order_by: - order_by_col_expr = list( - chain(*[ - sql_util.unwrap_order_by(o) - for o in context.order_by - ]) - ) + order_by_col_expr = \ + sql_util.expand_column_list_from_order_by( + context.primary_columns, + context.order_by + ) else: context.order_by = None order_by_col_expr = [] @@ -3319,15 +3318,12 @@ class Query(object): if not context.order_by: context.order_by = None - if self._distinct and context.order_by: - order_by_col_expr = list( - chain(*[ - sql_util.unwrap_order_by(o) - for o in context.order_by - ]) - ) - context.primary_columns += order_by_col_expr - + 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 + ) context.froms += tuple(context.eager_joins.values()) statement = sql.select( diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 1dcf0ee66..7e294d85f 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -176,6 +176,28 @@ def unwrap_order_by(clause): return result +def expand_column_list_from_order_by(collist, order_by): + """Given the columns clause and ORDER BY of a selectable, + return a list of column expressions that can be added to the collist + corresponding to the ORDER BY, without repeating those already + in the collist. + + """ + cols_already_present = set([ + col.element if col._order_by_label_element is not None + else col for col in collist + ]) + + return [ + col for col in + chain(*[ + unwrap_order_by(o) + for o in order_by + ]) + if col not in cols_already_present + ] + + def clause_is_present(clause, search): """Given a target clause and a second to search within, return True if the target is plainly present in the search without any |
