]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug regarding expression mutations which could express
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 5 Nov 2014 09:22:30 +0000 (04:22 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 5 Nov 2014 09:22:53 +0000 (04:22 -0500)
itself as a "Could not locate column" error when using
:class:`.Query` to  select from multiple, anonymous column
entities when querying against SQLite, as a side effect of the
"join rewriting" feature used by the SQLite dialect.
fixes #3241

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

index 6909da357035b358c84a0c0756216d183c0c8f62..8ed2ea77616c34541c1dc59fd3c5d976f4d26167 100644 (file)
 .. changelog::
     :version: 0.9.9
 
+    .. change::
+        :tags: bug, orm, sqlite
+        :versions: 1.0.0
+        :tickets: 3241
+
+        Fixed bug regarding expression mutations which could express
+        itself as a "Could not locate column" error when using
+        :class:`.Query` to  select from multiple, anonymous column
+        entities when querying against SQLite, as a side effect of the
+        "join rewriting" feature used by the SQLite dialect.
+
     .. change::
         :tags: feature, sqlite
         :versions: 1.0.0
index 6623db2c8a18d3c1597f0deb686f569babf6ff61..af01c7a619cd6d6fcc33c78f56c2da5df0a55a88 100644 (file)
@@ -795,6 +795,9 @@ class ColumnElement(operators.ColumnOperators, ClauseElement):
         expressions and function calls.
 
         """
+        while self._is_clone_of is not None:
+            self = self._is_clone_of
+
         return _anonymous_label(
             '%%(%d %s)s' % (id(self), getattr(self, 'name', 'anon'))
         )
@@ -2669,6 +2672,10 @@ class Grouping(ColumnElement):
     def self_group(self, against=None):
         return self
 
+    @property
+    def _key_label(self):
+        return self._label
+
     @property
     def _label(self):
         return getattr(self.element, '_label', None) or self.anon_label
index 51a8a77cc4a3e8b4312754cfc15ad55bda968496..35851e87a4a3f63b1b28aa4613d435934e03be34 100644 (file)
@@ -132,6 +132,19 @@ class TraversalTest(fixtures.TestBase, AssertsExecutionResults):
         assert struct == s2
         assert struct.is_other(s2)
 
+    def test_clone_anon_label(self):
+        from sqlalchemy.sql.elements import Grouping
+        c1 = Grouping(literal_column('q'))
+        s1 = select([c1])
+
+        class Vis(CloningVisitor):
+            def visit_grouping(self, elem):
+                pass
+
+        vis = Vis()
+        s2 = vis.traverse(s1)
+        eq_(list(s2.inner_columns)[0].anon_label, c1.anon_label)
+
     def test_change_in_place(self):
         struct = B(A("expr1"), A("expr2"), B(A("expr1b"),
                                              A("expr2b")), A("expr3"))
index c8b24e2f2af07b4c6967f86eed840c27314dd7cb..ced65d7f1256b58012799ac46dd1e72d1c1e8d71 100644 (file)
@@ -251,6 +251,16 @@ class _JoinRewriteTestBase(AssertsCompiledSQL):
             self._f_b1a_where_in_b2a
         )
 
+    def test_anon_scalar_subqueries(self):
+        s1 = select([1]).as_scalar()
+        s2 = select([2]).as_scalar()
+
+        s = select([s1, s2]).apply_labels()
+        self._test(
+            s,
+            self._anon_scalar_subqueries
+        )
+
 
 class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase):
 
@@ -389,6 +399,10 @@ class JoinRewriteTest(_JoinRewriteTestBase, fixtures.TestBase):
         "FROM a JOIN b2 ON a.id = b2.a_id)"
     )
 
+    _anon_scalar_subqueries = (
+        "SELECT (SELECT 1) AS anon_1, (SELECT 2) AS anon_2"
+    )
+
 
 class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase):
 
@@ -497,6 +511,10 @@ class JoinPlainTest(_JoinRewriteTestBase, fixtures.TestBase):
         "FROM a JOIN b2 ON a.id = b2.a_id)"
     )
 
+    _anon_scalar_subqueries = (
+        "SELECT (SELECT 1) AS anon_1, (SELECT 2) AS anon_2"
+    )
+
 
 class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase):
 
@@ -605,6 +623,10 @@ class JoinNoUseLabelsTest(_JoinRewriteTestBase, fixtures.TestBase):
         "FROM a JOIN b2 ON a.id = b2.a_id)"
     )
 
+    _anon_scalar_subqueries = (
+        "SELECT (SELECT 1) AS anon_1, (SELECT 2) AS anon_2"
+    )
+
 
 class JoinExecTest(_JoinRewriteTestBase, fixtures.TestBase):
 
@@ -615,7 +637,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 = \
-        _b_a_id_double_overlap_annotated = _f_b1a_where_in_b2a = None
+        _b_a_id_double_overlap_annotated = _f_b1a_where_in_b2a = \
+        _anon_scalar_subqueries = None
 
     @classmethod
     def setup_class(cls):