supports_empty_insert = False
supports_cast = True
supports_multivalues_insert = True
+ supports_right_nested_joins = False
default_paramstyle = 'qmark'
execution_ctx_cls = SQLiteExecutionContext
postfetch_lastrowid = True
implicit_returning = False
+ supports_right_nested_joins = True
+
supports_native_enum = False
supports_native_boolean = False
right_entity, onclause,
outerjoin, create_aliases, prop)
+ def _tables_overlap(self, left, right):
+ """Return True if parent/child tables have some overlap."""
+
+ return bool(
+ set(sql_util.find_tables(left)).intersection(
+ sql_util.find_tables(right)
+ )
+ )
+
def _join_left_to_right(self, left, right,
onclause, outerjoin, create_aliases, prop):
"""append a JOIN to the query's from clause."""
"are the same entity" %
(left, right))
+ # TODO: get the l_info, r_info passed into
+ # the methods so inspect() doesnt need to be called again
+ l_info = inspect(left)
+ r_info = inspect(right)
+ overlap = self._tables_overlap(l_info.selectable, r_info.selectable)
+
right, onclause = self._prepare_right_side(
right, onclause,
create_aliases,
- prop)
+ prop, overlap)
# if joining on a MapperProperty path,
# track the path to prevent redundant joins
self._join_to_left(left, right, onclause, outerjoin)
- def _prepare_right_side(self, right, onclause, create_aliases, prop):
+ def _prepare_right_side(self, right, onclause, create_aliases, prop, overlap):
info = inspect(right)
right_mapper, right_selectable, right_is_aliased = \
not right_is_aliased and \
(
right_mapper.with_polymorphic
- #isinstance(
- # right_mapper.mapped_table,
- # expression.Join)
+ or
+ overlap # test for overlap:
+ # orm/inheritance/relationships.py
+ # SelfReferentialM2MTest
)
if not need_adapter and (create_aliases or aliased_entity):
def _transform_select_for_nested_joins(self, select):
adapters = []
+ stop_on = []
+ # test for "unconditional" - any statement with
+ # no_replacement_traverse setup, i.e. query.statement, from_self(), etc.
traverse_options = {"cloned": {}, "unconditional": True}
def visit_join(elem):
while adapters:
adapt = adapters.pop(-1)
selectable = adapt.traverse(selectable)
+ #stop_on.append(selectable)
+
+ # test: see test_subquery_relations:
+ # CyclicalInheritingEagerTestTwo.test_integrate
+ stop_on.append(elem.left)
+
for c in selectable.c:
c._label = c._key_label = c.name
elem.right = selectable
adapter = sql_util.ClauseAdapter(selectable,
traverse_options=traverse_options)
+ adapter.__traverse_options__['stop_on'].extend(stop_on)
adapters.append(adapter)
select = visitors.cloned_traverse(select,
positional_names=None,
nested_join_translation=False, **kwargs):
- #nested_join_translation = True
+
+ if self.dialect.supports_right_nested_joins:
+ nested_join_translation = True
if not nested_join_translation:
transformed_select = self._transform_select_for_nested_joins(select)
text = self.visit_select(
dialect = default.DefaultDialect()
elif dialect == None and not allow_dialect_select:
dialect = getattr(self, '__dialect__', None)
- if dialect == 'default':
- dialect = default.DefaultDialect()
- elif dialect is None:
- dialect = config.db.dialect
- elif isinstance(dialect, util.string_types):
- dialect = create_engine("%s://" % dialect).dialect
+
+ if dialect == 'default':
+ dialect = default.DefaultDialect()
+ elif dialect is None:
+ dialect = config.db.dialect
+ elif isinstance(dialect, util.string_types):
+ dialect = create_engine("%s://" % dialect).dialect
kw = {}
if params is not None:
q = ctx.attributes[('subquery',
(inspect(Director), inspect(Director).attrs.movies))]
self.assert_compile(q,
- "SELECT anon_1.movie_id AS anon_1_movie_id, "
- "anon_1.persistent_id AS anon_1_persistent_id, "
- "anon_1.movie_director_id AS anon_1_movie_director_id, "
- "anon_1.movie_title AS anon_1_movie_title, "
- "anon_2.director_id AS anon_2_director_id FROM "
- "(SELECT director.id AS director_id FROM persistent JOIN director "
- "ON persistent.id = director.id) AS anon_2 "
- "JOIN (SELECT persistent.id AS persistent_id, movie.id AS movie_id, "
+ "SELECT movie.id AS movie_id, persistent.id AS persistent_id, "
"movie.director_id AS movie_director_id, "
- "movie.title AS movie_title FROM persistent JOIN movie "
- "ON persistent.id = movie.id) AS anon_1 "
- "ON anon_2.director_id = anon_1.movie_director_id "
- "ORDER BY anon_2.director_id")
+ "movie.title AS movie_title, "
+ "anon_1.director_id AS anon_1_director_id "
+ "FROM (SELECT director.id AS director_id "
+ "FROM persistent JOIN director "
+ "ON persistent.id = director.id) AS anon_1 "
+ "JOIN (persistent JOIN movie ON persistent.id = movie.id) "
+ "ON anon_1.director_id = movie.director_id "
+ "ORDER BY anon_1.director_id",
+ dialect="default"
+ )
def test_integrate(self):
Director = self.classes.Director