Commit f91b5a7e authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

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.
parent ee596888
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -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.
+5 −0
Original line number Diff line number Diff line
@@ -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`).
+12 −0
Original line number Diff line number Diff line
@@ -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):