使用SQLITE_LOCKED在iOS上使用fmbd删除SQLite索引失败

时间:2013-05-22 17:20:32

标签: ios sqlite fmdb

我在删除我在iOS应用程序中在SQLite中创建的索引时遇到了一些麻烦。我正在使用fmdb

尝试删除索引时,sqlite3_step始终返回SQLITE_LOCKED。结果,fmdb被一个无限循环捕获,它不断尝试重试drop语句(每次sqlite3_step返回SQLITE_LOCKED),语句永远不会成功。

据我所知,在drop语句正常运行之前没有其它进程触及数据库和语句而没有问题。我错过了什么?

这几乎是代码失败的逐字副本:

[db open];
/* ... */
[db executeUpdate:@"DROP INDEX IF EXISTS bookmark_hash_idx;"];
[db close];

db是指向文档目录中sqlite数据库的指针。

这是来自fmdb的相关代码,如果它有用:

do {
    rc      = sqlite3_step(pStmt);
    retry   = NO;

    if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
        // this will happen if the db is locked, like if we are doing an update or insert.
        // in that case, retry the step... and maybe wait just 10 milliseconds.
        retry = YES;
        if (SQLITE_LOCKED == rc) {
            rc = sqlite3_reset(pStmt);
            if (rc != SQLITE_LOCKED) {
                NSLog(@"Unexpected result from sqlite3_reset (%d) eu", rc);
            }
        }
        /* ... */
    }
    /* ... */
} while (retry);

1 个答案:

答案 0 :(得分:6)

您可能有打开的结果集阻止DROP INDEX通过。来自SQLite docs

  

“DROP TABLE”例外

     

当调用sqlite3_step()返回SQLITE_LOCKED时,几乎总是适合调用sqlite3_unlock_notify()。但是有一个例外。执行“DROP TABLE”或“DROP INDEX”语句时,SQLite会检查是否存在属于同一连接的任何当前正在执行的SELECT语句。如果有,则返回SQLITE_LOCKED。在这种情况下,没有“阻塞连接”,因此调用sqlite3_unlock_notify()会导致立即调用unlock-notify回调。如果应用程序然后重新尝试“DROP TABLE”或“DROP INDEX”查询,则结果可能是无限循环。

您应该在closeOpenResultSets对象上调用FMDatabase以确保在删除索引之前关闭所有打开的结果集。