From d24133e5c574676bbc0f30c2186d8da25f550ecb Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 3 Jan 2010 20:57:37 +0000 Subject: [PATCH] - Fixed a column arithmetic bug that affected column correspondence for cloned selectables which contain free-standing column expressions. This bug is generally only noticeable when exercising newer ORM behavior only availble in 0.6 via [ticket:1568], but is more correct at the SQL expression level as well. [ticket:1617] --- CHANGES | 10 +++++++++- lib/sqlalchemy/sql/expression.py | 3 ++- test/orm/test_query.py | 15 +++++++++++++++ test/sql/test_selectable.py | 13 +++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 140bd058c9..db6a7e6735 100644 --- a/CHANGES +++ b/CHANGES @@ -799,7 +799,15 @@ CHANGES unnamed Column objects. This allows easy creation of declarative helpers which place common columns on multiple subclasses. - + + - Fixed a column arithmetic bug that affected column + correspondence for cloned selectables which contain + free-standing column expressions. This bug is + generally only noticeable when exercising newer + ORM behavior only availble in 0.6 via [ticket:1568], + but is more correct at the SQL expression level + as well. [ticket:1617] + - postgresql - The extract() function, which was slightly improved in 0.5.7, needed a lot more work to generate the correct diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 842e76d159..43b22fc8e1 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1967,7 +1967,8 @@ class FromClause(Selectable): target_set = column.proxy_set cols = self.c for c in cols: - i = c.proxy_set.intersection(target_set) + i = target_set.intersection(itertools.chain(*[p._cloned_set for p in c.proxy_set])) + if i and \ (not require_embedded or c.proxy_set.issuperset(target_set)): diff --git a/test/orm/test_query.py b/test/orm/test_query.py index 0d98417f6d..967d1ac6cb 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -921,6 +921,21 @@ class FromSelfTest(QueryTest, AssertsCompiledSQL): # order_by(User.id, Address.id).first(), (User(id=8, addresses=[Address(), Address(), Address()]), Address(id=2)), ) + + def test_multiple_with_column_entities(self): + sess = create_session() + + eq_( + sess.query(User.id).from_self().\ + add_column(func.count().label('foo')).\ + group_by(User.id).\ + from_self().all(), + [ + (7,1), (8, 1), (9, 1), (10, 1) + ] + + ) + class SetOpsTest(QueryTest, AssertsCompiledSQL): diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 147e47cd96..f5f61aab13 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -57,7 +57,20 @@ class SelectableTest(TestBase, AssertsExecutionResults): # test alias of the join j2 = jjj.alias('foo') assert j2.corresponding_column(table1.c.col1) is j2.c.table1_col1 + + def test_against_cloned_non_table(self): + # test that corresponding column digs across + # clone boundaries with anonymous labeled elements + col = func.count().label('foo') + sel = select([col]) + + sel2 = visitors.ReplacingCloningVisitor().traverse(sel) + assert sel2.corresponding_column(col) is sel2.c.foo + sel3 = visitors.ReplacingCloningVisitor().traverse(sel2) + assert sel3.corresponding_column(col) is sel3.c.foo + + def test_select_on_table(self): sel = select([table1, table2], use_labels=True) assert sel.corresponding_column(table1.c.col1) is sel.c.table1_col1 -- 2.47.3