SQLite Forum

When using sqlite3_step(stmt) inside a transaction my busy-handler is not being called
Login
> I understand the lock, but why deadlock? Wouldn't calling my busy handler resolve this lock?

As was mentioned above, a deadlock (as in, a permanent deadlock that cannot be resolved no matter how long you wait) will occur when two read connections/transactions both try to write to the database. Consider the following scenario:

1. Connection A starts a (deferred) transaction. It starts with no database locks.
2. Connection B does the same. It too starts wit no database locks.
3. Connection A reads from the database to check if a particular record of table Foo exists. Consequently, it upgrades to a shared lock.
4. Connection B does the same. It also upgrades to a shared lock. (Note that any number of connections may hold shared locks in parallel.)
5. Connection A writes the missing record to the database. Thus it upgrades to a reserve lock. But it must wait for all pending shared locks (i.e., the one held by connection B) to be released before proceeding with the write.
6. Connection B tries to write the missing record as well. But it cannot upgrade to a reserve lock, because connection A already has one.

At this point, we have a deadlock - connection A is waiting for connection B to release its shared lock, and connection B is waiting for connection A to release its reserve lock. No amount of waiting will ever resolve this. SQLite detects the situation, and immediately returns SQLITE_BUSY to connection B rather than bothering with its busy handler.

Note that the above example describes what happens when using a rollback journal. With write-ahead logging, you don't have a deadlock issue per se, but since both writes cannot be allowed to proceed without violating the isolation property of ACID, it still fails anyway.

> In any case - if my busy handler is not being called it means that I cannot use this DEFFERED transaction, and alwys alternate to IMMEDIATE transaction...

If your transaction will only be reading, you can use BEGIN DEFERRED without issue. However, if you transaction will be writing to the database at all, it is best to use BEGIN IMMEDIATE to avoid this issue.