Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed Oracle backend not to use extra_select for limit/offset type qu…

…eries, which fixes a majority of the currently failing tests. Thanks, Ramiro Morales.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8445 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit db76b1e89dc621f9a926cd391326cc1e9f1325db 1 parent e7769c3
Matt Boersma authored August 19, 2008

Showing 1 changed file with 38 additions and 54 deletions. Show diff stats Hide diff stats

  1. 92  django/db/backends/oracle/query.py
92  django/db/backends/oracle/query.py
@@ -92,61 +92,45 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
92 92
             # the SQL needed to use limit/offset w/Oracle.
93 93
             do_offset = with_limits and (self.high_mark is not None
94 94
                                          or self.low_mark)
95  
-
96  
-            # If no offsets, just return the result of the base class
97  
-            # `as_sql`.
98  
-            if not do_offset:
99  
-                return super(OracleQuery, self).as_sql(with_limits=False,
100  
-                        with_col_aliases=with_col_aliases)
101  
-
102  
-            # `get_columns` needs to be called before `get_ordering` to
103  
-            # populate `_select_alias`.
104  
-            self.pre_sql_setup()
105  
-            out_cols = self.get_columns()
106  
-            ordering = self.get_ordering()
107  
-
108  
-            # Getting the "ORDER BY" SQL for the ROW_NUMBER() result.
109  
-            if ordering:
110  
-                rn_orderby = ', '.join(ordering)
111  
-            else:
112  
-                # Oracle's ROW_NUMBER() function always requires an
113  
-                # order-by clause.  So we need to define a default
114  
-                # order-by, since none was provided.
115  
-                qn = self.quote_name_unless_alias
116  
-                opts = self.model._meta
117  
-                rn_orderby = '%s.%s' % (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column))
118  
-
119  
-            # Getting the selection SQL and the params, which has the `rn`
120  
-            # extra selection SQL.
121  
-            self.extra_select['rn'] = 'ROW_NUMBER() OVER (ORDER BY %s )' % rn_orderby
122 95
             sql, params = super(OracleQuery, self).as_sql(with_limits=False,
123  
-                    with_col_aliases=True)
124  
-
125  
-            # Constructing the result SQL, using the initial select SQL
126  
-            # obtained above.
127  
-            result = ['SELECT * FROM (%s)' % sql]
128  
-
129  
-            # Place WHERE condition on `rn` for the desired range.
130  
-            result.append('WHERE rn > %d' % self.low_mark)
131  
-            if self.high_mark is not None:
132  
-                result.append('AND rn <= %d' % self.high_mark)
133  
-
134  
-            # Returning the SQL w/params.
135  
-            return ' '.join(result), params
136  
-
137  
-        def set_limits(self, low=None, high=None):
138  
-            super(OracleQuery, self).set_limits(low, high)
139  
-
140  
-            # We need to select the row number for the LIMIT/OFFSET sql.
141  
-            # A placeholder is added to extra_select now, because as_sql is
142  
-            # too late to be modifying extra_select.  However, the actual sql
143  
-            # depends on the ordering, so that is generated in as_sql.
144  
-            self.extra_select['rn'] = '1'
145  
-
146  
-        def clear_limits(self):
147  
-            super(OracleQuery, self).clear_limits()
148  
-            if 'rn' in self.extra_select:
149  
-                del self.extra_select['rn']
  96
+                                with_col_aliases=with_col_aliases or do_offset)
  97
+            if do_offset:
  98
+                # Get the "ORDER BY" SQL for the ROW_NUMBER() result.
  99
+                ordering = self.get_ordering()
  100
+                if ordering:
  101
+                    rn_orderby = ', '.join(ordering)
  102
+                else:
  103
+                    # Oracle's ROW_NUMBER() function always requires an
  104
+                    # order-by clause.  So we need to define a default
  105
+                    # order-by, since none was provided.
  106
+                    qn = self.quote_name_unless_alias
  107
+                    opts = self.model._meta
  108
+                    rn_orderby = '%s.%s' % (qn(opts.db_table),
  109
+                        qn(opts.fields[0].db_column or opts.fields[0].column))
  110
+
  111
+                # Collect all the selected column names or aliases.
  112
+                outer_cols = []
  113
+                for col in self.get_columns(True):
  114
+                    if ' AS ' in col:
  115
+                        outer_cols.append(col.split(' AS ', 1)[1])
  116
+                    else:
  117
+                        outer_cols.append(col.rsplit('.', 1)[1])
  118
+
  119
+                # Rewrite the original SQL query to select ROW_NUMBER() and involve
  120
+                # it in the WHERE clause, then wrap everything in an outer SELECT
  121
+                # statement that omits the "rn" column.  This is the canonical way
  122
+                # to emulate LIMIT and OFFSET on Oracle.
  123
+                sql = 'SELECT ROW_NUMBER() OVER (ORDER BY %s) rn, %s' % (rn_orderby, sql[7:])
  124
+                result = ['SELECT %s FROM (%s)' % (', '.join(outer_cols), sql)]
  125
+
  126
+                # Place WHERE condition on `rn` for the desired range.
  127
+                result.append('WHERE rn > %d' % self.low_mark)
  128
+                if self.high_mark is not None:
  129
+                    result.append('AND rn <= %d' % self.high_mark)
  130
+
  131
+                sql = ' '.join(result)
  132
+
  133
+            return sql, params
150 134
 
151 135
     _classes[QueryClass] = OracleQuery
152 136
     return OracleQuery

0 notes on commit db76b1e

Please sign in to comment.
Something went wrong with that request. Please try again.