]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Query called in the context of an expression will render
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 8 Feb 2010 18:37:47 +0000 (18:37 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 8 Feb 2010 18:37:47 +0000 (18:37 +0000)
disambiguating labels in all cases.    Note that this does
not apply to the existing .statement and .subquery()
accessor/method, which still honors the .with_labels()
setting that defaults to False.

- Query.union() retains disambiguating labels within the
returned statement, thus avoiding various SQL composition
errors which can result from column name conflicts.
[ticket:1676]

CHANGES
lib/sqlalchemy/orm/query.py
test/orm/test_query.py

diff --git a/CHANGES b/CHANGES
index 5ecb3c4dd5169dd1308ee45a529b1e0a7bb71801..13c5322ff288b01dad485c18554549a9912bcd05 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,17 @@ CHANGES
     being detached from any Session.   UnboundExecutionError
     is specific to engines bound to sessions and statements.
     
+   - Query called in the context of an expression will render
+     disambiguating labels in all cases.    Note that this does
+     not apply to the existing .statement and .subquery()
+     accessor/method, which still honors the .with_labels()
+     setting that defaults to False.  
+     
+   - Query.union() retains disambiguating labels within the
+     returned statement, thus avoiding various SQL composition
+     errors which can result from column name conflicts.
+     [ticket:1676]
+     
 - sql
   - Added math negation operator support, -x.
   
index fff7fb9d92f02aed34960ecffb61341b61091b4c..ed55351514fe885bbb59ab92fd09bee1c3741fc2 100644 (file)
@@ -355,7 +355,13 @@ class Query(object):
 
     @property
     def statement(self):
-        """The full SELECT statement represented by this Query."""
+        """The full SELECT statement represented by this Query.
+        
+        The statement by default will not have disambiguating labels
+        applied to the construct unless with_labels(True) is called
+        first.
+        
+        """
 
         return self._compile_context(labels=self._with_labels).\
                         statement._annotate({'_halt_adapt': True})
@@ -365,11 +371,15 @@ class Query(object):
 
         Eager JOIN generation within the query is disabled.
 
+        The statement by default will not have disambiguating labels
+        applied to the construct unless with_labels(True) is called
+        first.
+
         """
         return self.enable_eagerloads(False).statement.alias()
 
     def __clause_element__(self):
-        return self.enable_eagerloads(False).statement
+        return self.enable_eagerloads(False).with_labels().statement
 
     @_generative()
     def enable_eagerloads(self, value):
index 0d71b3025713da7931feb1239d56049f7b279033..c1201a14bb725f544e71532cfbc54e4282908761 100644 (file)
@@ -586,9 +586,12 @@ class ExpressionTest(QueryTest, AssertsCompiledSQL):
         
         # this is actually not legal on most DBs since the subquery has no alias
         q1 = s.query(User).filter(User.name=='ed')
+
+
         self.assert_compile(
             select([q1]),
-            "SELECT id, name FROM (SELECT users.id AS id, users.name AS name FROM users WHERE users.name = :name_1)",
+            "SELECT users_id, users_name FROM (SELECT users.id AS users_id, "
+            "users.name AS users_name FROM users WHERE users.name = :name_1)",
             dialect=default.DefaultDialect()
         )
         
@@ -959,8 +962,27 @@ class SetOpsTest(QueryTest, AssertsCompiledSQL):
             [User(name='ed'), User(name='fred'), User(name='jack')]
         )
     
+    def test_statement_labels(self):
+        """test that label conflicts don't occur with joins etc."""
+        
+        s = create_session()
+        q1 = s.query(User, Address).join(User.addresses).\
+                                    filter(Address.email_address=="ed@wood.com")
+        q2 = s.query(User, Address).join(User.addresses).\
+                                    filter(Address.email_address=="jack@bean.com")
+        q3 = q1.union(q2).order_by(User.name)
+        
+        eq_(
+            q3.all(),
+            [
+                (User(name='ed'), Address(email_address="ed@wood.com")),
+                (User(name='jack'), Address(email_address="jack@bean.com")),
+            ]
+        )
+        
     def test_union_labels(self):
-        """test that column expressions translate during the _from_statement() portion of union(), others"""
+        """test that column expressions translate during 
+            the _from_statement() portion of union(), others"""
         
         s = create_session()
         q1 = s.query(User, literal("x"))
@@ -969,9 +991,10 @@ class SetOpsTest(QueryTest, AssertsCompiledSQL):
 
         self.assert_compile(
             q3,
-            "SELECT anon_1.id AS anon_1_id, anon_1.name AS anon_1_name, anon_1.anon_2 AS anon_1_anon_2 FROM "
-            "(SELECT users.id AS id, users.name AS name, :param_1 AS anon_2 FROM users "
-            "UNION SELECT users.id AS id, users.name AS name, 'y' FROM users) AS anon_1"
+            "SELECT anon_1.users_id AS anon_1_users_id, anon_1.users_name AS anon_1_users_name,"
+            " anon_1.anon_2 AS anon_1_anon_2 FROM (SELECT users.id AS users_id, users.name AS"
+            " users_name, :param_1 AS anon_2 FROM users UNION SELECT users.id AS users_id, "
+            "users.name AS users_name, 'y' FROM users) AS anon_1"
             , use_default_dialect = True
         )