我在我的应用程序中使用了sqlite DB,我需要调用两个同时进行的查询,但是我给出了错误:由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'错误准备语句'
在按钮事件发生后从DB中选择行和在DB中插入行时,我每隔10秒运行一次计时器。
我的代码段为:
viewWillAppear
中的:
int result2 = sqlite3_open([dbPath UTF8String], &database);
if (result2 != SQLITE_OK) {
NSLog(@"Failure in connecting to the database with result %d",result2);
}
else {
NSLog(@ "Succesfully opened connection to DB") ;
}
和viewWillDisappear
:
int result = sqlite3_close(database);
if (result != SQLITE_OK){
NSLog(@"Failure in closing connection to database. Result %d",result);
}
else {
NSLog(@"Successfully closed DB connection") ;
}
Inserting rows
:
NSString *queryInsert = [NSString stringWithFormat: @"insert into mail_snoozlist (msgBody,msgSubject, msgSender,msgTo,msgDate,snoozTime) values('%@','%@','%@','%@','%@','%@')",strBody,msgSub,msgFrom,msgTo,strMsgDate,stringFromDate];
NSLog(@"queryInsert:%@",queryInsert);
const char *sql = [queryInsert UTF8String];
if(sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_step(statement);
sqlite3_reset(statement);
} else {
NSAssert1(0,@"error preparing statement",sqlite3_errmsg(database));
return;
}
sqlite3_finalize(statement);
和Selecting rows
:
NSString *querySQL2 = [NSString stringWithFormat: @"Select * from mail_snoozlist WHERE snoozTime = '%@'",_snoozTime];
NSLog(@"querySql:%@",querySQL2);
if (sqlite3_prepare_v2(database, [querySQL2 UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
Message *obj = [[Message alloc] init];
NSString *msgBody=[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
obj.msgBody= msgBody;
NSString *msgSub=[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)];
obj.msgSub= msgSub;
NSString *msgSender=[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)];
obj.msgFrom= msgSender;
NSString *msgTo=[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 4)];
obj.msgTo= msgTo;
NSString *msgDate=[[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 5)];
obj.msgDate= msgDate;
[listOfItems addObject:obj];
[self.tableView reloadData];
}
sqlite3_reset(statement);
sqlite3_finalize(statement);
任何人都可以帮我解决这个问题。
谢谢!
答案 0 :(得分:1)
您应该更改NSAssert
语句以包含错误消息:
NSAssert1(0, @"error preparing statement: %s", sqlite3_errmsg(database));
一旦你这样做,你应该得到一个有意义的回应,这将有助于你诊断问题。
不查看sqlite3_errmsg
消息,很难诊断问题。它可能像列名或表名中的拼写错误一样简单,也可能因为找不到表而复杂,因为在创建数据库时未找到该数据库,因此创建了一个空白数据库(没有该表)。在我们看到错误消息之前很难说。
顺便说一句,您不应该使用stringWithFormat
构建SQL,因为您将自己打开SQL注入攻击,并且如果其中任何文本值中包含撇号,则会出现问题。您应该使用?
占位符而不是printf样式格式化程序,然后使用sqlite3_bind_text
调用将值绑定到这些列:
NSString *queryInsert = @"insert into mail_snoozlist (msgBody,msgSubject, msgSender,msgTo,msgDate,snoozTime) values(?, ?, ?, ?, ?, ?)";
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
NSAssert1(0,@"error preparing statement: %s",sqlite3_errmsg(database));
return;
}
// for these 6 sqlite3_bind function calls, if any of these strings can be `nil`, then you'd
// want to call sqlite3_bind_null if that's the case, rather than sqlite3_bind_text
if (sqlite3_bind_text(statement, 1, [strBody UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 1: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 2, [msgSub UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 2: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 3, [msgFrom UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 3: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 4, [msgTo UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 4: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 5, [strMsgDate UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 5: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 6, [stringFromDate UTF8String], -1, NULL) != SQLITE_OK) {
NSAssert1(0,@"error binding 6: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_step(statement) != SQLITE_DONE) {
NSAssert1(0,@"error stepping: %s",sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
我用insert
语句说明了这个问题,但同样也应该用select
语句来解决。
答案 1 :(得分:0)
添加这两个方法,并在插入和选择之前用insert方法调用它们,
- (void) createEditableCopyOfDatabaseIfNeeded
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"dbname.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
//{
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"dbname.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
// }
if (!success)
{
NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
}
- (void)initializeDatabase
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"dbname.sqlite"];
sqlite3_open([path UTF8String], &database);
}