]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug in SQLite join rewriting where anonymized column names
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 25 May 2014 15:32:07 +0000 (11:32 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 25 May 2014 15:32:36 +0000 (11:32 -0400)
due to repeats would not correctly be rewritten in subqueries.
This would affect SELECT queries with any kind of subquery + join.
fixes #3057

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/sql/elements.py
test/sql/test_join_rewriting.py
test/sql/test_selectable.py

index 60ab05d128850feb25e48e283cbd0ce9f1fb684d..ecebfeab5913dd47a920133cef655a91e6cb8429 100644 (file)
 .. changelog::
     :version: 0.9.5
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3057
+        :versions: 1.0.0
+
+        Fixed bug in SQLite join rewriting where anonymized column names
+        due to repeats would not correctly be rewritten in subqueries.
+        This would affect SELECT queries with any kind of subquery + join.
+
     .. change::
         :tags: bug, sql
         :tickets: 3012
index ce6056418fb1dd4ca2bfc674e574a386eda60c7e..bf0ac3def36a4e60f53be267daed6a8014035235 100644 (file)
@@ -3488,3 +3488,6 @@ class AnnotatedColumnElement(Annotated):
     def info(self):
         return self._Annotated__element.info
 
+    @util.memoized_property
+    def anon_label(self):
+        return self._Annotated__element.anon_label
index 35797871a1d8348811913f04a3da52d100ae34ea..4e83cafabd6dfa2ddba18cdef13861f4da402152 100644 (file)
@@ -16,6 +16,10 @@ b = Table('b', m,
         Column('a_id', Integer, ForeignKey('a.id'))
     )
 
+b_a = Table('b_a', m,
+        Column('id', Integer, primary_key=True),
+    )
+
 b1 = Table('b1', m,
         Column('id', Integer, primary_key=True),
         Column('a_id', Integer, ForeignKey('a.id'))
@@ -201,6 +205,24 @@ class _JoinRewriteTestBase(AssertsCompiledSQL):
             self._b_ab1_union_c_ab2
         )
 
+    def test_b_a_id_double_overlap_annotated(self):
+        # test issue #3057
+        # this involves annotations so try to loop those in.
+        j1 = b.join(b_a, b.c.id == b_a.c.id)
+        annot = [
+                    b.c.id._annotate({}),
+                    b.c.a_id._annotate({}),
+                    b_a.c.id._annotate({})
+                ]
+
+        s = select(annot).select_from(j1).apply_labels().alias()
+
+        s = select(list(s.c)).apply_labels()
+
+        self._test(
+            s,
+            self._b_a_id_double_overlap_annotated
+        )
 
 class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase):
     """test rendering of each join with right-nested rewritten as
@@ -320,6 +342,13 @@ class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase):
         "FROM a JOIN b2 ON a.id = b2.a_id) AS anon_2 ON anon_2.a_id = b.a_id)"
     )
 
+    _b_a_id_double_overlap_annotated = (
+        "SELECT anon_1.b_id AS anon_1_b_id, anon_1.b_a_id AS anon_1_b_a_id, "
+        "anon_1.id_1 AS anon_1_id_1 "
+        "FROM (SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 "
+        "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1"
+    )
+
 class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase):
     """test rendering of each join with normal nesting."""
     @util.classproperty
@@ -413,6 +442,13 @@ class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase):
         "JOIN (a JOIN b2 ON a.id = b2.a_id) ON a.id = b.a_id)"
     )
 
+    _b_a_id_double_overlap_annotated = (
+        "SELECT anon_1.b_id AS anon_1_b_id, anon_1.b_a_id AS anon_1_b_a_id, "
+        "anon_1.id_1 AS anon_1_id_1 FROM "
+        "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 "
+        "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1"
+    )
+
 class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase):
     @util.classproperty
     def __dialect__(cls):
@@ -506,6 +542,12 @@ class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase):
         "FROM b JOIN (a JOIN b2 ON a.id = b2.a_id) ON a.id = b.a_id)"
     )
 
+    _b_a_id_double_overlap_annotated = (
+        "SELECT anon_1.b_id, anon_1.b_a_id, anon_1.id_1 FROM "
+        "(SELECT b.id AS b_id, b.a_id AS b_a_id, b_a.id AS id_1 "
+        "FROM b JOIN b_a ON b.id = b_a.id) AS anon_1"
+    )
+
 class JoinExecTest(_JoinRewriteTestBase, fixtures.TestBase):
     """invoke the SQL on the current backend to ensure compatibility"""
 
@@ -513,7 +555,8 @@ class JoinExecTest(_JoinRewriteTestBase, fixtures.TestBase):
 
     _a_bc = _a_bc_comma_a1_selbc = _a__b_dc = _a_bkeyassoc = \
         _a_bkeyassoc_aliased = _a_atobalias_balias_c_w_exists = \
-        _a_atobalias_balias = _b_ab1_union_c_ab2 = None
+        _a_atobalias_balias = _b_ab1_union_c_ab2 = \
+        _b_a_id_double_overlap_annotated = None
 
     @classmethod
     def setup_class(cls):
index ed97bb37f03b878591a0d7702745d74e78f63e9b..3ee8127b624f8cd87b3d46f6a75010c52de93126 100644 (file)
@@ -1549,6 +1549,19 @@ class AnnotationsTest(fixtures.TestBase):
         t = Table('t', MetaData(), c1)
         is_(c1_a.table, t)
 
+    def test_basic_attrs(self):
+        t = Table('t', MetaData(),
+                        Column('x', Integer, info={'q': 'p'}),
+                        Column('y', Integer, key='q'))
+        x_a = t.c.x._annotate({})
+        y_a = t.c.q._annotate({})
+        t.c.x.info['z'] = 'h'
+
+        eq_(y_a.key, 'q')
+        is_(x_a.table, t)
+        eq_(x_a.info, {'q': 'p', 'z': 'h'})
+        eq_(t.c.x.anon_label, x_a.anon_label)
+
     def test_custom_constructions(self):
         from sqlalchemy.schema import Column
         class MyColumn(Column):