summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-11-05 04:22:30 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2014-11-05 04:22:30 -0500
commitedec583b459e955a30d40b5c5d8baaed0a2ec1c6 (patch)
treefab94a50db294b0fd9ac8df493861f6505d533ce
parent7bf5ac9c1e814c999d4930941935e1d5cfd236bf (diff)
downloadsqlalchemy-edec583b459e955a30d40b5c5d8baaed0a2ec1c6.tar.gz
- 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. fixes #3241
-rw-r--r--doc/build/changelog/changelog_09.rst11
-rw-r--r--lib/sqlalchemy/sql/elements.py7
-rw-r--r--test/sql/test_generative.py13
-rw-r--r--test/sql/test_join_rewriting.py25
4 files changed, 55 insertions, 1 deletions
diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst
index 6909da357..8ed2ea776 100644
--- a/doc/build/changelog/changelog_09.rst
+++ b/doc/build/changelog/changelog_09.rst
@@ -14,6 +14,17 @@
: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
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 4d5bb9476..fa9b66024 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -861,6 +861,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'))
)
@@ -2779,6 +2782,10 @@ class Grouping(ColumnElement):
return self
@property
+ def _key_label(self):
+ return self._label
+
+ @property
def _label(self):
return getattr(self.element, '_label', None) or self.anon_label
diff --git a/test/sql/test_generative.py b/test/sql/test_generative.py
index 6044cecb0..6b86614e6 100644
--- a/test/sql/test_generative.py
+++ b/test/sql/test_generative.py
@@ -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"))
diff --git a/test/sql/test_join_rewriting.py b/test/sql/test_join_rewriting.py
index c8b24e2f2..ced65d7f1 100644
--- a/test/sql/test_join_rewriting.py
+++ b/test/sql/test_join_rewriting.py
@@ -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):