diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-12-03 17:28:36 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2008-12-03 17:28:36 +0000 |
| commit | 0410eae36b36dc8ea7e747c4b81c7ec9de5f2da4 (patch) | |
| tree | 86a53b2b2c33a3348d6aca9c7bc825315816748f /lib | |
| parent | 851a14aa1a0e7a734a6f810f0e6e5c39d8e63b1b (diff) | |
| download | sqlalchemy-0410eae36b36dc8ea7e747c4b81c7ec9de5f2da4.tar.gz | |
- Two fixes to help prevent out-of-band columns from
being rendered in polymorphic_union inheritance
scenarios (which then causes extra tables to be
rendered in the FROM clause causing cartesian
products):
- improvements to "column adaption" for
a->b->c inheritance situations to better
locate columns that are related to one
another via multiple levels of indirection,
rather than rendering the non-adapted
column.
- the "polymorphic discriminator" column is
only rendered for the actual mapper being
queried against. The column won't be
"pulled in" from a subclass or superclass
mapper since it's not needed.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 35 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/util.py | 6 |
2 files changed, 27 insertions, 14 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index b48297a64..48c2f9e27 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -612,7 +612,13 @@ class Mapper(object): # right set if hasattr(self, '_cols_by_table') and col.table in self._cols_by_table and col not in self._cols_by_table[col.table]: self._cols_by_table[col.table].add(col) - + + # if this ColumnProperty represents the "polymorphic discriminator" + # column, mark it. We'll need this when rendering columns + # in SELECT statements. + if not hasattr(prop, '_is_polymorphic_discriminator'): + prop._is_polymorphic_discriminator = (col is self.polymorphic_on or prop.columns[0] is self.polymorphic_on) + self.columns[key] = col for col in prop.columns: for col in col.proxy_set: @@ -860,20 +866,27 @@ class Mapper(object): else: return mappers, self._selectable_from_mappers(mappers) - @property - def _default_polymorphic_properties(self): - return util.unique_list( - chain(*[list(mapper.iterate_properties) for mapper in [self] + self._with_polymorphic_mappers]) - ) - def _iterate_polymorphic_properties(self, mappers=None): + """Return an iterator of MapperProperty objects which will render into a SELECT.""" + if mappers is None: - return iter(self._default_polymorphic_properties) + mappers = self._with_polymorphic_mappers + + if not mappers: + for c in self.iterate_properties: + yield c else: - return iter(util.unique_list( + # in the polymorphic case, filter out discriminator columns + # from other mappers, as these are sometimes dependent on that + # mapper's polymorphic selectable (which we don't want rendered) + for c in util.unique_list( chain(*[list(mapper.iterate_properties) for mapper in [self] + mappers]) - )) - + ): + if getattr(c, '_is_polymorphic_discriminator', False) and \ + (not self.polymorphic_on or c.columns[0] is not self.polymorphic_on): + continue + yield c + @property def properties(self): raise NotImplementedError("Public collection of MapperProperty objects is " diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index d5f2417c2..1bd4dd857 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -439,12 +439,12 @@ class ClauseAdapter(visitors.ReplacingCloningVisitor): self.exclude = exclude self.equivalents = equivalents or {} - def _corresponding_column(self, col, require_embedded): + def _corresponding_column(self, col, require_embedded, _seen=util.EMPTY_SET): newcol = self.selectable.corresponding_column(col, require_embedded=require_embedded) - if not newcol and col in self.equivalents: + if not newcol and col in self.equivalents and col not in _seen: for equiv in self.equivalents[col]: - newcol = self.selectable.corresponding_column(equiv, require_embedded=require_embedded) + newcol = self._corresponding_column(equiv, require_embedded=require_embedded, _seen=_seen.union([col])) if newcol: return newcol return newcol |
