[1.0.X] Fixed .distinct() not working with slicing in Oracle, due to the
row numbers necessarily being distinct. Backport of r9221 from trunk (since Ian doesn't have commit privileges at the moment). git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9228 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
6cfbd52138
commit
909371e5e5
|
@ -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 query_class(QueryClass, Database):
|
|||
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
|
||||
|
|
|
@ -334,6 +334,12 @@ Bug #4464
|
|||
>>> 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>]
|
||||
|
|
Loading…
Reference in New Issue