Hi sqlite people!
I haven't yet had the chance to say so but I want to thank Richard and all
other contributors - sqlite has truly changed the way I'm able to write
software. It rocks. Thank you.
Ok, on to my question. I have two programs, one that fills an sqlite
database, one that displays the result to users. These occasionally get into
situations with locks, sometimes prolonged. I've decided that users get to
deal with this, and should have their queries timed out after 10 seconds.
The program that fills the database can't deal with it, so it has an eternal
timeout.
My question is: can sqlite3_step return SQLITE_BUSY, without ever calling my
handler? It certainly does so in my application, which is written in single
threaded c++ and runs under linux 2.6.10-rc2, Debian sid, with sqlite
3.0.8. It happens with 3.0.7 as well.
I have only one sqlite instance in the process.
This is my handler:
extern "C" {
static int eternityHandler(void *, int)
{
cerr<<"timeout handler called"<<endl;
usleep(250);
return 1;
}
}
This is how I open the database:
int rc;
if((rc=sqlite3_open( database.c_str(), &d_db))) {
string error=sqlite3_errmsg(d_db);
sqlite3_close(d_db); // weird eh?
throw sPerrorException( "Could not connect to the SQLite database '" +
database + "': " + error);
}
sqlite3_busy_handler(d_db, &eternityHandler, 0);
This is how I do a query:
sqlite3_busy_handler(d_db, &eternityHandler, 0); // install it again, to be
sure
d_rc=sqlite3_prepare( d_db, query.c_str(), query.length(), &d_statement, 0);
if(d_rc != SQLITE_OK)
throw sPerrorException( "Could not create SQLite VM for query '"+query+"':
" + sqlite3_errmsg(d_db));
if ( !d_statement ) {
string report( "Unable to compile SQLite statement" );
throw sPerrorException( report );
}
d_rc = sqlite3_step( d_statement );
if(d_rc == SQLITE_BUSY) {
throw sPerrorException("SQL statement '"+query+"' timed out 1");
}
My belief from the documentation is that sqlite3_step should never ever
return SQLITE_BUSY in the case above, and instead call the eternityHandler
until the database can be opened. But it does return SQLITE_BUSY, as far as
I can determine, immediately without ever calling the busy handler. In other
cases I do see the busy handler being called however.
The documentation for sqlite3_busy_handler only mentions sqlite3_exec,
the part on sqlite3_step however says that it, too, calls the busy_handler:
If the busy callback is not NULL, then sqlite3_exec() invokes the callback
with two arguments. The second argument is the number of prior calls to the
busy callback for the same lock. If the busy callback returns 0, then
sqlite3_exec() immediately returns SQLITE_BUSY. If the callback returns
non-zero, then sqlite3_exec() tries to open the table again and the cycle
repeats.
vs
SQLITE_BUSY means that the database engine attempted to open a locked
database and there is no busy callback registered. Call sqlite3_step() again
to retry the open.
Any help would be appreciated - if need be I could also submit a patch to
update the documentation. Thanks.
--
http://www.PowerDNS.com Open source, database driven DNS Software
http://lartc.org Linux Advanced Routing & Traffic Control HOWTO