diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-11-08 18:06:21 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2007-11-08 18:06:21 +0000 |
| commit | 2cbb133567befca7e92f8e3bbc0aaae96b1781a8 (patch) | |
| tree | c5848def75457a3bb1c5887af09ee5bd7fee1b83 /lib/sqlalchemy/sql/expression.py | |
| parent | 7a25be0f4214720198029e85c2f1d18f4fc8bad3 (diff) | |
| download | sqlalchemy-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.py | 39 |
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))) |
