]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Omit onclause as source of FROMs from a Join
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 8 Oct 2019 20:42:21 +0000 (16:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 9 Oct 2019 15:05:58 +0000 (11:05 -0400)
The :class:`.Join` construct no longer considers the "onclause" as a source
of additional FROM objects to be omitted from the FROM list of an enclosing
:class:`.Select` object as standalone FROM objects. This applies to an ON
clause that includes a reference to another  FROM object outside the JOIN;
while this is usually not correct from a SQL perspective, it's also
incorrect for it to be omitted, and the behavioral change makes the
:class:`.Select` / :class:`.Join` behave a bit more intuitively.

Fixes: #4621
Change-Id: Iaa1e75b7c59b21e9701ab3c9b69e66930feaf8ee

doc/build/changelog/unreleased_14/4621.rst [new file with mode: 0644]
lib/sqlalchemy/sql/selectable.py
test/sql/test_selectable.py

diff --git a/doc/build/changelog/unreleased_14/4621.rst b/doc/build/changelog/unreleased_14/4621.rst
new file mode 100644 (file)
index 0000000..2247783
--- /dev/null
@@ -0,0 +1,12 @@
+.. change::
+    :tags: bug, sql
+    :tickets: 4621
+
+    The :class:`.Join` construct no longer considers the "onclause" as a source
+    of additional FROM objects to be omitted from the FROM list of an enclosing
+    :class:`.Select` object as standalone FROM objects. This applies to an ON
+    clause that includes a reference to another  FROM object outside the JOIN;
+    while this is usually not correct from a SQL perspective, it's also
+    incorrect for it to be omitted, and the behavioral change makes the
+    :class:`.Select` / :class:`.Join` behave a bit more intuitively.
+
index 6282cf2ee08e2254bb7798514ea37dca746ef8e2..6a7413fc098ae7cb9e70ba252cd81eef1baab97a 100644 (file)
@@ -1157,12 +1157,7 @@ class Join(FromClause):
 
     @property
     def _from_objects(self):
-        return (
-            [self]
-            + self.onclause._from_objects
-            + self.left._from_objects
-            + self.right._from_objects
-        )
+        return [self] + self.left._from_objects + self.right._from_objects
 
 
 # FromClause ->
index 00b9b68c7ea490f4343196332e572c5bb9dd9531..2bc7ccc9317a9b47f9c40991045f5f5d0a1d669e 100644 (file)
@@ -471,6 +471,32 @@ class SelectableTest(
         criterion = a.c.col1 == table2.c.col2
         self.assert_(criterion.compare(j.onclause))
 
+    def test_join_doesnt_derive_from_onclause(self):
+        # test issue #4621.   the hide froms from the join comes from
+        # Join._from_obj(), which should not include tables in the ON clause
+        t1 = table("t1", column("a"))
+        t2 = table("t2", column("b"))
+        t3 = table("t3", column("c"))
+        t4 = table("t4", column("d"))
+
+        j = t1.join(t2, onclause=t1.c.a == t3.c.c)
+
+        j2 = t4.join(j, onclause=t4.c.d == t2.c.b)
+
+        stmt = select([t1, t2, t3, t4]).select_from(j2)
+        self.assert_compile(
+            stmt,
+            "SELECT t1.a, t2.b, t3.c, t4.d FROM t3, "
+            "t4 JOIN (t1 JOIN t2 ON t1.a = t3.c) ON t4.d = t2.b",
+        )
+
+        stmt = select([t1]).select_from(t3).select_from(j2)
+        self.assert_compile(
+            stmt,
+            "SELECT t1.a FROM t3, t4 JOIN (t1 JOIN t2 ON t1.a = t3.c) "
+            "ON t4.d = t2.b",
+        )
+
     @testing.fails("not supported with rework, need a new approach")
     def test_alias_handles_column_context(self):
         # not quite a use case yet but this is expected to become