Browse Source

Fixed #24018 -- Allowed setting pragma options on SQLite.

Aaron Linville 1 year ago
parent
commit
7a05b8a2fa

+ 1 - 0
AUTHORS

@@ -6,6 +6,7 @@ people who have submitted patches, reported bugs, added translations, helped
 answer newbie questions, and generally made Django that much better:
 
     Aaron Cannon <cannona@fireantproductions.com>
+    Aaron Linville <aaron@linville.org>
     Aaron Swartz <http://www.aaronsw.com/>
     Aaron T. Myers <atmyers@gmail.com>
     Abeer Upadhyay <ab.esquarer@gmail.com>

+ 6 - 0
django/db/backends/sqlite3/base.py

@@ -187,6 +187,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
                 f"{allowed_transaction_modes}, or None."
             )
         self.transaction_mode = transaction_mode.upper() if transaction_mode else None
+
+        init_command = kwargs.pop("init_command", "")
+        self.init_commands = init_command.split(";")
         return kwargs
 
     def get_database_version(self):
@@ -201,6 +204,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         # The macOS bundled SQLite defaults legacy_alter_table ON, which
         # prevents atomic table renames.
         conn.execute("PRAGMA legacy_alter_table = OFF")
+        for init_command in self.init_commands:
+            if init_command := init_command.strip():
+                conn.execute(init_command)
         return conn
 
     def create_cursor(self, name=None):

+ 24 - 0
docs/ref/databases.txt

@@ -941,6 +941,30 @@ To enable the JSON1 extension you can follow the instruction on
 .. _JSON1 extension: https://www.sqlite.org/json1.html
 .. _the wiki page: https://code.djangoproject.com/wiki/JSON1Extension
 
+.. _sqlite-init-command:
+
+Setting pragma options
+----------------------
+
+.. versionadded:: 5.1
+
+`Pragma options`_ can be set upon connection by using the ``init_command`` in
+the :setting:`OPTIONS` part of your database configuration in
+:setting:`DATABASES`. The example below shows how to enable extra durability of
+synchronous writes and change the ``cache_size``::
+
+    DATABASES = {
+        "default": {
+            "ENGINE": "django.db.backends.sqlite3",
+            # ...
+            "OPTIONS": {
+                "init_command": "PRAGMA synchronous=3; PRAGMA cache_size=2000;",
+            },
+        }
+    }
+
+.. _Pragma options: https://www.sqlite.org/pragma.html
+
 .. _oracle-notes:
 
 Oracle notes

+ 7 - 0
docs/releases/5.1.txt

@@ -146,6 +146,13 @@ CSRF
 
 * ...
 
+Database backends
+~~~~~~~~~~~~~~~~~
+
+* ``"init_command"`` option is now supported in :setting:`OPTIONS` on SQLite
+  to allow specifying :ref:`pragma options <sqlite-init-command>` to set upon
+  connection.
+
 Decorators
 ~~~~~~~~~~
 

+ 1 - 0
docs/spelling_wordlist

@@ -361,6 +361,7 @@ postfix
 postgis
 postgres
 postgresql
+pragma
 pre
 precisions
 precomputation

+ 23 - 0
tests/backends/sqlite/tests.py

@@ -116,6 +116,29 @@ class Tests(TestCase):
             connection.check_database_version_supported()
         self.assertTrue(mocked_get_database_version.called)
 
+    def test_init_command(self):
+        settings_dict = {
+            "default": {
+                "ENGINE": "django.db.backends.sqlite3",
+                "NAME": ":memory:",
+                "OPTIONS": {
+                    "init_command": "PRAGMA synchronous=3; PRAGMA cache_size=2000;",
+                },
+            }
+        }
+        connections = ConnectionHandler(settings_dict)
+        connections["default"].ensure_connection()
+        try:
+            with connections["default"].cursor() as cursor:
+                cursor.execute("PRAGMA synchronous")
+                value = cursor.fetchone()[0]
+                self.assertEqual(value, 3)
+                cursor.execute("PRAGMA cache_size")
+                value = cursor.fetchone()[0]
+                self.assertEqual(value, 2000)
+        finally:
+            connections["default"].close()
+
 
 @unittest.skipUnless(connection.vendor == "sqlite", "SQLite tests")
 @isolate_apps("backends")