Skip to content

Sqlite ‘database table is locked’ error

You might think that the following two designs for a routine are equivalent.

First:
[cpp]
int lookup( int nKey )
{
m_qLookup.Reset();
m_qLookup.Bind( 1, nKey );
int rc = m_qLookup.Step();
if( rc != SQLITE_ROW )
return 0;

int n = m_qLookup.GetColumnInt(0);

// some more processing on n

return n;
}
[/cpp]

Second:
[cpp highlihght=”11″]
int lookup( int nKey )
{
int n = 0;

m_qLookup.Bind( 1, nKey );
int rc = m_qLookup.Step();
if( rc == SQLITE_ROW )
{
n = m_qLookup.GetColumnInt(0);

// some more processing on n
}
m_qLookup.Reset();

return n;
}
[/cpp]

Yeah, they’re logically equivalent. It’s no error to Reset() a query before it’s been used, and it’s fine for a query to be in-progress when you Finalize() it at the end of processing. The first way has an early return, which some people find ugly. Personally I think that indenting the extra processing (line 11 in example 2) is uglier, especially when it’s more than a few lines.

Except for the one big difference — that is, that the first version, once called, makes it impossible to drop any table, even a temp table, from the database.

I just ran into this. Apparently having any query in progress (after the first Step() and before any Reset()) creates a lock on the schema which prevents certain schema changes. In particular, adds are OK but drops are not. And the apparent action is non-local — shall I say, spooky action at a distance? In my case the query that was un-Reset was in one module and the code that created, used, and dropped (or rather, failed to drop) the temp table was in another module entirely.

Fortunately for me, I had not merged in anybody else’s code yet, so I knew that the the problem had been caused by something I did recently, and it only took a little while to track down. More fortunately, the code was trivially transformed into something that didn’t leave the query open.

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*