summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-02-21 22:46:31 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2016-02-21 22:49:29 -0500
commiteff7b4f29d2a98ef4ccd95b693c7d653eaa543eb (patch)
tree98dc9a49993792580df9d38f747f591054db68f6
parent01809bddff5b6e93010eb139aed54526c6e6c058 (diff)
downloadsqlalchemy-eff7b4f29d2a98ef4ccd95b693c7d653eaa543eb.tar.gz
- additional adjustment to the fix made in 8ad968f33100baeb3b13c7e0b724b6b79ab4277f
for ref #3657. The Oracle dialect makes more use of the "select_wraps_for" feature than SQL server because Oracle doesn't have "TOP" for a limit-only select, so tests are showing more happening here. In the case where the select() has some dupe columns, these are deduped from the .c collection so a positional match between the wrapper and original can't use .inner_columns, because these collections wont match. Using _columns_plus_names instead which is the deduped collection that determines the SELECT display, which definitely have to match up. (cherry picked from commit aa9ce3f521f254da9879ede011e520ec35b8270e)
-rw-r--r--lib/sqlalchemy/sql/compiler.py5
-rw-r--r--test/sql/test_compiler.py40
2 files changed, 44 insertions, 1 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index b75dc1c07..8600dbaeb 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -1640,7 +1640,10 @@ class SQLCompiler(Compiled):
# rewrite the targeted columns in the result map
translate = dict(
- zip(select.inner_columns, select_wraps_for.inner_columns)
+ zip(
+ [name for (key, name) in select._columns_plus_names],
+ [name for (key, name) in
+ select_wraps_for._columns_plus_names])
)
self._result_columns = [
diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py
index 1c5dc2340..041cd37b6 100644
--- a/test/sql/test_compiler.py
+++ b/test/sql/test_compiler.py
@@ -3878,3 +3878,43 @@ class ResultMapTest(fixtures.TestBase):
proxied
):
is_(orig_obj, proxied_obj)
+
+ def test_select_wraps_for_translate_ambiguity_dupe_cols(self):
+ # test for issue #3657
+ t = table('a', column('x'), column('y'), column('z'))
+
+ l1, l2, l3 = t.c.z.label('a'), t.c.x.label('b'), t.c.x.label('c')
+ orig = [t.c.x, t.c.y, l1, l2, l3]
+
+ # create the statement with some duplicate columns. right now
+ # the behavior is that these redundant columns are deduped.
+ stmt = select([t.c.x, t.c.y, l1, t.c.y, l2, t.c.x, l3])
+
+ # so the statement has 7 inner columns...
+ eq_(len(list(stmt.inner_columns)), 7)
+
+ # but only exposes 5 of them, the other two are dupes of x and y
+ eq_(len(stmt.c), 5)
+
+ # and when it generates a SELECT it will also render only 5
+ eq_(len(stmt._columns_plus_names), 5)
+
+ wrapped = stmt._generate()
+ wrapped = wrapped.column(
+ func.ROW_NUMBER().over(order_by=t.c.z)).alias()
+
+ # so when we wrap here we're going to have only 5 columns
+ wrapped_again = select([c for c in wrapped.c])
+
+ # so the compiler logic that matches up the "wrapper" to the
+ # "select_wraps_for" can't use inner_columns to match because
+ # these collections are not the same
+ compiled = wrapped_again.compile(
+ compile_kwargs={'select_wraps_for': stmt})
+
+ proxied = [obj[0] for (k, n, obj, type_) in compiled._result_columns]
+ for orig_obj, proxied_obj in zip(
+ orig,
+ proxied
+ ):
+ is_(orig_obj, proxied_obj)