Search code examples
iphonedatabasesqlitelocked

iPhone sqlite3 locked, can only read, not write


So I have been working on this project for a short while now. I have no problems with reading data from the DB, and formatting it into UITableViews and what not. But now I am wanting also to write to the DB as well. The problem is I keep getting a "Database is Locked" error from sqlite. After messing around with the original version I had the face-palm moment by realizing my database was in the bundle and therefore not writable. So I relocated the DB to the Apps Documents folder, which is writeable. But now I still get the same "Database is Locked" sql error. I only open and close the DB when necessary. And as far as I can tell, I don't leave it open anywhere. Below is the code where I am wanting to do updates. Any thoughts?

    - (BOOL) loanBookTo:(NSString *)newborrower{
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *path = [documentsDirectory stringByAppendingPathComponent:@"books.sqlite"];   

        if([[NSFileManager defaultManager] fileExistsAtPath:path]){
            NSLog(@"File Exists at: %@", path);
        }


        if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {  
            NSString *mySQL = @"UPDATE BOOKS SET LOANED = 1, BORROWER = \"<BORROWER>\" where ISBN = \"<ISBN>\"";
            mySQL = [mySQL stringByReplacingOccurrencesOfString:@"<ISBN>" withString:self.isbn];
            mySQL = [mySQL stringByReplacingOccurrencesOfString:@"<BORROWER>" withString:newborrower];
            const char *sql = [mySQL UTF8String];
            char* errmsg;
            sqlite3_exec(database, sql, NULL, NULL, &errmsg);

            // Q. Database is locked. Why?
            // A. Because it is in the Bundle and is ReadOnly.
            //    Need to write a copy to the Doc folder.

            // Database is Locked error gets spit out here. 
            printf(errmsg);
            sqlite3_close(database);
        }   
        return NO;
    }

Solution

  • Open the database once at the start of your app, then close it in applicationWillTerminate of the AppDelegate.

    After every exec you will want to do a reset to clear the connection state.

    Take a look at the SQLiteBooks sample app, it is coded this way.