KhoaNN
KhoaNN

Reputation: 9

Insert data into sqlite database

I'm insert data into sqlite database and I've seen NSLog(@"DONE") on my console result, but I don't see the data update in my sqlite database file. Pls help me !!!

Here my code to save data:

- (void)saveData:(NSString *)_Id
{
    sqlite3_stmt    *statement;
    NSString *_databasePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"data.db"];

    const char *dbpath = [_databasePath UTF8String];

    if (sqlite3_open(dbpath, &db) == SQLITE_OK)
    {

        NSString *insertSQL = [NSString stringWithFormat:
                               @"INSERT INTO MyTable (id) VALUES (\"%@\")", _Id];

        const char *insert_stmt = [insertSQL UTF8String];
        sqlite3_prepare_v2(db, insert_stmt,
                           -1, &statement, NULL);
        if (sqlite3_step(statement) == SQLITE_DONE)
        {
            NSLog(@"DONE");
        } else {
            NSLog(@"Failed to add contact");
        }
        sqlite3_finalize(statement);
        sqlite3_close(db);
    }
}

Upvotes: 1

Views: 986

Answers (1)

Rob
Rob

Reputation: 437592

You are opening the database in your bundle. The bundle is read-only on the device. You must copy the database to your Documents folder (if it doesn't exist there already) and open it from there.

Also be aware that you're dealing with multiple copies of the database (the one in your project, the one in the bundle and now the one in the device/simulator's Documents folder). Make sure you're checking for the inserted record in the correct database (the one in Documents)

As an aside, you should also check to see that sqlite3_prepare_v2 returned SQLITE_OK and if not, log sqlite3_errmsg.

You should also use ? placeholder in your SQL and bind values using sqlite3_bind_text (or, if it's possibly nil, sqlite_bind_null):

- (void)saveData:(NSString *)_Id
{
    sqlite3_stmt    *statement;
    NSString *bundlePath = [[[NSBundle mainBundle] resourcePath ] stringByAppendingPathComponent:@"data.db"];
    NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *documentsPath = [documentsFolder stringByAppendingPathComponent:@"data.db"];
    NSFileManager *fileManager = [NSFileManager defaultManager];

    if (![fileManager fileExistsAtPath:documentsPath isDirectory:NO]) {
        NSError *error;
        if (![fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error]) {
            NSLog(@"database copy failed: %@", error);
        }
    }

    const char *dbpath = [documentsPath UTF8String];

    if (sqlite3_open(dbpath, &db) == SQLITE_OK) {
        const char *insertSql = "INSERT INTO MyTable (id) VALUES (?)";
        if (sqlite3_prepare_v2(db, insertSql, -1, &statement, NULL) != SQLITE_OK) {
            NSLog(@"prepare error: %s", sqlite3_errmsg(db));
        }

        // bind a value to the ? placeholder in the SQL

        if (_Id) {
            if (sqlite3_bind_text(statement, 1, [_Id UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
                NSLog(@"bind text error: %s", sqlite3_errmsg(db));
            }
        } else {
            if (sqlite3_bind_null(statement, 1) != SQLITE_OK) {
                NSLog(@"bind null error: %s", sqlite3_errmsg(db));
            }
        }

        if (sqlite3_step(statement) == SQLITE_DONE) {
            NSLog(@"DONE");
        } else {
            NSLog(@"Failed to add contact: %s", sqlite3_errmsg(db));
        }

        sqlite3_finalize(statement);
        sqlite3_close(db);
    }
}

Most people move that "if database doesn't exist in documents, then copy it from the bundle and open it from there" logic inside a dedicated openDatabase method, but hopefully this illustrates the idea.

Upvotes: 1

Related Questions