2011-12-06 49 views
1

所以,我一直在我的頭靠在牆上,大約一個星期了。iPhone上的SQLite3 - 插入返回錯誤代碼8試圖寫一個只讀數據庫

我正在寫一個iPhone應用程序,它有一個sqlite數據庫。我可以打開數據庫並從中讀取數據(我通過命令行/終端將一些測試數據放在那裏),選擇特定的數據等。但是,我不能做的是從手機插入數據庫。當我執行sqlite3_exec(...)時,它會返回錯誤代碼8「嘗試寫入只讀數據庫」。

我在這裏讀過其他問題,說我使用的是Main Bundle的數據庫而不是用戶數據庫,而且模擬器通常只是「讓你這樣做」,而在現場設備上,你會得到一個錯誤。那麼,我的情況並非如此 - 我在模擬器上運行時遇到了這個錯誤。從我能告訴我的代碼來檢查數據庫的方式與其他許多人推薦的一樣。

下面是我用驗證數據庫中存在的代碼,如果沒有我複製:

// 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:「」試圖寫一個只讀數據庫。「

我也嘗試了通常的重新啓動,清理項目,重新設置模擬器數據,甚至進入我的Simu lator目錄並手動刪除所有應用程序數據。當我試圖回去時,它認識到數據庫不在那裏並且複製了它,但是我仍然遇到了這個錯誤。

編輯:

我剛剛注意到,如果我這樣做的checkDatabase方法:

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

它會導致模擬器崩潰首次面世(做內容復位後)但每次之後都會恢復上述錯誤而不會崩潰。所以也許我做了一些錯誤的checkDatabase方法。 ?? :(它從不告訴我的錯誤消息的輸出

回答

1

我想你的代碼,並將其與開放式= 21(SQLITE_MISUSE)在下面的行失敗:

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

因爲你傳遞-1標誌的參數,它應該是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:因爲複製操作成功時錯誤不會更改。

+0

學習Objective-C /諷刺的樂趣。非常感謝您的意見!我將測試這些並在回覆之後回覆或標記回答。 – rollhax

+0

這工作!我覺得自己像個白癡。再次感謝! – rollhax

2

嘗試改變open函數這個

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

或基本上用瑣碎的開放功能

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

希望幫助:)

相關問題