iPhone上的SQLite3 - 插入返回错误代码8尝试编写只读数据库

时间:2011-12-06 22:38:04

标签: iphone database sqlite insert readonly

所以,我已经在这上面撞墙了大约一个星期了。

我正在编写一个包含sqlite数据库的iPhone应用程序。我能够打开数据库并从中读取(我通过命令行/终端输入一些测试数据),选择特定数据等。但是,我不能做的是从手机插入数据库。当我执行sqlite3_exec(...)时,它返回错误代码8“尝试写一个只读数据库。”

我在这里已经阅读了其他问题,说我使用的是主捆绑包的数据库,而不是用户数据库,并且模拟器经常只是“让你这么做”而在实时设备上你会收到错误。嗯,这不是我的情况下发生的事情 - 我在模拟器上运行时遇到此错误。从我可以告诉我的代码来检查数据库,正如许多其他人推荐的那样。

以下是我用来验证数据库存在的代码,如果不存在,我将其复制:

// initialize db (if not already)
+(void) checkDatabase {
    // setup some variables
    Boolean success;
    dbName = @"daarma.sqlite";
    NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDirectory, YES);
    // I have tried this with both NSUserDirectory and NSUserDomainMask, desn't seem to make a difference
    NSString *documentsDir = [documentPath objectAtIndex:0];
    dbPath = [documentsDir stringByAppendingPathComponent:dbName];
    //    dbPath = [[NSBundle mainBundle] pathForResource:@"daarma" ofType:@"sqlite"];

    // check to see if the database already exists
    NSFileManager *fm = [NSFileManager defaultManager];
    success = [fm fileExistsAtPath:dbPath];
    if(success) {
        NSLog(@"Database exists, returning.");
        return;
    }

    // if not, we create it
    NSLog(@"Creating database in user profile...");
    NSString *dbPathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName];
    [fm copyItemAtPath:dbPathFromApp toPath:dbPath error:nil];    

    [fm release];
    [documentPath release];
    [documentsDir release];
}

当我使用它来插入数据时:

sqlite3 *db;
int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL);
if(open == 0) {
    NSLog(@"open, inserting");
    NSString *sql = [NSString stringWithFormat:@"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"];
    int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL);
    NSLog(@"exec = %d",exec);
}
sqlite3_close(db);

exec返回上面提到的错误代码8:“”尝试编写只读数据库。“

我还尝试了通常的重启,清理项目,重置模拟器数据。我甚至进入了我的Simulator目录并手动删除了所有应用程序数据。当我试图重新进入时,它认识到数据库不在那里并将其复制过来,但我仍然遇到了这个错误。

编辑:

我刚刚注意到,如果我在checkDatabase方法中执行此操作:

NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error]; 
NSLog(@"error = %@",error);

它导致模拟器在第一次运行时崩溃(在执行内容重置之后),但每次之后它恢复上述错误而没有崩溃。所以也许我在使用checkDatabase方法做错了。 ?? :(它永远不会告诉我错误信息的输出。

2 个答案:

答案 0 :(得分:2)

尝试将open功能更改为此

sqlite3_open_v2([dbPath UTF8String], &db, SQLITE_OPEN_READWRITE , NULL);

或基本上使用普通的开放功能

Sqlite3_open([dbPath UTF8String],&db);// this should do the job

希望有所帮助:)

答案 1 :(得分:1)

我尝试了您的代码,但在以下行中使用open = 21(SQLITE_MISUSE)失败了:

int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL);

因为您将-1传递给flags参数。它应该是SQLITE_OPEN_READWRITE。

我还有一些意见。

[fm release];
[documentPath release];
[documentsDir release];

这些版本不是必需的,因为您不会分配/初始化,保留或复制它们。

NSString *sql = [NSString stringWithFormat:@"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"];
int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL);

你应该使用sqlite3_prepare_v2并绑定参数而不是stringWithFormat:for SQL。

if(open == 0) { ... }

尽可能使用符号常量(SQLITE_OK)而不是幻数(0)。

NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error]; 
NSLog(@"error = %@",error);

您应该在调用copyItemAtPath之前初始化error = nil:因为复制操作成功时错误不会更改。