]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
got oracle LIMIT/OFFSET to use row_number() syntax
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 5 Feb 2006 17:04:37 +0000 (17:04 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 5 Feb 2006 17:04:37 +0000 (17:04 +0000)
sql: ColumnClause will use the given name when proxying itself (used for the "ora_rn" label)
ansisql: When adding on ORDER_BY, GROUP_BY, etc. clauses, if there is no string for the column list,
then dont add the clause (this allows oracle to strip out the ORDER BY)
Oracle is modifying the select statement, which is not ideal - should fix that

lib/sqlalchemy/ansisql.py
lib/sqlalchemy/databases/oracle.py
lib/sqlalchemy/sql.py

index 30060a93ce6daf5dc8b5b5a0b0054f82e0bfcdaf..fc4af5198f7e11429905b888da662c630fc75d4f 100644 (file)
@@ -319,7 +319,9 @@ class ANSICompiler(sql.Compiled):
                 text += " \nWHERE " + t
 
         for tup in select.clauses:
-            text += " " + tup[0] + " " + self.get_str(tup[1])
+            ss = self.get_str(tup[1])
+            if ss:
+                text += " " + tup[0] + " " + ss
 
         if select.having is not None:
             t = self.get_str(select.having)
index de4a76c3eff81458ef7932ea998153368494f7b3..857b0c2fce427f54746809cdd396574cc522f6d9 100644 (file)
@@ -191,17 +191,29 @@ class OracleCompiler(ansisql.ANSICompiler):
 
     def visit_select(self, select):
         """looks for LIMIT and OFFSET in a select statement, and if so tries to wrap it in a 
-        subquery with rownum criterion."""
+        subquery with row_number() criterion."""
+        # TODO: put a real copy-container on Select and copy, or somehow make this
+        # not modify the Select statement
         if getattr(select, '_oracle_visit', False):
+            # cancel out the compiled order_by on the select
+            if hasattr(select, "order_by_clause"):
+                self.strings[select.order_by_clause] = ""
             ansisql.ANSICompiler.visit_select(self, select)
             return
         if select.limit is not None or select.offset is not None:
             select._oracle_visit = True
+            if hasattr(select, "order_by_clause"):
+                orderby = self.strings[select.order_by_clause]
+            else:
+                orderby = "rowid ASC"
+            select.append_column(sql.ColumnClause("ROW_NUMBER() OVER (ORDER BY %s)" % orderby).label("ora_rn"))
             limitselect = select.select()
-            if select.limit is not None:
-                limitselect.append_whereclause("rownum<%d" % select.limit)
             if select.offset is not None:
-                limitselect.append_whereclause("rownum>%d" % select.offset)
+                limitselect.append_whereclause("ora_rn>%d" % select.offset)
+                if select.limit is not None:
+                    limitselect.append_whereclause("ora_rn<=%d" % (select.limit + select.offset))
+            else:
+                limitselect.append_whereclause("ora_rn<=%d" % select.limit)
             limitselect.accept_visitor(self)
             self.strings[select] = self.strings[limitselect]
             self.froms[select] = self.froms[limitselect]
index 8be40ac1dae9d41bae6d7ad4ad671775ca31bad3..c8a05470c1b73c7036fe537d02e303db1967dab2 100644 (file)
@@ -987,7 +987,7 @@ class ColumnClause(ColumnElement):
         else:
             return BindParamClause(self.table.name + "_" + self.text, obj, shortname = self.text, type=self.type)
     def _make_proxy(self, selectable, name = None):
-        c = ColumnClause(self.text or name, selectable)
+        c = ColumnClause(name or self.text, selectable)
         selectable.columns[c.key] = c
         return c