I'm currently getting an error when trying to insert data into my database.
#import "ReminderDB.h" @implementation ReminderDB @synthesize db = _db; -(id)init{ _db = [self openDB]; [self createTable:@"Reminders" withField1:@"Title" withField2:@"Who" withField3:@"Quantity"]; return self; } -(NSString *) filepath{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); return [[paths objectAtIndex:0] stringByAppendingPathComponent:@"reminders.sqlite"]; } - (sqlite3*)openDB { if (_db == NULL) { int rc; if ((rc = sqlite3_open([[self filepath] UTF8String], &(_db))) != SQLITE_OK) { NSLog(@"%s error (%1d)", __FUNCTION__, rc); _db = NULL; } else { NSLog(@"db opened"); } } return _db; } -(void)createTable: (NSString *) tableName withField1: (NSString *) field1 withField2: (NSString *) field2 withField3: (NSString *) field3 { char *err; NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS '%@' ('%@' TEXT PRIMARY KEY, '%@' TEXT, '%@' TEXT);", tableName, field1, field2, field3]; if(sqlite3_exec(_db, [sql UTF8String], NULL, NULL, &err) != SQLITE_OK){ sqlite3_close(_db); NSAssert(0, @"Could not create table"); } else{ NSLog(@"Table Created"); } } -(void)addReminder:(NSString*)title who:(NSString*)who quantity:(NSString*)quantity{ NSString *sql = [NSString stringWithFormat:@"INSERT INTO Reminders ('Title', 'Who', 'Quantity') VALUES ('%@', '%@', '%@')", title, who, quantity]; char *err; int rc; if((rc = sqlite3_exec(_db, [sql UTF8String], NULL, NULL, &err)) != SQLITE_OK){ NSLog(@"%s error (%1d)", __FUNCTION__, rc); sqlite3_close(_db); NSAssert(0, @"Could not update table"); } else{ NSLog(@"Table Update Successful"); } } @end This code successfully opens the database and creates the table. However when I call addReminder:who:quantity the table will not update and the error I am getting is an SQL Error or Missing Database error. Which doesn't make sense to me because I know the table is created and exists.
EDIT I have updated my addReminder:who:quantity: to use binds instead of exec's. I have also taken out the close calls. I am now getting an error when calling prepare.
-(void)addReminder:(NSString*)title who:(NSString*)who quantity:(NSString*)quantity{ const char *sql = "INSERT INTO Reminders ('Title', 'Who', 'Quantity') VALUES (?, ?, ?)"; sqlite3_stmt *statement; if (sqlite3_prepare_v2(_db, sql, -1, &statement, NULL) == SQLITE_OK) { // Bind the parameters (note that these use a 1-based index, not 0). sqlite3_bind_text(statement, 1, [title UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 2, [who UTF8String], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 3, [quantity UTF8String], -1, SQLITE_TRANSIENT); NSLog(@"Binding successful"); } int returnCode = sqlite3_step(statement); if (returnCode != SQLITE_DONE) { // error handling... NSLog(@"An error occoured (%d)", returnCode); } else{ NSLog(@"Table Updated"); } } I know the problem is in the prepare call because I am not getting "Binding successful" in my log.
[self openDB]before[self addReminder:::]?openDBmethod before callingaddReminder:who:quantity:? And why is your insert being done viasqlite3_execand why do you build your query withstringWithFormat?NULLif it's closed). Not to mention the SQL injection attacks alluded to by @rmaddy.sqlite3_execandstringWithFormat. If that is incorrect then what is the better way to do it?openDBandcreateTable:field1:field2:field3:are both called beforeaddReminder. If you see I am not closing the database in the methods if they run successfully. I am only closing the database if the opens or execs to not succeed.stringWithFormatto build queries or usessqlite_execto doINSERT,UPDATE, orDELETEstatements is a bad tutorial. Find a better one.