summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/elements.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-07-07 11:12:31 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2019-07-11 14:20:10 -0400
commitaceefb508ccd0911f52ff0e50324b3fefeaa3f16 (patch)
treee57124d3ea8b0e2cd7fe1d3ad22170fa956bcafb /lib/sqlalchemy/sql/elements.py
parent5c16367ee78fa1a41d6b715152dcc58f45323d2e (diff)
downloadsqlalchemy-aceefb508ccd0911f52ff0e50324b3fefeaa3f16.tar.gz
Allow duplicate columns in from clauses and selectables
The :func:`.select` construct and related constructs now allow for duplication of column labels and columns themselves in the columns clause, mirroring exactly how column expressions were passed in. This allows the tuples returned by an executed result to match what was SELECTed for in the first place, which is how the ORM :class:`.Query` works, so this establishes better cross-compatibility between the two constructs. Additionally, it allows column-positioning-sensitive structures such as UNIONs (i.e. :class:`.CompoundSelect`) to be more intuitively constructed in those cases where a particular column might appear in more than one place. To support this change, the :class:`.ColumnCollection` has been revised to support duplicate columns as well as to allow integer index access. Fixes: #4753 Change-Id: Ie09a8116f05c367995c1e43623c51e07971d3bf0
Diffstat (limited to 'lib/sqlalchemy/sql/elements.py')
-rw-r--r--lib/sqlalchemy/sql/elements.py28
1 files changed, 15 insertions, 13 deletions
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 5b4442222..735a125d7 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -184,6 +184,7 @@ class ClauseElement(roles.SQLRole, Visitable):
_is_returns_rows = False
_is_text_clause = False
_is_from_container = False
+ _is_select_container = False
_is_select_statement = False
_order_by_label_element = None
@@ -856,8 +857,7 @@ class ColumnElement(
co._proxies = [self]
if selectable._is_clone_of is not None:
co._is_clone_of = selectable._is_clone_of.columns.get(key)
- selectable._columns[key] = co
- return co
+ return key, co
def cast(self, type_):
"""Produce a type cast, i.e. ``CAST(<expression> AS <type>)``.
@@ -887,6 +887,12 @@ class ColumnElement(
"""
return Label(name, self, self.type)
+ def _anon_label(self, seed):
+ while self._is_clone_of is not None:
+ self = self._is_clone_of
+
+ return _anonymous_label("%%(%d %s)s" % (id(self), seed or "anon"))
+
@util.memoized_property
def anon_label(self):
"""provides a constant 'anonymous label' for this ColumnElement.
@@ -901,12 +907,11 @@ class ColumnElement(
expressions and function calls.
"""
- while self._is_clone_of is not None:
- self = self._is_clone_of
+ return self._anon_label(getattr(self, "name", None))
- return _anonymous_label(
- "%%(%d %s)s" % (id(self), getattr(self, "name", "anon"))
- )
+ @util.memoized_property
+ def _label_anon_label(self):
+ return self._anon_label(getattr(self, "_label", None))
class BindParameter(roles.InElementRole, ColumnElement):
@@ -3951,7 +3956,7 @@ class Label(roles.LabeledColumnExprRole, ColumnElement):
return self.element._from_objects
def _make_proxy(self, selectable, name=None, **kw):
- e = self.element._make_proxy(
+ key, e = self.element._make_proxy(
selectable,
name=name if name else self.name,
disallow_is_literal=True,
@@ -3959,7 +3964,7 @@ class Label(roles.LabeledColumnExprRole, ColumnElement):
e._proxies.append(self)
if self._type is not None:
e.type = self._type
- return e
+ return key, e
class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement):
@@ -4214,7 +4219,6 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement):
self,
selectable,
name=None,
- attach=True,
name_is_truncatable=False,
disallow_is_literal=False,
**kw
@@ -4249,9 +4253,7 @@ class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement):
if selectable._is_clone_of is not None:
c._is_clone_of = selectable._is_clone_of.columns.get(c.key)
- if attach:
- selectable._columns[c.key] = c
- return c
+ return c.key, c
class CollationClause(ColumnElement):