Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
bpo-45089: sqlite3 trace callbacks no longer clears exceptions
  • Loading branch information
Erlend E. Aasland committed Sep 2, 2021
commit 059f0cf30f56c1f44ee560074298adacd37f6beb
9 changes: 9 additions & 0 deletions Lib/sqlite3/test/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ def trace(statement):
con2.close()
self.assertEqual(traced_statements, queries)

@with_tracebacks(["ZeroDivisionError", "division by zero"])
def test_trace_bad_handler(self):
cx = sqlite.connect(":memory:")
cx.set_trace_callback(lambda stmt: 5/0)
self.assertRaisesRegex(
sqlite.OperationalError, "trace callback raised an exception",
cx.execute, "select 1"
)


def suite():
tests = [
Expand Down
30 changes: 18 additions & 12 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1002,27 +1002,33 @@ static void _trace_callback(void* user_arg, const char* statement_string)

PyGILState_STATE gilstate = PyGILState_Ensure();

PyObject *py_statement = NULL;
PyObject *ret = NULL;
py_statement = PyUnicode_DecodeUTF8(statement_string,
PyObject *py_statement = PyUnicode_DecodeUTF8(statement_string,
strlen(statement_string), "replace");
if (py_statement) {
ret = PyObject_CallOneArg((PyObject*)user_arg, py_statement);
Py_DECREF(py_statement);
if (py_statement == NULL) {
pysqlite_state *state = pysqlite_get_state(NULL);
if (state->enable_callback_tracebacks) {
PyErr_Print();
}
PyErr_SetString(state->DataError,
"trace callback unable to fetch statement string");
goto exit;
}

if (ret) {
Py_DECREF(ret);
} else {
PyObject *ret = PyObject_CallOneArg((PyObject*)user_arg, py_statement);
Py_DECREF(py_statement);
if (ret == NULL) {
pysqlite_state *state = pysqlite_get_state(NULL);
if (state->enable_callback_tracebacks) {
PyErr_Print();
}
else {
PyErr_Clear();
}
PyErr_SetString(state->OperationalError,
"trace callback raised an exception");
}
else {
Py_DECREF(ret);
}

exit:
PyGILState_Release(gilstate);
#ifdef HAVE_TRACE_V2
return 0;
Expand Down