Open lciti opened 8 years ago
It looks like the following does the job:
diff --git a/src/connection.c b/src/connection.c
index 9ca3afa..e61da6f 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1578,6 +1578,10 @@ pysqlite_connection_exit(pysqlite_Connection* self, PyObject* args)
result = PyObject_CallMethod((PyObject*)self, method_name, "");
if (!result) {
+ result = PyObject_CallMethod((PyObject*)self, "rollback", "");
+ if (result) {
+ Py_DECREF(result);
+ }
return NULL;
}
Py_DECREF(result);
The pysqlite3 context manager does not perform a rollback when a transaction fails because the database is locked by some other process performing non-DML statements (e.g. during the sqlite3 command line .dump method).
To reproduce the problem, open a terminal and run the following:
Leave this shell running and run the python3 interpreter from a different shell, then type:
You should receive the following:
Without exiting python, switch back to the first shell and kill the
'echo ... | sqlite3'
process. Then run:you should get:
This means that the python process never executed a
rollback
and is still holding the lock. To release the lock one can exit python (clearly, this is not the intended behaviour of the context manager).I believe the reason for this problem is that the exception happened in the implicit
commit
that is run on exiting the context manager, rather than inside it. In fact the exception is in thepass
line rather than in theexecute
line. This exception did not trigger arollback
because the it happened afterpysqlite_connection_exit
checks for exceptions.The expected behaviour (pysqlite3 rolling back and releasing the lock) is recovered if the initial blocking process is a Data Modification Language (DML) statement, e.g.:
because this raises an exception at the
execute
time rather than atcommit
time.To fix this problem, I think the
pysqlite_connection_exit
function in src/connection.c should handle the case when the commit itself raises an exception, and invoke a rollback.