Я только что отладил ту же проблему: незавершенные операторы не позволяли мне закрыть базу данных SQLite на iPhone. sqlite3_next_stmt
, похоже, ничего не делал, но мне удалось отследить нефинализированные операторы вручную. Мой код базы данных был основан на примере книг SQLite от Apple, особенно с лениво подготовленными утверждениями. Поскольку я делал это для нескольких различных операторов, я решил обернуть эту часть кода во вспомогательный метод, выглядя примерно так:
- (void)updateIntFieldStatement:(sqlite3_stmt *)update_field_statement WithCString:(char*)cString toValue:(int)value {
if (update_field_statement == nil) {
if (sqlite3_prepare_v2(database, cString, -1, &update_field_statement, NULL) != SQLITE_OK) {
NSAssert1(0, @"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
}
}
Я бы тогда назвал этот код так:
[self updateIntFieldStatement:static_statement WithCString:"UPDATE myTable SET myField = ? WHERE pk = ?" toValue:transmitted];
Проблема в том, что static_statement
никогда не изменится, просто останется равным нулю, поэтому будет лениво готовиться снова и снова, и мой код завершения никогда не дойдет до этого. Причиной была эта часть: &update_field_statement
. Мое утверждение было sqlite3_stmt *
, но sqlite3_prepare_v2
использует sqlite3_stmt **
, дескриптор, а не простой указатель. Пример кода от Apple получил дескриптор, взяв адрес указателя, но когда я сделал это в своем вспомогательном методе, я получил дескриптор локального параметра, а не глобальный дескриптор.
Область видимости указателя C: 1, me: 0 ...
Решение состояло в том, чтобы изменить мой вспомогательный метод, чтобы взять ручку:
- (void)updateIntFieldStatement:(sqlite3_stmt **)update_field_statement WithCString:(char*)cString toValue:(int)value {
if (*update_field_statement == nil) {
if (sqlite3_prepare_v2(database, cString, -1, update_field_statement, NULL) != SQLITE_OK) {
NSAssert1(0, @"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
}
}
и затем получите дескриптор в глобальной области видимости:
[self updateIntFieldStatement:&static_statement WithCString:"UPDATE myTable SET myField = ? WHERE pk = ?" toValue:transmitted];
Теперь оператор готовится только один раз, static_statement
назначается правильно, когда это происходит, и затем в конечном итоге завершается, поэтому я могу закрыть базу данных. Надеюсь, это поможет вам или кому-то еще!