Мое приложение вылетает из следующей строки:
sqlite3_prepare_v2(db, [sql UTF8String], -1, &pStmt, 0);
в методе оболочки sqlite FMDB:
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
if (![self databaseExists]) {
return 0x00;
}
if (inUse) {
[self warnInUse];
return 0x00;
}
[self setInUse:YES];
FMResultSet *rs = nil;
int rc = 0x00;
sqlite3_stmt *pStmt = 0x00;
FMStatement *statement = 0x00;
if (traceExecution && sql) {
NSLog(@"%@ executeQuery: %@", self, sql);
}
if (shouldCacheStatements) {
statement = [self cachedStatementForQuery:sql];
pStmt = statement ? [statement statement] : 0x00;
}
int numberOfRetries = 0;
BOOL retry = NO;
if (!pStmt) {
do {
retry = NO;
const char *sqlStatement = [sql UTF8String];
rc = sqlite3_prepare_v2(db, sqlStatement, -1, &pStmt, 0);
if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
retry = YES;
usleep(20);
if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) {
NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
NSLog(@"Database busy");
sqlite3_finalize(pStmt);
[self setInUse:NO];
return nil;
}
}
else if (SQLITE_OK != rc) {
if (logsErrors) {
NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
NSLog(@"DB Query: %@", sql);
#ifndef NS_BLOCK_ASSERTIONS
if (crashOnErrors) {
NSAssert2(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
}
#endif
}
sqlite3_finalize(pStmt);
[self setInUse:NO];
return nil;
}
}
while (retry);
}
id obj;
int idx = 0;
int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!)
while (idx < queryCount) {
if (arrayArgs) {
obj = [arrayArgs objectAtIndex:idx];
}
else {
obj = va_arg(args, id);
}
if (traceExecution) {
NSLog(@"obj: %@", obj);
}
idx++;
[self bindObject:obj toColumn:idx inStatement:pStmt];
}
if (idx != queryCount) {
NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)");
sqlite3_finalize(pStmt);
[self setInUse:NO];
return nil;
}
[statement retain]; // to balance the release below
if (!statement) {
statement = [[FMStatement alloc] init];
[statement setStatement:pStmt];
if (shouldCacheStatements) {
[self setCachedStatement:statement forQuery:sql];
}
}
// the statement gets closed in rs's dealloc or [rs close];
rs = [FMResultSet resultSetWithStatement:statement usingParentDatabase:self];
[rs setQuery:sql];
NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs];
[openResultSets addObject:openResultSet];
statement.useCount = statement.useCount + 1;
[statement release];
[self setInUse:NO];
return rs;
}
Приложение вылетает из-за EXC_BAD_ACCESS. Я пытался выяснить, почему, отлаживая с помощью NSZombieEnabled и malloc_history, но это не дает мне никаких ответов. Кроме того, отладчик сообщает мне, что в переменной sql имеется очень большое количество сохраненных значений (что, вероятно, связано с тем, что это статический NSString), поэтому EXC_BAD_ACCESS не должен быть из-за чрезмерного освобождения объекта sql.
Есть ли у кого-нибудь идеи, как продолжить отладку, чтобы выяснить, в чем проблема?