8000 Fixed #36143 -- Made max_query_params respect SQLITE_LIMIT_VARIABLE_N… · feanil/django@358fd21 · GitHub
[go: up one dir, main page]

Skip to content

Commit 358fd21

Browse files
laymonagethepsalmist
authored andcommitted
Fixed #36143 -- Made max_query_params respect SQLITE_LIMIT_VARIABLE_NUMBER.
Co-authored-by: Xavier Frankline <xf.xavierfrank@gmail.com>
1 parent 38660a6 commit 358fd21

File tree

4 files changed

< 10000 div class="ml-1 text-small text-bold fgColor-success">+55
-3
lines changed

4 files changed

+55
-3
lines changed

django/db/backends/sqlite3/features.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import operator
2+
import sqlite3
23

34
from django.db import transaction
45
from django.db.backends.base.features import BaseDatabaseFeatures
@@ -13,7 +14,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
1314
test_db_allows_multiple_connections = False
1415
supports_unspecified_pk = True
1516
supports_timezones = False
16-
max_query_params = 999
1717
supports_transactions = True
1818
atomic_transactions = False
1919
can_rollback_ddl = True
@@ -140,6 +140,16 @@ def introspected_field_types(self):
140140
"SmallAutoField": "AutoField",
141141
}
142142

143+
@property
144+
def max_query_params(self):
145+
"""
146+
SQLite has a variable limit per query. The limit can be changed using
147+
the SQLITE_MAX_VARIABLE_NUMBER compile-time option (which defaults to
148+
999 in versions < 3.32.0 or 32766 in newer versions) or lowered per
149+
connection at run-time with setlimit(SQLITE_LIMIT_VARIABLE_NUMBER, N).
150+
"""
151+
return self.connection.connection.getlimit(sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER)
152+
143153
@cached_property
144154
def supports_json_field(self):
145155
with self.connection.cursor() as cursor:

django/db/backends/sqlite3/operations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class DatabaseOperations(BaseDatabaseOperations):
3030

3131
def bulk_batch_size(self, fields, objs):
3232
"""
33-
SQLite has a compile-time default (SQLITE_LIMIT_VARIABLE_NUMBER) of
34-
999 variables per query.
33+
SQLite has a variable limit defined by SQLITE_LIMIT_VARIABLE_NUMBER
34+
(reflected in max_query_params).
3535
3636
If there's only a single field to insert, the limit is 500
3737
(SQLITE_MAX_COMPOUND_SELECT).

tests/backends/sqlite/test_features.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sqlite3
12
from unittest import mock, skipUnless
23

34
from django.db import OperationalError, connection
@@ -17,3 +18,14 @@ def test_supports_json_field_operational_error(self):
1718
):
1819
with self.assertRaisesMessage(OperationalError, msg):
1920
connection.features.supports_json_field
21+
22+
def test_max_query_params_respects_variable_limit(self):
23+
limit_name = sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER
24+
current_limit = connection.features.max_query_params
25+
new_limit = min(42, current_limit)
26+
try:
27+
connection.connection.setlimit(limit_name, new_limit)
28+
self.assertEqual(connection.features.max_query_params, new_limit)
29+
finally:
30+
connection.connection.setlimit(limit_name, current_limit)
31+
self.assertEqual(connection.features.max_query_params, current_limit)

tests/backends/sqlite/test_operations.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sqlite3
12
import unittest
23

34
from django.core.management.color import no_style
@@ -108,3 +109,32 @@ def test_bulk_batch_size(self):
108109
),
109110
connection.features.max_query_params // 3,
110111
)
112+
113+
def test_bulk_batch_size_respects_variable_limit(self):
114+
first_name_field = Person._meta.get_field("first_name")
115+
last_name_field = Person._meta.get_field("last_name")
116+
limit_name = sqlite3.SQLITE_LIMIT_VARIABLE_NUMBER
117+
current_limit = connection.features.max_query_params
118+
self.assertEqual(
119+
connection.ops.bulk_batch_size(
120+
[first_name_field, last_name_field], [Person()]
121+
),
122+
current_limit // 2,
123+
)
124+
new_limit = min(42, current_limit)
125+
try:
126+
connection.connection.setlimit(limit_name, new_limit)
127+
self.assertEqual(
128+
connection.ops.bulk_batch_size(
129+
[first_name_field, last_name_field], [Person()]
130+
),
131+
new_limit // 2,
132+
)
133+
finally:
134+
connection.connection.setlimit(limit_name, current_limit)
135+
self.assertEqual(
136+
connection.ops.bulk_batch_size(
137+
[first_name_field, last_name_field], [Person()]
138+
),
139+
current_limit // 2,
140+
)

0 commit comments

Comments
 (0)
0