From 1e1eea05538e43a41750ba8548da517d77284e9c Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 5 Feb 2006 17:04:37 +0000 Subject: [PATCH] got oracle LIMIT/OFFSET to use row_number() syntax 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 | 4 +++- lib/sqlalchemy/databases/oracle.py | 20 ++++++++++++++++---- lib/sqlalchemy/sql.py | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/sqlalchemy/ansisql.py b/lib/sqlalchemy/ansisql.py index 30060a93ce..fc4af5198f 100644 --- a/lib/sqlalchemy/ansisql.py +++ b/lib/sqlalchemy/ansisql.py @@ -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) diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py index de4a76c3ef..857b0c2fce 100644 --- a/lib/sqlalchemy/databases/oracle.py +++ b/lib/sqlalchemy/databases/oracle.py @@ -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] diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 8be40ac1da..c8a05470c1 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -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 -- 2.47.2