summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/expression.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-01-19 18:36:52 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-01-19 18:36:52 +0000
commit840a2fabb8999b4b3807dfa55d771627656ab1db (patch)
tree5486020ddf87fd932c6fd563a6319eeea8265c6f /lib/sqlalchemy/sql/expression.py
parent6d486fb2e77e338ac4d45ff5ed45561abb5c81b3 (diff)
downloadsqlalchemy-840a2fabb8999b4b3807dfa55d771627656ab1db.tar.gz
- some expression fixup:
- the '.c.' attribute on a selectable now gets an entry for every column expression in its columns clause; previously, "unnamed" columns like functions and CASE statements weren't getting put there. Now they will, using their full string representation if no 'name' is available. - The anonymous 'label' generated for otherwise unlabeled functions and expressions now propagates outwards at compile time for expressions like select([select([func.foo()])]) - a CompositeSelect, i.e. any union(), union_all(), intersect(), etc. now asserts that each selectable contains the same number of columns. This conforms to the corresponding SQL requirement. - building on the above ideas, CompositeSelects now build up their ".c." collection based on the names present in the first selectable only; corresponding_column() now works fully for all embedded selectables.
Diffstat (limited to 'lib/sqlalchemy/sql/expression.py')
-rw-r--r--lib/sqlalchemy/sql/expression.py64
1 files changed, 44 insertions, 20 deletions
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 3ebc4960f..c60341802 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -1402,17 +1402,37 @@ class ColumnElement(ClauseElement, _CompareMixin):
``ColumnElement`` as it appears in the select list of a
descending selectable.
- The default implementation returns a ``_ColumnClause`` if a
- name is given, else just returns self.
"""
if name is not None:
- co = _ColumnClause(name, selectable)
+ co = _ColumnClause(name, selectable, type_=getattr(self, 'type', None))
co.proxies = [self]
selectable.columns[name]= co
return co
else:
- return self
+ name = str(self)
+ co = _ColumnClause(self.anon_label.name, selectable, type_=getattr(self, 'type', None))
+ co.proxies = [self]
+ selectable.columns[name] = co
+ return co
+
+ def anon_label(self):
+ """provides a constant 'anonymous label' for this ColumnElement.
+
+ This is a label() expression which will be named at compile time.
+ The same label() is returned each time anon_label is called so
+ that expressions can reference anon_label multiple times, producing
+ the same label name at compile time.
+
+ the compiler uses this function automatically at compile time
+ for expressions that are known to be 'unnamed' like binary
+ expressions and function calls.
+ """
+
+ if not hasattr(self, '_ColumnElement__anon_label'):
+ self.__anon_label = self.label(None)
+ return self.__anon_label
+ anon_label = property(anon_label)
class ColumnCollection(util.OrderedProperties):
"""An ordered dictionary that stores a list of ColumnElement
@@ -2026,15 +2046,6 @@ class _Cast(ColumnElement):
def _get_from_objects(self, **modifiers):
return self.clause._get_from_objects(**modifiers)
- def _make_proxy(self, selectable, name=None):
- if name is not None:
- co = _ColumnClause(name, selectable, type_=self.type)
- co.proxies = [self]
- selectable.columns[name]= co
- return co
- else:
- return self
-
class _UnaryExpression(ColumnElement):
def __init__(self, element, operator=None, modifier=None, type_=None, negate=None):
@@ -2864,8 +2875,16 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
self.keyword = keyword
self.selects = []
+ numcols = None
+
# some DBs do not like ORDER BY in the inner queries of a UNION, etc.
for n, s in enumerate(selects):
+ if not numcols:
+ numcols = len(s.c)
+ elif len(s.c) != numcols:
+ raise exceptions.ArgumentError("All selectables passed to CompoundSelect must have identical numbers of columns; select #%d has %d columns, select #%d has %d" %
+ (1, len(self.selects[0].c), n+1, len(s.c))
+ )
if s._order_by_clause:
s = s.order_by(None)
# unions group from left to right, so don't group first select
@@ -2892,17 +2911,22 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
yield c
def _proxy_column(self, column):
- existing = self._col_map.get(column.name, None)
- if existing is not None:
- existing.proxies.append(column)
- return existing
- else:
+ selectable = column.table
+ col_ordering = self._col_map.get(selectable, None)
+ if col_ordering is None:
+ self._col_map[selectable] = col_ordering = []
+
+ if selectable is self.selects[0]:
if self.use_labels:
col = column._make_proxy(self, name=column._label)
else:
col = column._make_proxy(self)
- self._col_map[col.name] = col
- return col
+ col_ordering.append(col)
+ else:
+ col_ordering.append(column)
+ existing = self._col_map[self.selects[0]][len(col_ordering) - 1]
+ existing.proxies.append(column)
+ return existing
def _copy_internals(self, clone=_clone):
self._clone_from_clause()