diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py index d108dc13201..09112cebb62 100644 --- a/django/db/backends/base/features.py +++ b/django/db/backends/base/features.py @@ -90,8 +90,8 @@ class BaseDatabaseFeatures: # Does the backend order NULL values as largest or smallest? nulls_order_largest = False - # Is there a 1000 item limit on query parameters? - supports_1000_query_parameters = True + # The database's limit on the number of query parameters. + max_query_params = None # Can an object have an autoincrement primary key of 0? MySQL says No. allows_auto_pk_0 = True diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py index d67cab6cd04..2209adaa569 100644 --- a/django/db/backends/sqlite3/features.py +++ b/django/db/backends/sqlite3/features.py @@ -14,7 +14,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): test_db_allows_multiple_connections = False supports_unspecified_pk = True supports_timezones = False - supports_1000_query_parameters = False + max_query_params = 999 supports_mixed_date_datetime_comparisons = False has_bulk_insert = True supports_foreign_keys = False diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py index 95b17db3e85..ee18dd5439b 100644 --- a/django/db/backends/sqlite3/operations.py +++ b/django/db/backends/sqlite3/operations.py @@ -21,8 +21,12 @@ class DatabaseOperations(BaseDatabaseOperations): If there's only a single field to insert, the limit is 500 (SQLITE_MAX_COMPOUND_SELECT). """ - limit = 999 if len(fields) > 1 else 500 - return (limit // len(fields)) if len(fields) > 0 else len(objs) + if len(fields) == 1: + return 500 + elif len(fields) > 1: + return self.connection.features.max_query_params // len(fields) + else: + return len(objs) def check_expression_support(self, expression): bad_fields = (fields.DateField, fields.DateTimeField, fields.TimeField) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 19ef508eb10..576abc8e247 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -2523,32 +2523,17 @@ class ConditionalTests(TestCase): self.assertEqual(sql.find(fragment, pos + 1), -1) self.assertEqual(sql.find("NULL", pos + len(fragment)), pos + len(fragment)) - # Sqlite 3 does not support passing in more than 1000 parameters except by - # changing a parameter at compilation time. - @skipUnlessDBFeature('supports_1000_query_parameters') - def test_ticket14244(self): + def test_in_list_limit(self): # The "in" lookup works with lists of 1000 items or more. # The numbers amount is picked to force three different IN batches # for Oracle, yet to be less than 2100 parameter limit for MSSQL. numbers = list(range(2050)) - Number.objects.all().delete() - Number.objects.bulk_create(Number(num=num) for num in numbers) - self.assertEqual( - Number.objects.filter(num__in=numbers[:1000]).count(), - 1000 - ) - self.assertEqual( - Number.objects.filter(num__in=numbers[:1001]).count(), - 1001 - ) - self.assertEqual( - Number.objects.filter(num__in=numbers[:2000]).count(), - 2000 - ) - self.assertEqual( - Number.objects.filter(num__in=numbers).count(), - len(numbers) - ) + max_query_params = connection.features.max_query_params + if max_query_params is None or max_query_params >= len(numbers): + Number.objects.bulk_create(Number(num=num) for num in numbers) + for number in [1000, 1001, 2000, len(numbers)]: + with self.subTest(number=number): + self.assertEqual(Number.objects.filter(num__in=numbers[:number]).count(), number) class UnionTests(unittest.TestCase):