summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/expression.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-11-08 18:06:21 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-11-08 18:06:21 +0000
commit2cbb133567befca7e92f8e3bbc0aaae96b1781a8 (patch)
treec5848def75457a3bb1c5887af09ee5bd7fee1b83 /lib/sqlalchemy/sql/expression.py
parent7a25be0f4214720198029e85c2f1d18f4fc8bad3 (diff)
downloadsqlalchemy-2cbb133567befca7e92f8e3bbc0aaae96b1781a8.tar.gz
more changes to traverse-and-clone; a particular element will only be cloned once and is
then re-used. the FROM calculation of a Select normalizes the list of hide_froms against all previous incarnations of each FROM clause, using a tag attached from cloned clause to previous.
Diffstat (limited to 'lib/sqlalchemy/sql/expression.py')
-rw-r--r--lib/sqlalchemy/sql/expression.py39
1 files changed, 25 insertions, 14 deletions
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 6276f33bd..e066632af 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -844,6 +844,14 @@ class ClauseElement(object):
"""
c = self.__class__.__new__(self.__class__)
c.__dict__ = self.__dict__.copy()
+
+ # this is a marker that helps to "equate" clauses to each other
+ # when a Select returns its list of FROM clauses. the cloning
+ # process leaves around a lot of remnants of the previous clause
+ # typically in the form of column expressions still attached to the
+ # old table.
+ c._is_clone_of = self
+
return c
def _get_from_objects(self, **modifiers):
@@ -2212,7 +2220,7 @@ class Join(FromClause):
self.__primary_key = ColumnSet([c for c in self._flatten_exportable_columns() if c.primary_key and c not in omit])
def description(self):
- return "Join object on %s and %s" % (self.left.description, self.right.description)
+ return "Join object on %s(%d) and %s(%d)" % (self.left.description, id(self.left), self.right.description, id(self.right))
description = property(description)
primary_key = property(lambda s:s.__primary_key)
@@ -2394,15 +2402,6 @@ class Alias(FromClause):
#return self.selectable._exportable_columns()
return self.selectable.columns
- def _clone(self):
- # TODO: need test coverage to assert ClauseAdapter behavior
- # here; must identify non-ORM failure cases when a. _clone() returns 'self' in all
- # cases and b. when _clone() does an actual _clone() in all cases.
- if isinstance(self.selectable, TableClause):
- return self
- else:
- return super(Alias, self)._clone()
-
def _copy_internals(self, clone=_clone):
self._clone_from_clause()
self.selectable = _clone(self.selectable)
@@ -2996,6 +2995,9 @@ class Select(_SelectBaseMixin, FromClause):
for col in self._raw_columns:
for f in col._hide_froms():
hide_froms.add(f)
+ while hasattr(f, '_is_clone_of'):
+ hide_froms.add(f._is_clone_of)
+ f = f._is_clone_of
for f in col._get_from_objects():
froms.add(f)
@@ -3007,17 +3009,26 @@ class Select(_SelectBaseMixin, FromClause):
froms.add(elem)
for f in elem._get_from_objects():
froms.add(f)
-
+
for elem in froms:
for f in elem._hide_froms():
hide_froms.add(f)
-
+ while hasattr(f, '_is_clone_of'):
+ hide_froms.add(f._is_clone_of)
+ f = f._is_clone_of
+
froms = froms.difference(hide_froms)
-
+
if len(froms) > 1:
corr = self.__correlate
if self._should_correlate and existing_froms is not None:
corr = existing_froms.union(corr)
+
+ for f in list(corr):
+ while hasattr(f, '_is_clone_of'):
+ corr.add(f._is_clone_of)
+ f = f._is_clone_of
+
f = froms.difference(corr)
if len(f) == 0:
raise exceptions.InvalidRequestError("Select statement '%s' is overcorrelated; returned no 'from' clauses" % str(self.__dont_correlate()))
@@ -3070,8 +3081,8 @@ class Select(_SelectBaseMixin, FromClause):
def _copy_internals(self, clone=_clone):
self._clone_from_clause()
- self._raw_columns = [clone(c) for c in self._raw_columns]
self._recorrelate_froms([(f, clone(f)) for f in self._froms])
+ self._raw_columns = [clone(c) for c in self._raw_columns]
for attr in ('_whereclause', '_having', '_order_by_clause', '_group_by_clause'):
if getattr(self, attr) is not None:
setattr(self, attr, clone(getattr(self, attr)))