The update thread returns from its UPDATE command (within a transaction) with SQLITE_BUSY when it sees a pending lock. The insert thread returns SQLITE_BUSY from END TRANSACTION when it can't get an exclusive lock.
Attached is a simple C program that demonstrates this. I open two database handles on the same file (with a table "test" with a single column "num") and do:
db1: BEGIN TRANSACTION; db2: BEGIN TRANSACTION; db1: INSERT INTO test VALUES ( 1 );
At this point, both of these return SQLITE_BUSY:
db2: UPDATE test SET num = 2 WHERE num = 1; db1: END TRANSACTION;
Is this a bug? Or do I have to do something with sqlite 3 I didn't with 2?
Thanks, -Dave
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
#include "sqlite3.h" int execQuery(sqlite3* db, char* query) { char* err; int rc = sqlite3_exec(db, query, NULL, NULL, &err); if ( rc != SQLITE_OK ) { printf("sqlite3_exec error: %s\n", err); sqlite3_free(err); return 0; } return 1; } int main() { sqlite3* db1; sqlite3* db2; int rc; unlink("./test.db"); unlink("./test.db-journal"); rc = sqlite3_open("test.db", &db1); if ( rc != SQLITE_OK ) { printf("thread: Couldn't open database1\n"); exit(-1); } execQuery(db1, "CREATE TABLE test ( num int );"); rc = sqlite3_open("test.db", &db2); if ( rc != SQLITE_OK ) { printf("thread: Couldn't open database2\n"); exit(-1); } execQuery(db1, "BEGIN TRANSACTION;"); execQuery(db2, "BEGIN TRANSACTION;"); execQuery(db1, "INSERT INTO test VALUES ( 1 );"); while ( !execQuery(db2, "UPDATE test SET num = 2 WHERE num = 1;") && !execQuery(db2, "END TRANSACTION;") && !execQuery(db1, "END TRANSACTION;") ) usleep(1000); execQuery(db2, "END TRANSACTION;"); return 0; }