my application uses SQLite database to store certain data of contacts.. like (record_ID, timestamp etc.) I am trying to update SQLITE Records with certain values using this method.
After initializing the database, i used to call this method. Only 1 record is updated,. even if i call this method everytime to update.
- (void) updateRecord:(int)recordID:(NSString *)sapCustId:(NSString *)sapContactId: (NSString *)timestamp {
static sqlite3_stmt *updateStmt = nil;
if(updateStmt == nil) {
NSString *sql = [NSString stringWithFormat:@"update contactList set sapCustId = \"%@\", sapContactId = \"%@\", timestamp = \"%@\" Where record_ID = \"%d\"", sapCustId, sapContactId, timestamp, recordID];
const char *sql_stmt = [sql UTF8String];
if(sqlite3_prepare_v2(databaseHandle, sql_stmt, -1, &updateStmt, NULL) != SQLITE_OK)
NSAssert1(0, @"Error while creating update statement. '%s'", sqlite3_errmsg(databaseHandle));
}
// sqlite3_bind_text(updateStmt, 0, [sapCustId UTF8String], -1, SQLITE_TRANSIENT);
// sqlite3_bind_text(updateStmt, 1, [sapContactId UTF8String], -1, SQLITE_TRANSIENT);
// sqlite3_bind_int(updateStmt, 2, recordID);
// sqlite3_bind_text(updateStmt, 3, [timestamp UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(updateStmt))
NSAssert1(0, @"Error while updating. '%s'", sqlite3_errmsg(databaseHandle));
sqlite3_reset(updateStmt);
sqlite3_close(databaseHandle);
//Reclaim all memory here.
[sapContactId release];
[sapCustId release];
}
Let me know., how to solve it?
The critical issue is that you code is building
updateStmtonly once, because that’s astaticand you’re checking to see if it’s notnil. Thus, the first SQL statement is getting built, but none of the rest are. The simplest fix it to just get rid of thestaticqualifier as well as theif(updateStmt == nil) ...logic, and you should be off to the races. Also, make sure to replace thesqlite3_resetwithsqlite3_finalize.The
staticpattern that this code clearly used to do (reusing thesqlite3_stmt, binding?placeholders in the SQL with new values viasqlite3_bind_xxxeach iteration, performingsqlite3_resetbefore each subsequent iteration) makes sense if you’re using precisely the same SQL statement but are just binding new values each iteration. But it looks like you’ve commented out that portion of the code and have removed the?placeholders from the SQL, and are instead building the SQL usingstringWithFormat.The simplest solution is to just retire the
staticpattern (get rid of thestatickeyword, eliminate the check to see if it’snil, and usesqlite3_finalizein lieu ofsqlite3_reset) and you should be ok.Additional thoughts:
It looks like you’re closing the database every time you update a single row. If you’re updating a bunch of records, you might want to contemplate keeping the database open. And even if you decide to open and close the database, it probably makes sense to do those at the same logical level in the code (either both inside the
updateRecordmethod, or both outside theupdateRecordmethod). It just makes for more intuitive code.Assuming you decide that you don’t want to bother with reusing a previously prepared SQL statement in order to perform multiple
UPDATEstatements, which would require the use of the SQLitebindfunction calls, that does not mean that you shouldn’t contemplate using thosebindfunction calls anyway. While it might look a lot more convenient to just build the SQL viastringWithFormat, it generally is better to usesqlite3_bind_xxxcalls because (a) that protects you against injection attacks; and (b) you don’t have to worry about escaping parameter values that, for example, have quotation marks in them, etc.Don’t get in the habit of building SQL with
stringWithFormatbecause, as a general rule, it’s fragile and in some cases, it’s dangerous.In your SQL, you generally would not use quotation marks around numeric field values.
If you ever decided to try to make the
static sqlite3_stmt/sqlite3_resetlogic work, two minor observations:I would not use the same
sqlite3_stmtacross data sessions (i.e. don’t close the database and then reopen it). Maybe it works, but given that the database is a parameter tosqlite3_prepare_v2, I wouldn’t make any such assumptions.When you do, finally, close your database, you really should call
sqlite3_finalizeon thesqlite3_stmtand set it back tonilagain.