Skip to content
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

Add sqlite3.Connection.autocommit for PEP 249 compliant behaviour #35

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7b2064b
gh-93353: Add test.support.late_deletion() (#93774)
vstinner Jun 13, 2022
6fd4c8e
gh-93741: Add private C API _PyImport_GetModuleAttrString() (GH-93742)
serhiy-storchaka Jun 14, 2022
8352e32
gh-79512: Fixed names and __module__ value of weakref classes (GH-93719)
serhiy-storchaka Jun 14, 2022
d7db9dc
gh-91810: Fix regression with writing an XML declaration with encodin…
serhiy-storchaka Jun 14, 2022
5bcf33d
gh-93761: Fix test to avoid simple delay when synchronizing. (GH-93779)
vsajip Jun 14, 2022
3597c12
gh-89546: Clean up PyType_FromMetaclass (GH-93686)
encukou Jun 14, 2022
4caf5c2
gh-91321: Fix compatibility with C++ older than C++11 (#93784)
vstinner Jun 14, 2022
2bf7475
GH-93662: Make sure that column offsets are correct in multi-line met…
markshannon Jun 14, 2022
3cd1a5d
GH-93516: Store offset of first traceable instruction in code object …
markshannon Jun 14, 2022
cd543d0
gh-90473: Include stdlib dir in wasmtime PYTHONPATH (GH-93797)
tiran Jun 14, 2022
b083450
GH-93429: Merge `LOAD_METHOD` back into `LOAD_ATTR` (GH-93430)
Fidget-Spinner Jun 14, 2022
e566ce5
gh-93353: regrtest checks for leaked temporary files (#93776)
vstinner Jun 14, 2022
4674007
gh-79579: Improve DML query detection in sqlite3 (#93623)
erlend-aasland Jun 14, 2022
af15cc5
GH-93678: reduce boilerplate and code repetition in the compiler (GH-…
iritkatriel Jun 14, 2022
a338e10
gh-91877: Fix WriteTransport.get_write_buffer_{limits,size} docs (#92…
TechieBoy Jun 14, 2022
38a7f78
GH-93429: Document `LOAD_METHOD` removal (GH-93803)
Fidget-Spinner Jun 14, 2022
cdf7097
Include freelists in allocation total. (GH-93799)
markshannon Jun 14, 2022
d773c6e
gh-93795: Use test.support TESTFN/unlink in sqlite3 tests (#93796)
erlend-aasland Jun 14, 2022
ef6e44d
Remove LOAD_METHOD stats. (GH-93807)
markshannon Jun 14, 2022
6b33000
Rename 'LOAD_METHOD' specialization stat consts to 'ATTR'. (GH-93812)
markshannon Jun 14, 2022
36934a1
gh-93353: Fix regrtest for -jN with N >= 2 (GH-93813)
vstinner Jun 14, 2022
ad90d49
[docs] Fix LOAD_ATTR version changed (GH-93816)
Fidget-Spinner Jun 14, 2022
10d3a65
Add sqlite3.Connection.autocommit for PEP 249 compliant behaviour
erlend-aasland Jun 11, 2022
6ca9045
Add basic tests
erlend-aasland Jun 14, 2022
b942f64
Add documentation
erlend-aasland Jun 14, 2022
b3ae5c0
Add NEWS
erlend-aasland Jun 14, 2022
7a613d3
Add What's New
erlend-aasland Jun 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/library/asyncio-llapi-index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ pipes, etc). Returned from methods like

* - :meth:`transport.get_write_buffer_size()
<WriteTransport.get_write_buffer_size>`
- Return the current size of the output buffer.

* - :meth:`transport.get_write_buffer_limits()
<WriteTransport.get_write_buffer_limits>`
- Return high and low water marks for write flow control.

* - :meth:`transport.set_write_buffer_limits()
Expand Down
27 changes: 14 additions & 13 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,20 @@ iterations of the loop.

.. opcode:: LOAD_ATTR (namei)

Replaces TOS with ``getattr(TOS, co_names[namei])``.
If the low bit of ``namei`` is not set, this replaces TOS with
``getattr(TOS, co_names[namei>>1])``.

If the low bit of ``namei`` is set, this will attempt to load a method named
``co_names[namei>>1]`` from the TOS object. TOS is popped.
This bytecode distinguishes two cases: if TOS has a method with the correct
name, the bytecode pushes the unbound method and TOS. TOS will be used as
the first argument (``self``) by :opcode:`CALL` when calling the
unbound method. Otherwise, ``NULL`` and the object return by the attribute
lookup are pushed.

.. versionchanged:: 3.12
If the low bit of ``namei`` is set, then a ``NULL`` or ``self`` is
pushed to the stack before the attribute or unbound method respectively.


.. opcode:: COMPARE_OP (opname)
Expand Down Expand Up @@ -1189,18 +1202,6 @@ iterations of the loop.
.. versionadded:: 3.6


.. opcode:: LOAD_METHOD (namei)

Loads a method named ``co_names[namei]`` from the TOS object. TOS is popped.
This bytecode distinguishes two cases: if TOS has a method with the correct
name, the bytecode pushes the unbound method and TOS. TOS will be used as
the first argument (``self``) by :opcode:`CALL` when calling the
unbound method. Otherwise, ``NULL`` and the object return by the attribute
lookup are pushed.

.. versionadded:: 3.7


.. opcode:: PUSH_NULL

Pushes a ``NULL`` to the stack.
Expand Down
103 changes: 88 additions & 15 deletions Doc/library/sqlite3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Module functions and constants
the preceding space: the column name would simply be "Expiration date".


.. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri])
.. function:: connect(database[, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri, autocommit])

Opens a connection to the SQLite database file *database*. By default returns a
:class:`Connection` object, unless a custom *factory* is given.
Expand All @@ -255,6 +255,11 @@ Module functions and constants
For the *isolation_level* parameter, please see the
:attr:`~Connection.isolation_level` property of :class:`Connection` objects.

For the *autocommit* parameter, please see the
:attr:`~Connection.autocommit` property. *autocommit* currently defaults to
:data:`~Connection.DEPRECATED_TRANSACTION_CONTROL`.
The default will change to :const:`False` in a future Python release.

SQLite natively supports only the types TEXT, INTEGER, REAL, BLOB and NULL. If
you want to use other types you must add support for them yourself. The
*detect_types* parameter and the using custom **converters** registered with the
Expand Down Expand Up @@ -318,6 +323,9 @@ Module functions and constants
.. versionchanged:: 3.10
Added the ``sqlite3.connect/handle`` auditing event.

.. versionchanged:: 3.12
Added the *autocommit* parameter.


.. function:: register_converter(typename, callable)

Expand Down Expand Up @@ -385,6 +393,25 @@ Connection Objects

An SQLite database connection has the following attributes and methods:

.. attribute:: autocommit

Get or set the :pep:`249` transaction behaviour.
*autocommit* has tree allowed values:

* :const:`False`: PEP 249 compliant transaction behaviour,
implying that a transaction is always open.
Use :meth:`commit` and :meth:`rollback` to close transactions.
Closing a transaction immediately opens a new one.
This will be the default value of *autocommit* in a future Python
release.

* :const:`True`: Use SQLite's autocommit behaviour.
You are also free to :meth:`execute` custom transaction statements.

* :data:`DEPRECATED_TRANSACTION_CONTROL`: Pre Python 3.12 compliant
transaction control. See :attr:`isolation_level`.
This is currently the default value of *autocommit*.

.. attribute:: isolation_level

Get or set the current default isolation level. :const:`None` for autocommit mode or
Expand Down Expand Up @@ -1365,41 +1392,83 @@ timestamp converter.

.. _sqlite3-controlling-transactions:

Controlling Transactions
------------------------
Controlling Transactions Using the Autocommit Property
------------------------------------------------------

The underlying ``sqlite3`` library operates in ``autocommit`` mode by default,
but the Python :mod:`sqlite3` module by default does not.

``autocommit`` mode means that statements that modify the database take effect
Use the :attr:`~Connection.autocommit` property to select transaction mode.
This attribute can also be set when :meth:`connecting <~Connection.connect>`.

Currently, *autocommit* defaults to :const:`DEPRECATED_TRANSACTION_CONTROL`,
which means transaction control is selected using the
:attr:`~Connection.isolation_level` property.
See :ref:`sqlite3-deprecated-transaction-control` for more information.

In a future Python release, *autocommit* will default to :const:False,
which will imply :pep:`249` compliant transaction control. This means:

* A transaction is always open.
* Commit transactions using :meth:`~Connection.commit`.
* Roll back transactions using :meth:`~Connection.rollback`.
* Commit and rollback will open a new transaction immediately after execution.
* An implicit rollback is performed if the database is closed with pending
changes.

Set *autocommit* to :const:`True` to enable SQLite's autocommit mode.
This mode is equal to setting :attr:`~Connection.isolation_level` to
:const:`None`.

``autocommit=True`` means that statements that modify the database take effect
immediately. A ``BEGIN`` or ``SAVEPOINT`` statement disables ``autocommit``
mode, and a ``COMMIT``, a ``ROLLBACK``, or a ``RELEASE`` that ends the
outermost transaction, turns ``autocommit`` mode back on.

The Python :mod:`sqlite3` module by default issues a ``BEGIN`` statement
implicitly before a Data Modification Language (DML) statement (i.e.
``INSERT``/``UPDATE``/``DELETE``/``REPLACE``).

You can control which kind of ``BEGIN`` statements :mod:`sqlite3` implicitly
.. _sqlite3-deprecated-transaction-control:

Controlling Transactions Using the Isolation Level Property
-----------------------------------------------------------

.. note::

The recommended way of controlling transactions, is via the
:attr:`~Connection.autocommit` parameter.

If :attr:`~Connection.autocommit` is set to
:data:`DEPRECATED_TRANSACTION_CONTROL`, transaction control is selected using
the :attr:`~Connection.isolation_level` parameter.

``isolation_level`` defaults to the empty string: ``""``. This implies that
the Python :mod:`sqlite3` module issues a ``BEGIN`` statement
implicitly before a Data Modification Language (DML) statement
(``INSERT``, ``UPDATE``, ``DELETE``, and ``REPLACE``).

You can control the kind of ``BEGIN`` statement ``sqlite3`` implicitly
executes via the *isolation_level* parameter to the :func:`connect`
call, or via the :attr:`isolation_level` property of connections.
If you specify no *isolation_level*, a plain ``BEGIN`` is used, which is
equivalent to specifying ``DEFERRED``. Other possible values are ``IMMEDIATE``
and ``EXCLUSIVE``.
call, or via the :attr:`isolation_level` property of connection objects.
By default, ``BEGIN`` is used, which is equivalent to
``isolation_level="DEFERRED"``.
Other possible values are ``"IMMEDIATE"`` and ``"EXCLUSIVE"``.

You can disable the :mod:`sqlite3` module's implicit transaction management by
Disable the :mod:`sqlite3` module's implicit transaction control by
setting :attr:`isolation_level` to ``None``. This will leave the underlying
``sqlite3`` library operating in ``autocommit`` mode. You can then completely
control the transaction state by explicitly issuing ``BEGIN``, ``ROLLBACK``,
control transactions by explicitly executing ``BEGIN``, ``ROLLBACK``,
``SAVEPOINT``, and ``RELEASE`` statements in your code.

Note that :meth:`~Cursor.executescript` disregards
:attr:`isolation_level`; any transaction control must be added explicitly.

.. versionchanged:: 3.6
:mod:`sqlite3` used to implicitly commit an open transaction before DDL
``sqlite3`` used to implicitly commit an open transaction before DDL
statements. This is no longer the case.

.. versionchanged: 3.12
The recommended way of controlling transactions is now via the
:attr:`~Connection.autocommit` parameter.


Using :mod:`sqlite3` efficiently
--------------------------------
Expand Down Expand Up @@ -1441,6 +1510,10 @@ committed:

.. literalinclude:: ../includes/sqlite3/ctx_manager.py

.. note::

The context manager does not implicitly begin a new transaction.


.. rubric:: Footnotes

Expand Down
17 changes: 17 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ os
(Contributed by Kumar Aditya in :gh:`93312`.)


sqlite3
-------

* Add :attr:`~sqlite3.Connection.autocommit` parameter for :pep:`249` compliant
transaction handling.
(Contributed by Erlend E. Aasland in :gh:`83638`.)


Optimizations
=============

Expand All @@ -106,6 +114,15 @@ Optimizations
(Contributed by Inada Naoki in :gh:`92536`.)


CPython bytecode changes
========================

* Removed the :opcode:`LOAD_METHOD` instruction. It has been merged into
:opcode:`LOAD_ATTR`. :opcode:`LOAD_ATTR` will now behave like the old
:opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set.
(Contributed by Ken Jin in :gh:`93429`.)


Deprecated
==========

Expand Down
1 change: 1 addition & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ typedef uint16_t _Py_CODEUNIT;
PyObject *co_linetable; /* bytes object that holds location info */ \
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
void *_co_code; /* cached co_code object/attribute */ \
int _co_firsttraceable; /* index of first traceable instruction */ \
/* Scratch space for extra data relating to the code object. \
Type is a void* to keep the format private in codeobject.c to force \
people to go through the proper APIs. */ \
Expand Down
3 changes: 3 additions & 0 deletions Include/cpython/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ struct _frozen {
collection of frozen modules: */

PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules;

PyAPI_DATA(PyObject *) _PyImport_GetModuleAttr(PyObject *, PyObject *);
PyAPI_DATA(PyObject *) _PyImport_GetModuleAttrString(const char *, const char *);
12 changes: 5 additions & 7 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,18 @@ typedef struct {
_Py_CODEUNIT index;
} _PyAttrCache;

#define INLINE_CACHE_ENTRIES_LOAD_ATTR CACHE_ENTRIES(_PyAttrCache)

#define INLINE_CACHE_ENTRIES_STORE_ATTR CACHE_ENTRIES(_PyAttrCache)

typedef struct {
_Py_CODEUNIT counter;
_Py_CODEUNIT type_version[2];
_Py_CODEUNIT keys_version[2];
_Py_CODEUNIT descr[4];
} _PyLoadMethodCache;

#define INLINE_CACHE_ENTRIES_LOAD_METHOD CACHE_ENTRIES(_PyLoadMethodCache)

// MUST be the max(_PyAttrCache, _PyLoadMethodCache)
#define INLINE_CACHE_ENTRIES_LOAD_ATTR CACHE_ENTRIES(_PyLoadMethodCache)

#define INLINE_CACHE_ENTRIES_STORE_ATTR CACHE_ENTRIES(_PyAttrCache)

typedef struct {
_Py_CODEUNIT counter;
Expand Down Expand Up @@ -233,8 +233,6 @@ extern int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
extern int _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name);
extern int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name);
extern int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name);
extern int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr);
extern int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr);
extern int _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr,
Expand Down
4 changes: 0 additions & 4 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(_showwarnmsg)
STRUCT_FOR_ID(_shutdown)
STRUCT_FOR_ID(_slotnames)
STRUCT_FOR_ID(_strptime_time)
STRUCT_FOR_ID(_uninitialized_submodules)
STRUCT_FOR_ID(_warn_unawaited_coroutine)
STRUCT_FOR_ID(_xoptions)
Expand All @@ -252,7 +251,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(difference_update)
STRUCT_FOR_ID(dispatch_table)
STRUCT_FOR_ID(displayhook)
STRUCT_FOR_ID(enable)
STRUCT_FOR_ID(encode)
STRUCT_FOR_ID(encoding)
STRUCT_FOR_ID(end_lineno)
Expand Down Expand Up @@ -311,7 +309,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(opcode)
STRUCT_FOR_ID(open)
STRUCT_FOR_ID(parent)
STRUCT_FOR_ID(partial)
STRUCT_FOR_ID(path)
STRUCT_FOR_ID(peek)
STRUCT_FOR_ID(persistent_id)
Expand Down Expand Up @@ -357,7 +354,6 @@ struct _Py_global_strings {
STRUCT_FOR_ID(warnoptions)
STRUCT_FOR_ID(writable)
STRUCT_FOR_ID(write)
STRUCT_FOR_ID(zipimporter)
} identifiers;
struct {
PyASCIIObject _ascii;
Expand Down
Loading