8000 gh-105539: Emit ResourceWarning if sqlite3 database is not closed explicitly by erlend-aasland · Pull Request #108015 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-105539: Emit ResourceWarning if sqlite3 database is not closed explicitly #108015

8000
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

Merged
merged 12 commits into from
Aug 22, 2023
Merged
Prev Previous commit
Next Next commit
Pull in main
  • Loading branch information
erlend-aasland committed Aug 21, 2023
commit 6f6cd828b6dc1e5a806d57a0e9798e65987934b5
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ sqlite3
object is not :meth:`closed <sqlite3.Connection.close>` explicitly.
(Contributed by Erlend E. Aasland in :gh:`105539`.)

tkinter
-------

* Add :mod:`tkinter` widget methods:
:meth:`!tk_busy_hold`, :meth:`!tk_busy_configure`,
:meth:`!tk_busy_cget`, :meth:`!tk_busy_forget`,
:meth:`!tk_busy_current`, and :meth:`!tk_busy_status`.
(Contributed by Miguel, klappnase and Serhiy Storchaka in :gh:`72684`.)

traceback
---------

Expand Down
63 changes: 38 additions & 25 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,

PyTypeObject *tp = Py_TYPE(self);
tp->tp_clear((PyObject *)self);
if (self->db) {
connection_close(self);
if (connection_close(self) < 0) {
return -1;
}
self->initialized = 0;
}

// Create and configure SQLite database object.
Expand Down Expand Up @@ -453,22 +452,30 @@ remove_callbacks(sqlite3 *db)
static int
connection_close(pysqlite_Connection *self)
{
assert(self->db);
if (self->db == NULL) {
return 0;
}

int rc = 0;
if (self->autocommit == AUTOCOMMIT_DISABLED &&
!sqlite3_get_autocommit(self->db))
{
(void)connection_exec_stmt(self, "ROLLBACK");
if (connection_exec_stmt(self, "ROLLBACK") < 0) {
rc = -1;
}
}

free_callback_contexts(self);

sqlite3 *db = self->db;
self->db = NULL;

Py_BEGIN_ALLOW_THREADS
int rc = sqlite3_close_v2(db);
assert(rc == SQLITE_OK), (void)rc;
/* 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
Expand All @@ -477,24 +484,30 @@ connection_finalize(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. */
if (con->db) {
/*
* Before implicitly closing, make sure we're not accidentally part
* of the interpreter tear-down; in that case, we must not call back
* into Python code.
*/
if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) {
remove_callbacks(con->db);
if (PyErr_ResourceWarning(self, 1, "unclosed database in %R", self)) {
/* Spurious errors can appear at shutdown */
if (PyErr_ExceptionMatches(PyExc_Warning)) {
PyErr_WriteUnraisable(self);
}
if (PyErr_ResourceWarning(self, 1, "unclosed database in %R", self)) {
/* Spurious errors can appear at shutdown */
if (PyErr_ExceptionMatches(PyExc_Warning)) {
PyErr_WriteUnraisable(self);
}
}
if (connection_close(con) < 0) {
if (teardown) {
PyErr_Clear();
}
else {
PyErr_WriteUnraisable((PyObject *)self);
}
connection_close(con);
}

PyErr_SetRaisedException(exc);
}

Expand Down Expand Up @@ -654,8 +667,8 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)

pysqlite_close_all_blobs(self);
Py_CLEAR(self->statement_cache);
if (self->db) {
connection_close(self);
if (connection_close(self) < 0) {
return NULL;
}

Py_RETURN_NONE;
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.
0