summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2016-01-09 21:30:19 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2016-01-21 10:47:15 +0100
commitf91b5a7e4b2ac436b1fe3065b23217543d0f54c1 (patch)
treede35279fa5162111654cc04d706db5ecf78217ca
parentee596888e1149864e7828f5cf63c0eda395744c3 (diff)
Fixed #26063 -- Crash when passing > 2000 params.
If SQLITE_MAX_VARIABLE_NUMBER (default = 999) is changed at compile time to be greater than SQLITE_MAX_COLUMN (default = 2000), which Debian does by setting the former to 250000, Django raised an exception on queries containing more than 2000 parameters when DEBUG = True.
-rw-r--r--django/db/backends/sqlite3/operations.py13
-rw-r--r--docs/releases/1.9.2.txt5
-rw-r--r--tests/backends/tests.py12
3 files changed, 30 insertions, 0 deletions
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 91d1a27f8a..1a4f4baa6c 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -107,6 +107,19 @@ class DatabaseOperations(BaseDatabaseOperations):
"""
Only for last_executed_query! Don't use this to execute SQL queries!
"""
+ # This function is limited both by SQLITE_LIMIT_VARIABLE_NUMBER (the
+ # number of paramters, default = 999) and SQLITE_MAX_COLUMN (the
+ # number of return values, default = 2000). Since Python's sqlite3
+ # module doesn't expose the get_limit() C API, assume the default
+ # limits are in effect and split the work in batches if needed.
+ BATCH_SIZE = 999
+ if len(params) > BATCH_SIZE:
+ results = ()
+ for index in range(0, len(params), BATCH_SIZE):
+ chunk = params[index:index + BATCH_SIZE]
+ results += self._quote_params_for_last_executed_query(chunk)
+ return results
+
sql = 'SELECT ' + ', '.join(['QUOTE(?)'] * len(params))
# Bypass Django's wrappers and use the underlying sqlite3 connection
# to avoid logging this query - it would trigger infinite recursion.
diff --git a/docs/releases/1.9.2.txt b/docs/releases/1.9.2.txt
index 71709d0fb8..0da9cf65cd 100644
--- a/docs/releases/1.9.2.txt
+++ b/docs/releases/1.9.2.txt
@@ -44,3 +44,8 @@ Bugfixes
* Fixed a ``QuerySet.order_by()`` crash when ordering by a relational field of
a ``ManyToManyField`` ``through`` model (:ticket:`26092`).
+
+* Fixed a regression that caused an exception when making database queries on
+ SQLite with more than 2000 parameters when :setting:`DEBUG` is ``True`` on
+ distributions that increase the ``SQLITE_MAX_VARIABLE_NUMBER`` compile-time
+ limit to over 2000, such as Debian (:ticket:`26063`).
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index 693bb77180..460b522079 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -426,6 +426,18 @@ class LastExecutedQueryTest(TestCase):
substituted = "SELECT '\"''\\'"
self.assertEqual(connection.queries[-1]['sql'], substituted)
+ @unittest.skipUnless(connection.vendor == 'sqlite',
+ "This test is specific to SQLite.")
+ def test_large_number_of_parameters_on_sqlite(self):
+ # If SQLITE_MAX_VARIABLE_NUMBER (default = 999) has been changed to be
+ # greater than SQLITE_MAX_COLUMN (default = 2000), last_executed_query
+ # can hit the SQLITE_MAX_COLUMN limit. See #26063.
+ cursor = connection.cursor()
+ sql = "SELECT MAX(%s)" % ", ".join(["%s"] * 2001)
+ params = list(range(2001))
+ # This should not raise an exception.
+ cursor.db.ops.last_executed_query(cursor.cursor, sql, params)
+
class ParameterHandlingTest(TestCase):