]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
working through tests....
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 3 Jun 2013 00:23:03 +0000 (20:23 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 3 Jun 2013 00:23:03 +0000 (20:23 -0400)
lib/sqlalchemy/dialects/sqlite/base.py
lib/sqlalchemy/engine/default.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/sql/compiler.py
lib/sqlalchemy/testing/assertions.py
test/orm/test_subquery_relations.py

index 1ca8f4e64f0a9ec02eed8615aa81c1a4eeb4f0b1..c7e09b164d71f4fc91d1fe0ed69d3a144715e53c 100644 (file)
@@ -592,6 +592,7 @@ class SQLiteDialect(default.DefaultDialect):
     supports_empty_insert = False
     supports_cast = True
     supports_multivalues_insert = True
+    supports_right_nested_joins = False
 
     default_paramstyle = 'qmark'
     execution_ctx_cls = SQLiteExecutionContext
index 85d11ff36794379829f5a5ae9f4c9317b246bc22..94f59d388721f5eac5cea83c47fe1a448557e522 100644 (file)
@@ -49,6 +49,8 @@ class DefaultDialect(interfaces.Dialect):
     postfetch_lastrowid = True
     implicit_returning = False
 
+    supports_right_nested_joins = True
+
     supports_native_enum = False
     supports_native_boolean = False
 
index 66d208a74202852281f6996a31b0c7ede5ef21df..80fee4a09845581569b387bc0f6fb931d4802243 100644 (file)
@@ -1797,6 +1797,15 @@ class Query(object):
                                 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."""
@@ -1816,10 +1825,16 @@ class Query(object):
                         "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
@@ -1833,7 +1848,7 @@ class Query(object):
 
         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 = \
@@ -1875,9 +1890,10 @@ class Query(object):
                             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):
index ff041d5e4b7e765b3bdb1c96eee53e1c298ba33c..d5ba64938c05eaa7cd7a5a94cd1b498f8908c880 100644 (file)
@@ -1079,7 +1079,10 @@ class SQLCompiler(engine.Compiled):
 
     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):
@@ -1090,6 +1093,12 @@ class SQLCompiler(engine.Compiled):
                 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
@@ -1097,6 +1106,7 @@ class SQLCompiler(engine.Compiled):
                 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,
@@ -1119,7 +1129,9 @@ class SQLCompiler(engine.Compiled):
                             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(
index c041539619dcbdfdbb372d59485379612b5e8b04..59246730252fc229e1676b01ade53c1c42c87c8a 100644 (file)
@@ -186,12 +186,13 @@ class AssertsCompiledSQL(object):
             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:
index d493e0b7e65354c53695245e604b20f59d22dc2c..a6cc37691ca4e6f413861a2a0dabb7a3a45630ab 100644 (file)
@@ -1533,19 +1533,18 @@ class CyclicalInheritingEagerTestTwo(fixtures.DeclarativeMappedTest,
         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