diff options
author | shadchin <shadchin@yandex-team.com> | 2024-02-12 07:53:52 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@ydb.tech> | 2024-02-14 14:26:16 +0000 |
commit | 31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch) | |
tree | c1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Modules/_sqlite | |
parent | fe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff) | |
download | ydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz |
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Modules/_sqlite')
14 files changed, 1000 insertions, 275 deletions
diff --git a/contrib/tools/python3/src/Modules/_sqlite/clinic/blob.c.h b/contrib/tools/python3/src/Modules/_sqlite/clinic/blob.c.h index b467c99e2e..f3d8a35be4 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/clinic/blob.c.h +++ b/contrib/tools/python3/src/Modules/_sqlite/clinic/blob.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + PyDoc_STRVAR(blob_close__doc__, "close($self, /)\n" "--\n" @@ -213,4 +219,4 @@ blob_exit(pysqlite_Blob *self, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=382cbf0977bb158a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ad6a402f70e85977 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Modules/_sqlite/clinic/connection.c.h b/contrib/tools/python3/src/Modules/_sqlite/clinic/connection.c.h index 4bdf98b693..417abcc462 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/clinic/connection.c.h +++ b/contrib/tools/python3/src/Modules/_sqlite/clinic/connection.c.h @@ -2,20 +2,50 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + static int pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, double timeout, int detect_types, const char *isolation_level, int check_same_thread, PyObject *factory, - int cache_size, int uri); + int cache_size, int uri, + enum autocommit_mode autocommit); static int pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static const char * const _keywords[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "Connection", 0}; - PyObject *argsbuf[8]; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 9 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(database), &_Py_ID(timeout), &_Py_ID(detect_types), &_Py_ID(isolation_level), &_Py_ID(check_same_thread), &_Py_ID(factory), &_Py_ID(cached_statements), &_Py_ID(uri), &_Py_ID(autocommit), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", "autocommit", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "Connection", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[9]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; @@ -27,6 +57,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *factory = (PyObject*)clinic_state()->ConnectionType; int cache_size = 128; int uri = 0; + enum autocommit_mode autocommit = LEGACY_TRANSACTION_CONTROL; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 8, 0, argsbuf); if (!fastargs) { @@ -69,8 +100,8 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) } } if (fastargs[4]) { - check_same_thread = _PyLong_AsInt(fastargs[4]); - if (check_same_thread == -1 && PyErr_Occurred()) { + check_same_thread = PyObject_IsTrue(fastargs[4]); + if (check_same_thread < 0) { goto exit; } if (!--noptargs) { @@ -92,12 +123,24 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto skip_optional_pos; } } - uri = PyObject_IsTrue(fastargs[7]); - if (uri < 0) { - goto exit; + if (fastargs[7]) { + uri = PyObject_IsTrue(fastargs[7]); + if (uri < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } } skip_optional_pos: - return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database, timeout, detect_types, isolation_level, check_same_thread, factory, cache_size, uri); + if (!noptargs) { + goto skip_optional_kwonly; + } + if (!autocommit_converter(fastargs[8], &autocommit)) { + goto exit; + } +skip_optional_kwonly: + return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database, timeout, detect_types, isolation_level, check_same_thread, factory, cache_size, uri, autocommit); exit: return return_value; @@ -119,8 +162,31 @@ static PyObject * pysqlite_connection_cursor(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(factory), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"factory", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "cursor", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "cursor", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; PyObject *factory = NULL; @@ -168,8 +234,31 @@ static PyObject * blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(readonly), &_Py_ID(name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"", "", "", "readonly", "name", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "blobopen", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "blobopen", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; const char *table; @@ -215,8 +304,8 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO goto skip_optional_kwonly; } if (args[3]) { - readonly = _PyLong_AsInt(args[3]); - if (readonly == -1 && PyErr_Occurred()) { + readonly = PyObject_IsTrue(args[3]); + if (readonly < 0) { goto exit; } if (!--noptargs) { @@ -322,8 +411,31 @@ static PyObject * pysqlite_connection_create_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(narg), &_Py_ID(func), &_Py_ID(deterministic), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"name", "narg", "func", "deterministic", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_function", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create_function", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[4]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; const char *name; @@ -396,8 +508,19 @@ static PyObject * create_window_function(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + static const char * const _keywords[] = {"", "", "", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_window_function", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create_window_function", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[3]; const char *name; int num_params; @@ -452,8 +575,31 @@ static PyObject * pysqlite_connection_create_aggregate(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(n_arg), &_Py_ID(aggregate_class), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"name", "n_arg", "aggregate_class", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_aggregate", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create_aggregate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[3]; const char *name; int n_arg; @@ -505,8 +651,31 @@ static PyObject * pysqlite_connection_set_authorizer(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(authorizer_callback), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"authorizer_callback", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_authorizer", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_authorizer", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; PyObject *callable; @@ -539,8 +708,31 @@ static PyObject * pysqlite_connection_set_progress_handler(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(progress_handler), &_Py_ID(n), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"progress_handler", "n", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_progress_handler", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_progress_handler", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[2]; PyObject *callable; int n; @@ -578,8 +770,31 @@ static PyObject * pysqlite_connection_set_trace_callback(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(trace_callback), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"trace_callback", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "set_trace_callback", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_trace_callback", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; PyObject *callable; @@ -615,8 +830,8 @@ pysqlite_connection_enable_load_extension(pysqlite_Connection *self, PyObject *a PyObject *return_value = NULL; int onoff; - onoff = _PyLong_AsInt(arg); - if (onoff == -1 && PyErr_Occurred()) { + onoff = PyObject_IsTrue(arg); + if (onoff < 0) { goto exit; } return_value = pysqlite_connection_enable_load_extension_impl(self, onoff); @@ -630,30 +845,63 @@ exit: #if defined(PY_SQLITE_ENABLE_LOAD_EXTENSION) PyDoc_STRVAR(pysqlite_connection_load_extension__doc__, -"load_extension($self, name, /)\n" +"load_extension($self, name, /, *, entrypoint=None)\n" "--\n" "\n" "Load SQLite extension module."); #define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF \ - {"load_extension", (PyCFunction)pysqlite_connection_load_extension, METH_O, pysqlite_connection_load_extension__doc__}, + {"load_extension", _PyCFunction_CAST(pysqlite_connection_load_extension), METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_load_extension__doc__}, static PyObject * pysqlite_connection_load_extension_impl(pysqlite_Connection *self, - const char *extension_name); + const char *extension_name, + const char *entrypoint); static PyObject * -pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *arg) +pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(entrypoint), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "entrypoint", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "load_extension", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; const char *extension_name; + const char *entrypoint = NULL; - if (!PyUnicode_Check(arg)) { - _PyArg_BadArgument("load_extension", "argument", "str", arg); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("load_extension", "argument 1", "str", args[0]); goto exit; } Py_ssize_t extension_name_length; - extension_name = PyUnicode_AsUTF8AndSize(arg, &extension_name_length); + extension_name = PyUnicode_AsUTF8AndSize(args[0], &extension_name_length); if (extension_name == NULL) { goto exit; } @@ -661,7 +909,29 @@ pysqlite_connection_load_extension(pysqlite_Connection *self, PyObject *arg) PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - return_value = pysqlite_connection_load_extension_impl(self, extension_name); + if (!noptargs) { + goto skip_optional_kwonly; + } + if (args[1] == Py_None) { + entrypoint = NULL; + } + else if (PyUnicode_Check(args[1])) { + Py_ssize_t entrypoint_length; + entrypoint = PyUnicode_AsUTF8AndSize(args[1], &entrypoint_length); + if (entrypoint == NULL) { + goto exit; + } + if (strlen(entrypoint) != (size_t)entrypoint_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + } + else { + _PyArg_BadArgument("load_extension", "argument 'entrypoint'", "str or None", args[1]); + goto exit; + } +skip_optional_kwonly: + return_value = pysqlite_connection_load_extension_impl(self, extension_name, entrypoint); exit: return return_value; @@ -814,8 +1084,31 @@ static PyObject * pysqlite_connection_backup(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(target), &_Py_ID(pages), &_Py_ID(progress), &_Py_ID(name), &_Py_ID(sleep), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"target", "pages", "progress", "name", "sleep", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "backup", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "backup", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[5]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; pysqlite_Connection *target; @@ -905,8 +1198,19 @@ static PyObject * pysqlite_connection_create_collation(pysqlite_Connection *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + static const char * const _keywords[] = {"", "", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "create_collation", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "create_collation", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[2]; const char *name; PyObject *callable; @@ -961,8 +1265,31 @@ static PyObject * serialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"name", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "serialize", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "serialize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; const char *name = "main"; @@ -1027,8 +1354,31 @@ static PyObject * deserialize(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"", "name", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "deserialize", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "deserialize", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; Py_buffer data = {NULL, NULL}; @@ -1217,6 +1567,85 @@ exit: return return_value; } +PyDoc_STRVAR(setconfig__doc__, +"setconfig($self, op, enable=True, /)\n" +"--\n" +"\n" +"Set a boolean connection configuration option.\n" +"\n" +" op\n" +" The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes."); + +#define SETCONFIG_METHODDEF \ + {"setconfig", _PyCFunction_CAST(setconfig), METH_FASTCALL, setconfig__doc__}, + +static PyObject * +setconfig_impl(pysqlite_Connection *self, int op, int enable); + +static PyObject * +setconfig(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int op; + int enable = 1; + + if (!_PyArg_CheckPositional("setconfig", nargs, 1, 2)) { + goto exit; + } + op = _PyLong_AsInt(args[0]); + if (op == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + enable = PyObject_IsTrue(args[1]); + if (enable < 0) { + goto exit; + } +skip_optional: + return_value = setconfig_impl(self, op, enable); + +exit: + return return_value; +} + +PyDoc_STRVAR(getconfig__doc__, +"getconfig($self, op, /)\n" +"--\n" +"\n" +"Query a boolean connection configuration option.\n" +"\n" +" op\n" +" The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes."); + +#define GETCONFIG_METHODDEF \ + {"getconfig", (PyCFunction)getconfig, METH_O, getconfig__doc__}, + +static int +getconfig_impl(pysqlite_Connection *self, int op); + +static PyObject * +getconfig(pysqlite_Connection *self, PyObject *arg) +{ + PyObject *return_value = NULL; + int op; + int _return_value; + + op = _PyLong_AsInt(arg); + if (op == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = getconfig_impl(self, op); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + #ifndef CREATE_WINDOW_FUNCTION_METHODDEF #define CREATE_WINDOW_FUNCTION_METHODDEF #endif /* !defined(CREATE_WINDOW_FUNCTION_METHODDEF) */ @@ -1236,4 +1665,4 @@ exit: #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=67e5b3dbade4a15b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=834a99827555bf1a input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Modules/_sqlite/clinic/cursor.c.h b/contrib/tools/python3/src/Modules/_sqlite/clinic/cursor.c.h index b29c333074..43e912d134 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/clinic/cursor.c.h +++ b/contrib/tools/python3/src/Modules/_sqlite/clinic/cursor.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + static int pysqlite_cursor_init_impl(pysqlite_Cursor *self, pysqlite_Connection *connection); @@ -10,10 +16,11 @@ static int pysqlite_cursor_init(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; + PyTypeObject *base_tp = clinic_state()->CursorType; pysqlite_Connection *connection; - if ((Py_IS_TYPE(self, clinic_state()->CursorType) || - Py_TYPE(self)->tp_new == clinic_state()->CursorType->tp_new) && + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && !_PyArg_NoKeywords("Cursor", kwargs)) { goto exit; } @@ -186,8 +193,31 @@ static PyObject * pysqlite_cursor_fetchmany(pysqlite_Cursor *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(size), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"size", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "fetchmany", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "fetchmany", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; int maxrows = self->arraysize; @@ -289,4 +319,4 @@ pysqlite_cursor_close(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored)) { return pysqlite_cursor_close_impl(self); } -/*[clinic end generated code: output=2b9c6a3ca8a8caff input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1f82e3c9791bb9a5 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Modules/_sqlite/clinic/module.c.h b/contrib/tools/python3/src/Modules/_sqlite/clinic/module.c.h index f5278078a3..12f6083588 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/clinic/module.c.h +++ b/contrib/tools/python3/src/Modules/_sqlite/clinic/module.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + PyDoc_STRVAR(pysqlite_complete_statement__doc__, "complete_statement($module, /, statement)\n" "--\n" @@ -18,8 +24,31 @@ static PyObject * pysqlite_complete_statement(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(statement), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + static const char * const _keywords[] = {"statement", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "complete_statement", 0}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "complete_statement", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE PyObject *argsbuf[1]; const char *statement; @@ -46,46 +75,6 @@ exit: return return_value; } -PyDoc_STRVAR(pysqlite_enable_shared_cache__doc__, -"enable_shared_cache($module, /, do_enable)\n" -"--\n" -"\n" -"Enable or disable shared cache mode for the calling thread.\n" -"\n" -"This method is deprecated and will be removed in Python 3.12.\n" -"Shared cache is strongly discouraged by the SQLite 3 documentation.\n" -"If shared cache must be used, open the database in URI mode using\n" -"the cache=shared query parameter."); - -#define PYSQLITE_ENABLE_SHARED_CACHE_METHODDEF \ - {"enable_shared_cache", _PyCFunction_CAST(pysqlite_enable_shared_cache), METH_FASTCALL|METH_KEYWORDS, pysqlite_enable_shared_cache__doc__}, - -static PyObject * -pysqlite_enable_shared_cache_impl(PyObject *module, int do_enable); - -static PyObject * -pysqlite_enable_shared_cache(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *return_value = NULL; - static const char * const _keywords[] = {"do_enable", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "enable_shared_cache", 0}; - PyObject *argsbuf[1]; - int do_enable; - - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); - if (!args) { - goto exit; - } - do_enable = _PyLong_AsInt(args[0]); - if (do_enable == -1 && PyErr_Occurred()) { - goto exit; - } - return_value = pysqlite_enable_shared_cache_impl(module, do_enable); - -exit: - return return_value; -} - PyDoc_STRVAR(pysqlite_register_adapter__doc__, "register_adapter($module, type, adapter, /)\n" "--\n" @@ -222,4 +211,4 @@ skip_optional: exit: return return_value; } -/*[clinic end generated code: output=ecaf4e0a239c2685 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=39d38c6cfc455042 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Modules/_sqlite/clinic/row.c.h b/contrib/tools/python3/src/Modules/_sqlite/clinic/row.c.h index c936ef75fd..89a48fd52d 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/clinic/row.c.h +++ b/contrib/tools/python3/src/Modules/_sqlite/clinic/row.c.h @@ -2,6 +2,12 @@ preserve [clinic start generated code]*/ +#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head +# include "pycore_runtime.h" // _Py_ID() +#endif + + static PyObject * pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor, PyObject *data); @@ -10,11 +16,11 @@ static PyObject * pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; + PyTypeObject *base_tp = clinic_state()->RowType; pysqlite_Cursor *cursor; PyObject *data; - if ((type == clinic_state()->RowType || - type->tp_init == clinic_state()->RowType->tp_init) && + if ((type == base_tp || type->tp_init == base_tp->tp_init) && !_PyArg_NoKeywords("Row", kwargs)) { goto exit; } @@ -54,4 +60,4 @@ pysqlite_row_keys(pysqlite_Row *self, PyObject *Py_UNUSED(ignored)) { return pysqlite_row_keys_impl(self); } -/*[clinic end generated code: output=9d54919dbb4ba5f1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=157b31ac3f6af1ba input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Modules/_sqlite/connection.c b/contrib/tools/python3/src/Modules/_sqlite/connection.c index e3650de7fb..12e5c135aa 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/connection.c +++ b/contrib/tools/python3/src/Modules/_sqlite/connection.c @@ -30,6 +30,8 @@ #include "prepare_protocol.h" #include "util.h" +#include <stdbool.h> + #if SQLITE_VERSION_NUMBER >= 3014000 #define HAVE_TRACE_V2 #endif @@ -93,6 +95,30 @@ isolation_level_converter(PyObject *str_or_none, const char **result) } static int +autocommit_converter(PyObject *val, enum autocommit_mode *result) +{ + if (Py_IsTrue(val)) { + *result = AUTOCOMMIT_ENABLED; + return 1; + } + if (Py_IsFalse(val)) { + *result = AUTOCOMMIT_DISABLED; + return 1; + } + if (PyLong_Check(val) && + PyLong_AsLong(val) == LEGACY_TRANSACTION_CONTROL) + { + *result = AUTOCOMMIT_LEGACY; + return 1; + } + + PyErr_SetString(PyExc_ValueError, + "autocommit must be True, False, or " + "sqlite3.LEGACY_TRANSACTION_CONTROL"); + return 0; +} + +static int sqlite3_int64_converter(PyObject *obj, sqlite3_int64 *result) { if (!PyLong_Check(obj)) { @@ -120,7 +146,7 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void free_callback_context(callback_context *ctx); static void set_callback_context(callback_context **ctx_pp, callback_context *ctx); -static void connection_close(pysqlite_Connection *self); +static int connection_close(pysqlite_Connection *self); PyObject *_pysqlite_query_execute(pysqlite_Cursor *, int, PyObject *, PyObject *); static PyObject * @@ -146,17 +172,42 @@ new_statement_cache(pysqlite_Connection *self, pysqlite_state *state, return res; } +static inline int +connection_exec_stmt(pysqlite_Connection *self, const char *sql) +{ + int rc; + Py_BEGIN_ALLOW_THREADS + int len = (int)strlen(sql) + 1; + sqlite3_stmt *stmt; + rc = sqlite3_prepare_v2(self->db, sql, len, &stmt, NULL); + if (rc == SQLITE_OK) { + (void)sqlite3_step(stmt); + rc = sqlite3_finalize(stmt); + } + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + (void)_pysqlite_seterror(self->state, self->db); + return -1; + } + return 0; +} + /*[python input] class IsolationLevel_converter(CConverter): type = "const char *" converter = "isolation_level_converter" +class Autocommit_converter(CConverter): + type = "enum autocommit_mode" + converter = "autocommit_converter" + class sqlite3_int64_converter(CConverter): type = "sqlite3_int64" converter = "sqlite3_int64_converter" [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=e9bee126e0500e61]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=dff8760fb1eba6a1]*/ // NB: This needs to be in sync with the sqlite3.connect docstring /*[clinic input] @@ -166,10 +217,12 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init timeout: double = 5.0 detect_types: int = 0 isolation_level: IsolationLevel = "" - check_same_thread: bool(accept={int}) = True + check_same_thread: bool = True factory: object(c_default='(PyObject*)clinic_state()->ConnectionType') = ConnectionType cached_statements as cache_size: int = 128 uri: bool = False + * + autocommit: Autocommit(c_default='LEGACY_TRANSACTION_CONTROL') = sqlite3.LEGACY_TRANSACTION_CONTROL [clinic start generated code]*/ static int @@ -177,8 +230,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, double timeout, int detect_types, const char *isolation_level, int check_same_thread, PyObject *factory, - int cache_size, int uri) -/*[clinic end generated code: output=839eb2fee4293bda input=b8ce63dc6f70a383]*/ + int cache_size, int uri, + enum autocommit_mode autocommit) +/*[clinic end generated code: output=cba057313ea7712f input=9b0ab6c12f674fa3]*/ { if (PySys_Audit("sqlite3.connect", "O", database) < 0) { return -1; @@ -190,10 +244,13 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, } if (self->initialized) { + self->initialized = 0; + PyTypeObject *tp = Py_TYPE(self); tp->tp_clear((PyObject *)self); - connection_close(self); - self->initialized = 0; + if (connection_close(self) < 0) { + return -1; + } } // Create and configure SQLite database object. @@ -245,6 +302,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, self->state = state; self->detect_types = detect_types; self->isolation_level = isolation_level; + self->autocommit = autocommit; self->check_same_thread = check_same_thread; self->thread_ident = PyThread_get_thread_ident(); self->statement_cache = statement_cache; @@ -274,6 +332,12 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, } self->initialized = 1; + + if (autocommit == AUTOCOMMIT_DISABLED) { + if (connection_exec_stmt(self, "BEGIN") < 0) { + return -1; + } + } return 0; error: @@ -340,31 +404,90 @@ free_callback_contexts(pysqlite_Connection *self) } static void -connection_close(pysqlite_Connection *self) +remove_callbacks(sqlite3 *db) { - if (self->db) { - free_callback_contexts(self); + assert(db != NULL); + /* None of these APIs can fail, as long as they are given a valid + * database pointer. */ + int rc; +#ifdef HAVE_TRACE_V2 + rc = sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0); + assert(rc == SQLITE_OK), (void)rc; +#else + sqlite3_trace(db, 0, (void*)0); +#endif - sqlite3 *db = self->db; - self->db = NULL; + sqlite3_progress_handler(db, 0, 0, (void *)0); - Py_BEGIN_ALLOW_THREADS - int rc = sqlite3_close_v2(db); - assert(rc == SQLITE_OK), (void)rc; - Py_END_ALLOW_THREADS + rc = sqlite3_set_authorizer(db, NULL, NULL); + assert(rc == SQLITE_OK), (void)rc; +} + +static int +connection_close(pysqlite_Connection *self) +{ + if (self->db == NULL) { + return 0; + } + + int rc = 0; + if (self->autocommit == AUTOCOMMIT_DISABLED && + !sqlite3_get_autocommit(self->db)) + { + if (connection_exec_stmt(self, "ROLLBACK") < 0) { + rc = -1; + } } + + sqlite3 *db = self->db; + self->db = NULL; + + Py_BEGIN_ALLOW_THREADS + /* The v2 close call always returns SQLITE_OK if given a valid database + * pointer (which we do), so we can safely ignore the return value */ + (void)sqlite3_close_v2(db); + Py_END_ALLOW_THREADS + + free_callback_contexts(self); + return rc; } static void -connection_dealloc(pysqlite_Connection *self) +connection_finalize(PyObject *self) { - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - tp->tp_clear((PyObject *)self); + pysqlite_Connection *con = (pysqlite_Connection *)self; + PyObject *exc = PyErr_GetRaisedException(); + + /* If close is implicitly called as a result of interpreter + * tear-down, we must not call back into Python. */ + PyInterpreterState *interp = PyInterpreterState_Get(); + int teardown = _Py_IsInterpreterFinalizing(interp); + if (teardown && con->db) { + remove_callbacks(con->db); + } /* Clean up if user has not called .close() explicitly. */ - connection_close(self); + if (connection_close(con) < 0) { + if (teardown) { + PyErr_Clear(); + } + else { + PyErr_WriteUnraisable((PyObject *)self); + } + } + + PyErr_SetRaisedException(exc); +} +static void +connection_dealloc(PyObject *self) +{ + if (PyObject_CallFinalizerFromDealloc(self) < 0) { + return; + } + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_clear(self); tp->tp_free(self); Py_DECREF(tp); } @@ -423,7 +546,7 @@ _sqlite3.Connection.blobopen as blobopen Row index. / * - readonly: bool(accept={int}) = False + readonly: bool = False Open the BLOB without write permissions. name: str = "main" Database name. @@ -434,7 +557,7 @@ Open and return a BLOB object. static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, sqlite3_int64 row, int readonly, const char *name) -/*[clinic end generated code: output=6a02d43efb885d1c input=4180b11a0591d80d]*/ +/*[clinic end generated code: output=6a02d43efb885d1c input=23576bd1108d8774]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -512,7 +635,9 @@ pysqlite_connection_close_impl(pysqlite_Connection *self) pysqlite_close_all_blobs(self); Py_CLEAR(self->statement_cache); - connection_close(self); + if (connection_close(self) < 0) { + return NULL; + } Py_RETURN_NONE; } @@ -556,24 +681,21 @@ pysqlite_connection_commit_impl(pysqlite_Connection *self) return NULL; } - if (!sqlite3_get_autocommit(self->db)) { - int rc; - - Py_BEGIN_ALLOW_THREADS - sqlite3_stmt *statement; - rc = sqlite3_prepare_v2(self->db, "COMMIT", 7, &statement, NULL); - if (rc == SQLITE_OK) { - (void)sqlite3_step(statement); - rc = sqlite3_finalize(statement); + if (self->autocommit == AUTOCOMMIT_LEGACY) { + if (!sqlite3_get_autocommit(self->db)) { + if (connection_exec_stmt(self, "COMMIT") < 0) { + return NULL; + } } - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { - (void)_pysqlite_seterror(self->state, self->db); + } + else if (self->autocommit == AUTOCOMMIT_DISABLED) { + if (connection_exec_stmt(self, "COMMIT") < 0) { + return NULL; + } + if (connection_exec_stmt(self, "BEGIN") < 0) { return NULL; } } - Py_RETURN_NONE; } @@ -593,25 +715,21 @@ pysqlite_connection_rollback_impl(pysqlite_Connection *self) return NULL; } - if (!sqlite3_get_autocommit(self->db)) { - int rc; - - Py_BEGIN_ALLOW_THREADS - sqlite3_stmt *statement; - rc = sqlite3_prepare_v2(self->db, "ROLLBACK", 9, &statement, NULL); - if (rc == SQLITE_OK) { - (void)sqlite3_step(statement); - rc = sqlite3_finalize(statement); + if (self->autocommit == AUTOCOMMIT_LEGACY) { + if (!sqlite3_get_autocommit(self->db)) { + if (connection_exec_stmt(self, "ROLLBACK") < 0) { + return NULL; + } } - Py_END_ALLOW_THREADS - - if (rc != SQLITE_OK) { - (void)_pysqlite_seterror(self->state, self->db); + } + else if (self->autocommit == AUTOCOMMIT_DISABLED) { + if (connection_exec_stmt(self, "ROLLBACK") < 0) { + return NULL; + } + if (connection_exec_stmt(self, "BEGIN") < 0) { return NULL; } - } - Py_RETURN_NONE; } @@ -853,7 +971,6 @@ final_callback(sqlite3_context *context) PyObject* function_result; PyObject** aggregate_instance; int ok; - PyObject *exception, *value, *tb; aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, 0); if (aggregate_instance == NULL) { @@ -868,7 +985,7 @@ final_callback(sqlite3_context *context) } // Keep the exception (if any) of the last call to step, value, or inverse - PyErr_Fetch(&exception, &value, &tb); + PyObject *exc = PyErr_GetRaisedException(); callback_context *ctx = (callback_context *)sqlite3_user_data(context); assert(ctx != NULL); @@ -883,7 +1000,7 @@ final_callback(sqlite3_context *context) } if (!ok) { int attr_err = PyErr_ExceptionMatches(PyExc_AttributeError); - _PyErr_ChainExceptions(exception, value, tb); + _PyErr_ChainExceptions1(exc); /* Note: contrary to the step, value, and inverse callbacks, SQLite * does _not_, as of SQLite 3.38.0, propagate errors to sqlite3_step() @@ -894,7 +1011,7 @@ final_callback(sqlite3_context *context) : "user-defined aggregate's 'finalize' method raised error"); } else { - PyErr_Restore(exception, value, tb); + PyErr_SetRaisedException(exc); } error: @@ -1509,7 +1626,7 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, /*[clinic input] _sqlite3.Connection.enable_load_extension as pysqlite_connection_enable_load_extension - enable as onoff: bool(accept={int}) + enable as onoff: bool / Enable dynamic loading of SQLite extension modules. @@ -1518,7 +1635,7 @@ Enable dynamic loading of SQLite extension modules. static PyObject * pysqlite_connection_enable_load_extension_impl(pysqlite_Connection *self, int onoff) -/*[clinic end generated code: output=9cac37190d388baf input=5f00e93f7a9d3540]*/ +/*[clinic end generated code: output=9cac37190d388baf input=2a1e87931486380f]*/ { int rc; @@ -1547,14 +1664,17 @@ _sqlite3.Connection.load_extension as pysqlite_connection_load_extension name as extension_name: str / + * + entrypoint: str(accept={str, NoneType}) = None Load SQLite extension module. [clinic start generated code]*/ static PyObject * pysqlite_connection_load_extension_impl(pysqlite_Connection *self, - const char *extension_name) -/*[clinic end generated code: output=47eb1d7312bc97a7 input=edd507389d89d621]*/ + const char *extension_name, + const char *entrypoint) +/*[clinic end generated code: output=7e61a7add9de0286 input=c36b14ea702e04f5]*/ { int rc; char* errmsg; @@ -1567,7 +1687,7 @@ pysqlite_connection_load_extension_impl(pysqlite_Connection *self, return NULL; } - rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg); + rc = sqlite3_load_extension(self->db, extension_name, entrypoint, &errmsg); if (rc != 0) { PyErr_SetString(self->OperationalError, errmsg); return NULL; @@ -1607,9 +1727,8 @@ static PyObject* pysqlite_connection_get_total_changes(pysqlite_Connection* self { if (!pysqlite_check_connection(self)) { return NULL; - } else { - return Py_BuildValue("i", sqlite3_total_changes(self->db)); } + return PyLong_FromLong(sqlite3_total_changes(self->db)); } static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* self, void* unused) @@ -1868,43 +1987,21 @@ static PyObject * pysqlite_connection_iterdump_impl(pysqlite_Connection *self) /*[clinic end generated code: output=586997aaf9808768 input=1911ca756066da89]*/ { - PyObject* retval = NULL; - PyObject* module = NULL; - PyObject* module_dict; - PyObject* pyfn_iterdump; - if (!pysqlite_check_connection(self)) { - goto finally; - } - - module = PyImport_ImportModule(MODULE_NAME ".dump"); - if (!module) { - goto finally; - } - - module_dict = PyModule_GetDict(module); - if (!module_dict) { - goto finally; + return NULL; } - PyObject *meth = PyUnicode_InternFromString("_iterdump"); - if (meth == NULL) { - goto finally; - } - pyfn_iterdump = PyDict_GetItemWithError(module_dict, meth); - Py_DECREF(meth); - if (!pyfn_iterdump) { + PyObject *iterdump = _PyImport_GetModuleAttrString(MODULE_NAME ".dump", "_iterdump"); + if (!iterdump) { if (!PyErr_Occurred()) { PyErr_SetString(self->OperationalError, "Failed to obtain _iterdump() reference"); } - goto finally; + return NULL; } - retval = PyObject_CallOneArg(pyfn_iterdump, (PyObject *)self); - -finally: - Py_XDECREF(module); + PyObject *retval = PyObject_CallOneArg(iterdump, (PyObject *)self); + Py_DECREF(iterdump); return retval; } @@ -2244,15 +2341,14 @@ pysqlite_connection_exit_impl(pysqlite_Connection *self, PyObject *exc_type, if (commit) { /* Commit failed; try to rollback in order to unlock the database. * If rollback also fails, chain the exceptions. */ - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); result = pysqlite_connection_rollback_impl(self); if (result == NULL) { - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); } else { Py_DECREF(result); - PyErr_Restore(exc, val, tb); + PyErr_SetRaisedException(exc); } } return NULL; @@ -2312,6 +2408,161 @@ getlimit_impl(pysqlite_Connection *self, int category) return setlimit_impl(self, category, -1); } +static inline bool +is_int_config(const int op) +{ + switch (op) { + case SQLITE_DBCONFIG_ENABLE_FKEY: + case SQLITE_DBCONFIG_ENABLE_TRIGGER: +#if SQLITE_VERSION_NUMBER >= 3012002 + case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: +#endif +#if SQLITE_VERSION_NUMBER >= 3013000 + case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: +#endif +#if SQLITE_VERSION_NUMBER >= 3016000 + case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: +#endif +#if SQLITE_VERSION_NUMBER >= 3020000 + case SQLITE_DBCONFIG_ENABLE_QPSG: +#endif +#if SQLITE_VERSION_NUMBER >= 3022000 + case SQLITE_DBCONFIG_TRIGGER_EQP: +#endif +#if SQLITE_VERSION_NUMBER >= 3024000 + case SQLITE_DBCONFIG_RESET_DATABASE: +#endif +#if SQLITE_VERSION_NUMBER >= 3026000 + case SQLITE_DBCONFIG_DEFENSIVE: +#endif +#if SQLITE_VERSION_NUMBER >= 3028000 + case SQLITE_DBCONFIG_WRITABLE_SCHEMA: +#endif +#if SQLITE_VERSION_NUMBER >= 3029000 + case SQLITE_DBCONFIG_DQS_DDL: + case SQLITE_DBCONFIG_DQS_DML: + case SQLITE_DBCONFIG_LEGACY_ALTER_TABLE: +#endif +#if SQLITE_VERSION_NUMBER >= 3030000 + case SQLITE_DBCONFIG_ENABLE_VIEW: +#endif +#if SQLITE_VERSION_NUMBER >= 3031000 + case SQLITE_DBCONFIG_LEGACY_FILE_FORMAT: + case SQLITE_DBCONFIG_TRUSTED_SCHEMA: +#endif + return true; + default: + return false; + } +} + +/*[clinic input] +_sqlite3.Connection.setconfig as setconfig + + op: int + The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes. + enable: bool = True + / + +Set a boolean connection configuration option. +[clinic start generated code]*/ + +static PyObject * +setconfig_impl(pysqlite_Connection *self, int op, int enable) +/*[clinic end generated code: output=c60b13e618aff873 input=a10f1539c2d7da6b]*/ +{ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!is_int_config(op)) { + return PyErr_Format(PyExc_ValueError, "unknown config 'op': %d", op); + } + + int actual; + int rc = sqlite3_db_config(self->db, op, enable, &actual); + if (rc != SQLITE_OK) { + (void)_pysqlite_seterror(self->state, self->db); + return NULL; + } + if (enable != actual) { + PyErr_SetString(self->state->OperationalError, "Unable to set config"); + return NULL; + } + Py_RETURN_NONE; +} + +/*[clinic input] +_sqlite3.Connection.getconfig as getconfig -> bool + + op: int + The configuration verb; one of the sqlite3.SQLITE_DBCONFIG codes. + / + +Query a boolean connection configuration option. +[clinic start generated code]*/ + +static int +getconfig_impl(pysqlite_Connection *self, int op) +/*[clinic end generated code: output=25ac05044c7b78a3 input=b0526d7e432e3f2f]*/ +{ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return -1; + } + if (!is_int_config(op)) { + PyErr_Format(PyExc_ValueError, "unknown config 'op': %d", op); + return -1; + } + + int current; + int rc = sqlite3_db_config(self->db, op, -1, ¤t); + if (rc != SQLITE_OK) { + (void)_pysqlite_seterror(self->state, self->db); + return -1; + } + return current; +} + +static PyObject * +get_autocommit(pysqlite_Connection *self, void *Py_UNUSED(ctx)) +{ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (self->autocommit == AUTOCOMMIT_ENABLED) { + Py_RETURN_TRUE; + } + if (self->autocommit == AUTOCOMMIT_DISABLED) { + Py_RETURN_FALSE; + } + return PyLong_FromLong(LEGACY_TRANSACTION_CONTROL); +} + +static int +set_autocommit(pysqlite_Connection *self, PyObject *val, void *Py_UNUSED(ctx)) +{ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return -1; + } + if (!autocommit_converter(val, &self->autocommit)) { + return -1; + } + if (self->autocommit == AUTOCOMMIT_ENABLED) { + if (!sqlite3_get_autocommit(self->db)) { + if (connection_exec_stmt(self, "COMMIT") < 0) { + return -1; + } + } + } + else if (self->autocommit == AUTOCOMMIT_DISABLED) { + if (sqlite3_get_autocommit(self->db)) { + if (connection_exec_stmt(self, "BEGIN") < 0) { + return -1; + } + } + } + return 0; +} + static const char connection_doc[] = PyDoc_STR("SQLite database connection object."); @@ -2320,6 +2571,7 @@ static PyGetSetDef connection_getset[] = { {"isolation_level", (getter)pysqlite_connection_get_isolation_level, (setter)pysqlite_connection_set_isolation_level}, {"total_changes", (getter)pysqlite_connection_get_total_changes, (setter)0}, {"in_transaction", (getter)pysqlite_connection_get_in_transaction, (setter)0}, + {"autocommit", (getter)get_autocommit, (setter)set_autocommit}, {NULL} }; @@ -2350,6 +2602,8 @@ static PyMethodDef connection_methods[] = { DESERIALIZE_METHODDEF CREATE_WINDOW_FUNCTION_METHODDEF BLOBOPEN_METHODDEF + SETCONFIG_METHODDEF + GETCONFIG_METHODDEF {NULL, NULL} }; @@ -2371,6 +2625,7 @@ static struct PyMemberDef connection_members[] = }; static PyType_Slot connection_slots[] = { + {Py_tp_finalize, connection_finalize}, {Py_tp_dealloc, connection_dealloc}, {Py_tp_doc, (void *)connection_doc}, {Py_tp_methods, connection_methods}, diff --git a/contrib/tools/python3/src/Modules/_sqlite/connection.h b/contrib/tools/python3/src/Modules/_sqlite/connection.h index 629fe3d3a9..1df92065a5 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/connection.h +++ b/contrib/tools/python3/src/Modules/_sqlite/connection.h @@ -39,6 +39,12 @@ typedef struct _callback_context pysqlite_state *state; } callback_context; +enum autocommit_mode { + AUTOCOMMIT_LEGACY = LEGACY_TRANSACTION_CONTROL, + AUTOCOMMIT_ENABLED = 1, + AUTOCOMMIT_DISABLED = 0, +}; + typedef struct { PyObject_HEAD @@ -51,6 +57,7 @@ typedef struct /* NULL for autocommit, otherwise a string with the isolation level */ const char *isolation_level; + enum autocommit_mode autocommit; /* 1 if a check should be performed for each API call if the connection is * used from the same thread it was created in */ diff --git a/contrib/tools/python3/src/Modules/_sqlite/cursor.c b/contrib/tools/python3/src/Modules/_sqlite/cursor.c index 3f5cfef0c3..caeedbddb8 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/cursor.c +++ b/contrib/tools/python3/src/Modules/_sqlite/cursor.c @@ -130,14 +130,10 @@ stmt_reset(pysqlite_Statement *self) { int rc = SQLITE_OK; - if (self->in_use && self->st) { + if (self->st != NULL) { Py_BEGIN_ALLOW_THREADS rc = sqlite3_reset(self->st); Py_END_ALLOW_THREADS - - if (rc == SQLITE_OK) { - self->in_use = 0; - } } return rc; @@ -666,6 +662,19 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self, return; } for (i = 0; i < num_params; i++) { + const char *name = sqlite3_bind_parameter_name(self->st, i+1); + if (name != NULL) { + int ret = PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "Binding %d ('%s') is a named parameter, but you " + "supplied a sequence which requires nameless (qmark) " + "placeholders. Starting with Python 3.14 an " + "sqlite3.ProgrammingError will be raised.", + i+1, name); + if (ret < 0) { + return; + } + } + if (PyTuple_CheckExact(parameters)) { PyObject *item = PyTuple_GET_ITEM(parameters, i); current_param = Py_NewRef(item); @@ -696,11 +705,10 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self, Py_DECREF(adapted); if (rc != SQLITE_OK) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); sqlite3 *db = sqlite3_db_handle(self->st); _pysqlite_seterror(state, db); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); return; } } @@ -756,11 +764,10 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self, Py_DECREF(adapted); if (rc != SQLITE_OK) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); sqlite3 *db = sqlite3_db_handle(self->st); _pysqlite_seterror(state, db); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); return; } } @@ -770,12 +777,6 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self, } } -static inline void -stmt_mark_dirty(pysqlite_Statement *self) -{ - self->in_use = 1; -} - PyObject * _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation, PyObject* second_argument) { @@ -830,16 +831,12 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation } } - if (self->statement != NULL) { - /* There is an active statement */ - stmt_reset(self->statement); - } - /* reset description */ Py_INCREF(Py_None); Py_SETREF(self->description, Py_None); if (self->statement) { + // Reset pending statements on this cursor. (void)stmt_reset(self->statement); } @@ -856,7 +853,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation goto error; } - if (self->statement->in_use) { + if (sqlite3_stmt_busy(self->statement->st)) { Py_SETREF(self->statement, pysqlite_statement_create(self->connection, operation)); if (self->statement == NULL) { @@ -864,13 +861,13 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation } } - stmt_reset(self->statement); - stmt_mark_dirty(self->statement); + (void)stmt_reset(self->statement); self->rowcount = self->statement->is_dml ? 0L : -1L; /* We start a transaction implicitly before a DML statement. SELECT is the only exception. See #9924. */ - if (self->connection->isolation_level + if (self->connection->autocommit == AUTOCOMMIT_LEGACY + && self->connection->isolation_level && self->statement->is_dml && sqlite3_get_autocommit(self->connection->db)) { @@ -879,14 +876,13 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation } } + assert(!sqlite3_stmt_busy(self->statement->st)); while (1) { parameters = PyIter_Next(parameters_iter); if (!parameters) { break; } - stmt_mark_dirty(self->statement); - bind_parameters(state, self->statement, parameters); if (PyErr_Occurred()) { goto error; @@ -902,7 +898,6 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation PyErr_Clear(); } } - (void)stmt_reset(self->statement); _pysqlite_seterror(state, self->connection->db); goto error; } @@ -944,16 +939,8 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation } } - if (rc == SQLITE_DONE && !multiple) { + if (rc == SQLITE_DONE) { if (self->statement->is_dml) { - self->rowcount = (long)sqlite3_changes(self->connection->db); - } - stmt_reset(self->statement); - Py_CLEAR(self->statement); - } - - if (multiple) { - if (self->statement->is_dml && rc == SQLITE_DONE) { self->rowcount += (long)sqlite3_changes(self->connection->db); } stmt_reset(self->statement); @@ -980,11 +967,17 @@ error: self->locked = 0; if (PyErr_Occurred()) { + if (self->statement) { + (void)stmt_reset(self->statement); + Py_CLEAR(self->statement); + } self->rowcount = -1L; return NULL; - } else { - return Py_NewRef((PyObject *)self); } + if (self->statement && !sqlite3_stmt_busy(self->statement->st)) { + Py_CLEAR(self->statement); + } + return Py_NewRef((PyObject *)self); } /*[clinic input] @@ -1052,7 +1045,9 @@ pysqlite_cursor_executescript_impl(pysqlite_Cursor *self, // Commit if needed sqlite3 *db = self->connection->db; - if (!sqlite3_get_autocommit(db)) { + if (self->connection->autocommit == AUTOCOMMIT_LEGACY + && !sqlite3_get_autocommit(db)) + { int rc = SQLITE_OK; Py_BEGIN_ALLOW_THREADS @@ -1111,11 +1106,7 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self) sqlite3_stmt *stmt = self->statement->st; assert(stmt != NULL); - if (sqlite3_data_count(stmt) == 0) { - (void)stmt_reset(self->statement); - Py_CLEAR(self->statement); - return NULL; - } + assert(sqlite3_data_count(stmt) != 0); self->locked = 1; // GH-80254: Prevent recursive use of cursors. PyObject *row = _pysqlite_fetch_one_row(self); @@ -1143,8 +1134,7 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self) PyObject *factory = self->row_factory; PyObject *args[] = { (PyObject *)self, row, }; PyObject *new_row = PyObject_Vectorcall(factory, args, 2, NULL); - Py_DECREF(row); - row = new_row; + Py_SETREF(row, new_row); } return row; } diff --git a/contrib/tools/python3/src/Modules/_sqlite/microprotocols.c b/contrib/tools/python3/src/Modules/_sqlite/microprotocols.c index a79f0067b1..148220d0f9 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/microprotocols.c +++ b/contrib/tools/python3/src/Modules/_sqlite/microprotocols.c @@ -57,7 +57,7 @@ pysqlite_microprotocols_add(pysqlite_state *state, PyTypeObject *type, assert(type != NULL); assert(proto != NULL); - key = Py_BuildValue("(OO)", (PyObject*)type, proto); + key = PyTuple_Pack(2, (PyObject *)type, proto); if (!key) { return -1; } @@ -81,7 +81,7 @@ pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj, way to get a quotable object to be its instance */ /* look for an adapter in the registry */ - key = Py_BuildValue("(OO)", (PyObject*)Py_TYPE(obj), proto); + key = PyTuple_Pack(2, (PyObject *)Py_TYPE(obj), proto); if (!key) { return NULL; } diff --git a/contrib/tools/python3/src/Modules/_sqlite/module.c b/contrib/tools/python3/src/Modules/_sqlite/module.c index e633a63ae9..27bd42f459 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/module.c +++ b/contrib/tools/python3/src/Modules/_sqlite/module.c @@ -46,7 +46,8 @@ module _sqlite3 PyDoc_STRVAR(module_connect_doc, "connect($module, /, database, timeout=5.0, detect_types=0,\n" " isolation_level='', check_same_thread=True,\n" -" factory=ConnectionType, cached_statements=128, uri=False)\n" +" factory=ConnectionType, cached_statements=128, uri=False, *,\n" +" autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)\n" "--\n" "\n" "Opens a connection to the SQLite database file database.\n" @@ -102,36 +103,6 @@ pysqlite_complete_statement_impl(PyObject *module, const char *statement) } /*[clinic input] -_sqlite3.enable_shared_cache as pysqlite_enable_shared_cache - - do_enable: int - -Enable or disable shared cache mode for the calling thread. - -This method is deprecated and will be removed in Python 3.12. -Shared cache is strongly discouraged by the SQLite 3 documentation. -If shared cache must be used, open the database in URI mode using -the cache=shared query parameter. -[clinic start generated code]*/ - -static PyObject * -pysqlite_enable_shared_cache_impl(PyObject *module, int do_enable) -/*[clinic end generated code: output=259c74eedee1516b input=26e40d5971d3487d]*/ -{ - int rc; - - rc = sqlite3_enable_shared_cache(do_enable); - - if (rc != SQLITE_OK) { - pysqlite_state *state = pysqlite_get_state(module); - PyErr_SetString(state->OperationalError, "Changing the shared_cache flag failed"); - return NULL; - } else { - Py_RETURN_NONE; - } -} - -/*[clinic input] _sqlite3.register_adapter as pysqlite_register_adapter type: object(type='PyTypeObject *') @@ -254,14 +225,8 @@ static int converters_init(PyObject* module) static int load_functools_lru_cache(PyObject *module) { - PyObject *functools = PyImport_ImportModule("functools"); - if (functools == NULL) { - return -1; - } - pysqlite_state *state = pysqlite_get_state(module); - state->lru_cache = PyObject_GetAttrString(functools, "lru_cache"); - Py_DECREF(functools); + state->lru_cache = _PyImport_GetModuleAttrString("functools", "lru_cache"); if (state->lru_cache == NULL) { return -1; } @@ -273,7 +238,6 @@ static PyMethodDef module_methods[] = { PYSQLITE_COMPLETE_STATEMENT_METHODDEF PYSQLITE_CONNECT_METHODDEF PYSQLITE_ENABLE_CALLBACK_TRACE_METHODDEF - PYSQLITE_ENABLE_SHARED_CACHE_METHODDEF PYSQLITE_REGISTER_ADAPTER_METHODDEF PYSQLITE_REGISTER_CONVERTER_METHODDEF {NULL, NULL} @@ -535,6 +499,49 @@ add_integer_constants(PyObject *module) { #if SQLITE_VERSION_NUMBER >= 3008007 ADD_INT(SQLITE_LIMIT_WORKER_THREADS); #endif + + /* + * Database connection configuration options. + * See https://www.sqlite.org/c3ref/c_dbconfig_defensive.html + */ + ADD_INT(SQLITE_DBCONFIG_ENABLE_FKEY); + ADD_INT(SQLITE_DBCONFIG_ENABLE_TRIGGER); +#if SQLITE_VERSION_NUMBER >= 3012002 + ADD_INT(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER); +#endif +#if SQLITE_VERSION_NUMBER >= 3013000 + ADD_INT(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION); +#endif +#if SQLITE_VERSION_NUMBER >= 3016000 + ADD_INT(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE); +#endif +#if SQLITE_VERSION_NUMBER >= 3020000 + ADD_INT(SQLITE_DBCONFIG_ENABLE_QPSG); +#endif +#if SQLITE_VERSION_NUMBER >= 3022000 + ADD_INT(SQLITE_DBCONFIG_TRIGGER_EQP); +#endif +#if SQLITE_VERSION_NUMBER >= 3024000 + ADD_INT(SQLITE_DBCONFIG_RESET_DATABASE); +#endif +#if SQLITE_VERSION_NUMBER >= 3026000 + ADD_INT(SQLITE_DBCONFIG_DEFENSIVE); +#endif +#if SQLITE_VERSION_NUMBER >= 3028000 + ADD_INT(SQLITE_DBCONFIG_WRITABLE_SCHEMA); +#endif +#if SQLITE_VERSION_NUMBER >= 3029000 + ADD_INT(SQLITE_DBCONFIG_DQS_DDL); + ADD_INT(SQLITE_DBCONFIG_DQS_DML); + ADD_INT(SQLITE_DBCONFIG_LEGACY_ALTER_TABLE); +#endif +#if SQLITE_VERSION_NUMBER >= 3030000 + ADD_INT(SQLITE_DBCONFIG_ENABLE_VIEW); +#endif +#if SQLITE_VERSION_NUMBER >= 3031000 + ADD_INT(SQLITE_DBCONFIG_LEGACY_FILE_FORMAT); + ADD_INT(SQLITE_DBCONFIG_TRUSTED_SCHEMA); +#endif #undef ADD_INT return 0; } @@ -735,7 +742,7 @@ module_exec(PyObject *module) goto error; } - if (PyModule_AddStringConstant(module, "version", PYSQLITE_VERSION) < 0) { + if (PyModule_AddStringConstant(module, "_deprecated_version", PYSQLITE_VERSION) < 0) { goto error; } @@ -743,6 +750,10 @@ module_exec(PyObject *module) goto error; } + if (PyModule_AddIntMacro(module, LEGACY_TRANSACTION_CONTROL) < 0) { + goto error; + } + int threadsafety = get_threadsafety(state); if (threadsafety < 0) { goto error; @@ -774,6 +785,7 @@ error: static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/contrib/tools/python3/src/Modules/_sqlite/module.h b/contrib/tools/python3/src/Modules/_sqlite/module.h index 7deba22ffe..daa22091d3 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/module.h +++ b/contrib/tools/python3/src/Modules/_sqlite/module.h @@ -26,6 +26,8 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#define LEGACY_TRANSACTION_CONTROL -1 + #define PYSQLITE_VERSION "2.6.0" #define MODULE_NAME "sqlite3" diff --git a/contrib/tools/python3/src/Modules/_sqlite/statement.c b/contrib/tools/python3/src/Modules/_sqlite/statement.c index aee460747b..229bfc3b50 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/statement.c +++ b/contrib/tools/python3/src/Modules/_sqlite/statement.c @@ -88,7 +88,6 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql) } self->st = stmt; - self->in_use = 0; self->is_dml = is_dml; PyObject_GC_Track(self); diff --git a/contrib/tools/python3/src/Modules/_sqlite/statement.h b/contrib/tools/python3/src/Modules/_sqlite/statement.h index 5e61227424..11a6464b1a 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/statement.h +++ b/contrib/tools/python3/src/Modules/_sqlite/statement.h @@ -33,7 +33,6 @@ typedef struct { PyObject_HEAD sqlite3_stmt* st; - int in_use; int is_dml; } pysqlite_Statement; diff --git a/contrib/tools/python3/src/Modules/_sqlite/ya.make b/contrib/tools/python3/src/Modules/_sqlite/ya.make index f9aac2dab3..d0d953c7e6 100644 --- a/contrib/tools/python3/src/Modules/_sqlite/ya.make +++ b/contrib/tools/python3/src/Modules/_sqlite/ya.make @@ -2,9 +2,9 @@ LIBRARY() -VERSION(3.11.8) +VERSION(3.12.2) -ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.11.8.tar.gz) +ORIGINAL_SOURCE(https://github.com/python/cpython/archive/v3.12.2.tar.gz) LICENSE(Python-2.0) @@ -14,6 +14,7 @@ PEERDIR( ADDINCL( contrib/libs/sqlite3 + contrib/tools/python3/src/Include/internal ) IF (USE_SYSTEM_PYTHON) |