summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--lib/sqlalchemy/databases/oracle.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py13
-rw-r--r--test/dialect/oracle.py9
-rw-r--r--test/sql/labels.py25
5 files changed, 49 insertions, 5 deletions
diff --git a/CHANGES b/CHANGES
index 7087bcc84..5d2d83375 100644
--- a/CHANGES
+++ b/CHANGES
@@ -84,6 +84,11 @@ CHANGES
- reflect the sequence associated to a PK field (tipically
with a BEFORE INSERT trigger) under Firebird
+ - Oracle assembles the correct columns in the result set
+ column mapping when generating a LIMIT/OFFSET subquery,
+ allows columns to map properly to result sets even
+ if long-name truncation kicks in [ticket:941]
+
0.4.2p3
------
- general
diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py
index c7ab13441..55bdf74b1 100644
--- a/lib/sqlalchemy/databases/oracle.py
+++ b/lib/sqlalchemy/databases/oracle.py
@@ -675,7 +675,7 @@ class OracleCompiler(compiler.DefaultCompiler):
limitselect.append_whereclause("ora_rn<=%d" % (select._limit + select._offset))
else:
limitselect.append_whereclause("ora_rn<=%d" % select._limit)
- return self.process(limitselect, **kwargs)
+ return self.process(limitselect, iswrapper=True, **kwargs)
else:
return compiler.DefaultCompiler.visit_select(self, select, **kwargs)
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 666a38d39..71bfd1765 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -468,13 +468,20 @@ class DefaultCompiler(engine.Compiled):
else:
return column
- def visit_select(self, select, asfrom=False, parens=True, **kwargs):
+ def visit_select(self, select, asfrom=False, parens=True, iswrapper=False, **kwargs):
stack_entry = {'select':select}
-
- if asfrom or (self.stack and 'select' in self.stack[-1]):
+ prev_entry = self.stack and self.stack[-1] or None
+
+ if asfrom or (prev_entry and 'select' in prev_entry):
stack_entry['is_subquery'] = True
+ if prev_entry and 'iswrapper' in prev_entry:
+ column_clause_args = {'result_map':self.result_map}
+ else:
+ column_clause_args = {}
+ elif iswrapper:
column_clause_args = {}
+ stack_entry['iswrapper'] = True
else:
column_clause_args = {'result_map':self.result_map}
diff --git a/test/dialect/oracle.py b/test/dialect/oracle.py
index cc171af5f..9436d1915 100644
--- a/test/dialect/oracle.py
+++ b/test/dialect/oracle.py
@@ -41,12 +41,21 @@ class CompileTest(SQLCompileTest):
def test_limit(self):
t = table('sometable', column('col1'), column('col2'))
+ s = select([t])
+ c = s.compile(dialect=oracle.OracleDialect())
+ assert t.c.col1 in set(c.result_map['col1'][1])
+
s = select([t]).limit(10).offset(20)
self.assert_compile(s, "SELECT col1, col2 FROM (SELECT sometable.col1 AS col1, sometable.col2 AS col2, "
"ROW_NUMBER() OVER (ORDER BY sometable.rowid) AS ora_rn FROM sometable) WHERE ora_rn>20 AND ora_rn<=30"
)
+ # assert that despite the subquery, the columns from the table,
+ # not the select, get put into the "result_map"
+ c = s.compile(dialect=oracle.OracleDialect())
+ assert t.c.col1 in set(c.result_map['col1'][1])
+
s = select([s.c.col1, s.c.col2])
self.assert_compile(s, "SELECT col1, col2 FROM (SELECT col1, col2 FROM (SELECT sometable.col1 AS col1, "
diff --git a/test/sql/labels.py b/test/sql/labels.py
index 3d4f0adde..8164d7f77 100644
--- a/test/sql/labels.py
+++ b/test/sql/labels.py
@@ -44,7 +44,8 @@ class LongLabelsTest(SQLCompileTest):
table1.insert().execute(**{"this_is_the_primarykey_column":3, "this_is_the_data_column":"data3"})
table1.insert().execute(**{"this_is_the_primarykey_column":4, "this_is_the_data_column":"data4"})
- r = table1.select(use_labels=True, order_by=[table1.c.this_is_the_primarykey_column]).execute()
+ s = table1.select(use_labels=True, order_by=[table1.c.this_is_the_primarykey_column])
+ r = s.execute()
result = []
for row in r:
result.append((row[table1.c.this_is_the_primarykey_column], row[table1.c.this_is_the_data_column]))
@@ -55,6 +56,28 @@ class LongLabelsTest(SQLCompileTest):
(4, "data4"),
], repr(result)
+ # some dialects such as oracle (and possibly ms-sql in a future version)
+ # generate a subquery for limits/offsets.
+ # ensure that the generated result map corresponds to the selected table, not
+ # the select query
+ r = s.limit(2).execute()
+ result = []
+ for row in r:
+ result.append((row[table1.c.this_is_the_primarykey_column], row[table1.c.this_is_the_data_column]))
+ assert result == [
+ (1, "data1"),
+ (2, "data2"),
+ ], repr(result)
+
+ r = s.limit(2).offset(1).execute()
+ result = []
+ for row in r:
+ result.append((row[table1.c.this_is_the_primarykey_column], row[table1.c.this_is_the_data_column]))
+ assert result == [
+ (2, "data2"),
+ (3, "data3"),
+ ], repr(result)
+
def test_colbinds(self):
table1.insert().execute(**{"this_is_the_primarykey_column":1, "this_is_the_data_column":"data1"})
table1.insert().execute(**{"this_is_the_primarykey_column":2, "this_is_the_data_column":"data2"})