I am working with sqlite database in iOS.I have used CURD operation in my app.For example to insert data into the database i have used below code.
- (BOOL) saveData:(User *)user
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
if([self getUserData:user.email] != nil)
{
[self updateUserData:user];
return YES;
}
else
{
NSString *insertSQL = [NSString stringWithFormat:
#"insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",user.userid,user.name,user.email,user.password,user.address,user.age,user.gender,user.phone,user.qualification,user.role,user.createddate,user.api_key,user.priority_id,user.user_type];
NSLog(#"%#",insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_finalize(statement);
// sqlite3_close(database);
return YES;
}
else
{
NSLog(#"%serrr is ",sqlite3_errmsg(database));
//sqlite3_reset(statement);
sqlite3_close(database);
return NO;
}
}
}
//sqlite3_reset(statement);
sqlite3_close(database);
return NO;
}
I am getting memory issues in my app due to sqlite database.I am not able to understand what should be order of calling sqlite3_reset();,sqlite3_finalize(), sqlite3_close().Please tell in reference to my code so that i can resolve all memory issues in my app
EDIT:
- (BOOL) insertSeMapData:(Client *)client : (NSString *)userid : (NSString *)sendemailto : (NSString *)assignworkordersto
{
BOOL result=NO;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
InspectionMapDetails *inspMap = [self getSEMapData:client :userid];
if(inspMap != nil)
{
[self updateSEMapData:client :userid :inspMap : sendemailto : assignworkordersto];
result=YES;
}
else
{
const char *insert_stmt = "insert into map(inspid,inspectorid,clientid,status,createddate,sendemailreportto,assignworkordersto) values (?,?,?,?, datetime(),?,?)";
if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK)
{
NSString *clientinspid=[NSString stringWithFormat:#"%#",client.inspid];
NSString *clientid=[NSString stringWithFormat:#"%#",client.clientid];
userid=[NSString stringWithFormat:#"%#",userid];
sqlite3_bind_text(statement, 1, [clientinspid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [userid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [clientid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [sendemailto UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 5, [assignworkordersto UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
result = YES;
}
sqlite3_finalize(statement);
}
else
{
NSLog(#"Unable to prepare statement: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
}
else
{
NSLog(#"Unable to open database: %s",sqlite3_errmsg(database));
}
return result;
}
Above function causing memory issue.Here Sqlite_open statement is causing a memory leak which i don't understand why?
There are simple guidelines, and to be blunt, your code doesn't follow any of them at all.
For each successful call to sqlite3_open you must call sqlite3_close.
For each successful call to sqlite3_prepare_v2 you must call sqlite3_finalize. Optionally, in between you may call sqlite3_reset zero or more times in cases where you reuse the prepared statement.
You should always check the result of calls to sqlite3_open and sqlite3_prepare_v2. If they fail, you should use sqlite3_errmsg to log what the problem was.
Do not build query strings using stringWithFormat. Instead, properly bind values to the query using appropriate calls to the various sqlite3_bind_xxx functions.
The code you posted violates all of these. You have plenty of cases where you don't close the database or finalize the prepared statement. And you are incorrectly building your query with stringWithFormat:.
Here's your code all fixed up. Note that I'm assuming all the values you are inserting are strings. Adjust accordingly for any non-string values.
- (BOOL) saveData:(User *)user
{
BOOL result = NO;
if([self getUserData:user.email] != nil)
{
[self updateUserData:user];
result = YES;
}
else
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
const char *insert_stmt = "insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, [user.userid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [user.name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [user.email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, [user.password UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, [user.address UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, [user.age UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, [user.gender UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 8, [user.phone UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 9, [user.qualification UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 10, [user.role UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 11, [user.createddate UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 12, [user.api_key UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 13, [user.priority_id UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 14, [user.user_type UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
result = YES;
}
sqlite3_finalize(statement);
}
else
{
NSLog(#"Unable to prepare statement: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
else
{
NSLog(#"Unable to open database: %s",sqlite3_errmsg(database));
}
}
return result;
}
Update based on the new edit:
Just like your original code, you violate a few of the rules. Your updated code doesn't quite follow the pattern I gave in my answer above.
The main issue now is that you open the database but you only close it under one of two possible code paths. If inspMap != nil you never close the database.
You really should refactor the code so you only open the database if inspMap is nil. I did something similar to your original code in my original answer.
Related
I am trying to update a table in my sqlite database within an iOS app. I have used this update statement before, and it worked.
The below statement is returning a sqlite commit value of 0, BUT all the fields in the row to be updated are set to "< null >".
I don't get an error message ...
What is wrong with the statement?
-(void) UpdateSMUser :(NSString *) tableName
withField1:(NSString *) field1
field1Value:(NSString *) field1Value
andField2:(NSString *) field2
field2Value:(NSString *) field2Value
andField3:(NSString *) field3
field3Value:(NSString *) field3Value
andField4:(NSString *) field4
field4Value:(NSString *) field4Value
{
[self openDB];
sqlite3_stmt *updateStmt;
NSString *sql = [NSString stringWithFormat:#"UPDATE SMUser SET UserID = ?, Profile = ?, SMReg = ?, Date = ? WHERE UserID = '%#'" ,field1Value];
if (sqlite3_prepare_v2(db, [sql UTF8String] , -1,
&updateStmt, NULL) == SQLITE_OK)
{
sqlite3_bind_text(updateStmt, 1, [field1Value UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updateStmt, 2, [field2Value UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updateStmt, 3, [field3Value UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updateStmt, 4, [field4Value UTF8String], -1, SQLITE_TRANSIENT);
}
// [self openDB];
char* errmsg;
NSLog(#"sqlite commit %d",sqlite3_exec(db, [sql UTF8String], NULL, NULL, &errmsg));
sqlite3_exec(db, [sql UTF8String], NULL, NULL, &errmsg);
if(SQLITE_DONE != sqlite3_step(updateStmt)){
NSLog(#"Error while updating. %s", sqlite3_errmsg(db));
}
else{
// [self clearClick:nil];
}
sqlite3_finalize(updateStmt);
sqlite3_close(db);
}
Thank you very much in advance ... it is driving me crazy!
sqlite3_exec() is an (obsolete) wrapper around sqlite3_prepare*()/sqlite3_step()/sqlite3_finalize().
You cannot use sqlite3_exec() with parameters.
You still have the correct sqlite3_step() call in your program; just remove both sqlite3_exec() calls.
I am new to Sqlite and I am working on an application which uses Sqlite.
I have succeeded in creation of table and inserting values into it.
I am trying to update the table but the table is not getting updated.
Below is the code for updating a table:
-(BOOL)updateData:(NSString *)screenName status:(NSString *)currentStatus{
const char *dbPath = [databasePath UTF8String];
if (sqlite3_open (dbPath, &database) == SQLITE_OK) {
NSString *updateSQL = [NSString stringWithFormat:#"Update productDetail Set status = \"%#\" where current_screen = \"%#\"",currentStatus,screenName];
// const char *update_stmt = "update productDetail Set status = ? Where screenName=?";
const char *update_stmt = [updateSQL UTF8String];
/*
if (sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL)) {
sqlite3_bind_text(statement, 0, [currentStatus UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [screenName UTF8String], -1, SQLITE_TRANSIENT);
}
*/
/*
char* errmsg;
sqlite3_exec(database, "COMMIT", NULL, NULL, &errmsg);
*/
sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL);
/*
sqlite3_bind_text(statement, 1, [currentStatus UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [screenName UTF8String], -1, SQLITE_TRANSIENT);
*/
if (sqlite3_step(statement) == SQLITE_OK) {
NSLog(#"Updated Successfully!!");
return YES;
}
else{
NSLog(#"error: %s",sqlite3_errmsg(database));
NSLog(#"Failed Updated");
}
int result=sqlite3_bind_text(statement, 1, Nil , -1, SQLITE_TRANSIENT);
NSLog(#"bind result= %i", result);
if(sqlite3_step(statement) != SQLITE_DONE) {
NSLog(#"Problems updating");
NSLog(#"error: %s",sqlite3_errmsg(database));
return NO;
}
else{
NSLog(#"Updated");
}
sqlite3_finalize(statement);
}
return YES;
}
Please let me know what I am doing wrong.
Thanks
ERROR:
Failed Updated
bind result= 21
Problems updating
rror: library routine called out of sequence
You have too much commented-out code, and the remaining code is garbled as a result.
Your code tries to bind a parameter, but your current query does not use parameters.
Furthermore, the return value of sqlite3_step can never be SQLITE_OK, and you are trying to execute the query twice (and the database complains because you did not call sqlite3_reset).
Use this code:
result = NO;
const char *update_stmt = "UPDATE productDetail SET status=? WHERE screenName=?";
if (sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL) != SQLITE_OK) {
NSLog(#"prepare error: %s", sqlite3_errmsg(database));
} else {
sqlite3_bind_text(statement, 1, [currentStatus UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [screenName UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) != SQLITE_DONE)
NSLog(#"execution error: %s", sqlite3_errmsg(database));
else
result = YES;
sqlite3_finalize(statement);
}
return result;
I'm new to xcode and I'm trying to update an sqlite table, if a row already exists. When I run this code, it builds but does not execute the updateAlumni query. It logs "update!" though.
sqlite3_stmt *stmt;
IF (sqlite3_prepare(alumniDB, update_stmt, -1, &stmt, nil)== SQLITE_OK) {
IF (sqlite3_step(stmt) == SQLITE_ROW) {
NSLog(#"update!");
const CHAR *updateAlumni = [[NSString stringWithFormat:#"UPDATE ALUMNI SET EMAIL = ?, PHONE = ?, ADDRESS = ?, BIRTHDAY = ? WHERE FIRSTNAME = '%s' AND LASTNAME = '%s'", [ContactFirstName UTF8String], [ContactLastName UTF8String]] UTF8String];
sqlite3_bind_text(stmt, 1, [ContactEmail UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [ContactPhone UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [ContactAddress UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, [ContactBday UTF8String], -1, SQLITE_TRANSIENT);
IF(sqlite3_exec(alumniDB, updateAlumni, NULL, NULL, &error)==SQLITE_OK){
NSLog(#"Alumni updated");
}
}
ELSE{
NSLog(#"add!");
NSString *ADD = [NSString stringWithFormat:#"INSERT OR REPLACE INTO ALUMNI(FIRSTNAME,LASTNAME,EMAIL,PHONE,ADDRESS,BIRTHDAY) VALUES('%s','%s','%s','%s','%s','%s')",[ContactFirstName UTF8String],[ContactLastName UTF8String],[ContactEmail UTF8String],[ContactPhone UTF8String],[ContactAddress UTF8String],[ContactBday UTF8String]];
const CHAR *addAlumni = [ADD UTF8String];
IF(sqlite3_exec(alumniDB, addAlumni, NULL, NULL, &error)==SQLITE_OK){
NSLog(#"Alumni added");
}
}
}
I'm trying to updating the SQLite db on the iPhone with a dictionary returned by my server.
sqlite3_step return sqlite_ok but the database still remain empty.
Anyway inserted a log for a possible error after sqlite3_step and this return "database locked" so I think something is wrong with the sqlite function order in my code.
I've also verified that the dictionary contains data with a log inside the iteration and it gives me all I expect to find.
What's wrong here? Can someone help me?
Sorry for my bad english and thanks
Marco
//----- database update -----------------------------------------------------------------------------------------------------
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"DB.sqlite"];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
hasError= false;
const char *update_stmt="REPLACE INTO table VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)";
sqlite3_stmt *compiledstatement;
if(sqlite3_prepare_v2(database,update_stmt , -1, &compiledstatement, NULL)==SQLITE_OK) {
for (NSDictionary *item in [update objectForKey:#"table1"]) {
sqlite3_bind_int(compiledstatement, 1,[[item objectForKey:#"a"]integerValue]);
sqlite3_bind_text(compiledstatement,2,[[item objectForKey:#"b"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,3,[[item objectForKey:#"c"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,4,[[item objectForKey:#"d"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(compiledstatement,5,[[item objectForKey:#"e"] integerValue]);
sqlite3_bind_double(compiledstatement,6,[[item objectForKey:#"f"] doubleValue]);
sqlite3_bind_text(compiledstatement,7,[[item objectForKey:#"g"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,8,[[item objectForKey:#"s"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,9,[[item objectForKey:#"g"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,10,[[item objectForKey:#"u"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,11,[[item objectForKey:#"y"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(compiledstatement,12,[[item objectForKey:#"n"] integerValue]);
sqlite3_bind_int(compiledstatement,13,[[item objectForKey:#"k"] integerValue]);
//sqlite3_bind_text(compiledstatement,2,[#"" UTF8String], -1, SQLITE_TRANSIENT);
if(!sqlite3_step(compiledstatement)==SQLITE_DONE) {hasError= true; NSLog(#"error (%s)", sqlite3_errmsg(database));} //error
NSLog(#"error (%s)", sqlite3_errmsg(database));
sqlite3_reset(compiledstatement);
}
sqlite3_finalize(compiledstatement);
}else { NSLog(#"prepare FAILED (%s)", sqlite3_errmsg(database));}
} else {NSLog(#"opening error");}
sqlite3_close(database);
EDIT:
I'm not able to understand why this code won't work!!! I've not find the final solution.
I always get "library routine called out of sequence" at COMMIT, why?
Isn't this sequence correct?
-open
-begin
-prepare
-cycle the dictionary(bind, step and reset; for every item in dictionary I must insert or replace a row)
-finalize
-commit
-close
If I remove the begin and commit exec I have the error "database is locked" on "step", when the code try to insert the first row...
it's a nightmare...
Thank you again for your help!!
//----- database update -----------------------------------------------------------------------------------------------------
const char *updateTags_stmt="REPLACE INTO tags VALUES(?,?,?)";
if (sqlite3_open_v2([dbPath UTF8String], &database,SQLITE_OPEN_READWRITE,NULL) != SQLITE_OK) {
sqlite3_close(database);return;
}
if (sqlite3_exec(database, "BEGIN", 0, 0, 0)!=SQLITE_OK) {sqlite3_close(database);return;}
sqlite3_stmt *compiledstatement;
if(sqlite3_prepare_v2(database,updateTags_stmt , -1, &compiledstatement, NULL)!=SQLITE_OK) {sqlite3_close(database);return;}
for (NSDictionary *item in [update objectForKey:#"tags"]) {
sqlite3_bind_int(compiledstatement,1,[[item objectForKey:#"tid"] integerValue]);
sqlite3_bind_text(compiledstatement,2,[[item objectForKey:#"categoria"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledstatement,3,[[item objectForKey:#"tag"] UTF8String], -1, SQLITE_TRANSIENT);
if(sqlite3_step(compiledstatement)!=SQLITE_DONE) {
sqlite3_finalize(compiledstatement);
sqlite3_close(database);
return;
} else {if (sqlite3_reset(compiledstatement)!=SQLITE_OK){sqlite3_close(database);return;}}
}
if (sqlite3_finalize(compiledstatement)!=SQLITE_OK){sqlite3_close(database);return;}
if (sqlite3_exec(database, "COMMIT", NULL, NULL, 0)!=SQLITE_OK) {sqlite3_close(database);return;}
if (sqlite3_close(database)!=SQLITE_DONE){sqlite3_close(database);return;}
This code is wrong; it first inverts the return value of sqlite3_step, and then compares that value to SQLITE_DONE (which never succeeds because ! returns 0 or 1):
if(!sqlite3_step(compiledstatement)==SQLITE_DONE)
Do it correctly:
if (sqlite3_step(compiledstatement) != SQLITE_DONE)
Finally I've found the problem: there was another query on a different class in which then statement was not finalized so the DB still remains always open... two weeks for this lesson!! heheh sorry!
This thing is really weird for me i create an app, on my first view (login view) i enter email id and password and then verify this from database and if it ok then move to new view and in that view i fill some fields and then enter that data into database but it dnt enter data into my database .this verification of login view
-(NSInteger)verifyLoginEmail:(NSString *)email Password:(NSString *)password
{
NSInteger a=1;
const char *selectQuery="SELECT * FROM CreateProfile where email=? AND password=?";
sqlite3_stmt *statement;
if(sqlite3_open([destPath UTF8String],&studentDB)==SQLITE_OK)
{
//sqlite3_bind_int(statement, 1, sid);
if(sqlite3_prepare_v2(studentDB,selectQuery, -1, &statement, nil)==SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [password UTF8String], -1, SQLITE_TRANSIENT);
if(sqlite3_step(statement)==SQLITE_ROW)
{
return a;
}
else
{
return 2;
}
}
sqlite3_finalize(statement);
}
sqlite3_close(studentDB);
return 0;
}
and this code is for insert data from new view
-(void)insertName:(NSString *)name Email:(NSString *)email Password:(NSString *)password Pic:(NSString *)pic;
{
const char *insertQuery="insert into CreateProfile (name,email,pic,password) values (?,?,?,?)";
sqlite3_stmt *statement;
if(sqlite3_open([destPath UTF8String],&studentDB)==SQLITE_OK)
{
if(sqlite3_prepare_v2(studentDB, insertQuery, -1, &statement, nil)==SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [pic UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [password UTF8String], -1, SQLITE_TRANSIENT);
//sqlite3_bind_int(statement, 2, rollno);
}
if(sqlite3_step(statement)==SQLITE_DONE){
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Profile Created" message:#"Your profile successfully added" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
[alert release];
}
sqlite3_finalize(statement);
}
sqlite3_close(studentDB);
}
when i directly go to view from changing view from main window i can enter fields into database but i cant enter into database when i login and then move to new view
In your (NSInteger)verifyLoginEmail:(NSString *)email Password:(NSString *)password funcation
You have written
sqlite3_bind_text(statement, 1, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [password UTF8String], -1, SQLITE_TRANSIENT);
replace those two lines with lines shown below
sqlite3_bind_text(statement, 0, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 1, [password UTF8String], -1, SQLITE_TRANSIENT);
In Select Query the binding starts from 0 . and In insert statements the binding starts from 1.
and Instead of returning a , return some integer value like 1 , because your method's return type is NSInteger.
Hope it will work.