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.