summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-12-03 17:28:36 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-12-03 17:28:36 +0000
commit0410eae36b36dc8ea7e747c4b81c7ec9de5f2da4 (patch)
tree86a53b2b2c33a3348d6aca9c7bc825315816748f /lib
parent851a14aa1a0e7a734a6f810f0e6e5c39d8e63b1b (diff)
downloadsqlalchemy-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.py35
-rw-r--r--lib/sqlalchemy/sql/util.py6
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