可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How to insert data into table in sqlite iPhone?
I am trying following, but its failing:
NSString *query=[NSString stringWithFormat:@"insert into %@ (name) values ('%@')", table name,myName ]; sqlite3 *database; sqlite3_stmt *createStmt = nil; if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) { if (createStmt == nil) { if (sqlite3_prepare_v2(database, [query UTF8String], -1, &createStmt, NULL) != SQLITE_OK) { return NO; } sqlite3_exec(database, [query UTF8String], NULL, NULL, NULL); return YES; } return YES; }else { return NO; }
I have created table in following manner:
create table if not exists myDets (dets_id integer primary key asc, name text);
I am also using Firefox SQLite plugin to check db. When I try to insert record via firefox into my db it gives me following error:
Failed to insert values Exception Name: NS_ERROR_STORAGE_IOERR Exception Message: Component returned failure code: 0x80630002 (NS_ERROR_STORAGE_IOERR) [mozIStorageStatement.execute]
Badly stuck :(
Also, i am running this on iPhone simulator, does it matter?
Please help
Thanks in advance.
回答1:
- Use parameters and don't string format your update statement
- Add lots of tracing, check return codes and check for error codes (you're question isn't clear what error, issue you're hitting on iPhone).
- use sqlite3_errmsg to get error messages
- construct your dbPath and log it out. Ensure you can open the db from terminal under the emulator. Remember that sqlite will create a database in memory passively so if you're path is off and the db doesn't exist it can be confusing.
- print out your update statement and try it from sqlite cmdline app in terminal in the path you logged.
- if you're putting the db in the main bundle resources, it's a template and needs to be copied in order to open and write to it.
Here's an update function from a sample of mine:
- (void)updateContact: (Contact*)contact error:(NSError**)error { if (![self ensureDatabaseOpen:error]) { return; } NSLog(@">> ContactManager::updateContact"); // prep statement sqlite3_stmt *statement; NSString *querySQL = @"update contacts set name=?,address=?,phone=? where id=?"; NSLog(@"query: %@", querySQL); const char *query_stmt = [querySQL UTF8String]; // preparing a query compiles the query so it can be re-used. sqlite3_prepare_v2(_contactDb, query_stmt, -1, &statement, NULL); sqlite3_bind_text(statement, 1, [[contact name] UTF8String], -1, SQLITE_STATIC); sqlite3_bind_text(statement, 2, [[contact address] UTF8String], -1, SQLITE_STATIC); sqlite3_bind_text(statement, 3, [[contact phone] UTF8String], -1, SQLITE_STATIC); sqlite3_bind_int64(statement, 4, [[contact id] longLongValue]); NSLog(@"bind name: %@", [contact name]); NSLog(@"bind address: %@", [contact address]); NSLog(@"bind phone: %@", [contact phone]); NSLog(@"bind int64: %qi", [[contact id] longLongValue]); // process result if (sqlite3_step(statement) != SQLITE_DONE) { NSLog(@"error: %s", sqlite3_errmsg(_contactDb)); } sqlite3_finalize(statement); }
In the sample, the db is copied from resources to a path and opened. Here's the ensure opened function I use to do that:
- (BOOL)ensureDatabaseOpen: (NSError **)error { // already created db connection if (_contactDb != nil) { return YES; } NSLog(@">> ContactManager::ensureDatabaseOpen"); if (![self ensureDatabasePrepared:error]) { return NO; } const char *dbpath = [_dbPath UTF8String]; if (sqlite3_open(dbpath, &_contactDb) != SQLITE_OK && error != nil) { *error = [[[NSError alloc] initWithDomain:@"ContactsManager" code:1000 userInfo:nil] autorelease]; return NO; } NSLog(@"opened"); return YES; } - (BOOL)ensureDatabasePrepared: (NSError **)error { // already prepared if ((_dbPath != nil) && ([[NSFileManager defaultManager] fileExistsAtPath:_dbPath])) { return YES; } // db in main bundle - cant edit. copy to library if !exist NSString *dbTemplatePath = [[NSBundle mainBundle] pathForResource:@"contacts" ofType:@"db"]; NSLog(@"%@", dbTemplatePath); NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject]; _dbPath = [libraryPath stringByAppendingPathComponent:@"contacts.db"]; NSLog(@"dbPath: %@", _dbPath); // copy db from template to library if (![[NSFileManager defaultManager] fileExistsAtPath:_dbPath]) { NSLog(@"db not exists"); NSError *error = nil; if (![[NSFileManager defaultManager] copyItemAtPath:dbTemplatePath toPath:_dbPath error:&error]) { return NO; } NSLog(@"copied"); } return YES; }
回答2:
- (NSString *) getDBPath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); NSString *documentsDir = [paths objectAtIndex:0]; return [documentsDir stringByAppendingPathComponent:@"iHadDB.sqlite"]; } - (void) insertValueToDatabase { NSString *dbPath =[self getDBPath]; NSString *select_Meal = dummy_select_Meal; NSString *dateTime = dummy_date_Time; NSString *location = dummy_location; NSString *mealItem = dummy_mealItem; if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) { const char *sqlDB = "Insert into iHad(Mealtype,DateAndTime,Location,Mealitem) VALUES (?,?,?,?)"; if(sqlite3_prepare_v2(database, sqlDB, -1, &addStmt, NULL) != SQLITE_OK) NSAssert1(0, @"Error while creating add statement. '%s'", sqlite3_errmsg(database)); sqlite3_bind_text(addStmt, 1, [select_Meal UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(addStmt, 2, [dateTime UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(addStmt, 3, [location UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(addStmt, 4, [mealItem UTF8String], -1, SQLITE_TRANSIENT); if(SQLITE_DONE != sqlite3_step(addStmt)) NSAssert1(0, @"Error while inserting data. '%s'", sqlite3_errmsg(database)); //else //SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid //coffeeID = sqlite3_last_insert_rowid(database); //Reset the add statement. sqlite3_reset(addStmt); } else sqlite3_close(database); }