iPhone 上的 SQLite3 - 插入返回错误代码 8 尝试写入只读数据库
所以,我已经在这件事上苦苦挣扎了大约一周了。
我正在编写一个 iPhone 应用程序,其中有一个 sqlite 数据库。我可以打开数据库并从中读取(我通过命令行/终端在其中放入一些测试数据),选择特定数据等。但是,我不能做的是从手机插入数据库。当我执行 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:“”尝试写入只读数据库。 “
我还尝试了通常的重新启动、清理项目、重置模拟器数据。我什至进入我的模拟器目录并手动删除所有应用程序数据。当我尝试返回时,它识别出数据库不存在”那里并复制了它,但我仍然 错误
编辑:
我刚刚注意到,如果我在 checkDatabase 方法中执行此操作:
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(@"error = %@",error);
它会导致模拟器在第一次运行时崩溃(在执行内容重置后),但每次之后它都会恢复上述 没有崩溃。所以也许我的 checkDatabase 方法做错了。??:(它从来没有告诉我错误消息的输出。
So, I have been beating my head against the wall on this for about a week now.
I'm writing an iPhone app that has an sqlite database in it. I'm able to open the database and read from it (I put some test data in there through via the command line / terminal), select specific data, etc. But, what I cannot do is insert into the database from the phone. When I execute sqlite3_exec(...) it returns error code 8 "attempt to write a readonly database."
I had read other questions on here saying that I was using the Main Bundle's database and not the users database, and that the simulator will often times just "let you do it" while on a live device you'll get an error. Well, that's not what's happening in my case - I'm getting this error while running on the simulator. And from what I can tell my code to check the database is exactly as a lot of others recommend it to be.
Here is the code I use to verify the database exists, and if it doesn't I copy it:
// 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];
}
When I go to insert data using this:
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 returns with the above mentioned error code 8: ""attempt to write a readonly database."
I've also tried the usual restarts, cleaning the project, resetting the simulator data. I even went in to my Simulator directory and deleted all the application data out manually. When I tried to go back in, it recognized the database wasn't there and copied it over, but I still get that error.
EDIT:
I've just noticed that if I do this in the checkDatabase method:
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(@"error = %@",error);
it causes the simulator to crash the first go around (after doing a content reset), but each time after that it resumes the above error with no crashes. So maybe I am doing something wrong with my checkDatabase method. ?? :( It never tells me the output of the error message.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试将 open 函数更改为此
或基本上使用简单的 open 函数
希望有帮助:)
try to change the open function to this
or basically use the trivial open function
hope that helps :)
我尝试了您的代码,但在以下行中失败, open = 21 (SQLITE_MISUSE) :
因为您将 -1 传递给了 flags 参数。它应该是 SQLITE_OPEN_READWRITE。
我还有一些意见。
这些版本不是必需的,因为您不需要分配/初始化、保留或复制它们。
对于 SQL,您应该使用 sqlite3_prepare_v2 并绑定参数而不是 stringWithFormat: 。
只要有可能,您应该使用符号常量 (SQLITE_OK) 而不是幻数 (0)。
您应该在调用 copyItemAtPath: 之前初始化 error = nil,因为复制操作成功时 error 不会更改。
I tried your code, and it failed with open = 21 (SQLITE_MISUSE) in the following line:
Because you pass -1 to flags parameter. It should be SQLITE_OPEN_READWRITE.
I have some more comments.
These release's are not necessary, because you don't alloc/init, retain, or copy them.
You should use sqlite3_prepare_v2 and bind parameters instead of stringWithFormat: for SQL.
Whenever possible, you should use symbolic constant (SQLITE_OK) instead of magic number (0).
You should initialize error = nil before calling copyItemAtPath: because error is not changed when the copy operation succeeds.