diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py index 91d1a27f8a1..1a4f4baa6c3 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 71709d0fb8a..0da9cf65cd2 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 693bb771801..460b5220790 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):