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.
Related
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.
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");
}
}
}
For some reason, the following code is not storing any data in my sqlite database. The return code is SQLITE_DONE (101) so it is not giving me any error messages. The method is being called a number of times to populate a few rows in the database. Can anyone see where i'm going wrong?
- (void)storePersonInDatabase:(Person *)person {
const char *sql = "INSERT INTO PERSON (ID, NAME, NOTES, ADDRESS, PROMOTED, VEGETARIAN) values (?, ?, ?, ?, ?, ?)";
sqlite3_stmt *statement;
// Prepare the data to bind.
NSData *imageData = person.imageData;
NSString *personId = [person.personId stringValue];
NSString *personName = person.name;
NSString *address = person.address;
NSString *notes = person.notes;
NSString *isVegetarian = (person.isVegetarian) ? #"1" : #"0";
NSString *isPromoted = (person.isPromoted) ? #"1" : #"0";
// Prepare the statement.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
// Bind the parameters (note that these use a 1-based index, not 0).
sqlite3_bind_text(statement, 1, [personId UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [personName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [notes UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [address UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 5, [isPromoted UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 6, [isVegetarian UTF8String], -1, SQLITE_TRANSIENT);
}
// Execute the statement.
int returnCode = sqlite3_step(statement);
if (returnCode != SQLITE_DONE) {
// error handling...
NSLog(#"An error occoured");
}
//This is how I set up the db
NSString *sqliteDb = [[NSBundle mainBundle] pathForResource:#"Persons" ofType:#"sqlite"];
if(sqlite3_open([sqliteDb UTF8String], &database) != SQLITE_OK){
NSLog(#"Unable to open database");
}
As a few people have suggested, you need to copy the database to a location outside of your project bundle. There you can read and write as you wish, otherwise you are essentially just creating new databases every time you try to run your 'storePersonInDatabase' method.
You should perform that same check that Daij-Djan provided before trying to interact with your database. You should also save the location or name of your database somewhere for easy access and file checking.
you show how you try to open a sqlite file in your app bundle
you cant write to your app bundle
the app bundle is read only
you need to copy it somewhere you can write to. It sounds like it should go to library/documents.
the pseudo code is:
if(!sqlite_already_in_library) {
[file_manager copyFileFrom:sqlite-in-bundle to:sqlite-in-library_path];
}
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.