summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/elements.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-10-05 18:27:44 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2019-10-07 11:26:10 -0400
commite0396633e72bc09bd7cec715101d516ea87fa840 (patch)
tree9486b4566942af674e669eddc38c14bee1e2ecfd /lib/sqlalchemy/sql/elements.py
parentc6abd4766abb0396c9bf532d81d16226b970a35a (diff)
downloadsqlalchemy-e0396633e72bc09bd7cec715101d516ea87fa840.tar.gz
create second level deduping when use_labels is turned on
As of #4753 we allow duplicate columns. This creates some new problems that there can be duplicate columns in a subquery which are then not addressible on the outside because they are ambiguous (Postgresql has this behavior at least). Additionally it creates situations where we are making an anon label of an anon label which is leaking into the query. New logic for generating anon labels handles this situation and also alters the .c collection of a subquery such that we are only getting the first column from the derived selectable that has that name, the subsequent ones have a new deduping label with two underscores and are not exposed in .c. The dedupe logic when rendering the columns will handle duplicate label names for different columns, vs. the same column repeated, as separate cases. Fixes: #4892 Change-Id: I929fbd8da14bcc239e0481c24bbd9b5ce826e8fa
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r--lib/sqlalchemy/sql/elements.py12
1 files changed, 11 insertions, 1 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 8ee157b6f..b6462b334 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -878,7 +878,13 @@ class ColumnElement(
while self._is_clone_of is not None:
self = self._is_clone_of
- return _anonymous_label("%%(%d %s)s" % (id(self), seed or "anon"))
+ # as of 1.4 anonymous label for ColumnElement uses hash(), not id(),
+ # as the identifier, because a column and its annotated version are
+ # the same thing in a SQL statement
+ if isinstance(seed, _anonymous_label):
+ return _anonymous_label("%s%%(%d %s)s" % (seed, hash(self), ""))
+
+ return _anonymous_label("%%(%d %s)s" % (hash(self), seed or "anon"))
@util.memoized_property
def anon_label(self):
@@ -900,6 +906,10 @@ class ColumnElement(
def _label_anon_label(self):
return self._anon_label(getattr(self, "_label", None))
+ @util.memoized_property
+ def _dedupe_label_anon_label(self):
+ return self._anon_label(getattr(self, "_label", "anon") + "_")
+
class WrapsColumnExpression(object):
"""Mixin that defines a :class:`.ColumnElement` as a wrapper with special