"BusyError: cannot rollback savepoint – SQL statements in progress" when using SQLite with APSW

Question:

I’m working with an SQLite database using the Python apsw bindings. The code goes like this:

with apsw.Connection(path) as t:
    c = t.cursor()
    c.execute(...)
    ... more code ...
    if c.execute(...).next()[0]:
        raise Exception

I expect the with statement to put a savepoint and the raise statement to rollback to that savepoint (or, if there’s nothing to raise, commit the transaction). It commits just fine, but when there’s something to raise it refuses to rollback with:

BusyError: BusyError: cannot rollback savepoint - SQL statements in progress

I’m not sure where to look first. As far as I understand the error means there’s another connection that blocks the access, but this doesn’t look so from the code, and, if this was so, wouldn’t it fail on commits as well?

SQLite 3.7.7.1, matching apsw, Python 2.7.

Asked By: Mikhail Edoshin

||

Answers:

Well, I found it:

if c.execute(...).next()[0]:
    raise Exception

The problem is that at the moment I get the next row with next(), the underlying cursor stays active, ready to return more rows. It has to be closed explicitly:

if c.execute(...).next()[0]:
    c.close()
    raise Exception

or implicitly, by reading out all data:

if list(c.execute(...))[0][0]:
    raise Exception

UPDATE. For convenience I wrote a Python class that wraps apsw.Cursor and provides a context manager, so I can write:

with Cursor(connection) as c:
    c.execute(...)
Answered By: Mikhail Edoshin

This was an issue in SQLite itself. It was fixed in March 2012, in version 3.7.11. From the changelog:

Pending statements no longer block ROLLBACK. Instead, the pending statement will return SQLITE_ABORT upon next access after the ROLLBACK.

Answered By: Roger Binns
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.