|
@@ -4,7 +4,8 @@ SQLite backend for the sqlite3 module in the standard library.
|
|
|
import datetime
|
|
|
import decimal
|
|
|
import warnings
|
|
|
-from itertools import chain
|
|
|
+from collections.abc import Mapping
|
|
|
+from itertools import chain, tee
|
|
|
from sqlite3 import dbapi2 as Database
|
|
|
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
@@ -357,20 +358,40 @@ FORMAT_QMARK_REGEX = _lazy_re_compile(r"(?<!%)%s")
|
|
|
|
|
|
class SQLiteCursorWrapper(Database.Cursor):
|
|
|
"""
|
|
|
- Django uses "format" style placeholders, but sqlite3 uses "qmark" style.
|
|
|
- This fixes it -- but note that if you want to use a literal "%s" in a query,
|
|
|
- you'll need to use "%%s".
|
|
|
+ Django uses the "format" and "pyformat" styles, but Python's sqlite3 module
|
|
|
+ supports neither of these styles.
|
|
|
+
|
|
|
+ This wrapper performs the following conversions:
|
|
|
+
|
|
|
+ - "format" style to "qmark" style
|
|
|
+ - "pyformat" style to "named" style
|
|
|
+
|
|
|
+ In both cases, if you want to use a literal "%s", you'll need to use "%%s".
|
|
|
"""
|
|
|
|
|
|
def execute(self, query, params=None):
|
|
|
if params is None:
|
|
|
return Database.Cursor.execute(self, query)
|
|
|
- query = self.convert_query(query)
|
|
|
+
|
|
|
+ param_names = list(params) if isinstance(params, Mapping) else None
|
|
|
+ query = self.convert_query(query, param_names=param_names)
|
|
|
return Database.Cursor.execute(self, query, params)
|
|
|
|
|
|
def executemany(self, query, param_list):
|
|
|
- query = self.convert_query(query)
|
|
|
+
|
|
|
+
|
|
|
+ peekable, param_list = tee(iter(param_list))
|
|
|
+ if (params := next(peekable, None)) and isinstance(params, Mapping):
|
|
|
+ param_names = list(params)
|
|
|
+ else:
|
|
|
+ param_names = None
|
|
|
+ query = self.convert_query(query, param_names=param_names)
|
|
|
return Database.Cursor.executemany(self, query, param_list)
|
|
|
|
|
|
- def convert_query(self, query):
|
|
|
- return FORMAT_QMARK_REGEX.sub("?", query).replace("%%", "%")
|
|
|
+ def convert_query(self, query, *, param_names=None):
|
|
|
+ if param_names is None:
|
|
|
+
|
|
|
+ return FORMAT_QMARK_REGEX.sub("?", query).replace("%%", "%")
|
|
|
+ else:
|
|
|
+
|
|
|
+ return query % {name: f":{name}" for name in param_names}
|