-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
gh-137205: Document how to safely use PRAGMA during SQLite transactions #137505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a637bde
9b0e56e
b525dd8
ae5d700
fc2e957
5ef2d72
155013f
345043f
000e4c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -243,6 +243,7 @@ inserted data and retrieved values from it in multiple ways. | |||||||||||||||||||
* :ref:`sqlite3-converters` | ||||||||||||||||||||
* :ref:`sqlite3-connection-context-manager` | ||||||||||||||||||||
* :ref:`sqlite3-howto-row-factory` | ||||||||||||||||||||
* :ref:`sqlite3-howto-pragma-in-transaction` | ||||||||||||||||||||
|
||||||||||||||||||||
* :ref:`sqlite3-explanation` for in-depth background on transaction control. | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -1353,8 +1354,6 @@ Connection objects | |||||||||||||||||||
implying that :mod:`!sqlite3` ensures a transaction is always open. | ||||||||||||||||||||
Use :meth:`commit` and :meth:`rollback` to close transactions. | ||||||||||||||||||||
|
||||||||||||||||||||
This is the recommended value of :attr:`!autocommit`. | ||||||||||||||||||||
|
||||||||||||||||||||
* ``True``: Use SQLite's `autocommit mode`_. | ||||||||||||||||||||
:meth:`commit` and :meth:`rollback` have no effect in this mode. | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -1367,7 +1366,10 @@ Connection objects | |||||||||||||||||||
Changing :attr:`!autocommit` to ``False`` will open a new transaction, | ||||||||||||||||||||
and changing it to ``True`` will commit any pending transaction. | ||||||||||||||||||||
|
||||||||||||||||||||
See :ref:`sqlite3-transaction-control-autocommit` for more details. | ||||||||||||||||||||
.. seealso:: | ||||||||||||||||||||
|
||||||||||||||||||||
* :ref:`sqlite3-transaction-control-autocommit` | ||||||||||||||||||||
* :ref:`sqlite3-howto-pragma-in-transaction` | ||||||||||||||||||||
|
||||||||||||||||||||
.. note:: | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -2429,6 +2431,39 @@ the context manager does nothing. | |||||||||||||||||||
couldn't add Python twice | ||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
.. _sqlite3-howto-pragma-in-transaction: | ||||||||||||||||||||
|
||||||||||||||||||||
How to use ``PRAGMA`` statements with implicit transaction control | ||||||||||||||||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||||||||||||||||||||
|
||||||||||||||||||||
Some ``PRAGMA`` statements have no effect within transactions. | ||||||||||||||||||||
For example, a ``PRAGMA foreign_keys=ON`` query will silently fail | ||||||||||||||||||||
if there is an open transaction. | ||||||||||||||||||||
In order to safely use ``PRAGMA`` statements, | ||||||||||||||||||||
ensure that there is no open transaction: | ||||||||||||||||||||
|
||||||||||||||||||||
* If :attr:`~Connection.autocommit` is ``True`` | ||||||||||||||||||||
and a transaction was explicitly opened, | ||||||||||||||||||||
make sure to :meth:`~Cursor.execute` a ``COMMIT`` | ||||||||||||||||||||
before executing the ``PRAGMA`` statement. | ||||||||||||||||||||
* Else, temporarily disable implicit transaction control | ||||||||||||||||||||
using the :attr:`!autocommit` attribute | ||||||||||||||||||||
before executing the ``PRAGMA`` statement: | ||||||||||||||||||||
|
||||||||||||||||||||
.. testcode:: | ||||||||||||||||||||
:hide: | ||||||||||||||||||||
|
||||||||||||||||||||
con = sqlite3.connect(":memory:", autocommit=False) | ||||||||||||||||||||
|
||||||||||||||||||||
.. testcode:: | ||||||||||||||||||||
|
||||||||||||||||||||
cur = con.cursor() | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wish the state of affairs was better here, but while I can think of various API features that would make this less klunky, I dont think any of them would be worth it, so here we are. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think a decorator is worth it. Since PRAGMAs are mostly used during the setup of a database connection, I think @layday's approach is the most sane: connect using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. my API features would be either:
in your comment I assume you meant "connect with autocommit=True". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a few things I don't like about the proposed workaround:
I don't really know what'd work better, but I'm gravitating towards an init hook that'd be executed before the first
Suggested change
I don't think an autocommit context manager is generally useful, and I can see it being misused to break out of a transaction for any number of reasons, e.g. to fetch changes made by another connection with WAL on.
I don't know how this would work, but SQLite has pragmas which have no effect outside of a transaction - |
||||||||||||||||||||
saved = con.autocommit | ||||||||||||||||||||
con.autocommit = True # Disable implicit transaction control. | ||||||||||||||||||||
cur.execute("PRAGMA foreign_keys=ON") | ||||||||||||||||||||
con.autocommit = saved # Restore the previous setting. | ||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
.. _sqlite3-uri-tricks: | ||||||||||||||||||||
|
||||||||||||||||||||
How to work with SQLite URIs | ||||||||||||||||||||
|
@@ -2643,11 +2678,9 @@ Transaction control via the ``autocommit`` attribute | |||||||||||||||||||
|
||||||||||||||||||||
The recommended way of controlling transaction behaviour is through | ||||||||||||||||||||
the :attr:`Connection.autocommit` attribute, | ||||||||||||||||||||
which should preferably be set using the *autocommit* parameter | ||||||||||||||||||||
of :func:`connect`. | ||||||||||||||||||||
normally set using the *autocommit* parameter of :func:`connect`. | ||||||||||||||||||||
|
||||||||||||||||||||
It is suggested to set *autocommit* to ``False``, | ||||||||||||||||||||
which implies :pep:`249`-compliant transaction control. | ||||||||||||||||||||
Set *autocommit* to ``False`` for :pep:`249`-compliant transaction control. | ||||||||||||||||||||
This means: | ||||||||||||||||||||
|
||||||||||||||||||||
* :mod:`!sqlite3` ensures that a transaction is always open, | ||||||||||||||||||||
|
@@ -2660,6 +2693,16 @@ This means: | |||||||||||||||||||
* An implicit rollback is performed if the database is | ||||||||||||||||||||
:meth:`~Connection.close`-ed with pending changes. | ||||||||||||||||||||
|
||||||||||||||||||||
.. note:: | ||||||||||||||||||||
|
||||||||||||||||||||
Some ``PRAGMA`` statements have no effect when a transaction is open. | ||||||||||||||||||||
If ``PRAGMA`` statements are a part of the database connection setup | ||||||||||||||||||||
and you want :pep:`249`-compliant transaction control, | ||||||||||||||||||||
set *autocommit* to ``True`` in :func:`connect`, | ||||||||||||||||||||
execute the needed ``PRAGMA`` statements, | ||||||||||||||||||||
then set :attr:`Connection.autocommit` to ``False``. | ||||||||||||||||||||
See :ref:`sqlite3-howto-pragma-in-transaction` for details. | ||||||||||||||||||||
|
||||||||||||||||||||
Set *autocommit* to ``True`` to enable SQLite's `autocommit mode`_. | ||||||||||||||||||||
In this mode, :meth:`Connection.commit` and :meth:`Connection.rollback` | ||||||||||||||||||||
have no effect. | ||||||||||||||||||||
|
@@ -2716,6 +2759,11 @@ The :meth:`~Cursor.executescript` method implicitly commits | |||||||||||||||||||
any pending transaction before execution of the given SQL script, | ||||||||||||||||||||
regardless of the value of :attr:`~Connection.isolation_level`. | ||||||||||||||||||||
|
||||||||||||||||||||
.. note:: | ||||||||||||||||||||
|
||||||||||||||||||||
Some ``PRAGMA`` statements cannot be set when a transaction is open. | ||||||||||||||||||||
See :ref:`sqlite3-howto-pragma-in-transaction` for details. | ||||||||||||||||||||
|
||||||||||||||||||||
.. versionchanged:: 3.6 | ||||||||||||||||||||
:mod:`!sqlite3` used to implicitly commit an open transaction before DDL | ||||||||||||||||||||
statements. This is no longer the case. | ||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.