Author: ikelly
Date: 2010-09-16 14:53:41 -0500 (Thu, 16 Sep 2010)
New Revision: 13859
Modified:
django/trunk/django/db/backends/__init__.py
django/trunk/django/db/backends/oracle/base.py
django/trunk/django/db/models/sql/where.py
django/trunk/tests/regressiontests/queries/models.py
Log:
Fixed #14244: Allow lists of more than 1000 items to be used with the 'in'
lookup in Oracle, by breaking them up into groups of 1000 items and ORing them
together. Thanks to rlynch for the report and initial patch.
Modified: django/trunk/django/db/backends/__init__.py
===================================================================
--- django/trunk/django/db/backends/__init__.py 2010-09-14 21:42:06 UTC (rev
13858)
+++ django/trunk/django/db/backends/__init__.py 2010-09-16 19:53:41 UTC (rev
13859)
@@ -233,6 +233,13 @@
"""
return "%s"
+ def max_in_list_size(self):
+ """
+ Returns the maximum number of items that can be passed in a single 'IN'
+ list condition, or None if the backend does not impose a limit.
+ """
+ return None
+
def max_name_length(self):
"""
Returns the maximum length of table and column names, or None if there
Modified: django/trunk/django/db/backends/oracle/base.py
===================================================================
--- django/trunk/django/db/backends/oracle/base.py 2010-09-14 21:42:06 UTC
(rev 13858)
+++ django/trunk/django/db/backends/oracle/base.py 2010-09-16 19:53:41 UTC
(rev 13859)
@@ -178,6 +178,9 @@
return "UPPER(%s)"
return "%s"
+ def max_in_list_size(self):
+ return 1000
+
def max_name_length(self):
return 30
Modified: django/trunk/django/db/models/sql/where.py
===================================================================
--- django/trunk/django/db/models/sql/where.py 2010-09-14 21:42:06 UTC (rev
13858)
+++ django/trunk/django/db/models/sql/where.py 2010-09-16 19:53:41 UTC (rev
13859)
@@ -2,6 +2,7 @@
Code to manage the creation and SQL rendering of 'where' constraints.
"""
import datetime
+from itertools import repeat
from django.utils import tree
from django.db.models.fields import Field
@@ -178,8 +179,24 @@
raise EmptyResultSet
if extra:
return ('%s IN %s' % (field_sql, extra), params)
- return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] *
len(params))),
- params)
+ max_in_list_size = connection.ops.max_in_list_size()
+ if max_in_list_size and len(params) > max_in_list_size:
+ # Break up the params list into an OR of manageable chunks.
+ in_clause_elements = ['(']
+ for offset in xrange(0, len(params), max_in_list_size):
+ if offset > 0:
+ in_clause_elements.append(' OR ')
+ in_clause_elements.append('%s IN (' % field_sql)
+ group_size = min(len(params) - offset, max_in_list_size)
+ param_group = ', '.join(repeat('%s', group_size))
+ in_clause_elements.append(param_group)
+ in_clause_elements.append(')')
+ in_clause_elements.append(')')
+ return ''.join(in_clause_elements), params
+ else:
+ return ('%s IN (%s)' % (field_sql,
+ ', '.join(repeat('%s', len(params)))),
+ params)
elif lookup_type in ('range', 'year'):
return ('%s BETWEEN %%s and %%s' % field_sql, params)
elif lookup_type in ('month', 'day', 'week_day'):
Modified: django/trunk/tests/regressiontests/queries/models.py
===================================================================
--- django/trunk/tests/regressiontests/queries/models.py 2010-09-14
21:42:06 UTC (rev 13858)
+++ django/trunk/tests/regressiontests/queries/models.py 2010-09-16
19:53:41 UTC (rev 13859)
@@ -1339,3 +1339,23 @@
[]
"""
+
+# Sqlite 3 does not support passing in more than 1000 parameters except by
+# changing a parameter at compilation time.
+if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] !=
"django.db.backends.sqlite3":
+ __test__["API_TESTS"] += """
+Bug #14244: Test that the "in" lookup works with lists of 1000 items or more.
+>>> Number.objects.all().delete()
+>>> numbers = range(2500)
+>>> for num in numbers:
+... _ = Number.objects.create(num=num)
+>>> Number.objects.filter(num__in=numbers[:1000]).count()
+1000
+>>> Number.objects.filter(num__in=numbers[:1001]).count()
+1001
+>>> Number.objects.filter(num__in=numbers[:2000]).count()
+2000
+>>> Number.objects.filter(num__in=numbers).count()
+2500
+
+"""
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.