Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed .distinct() not working with slicing in Oracle, due to the

row numbers necessarily being distinct.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@9221 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9a72913edd10dbf2214397b20c3f5f501afd506b 1 parent 227a5a4
@ikelly ikelly authored
View
46 django/db/backends/oracle/query.py
@@ -26,8 +26,16 @@ def query_class(QueryClass, Database):
class OracleQuery(QueryClass):
def resolve_columns(self, row, fields=()):
- index_start = len(self.extra_select.keys())
- values = [self.convert_values(v, None) for v in row[:index_start]]
+ # If this query has limit/offset information, then we expect the
+ # first column to be an extra "_RN" column that we need to throw
+ # away.
+ if self.high_mark is not None or self.low_mark:
+ rn_offset = 1
+ else:
+ rn_offset = 0
+ index_start = rn_offset + len(self.extra_select.keys())
+ values = [self.convert_values(v, None)
+ for v in row[rn_offset:index_start]]
for value, field in map(None, row[index_start:], fields):
values.append(self.convert_values(value, field))
return values
@@ -97,49 +105,17 @@ def as_sql(self, with_limits=True, with_col_aliases=False):
sql, params = super(OracleQuery, self).as_sql(with_limits=False,
with_col_aliases=with_col_aliases)
else:
- # `get_columns` needs to be called before `get_ordering` to
- # populate `_select_alias`.
- self.pre_sql_setup()
- self.get_columns()
- ordering = self.get_ordering()
-
- # Oracle's ROW_NUMBER() function requires an ORDER BY clause.
- if ordering:
- rn_orderby = ', '.join(ordering)
- else:
- # Create a default ORDER BY since none was specified.
- qn = self.quote_name_unless_alias
- opts = self.model._meta
- rn_orderby = '%s.%s' % (qn(opts.db_table),
- qn(opts.fields[0].db_column or opts.fields[0].column))
-
- # Ensure the base query SELECTs our special "_RN" column
- self.extra_select['_RN'] = ('ROW_NUMBER() OVER (ORDER BY %s)'
- % rn_orderby, '')
sql, params = super(OracleQuery, self).as_sql(with_limits=False,
with_col_aliases=True)
# Wrap the base query in an outer SELECT * with boundaries on
# the "_RN" column. This is the canonical way to emulate LIMIT
# and OFFSET on Oracle.
- sql = 'SELECT * FROM (%s) WHERE "_RN" > %d' % (sql, self.low_mark)
+ sql = 'SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY 1) AS "_RN", "_SUB".* FROM (%s) "_SUB") WHERE "_RN" > %d' % (sql, self.low_mark)
if self.high_mark is not None:
sql = '%s AND "_RN" <= %d' % (sql, self.high_mark)
return sql, params
- def set_limits(self, low=None, high=None):
- super(OracleQuery, self).set_limits(low, high)
- # We need to select the row number for the LIMIT/OFFSET sql.
- # A placeholder is added to extra_select now, because as_sql is
- # too late to be modifying extra_select. However, the actual sql
- # depends on the ordering, so that is generated in as_sql.
- self.extra_select['_RN'] = ('1', '')
-
- def clear_limits(self):
- super(OracleQuery, self).clear_limits()
- if '_RN' in self.extra_select:
- del self.extra_select['_RN']
-
_classes[QueryClass] = OracleQuery
return OracleQuery
View
6 tests/regressiontests/queries/models.py
@@ -334,6 +334,12 @@ def __unicode__(self):
>>> Item.objects.filter(tags__in=[t1, t2]).filter(tags=t3)
[<Item: two>]
+Make sure .distinct() works with slicing (this was broken in Oracle).
+>>> Item.objects.filter(tags__in=[t1, t2]).order_by('name')[:3]
+[<Item: one>, <Item: one>, <Item: two>]
+>>> Item.objects.filter(tags__in=[t1, t2]).distinct().order_by('name')[:3]
+[<Item: one>, <Item: two>]
+
Bug #2080, #3592
>>> Author.objects.filter(item__name='one') | Author.objects.filter(name='a3')
[<Author: a1>, <Author: a3>]
Please sign in to comment.
Something went wrong with that request. Please try again.