mirror of
https://github.com/simonw/datasette.git
synced 2026-09-27 20:34:08 +02:00
Make execute_write_script transactional, matching its documentation
execute_write_script() was documented as running inside a transaction but actually passed transaction=False and used conn.executescript(), which commits each statement as it executes - a failing script could half-apply. Scripts are now split into complete statements (via sqlite3.complete_statement) and executed one at a time inside the task transaction, so a failing script applies nothing. Scripts containing statements that cannot run in a transaction (VACUUM, ATTACH, DETACH, PRAGMA) or that manage transactions themselves (BEGIN, COMMIT, SAVEPOINT etc) keep the previous executescript() autocommit behavior. Refs #2831 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N76afGMhBRQk528VF1LTpR
This commit is contained in:
parent
84fb4221ab
commit
1ff4e67b79
4 changed files with 83 additions and 4 deletions
|
|
@ -11,6 +11,7 @@ Unreleased
|
|||
|
||||
- Write functions run via ``await db.execute_write_fn()`` now execute inside an explicitly opened ``BEGIN IMMEDIATE`` transaction, committed when the function returns or rolled back if it raises. Previously the transaction was only opened implicitly by the first raw data-modifying statement, which meant writes made through sqlite-utils committed independently mid-task - a function that used sqlite-utils and then failed could leave those writes permanently committed. sqlite-utils write methods now nest inside the task transaction as savepoints, so a failing write function rolls back everything it did. Functions run with ``transaction=True`` should no longer manage transactions themselves - use ``transaction=False`` for manual transaction control. (:issue:`2831`)
|
||||
- ``await db.execute_write()`` detects statements that SQLite cannot execute inside a transaction - ``VACUUM``, ``ATTACH``, ``DETACH`` and ``PRAGMA`` - and runs them in autocommit mode instead. (:issue:`2831`)
|
||||
- ``await db.execute_write_script()`` is now transactional, matching its documentation: if any statement in the script fails, none of its statements are applied. Scripts containing statements that cannot run inside a transaction, or that manage transactions themselves, fall back to the previous ``conn.executescript()`` autocommit behavior. (:issue:`2831`)
|
||||
|
||||
.. _v1_0_a36:
|
||||
|
||||
|
|
|
|||
|
|
@ -2066,9 +2066,11 @@ Each call to ``execute_write()`` will be executed inside a transaction, with the
|
|||
await db.execute_write_script(sql, block=True)
|
||||
----------------------------------------------
|
||||
|
||||
Like ``execute_write()`` but can be used to send multiple SQL statements in a single string separated by semicolons, using the ``sqlite3`` `conn.executescript() <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executescript>`__ method.
|
||||
Like ``execute_write()`` but can be used to send multiple SQL statements in a single string separated by semicolons.
|
||||
|
||||
Each call to ``execute_write_script()`` will be executed inside a transaction.
|
||||
Each call to ``execute_write_script()`` will be executed inside a transaction - if any statement fails, none of the statements will be applied.
|
||||
|
||||
The exception is scripts that include statements which SQLite cannot execute inside a transaction - ``VACUUM``, ``ATTACH``, ``DETACH``, ``PRAGMA`` - or that manage transactions themselves using ``BEGIN``, ``COMMIT``, ``ROLLBACK``, ``SAVEPOINT`` or ``RELEASE``. Those scripts are executed using the ``sqlite3`` `conn.executescript() <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executescript>`__ method instead, where each statement is committed as it executes.
|
||||
|
||||
.. _database_execute_write_many:
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue