From f65eac16bf2ffa2cb93214361b45a1d15233164e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 1 Feb 2026 11:04:47 +0000 Subject: [PATCH] Clean up sqlite3 Connection's list of weakrefs to Cursor objects --- Modules/_sqlite/connection.c | 51 +----------------------------------- Modules/_sqlite/connection.h | 7 +---- Modules/_sqlite/cursor.c | 32 ---------------------- 3 files changed, 2 insertions(+), 88 deletions(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index cde06c965ad4e3..93eebb1d6f21bb 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -144,7 +144,6 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=67369db2faf80891]*/ -static int _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void incref_callback_context(callback_context *ctx); static void decref_callback_context(callback_context *ctx); static void set_callback_context(callback_context **ctx_pp, @@ -285,17 +284,10 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, goto error; } - /* Create lists of weak references to cursors and blobs */ - PyObject *cursors = PyList_New(0); - if (cursors == NULL) { - Py_DECREF(statement_cache); - goto error; - } - + /* Create lists of weak references to blobs */ PyObject *blobs = PyList_New(0); if (blobs == NULL) { Py_DECREF(statement_cache); - Py_DECREF(cursors); goto error; } @@ -308,9 +300,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, self->check_same_thread = check_same_thread; self->thread_ident = PyThread_get_thread_ident(); self->statement_cache = statement_cache; - self->cursors = cursors; self->blobs = blobs; - self->created_cursors = 0; self->row_factory = Py_NewRef(Py_None); self->text_factory = Py_NewRef(&PyUnicode_Type); self->trace_ctx = NULL; @@ -392,7 +382,6 @@ connection_traverse(PyObject *op, visitproc visit, void *arg) pysqlite_Connection *self = _pysqlite_Connection_CAST(op); Py_VISIT(Py_TYPE(self)); Py_VISIT(self->statement_cache); - Py_VISIT(self->cursors); Py_VISIT(self->blobs); Py_VISIT(self->row_factory); Py_VISIT(self->text_factory); @@ -417,7 +406,6 @@ connection_clear(PyObject *op) { pysqlite_Connection *self = _pysqlite_Connection_CAST(op); Py_CLEAR(self->statement_cache); - Py_CLEAR(self->cursors); Py_CLEAR(self->blobs); Py_CLEAR(self->row_factory); Py_CLEAR(self->text_factory); @@ -562,11 +550,6 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) return NULL; } - if (_pysqlite_drop_unused_cursor_references(self) < 0) { - Py_DECREF(cursor); - return NULL; - } - if (cursor && self->row_factory != Py_None) { Py_INCREF(self->row_factory); Py_XSETREF(((pysqlite_Cursor *)cursor)->row_factory, self->row_factory); @@ -1067,38 +1050,6 @@ final_callback(sqlite3_context *context) PyGILState_Release(threadstate); } -static int -_pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) -{ - /* we only need to do this once in a while */ - if (self->created_cursors++ < 200) { - return 0; - } - - self->created_cursors = 0; - - PyObject* new_list = PyList_New(0); - if (!new_list) { - return -1; - } - - assert(PyList_CheckExact(self->cursors)); - Py_ssize_t imax = PyList_GET_SIZE(self->cursors); - for (Py_ssize_t i = 0; i < imax; i++) { - PyObject* weakref = PyList_GET_ITEM(self->cursors, i); - if (_PyWeakref_IsDead(weakref)) { - continue; - } - if (PyList_Append(new_list, weakref) != 0) { - Py_DECREF(new_list); - return -1; - } - } - - Py_SETREF(self->cursors, new_list); - return 0; -} - /* Allocate a UDF/callback context structure. In order to ensure that the state * pointer always outlives the callback context, we make sure it owns a * reference to the module itself. create_callback_context() is always called diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h index 703396a0c8db53..a2241bd540669c 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -70,14 +70,9 @@ typedef struct PyObject *statement_cache; - /* Lists of weak references to cursors and blobs used within this connection */ - PyObject *cursors; + /* Lists of weak references to blobs used within this connection */ PyObject *blobs; - /* Counters for how many cursors were created in the connection. May be - * reset to 0 at certain intervals */ - int created_cursors; - PyObject* row_factory; /* Determines how bytestrings from SQLite are converted to Python objects: diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 4611c9e5e3e437..2b41e60fdcad07 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -93,34 +93,6 @@ cursor_cannot_reset_stmt_error(pysqlite_Cursor *cursor, int chain_exceptions) chain_exceptions); } -/*[clinic input] -module _sqlite3 -class _sqlite3.Cursor "pysqlite_Cursor *" "clinic_state()->CursorType" -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c5b8115c5cf30f1]*/ - -/* - * Registers a cursor with the connection. - * - * 0 => error; 1 => ok - */ -static int -register_cursor(pysqlite_Connection *connection, PyObject *cursor) -{ - PyObject *weakref = PyWeakref_NewRef((PyObject *)cursor, NULL); - if (weakref == NULL) { - return 0; - } - - if (PyList_Append(connection->cursors, weakref) < 0) { - Py_CLEAR(weakref); - return 0; - } - - Py_DECREF(weakref); - return 1; -} - /*[clinic input] _sqlite3.Cursor.__init__ as pysqlite_cursor_init @@ -160,10 +132,6 @@ pysqlite_cursor_init_impl(pysqlite_Cursor *self, return -1; } - if (!register_cursor(connection, (PyObject *)self)) { - return -1; - } - self->initialized = 1; return 0;