Crashing on sqlite3_step line? - iphone

Crashing on sqlite3_step line?
I am just deleting the row from the database. It throws EXC_BAD_ACCESS sometimes not always.
Below is the screenshot of code.
Any suggestions guys.

The above problem is due to multiple write process to the DB. I synchronized the DB operations. Thanks for suggestions.

You have not opened the database using
if(sqlite3_open([databaseName UTF8String], &database) == SQLITE_OK)
{
// perform your operations here e.g. delete, insert, update
}
else
{
NSString *databaseName = [self.GetDocumentDirectory stringByAppendingPathComponent: #"yourDatabaseName.sqlite"];
sqlite3_open([databaseName UTF8String], &db);
// perform your operations here e.g. delete, insert, update
}
Refer Deleting Records in this

Related

how to save data to different table of sqlite database

I am new in sqlite in ios. Thus, what I have to do first and next in order to save data to different tables of database?
I have used Sqlite database in my various application, it works fine for me. You have to follow these steps for inserting the data in the tables of Sqlite database ...
1.First of all you need to create your database... I hope you have created and inserted in your project and also added linked framework libsqlite3.0.dylib and import these in your classes.
2. Replace your insertion method write this code ...
+(void)insertRecord:(NSString *)dbPath record:(NSMutableArray*)dataArray{
#try{
sqlite3_stmt *insertStmnt;
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK){
for(int i=0; i<[dataArray count]; i++){
id record=[dataArray objectAtIndex:i];
NSString *insertQuery = [NSString stringWithFormat:#"INSERT INTO Table_Name (\"Column1\",\"Column2\",\"Column3\",\"Column4\",) VALUES('%#','%#','%#','%#')",[[record objectForKey:#"col1"] stringByReplacingOccurrencesOfString:#"'" withString:#"''"],[[record objectForKey:#"col2"] stringByReplacingOccurrencesOfString:#"'" withString:#"''"],[[record objectForKey:#"col3"] stringByReplacingOccurrencesOfString:#"'" withString:#"''"],[[record objectForKey:#"col4"] stringByReplacingOccurrencesOfString:#"'" withString:#"''"]];
const char *sql = [insertQuery cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_prepare_v2(database, sql, -1, &insertStmnt, NULL) == SQLITE_OK){
}else{
}
if(SQLITE_DONE != sqlite3_step(insertStmnt)){
}
}
}
}#catch (NSException *r) {
NSLog(#"UU %#",r);
}
}
Where record is the array of dictionary, which contains the values which you want to insert in the table or values get from the user.
stringByReplacingOccurrencesOfString:
The above method is necessary because if any user enters the data with single cote, then it will lead to your application crash.(you may remove this if you does not take input from the user)
Yes, You can also follow these links for better understanding..
1.http://www.techotopia.com/index.php/IOS_4_iPhone_Database_Implementation_using_SQLite
2.SQLite Tutorial
Hope it will work for you, if you have any query then may reply..
If you're using SQLite then go get FMDB as it will make your life alot easier. All that code above can be shrunk down to a thread safe call something like (off the top of my head, so probably not compile ready).
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdateWithFormat:#"INSERT OR REPLACE INTO table (f1,f2) VALUES (%#, %#);", field1, field2];
DLog(#"insert error: %#", [db lastErrorMessage]);
}];

the select method is adjusting but insert method not working properly

I am working on sqlite database , trying to insert into database but it is giving error "Error while inserting " Database is locked .
I searched some post and also write reset and finalize statement but it is giving same error.
Here is my code
if(addStmt == nil)
{
//const char *sql = "insert into Limittabel (limitAmt) Values(?)";
//const char *sql="INSERT INTO Limittabel (limitAmt, Profileid) VALUES(?, ?)";
const char *sql="insert into Limittabel (limitAmt,Profileid) Values (?,?)";
// Insert into Limittabel (limitAmt,Profileid) Values ($500,1)
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1, [limitAmt UTF8String], -1, SQLITE_TRANSIENT);
// NSString *str_id_poi = [[NSString alloc] initWithFormat:#"%d", [Profileid integerValue]];
// sqlite3_bind_text(addStmt, 2, [str_id_poi UTF8String], -1, SQLITE_TRANSIENT);
//sqlite3_bind_text(addStmt, 2, [ UTF8String], -1, SQLITE_TRANSIENT);
NSLog(#"***Storing END on Database ***");
if(SQLITE_DONE != sqlite3_step(addStmt))
{
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
} // sqlite3_finalize(addStmt);
else{
//sqlite3_last_insert_rowid;
limitid = sqlite3_last_insert_rowid(database);
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
sqlite3_finalize(addStmt);
}
sqlite3_reset(addStmt);
//sqlite3_finalize(addStmt);
}
If I am not opening the database it is giving Database locked error, if opening database it is giving ' No such Table ' error
Please Help me.
Thanks
I don't understand the "if I am not opening the database it is giving Database locked error" comment, because you simply can't use a database without opening it. It makes no sense to call SQLite functions without first opening database. Maybe I'm not understanding this comment.
But ignoring that for a second, you later say, "if opening database it is giving 'No such table' error": Are you sure you're finding the database correctly? The problem is, if you open database and it's not found, then a blank database will be created. Are you sure this hasn't happened to you? If this may have happened to you, you might want to
Reset the simulator (if you're using simulator) or delete and reinstall the app to make sure any blank databases that sqlite3_open may have created for you will be removed; and
Check to make sure the database exists before you open it or replace your occurrence of sqlite3_open with sqlite3_open_v2 with a third parameter of SQLITE_OPEN_READWRITE and fourth parameter of NULL. See SQLite will not prepare query when accessing database in Xcode
As an aside, you don't mention whether you're opening this from the bundle or Documents, but generally I advise to programmatically copy from bundle to Documents and then open it from there.
If you're doing this on the simulator, I sometimes find it helpful to examine the database used by the simulator from my Mac. Thus, I go to "~/Library/Application Support/iPhone Simulator/5.1/Applications/" (replace the 5.1 with whatever version of your simulator you are using ... if the Library is hidden, unhide it from Terminal with chflags nohidden ~/Library), I then go into the directory for the particular application, go into it's Documents folder, and then open the database in the Mac command line sqlite3 program. You can use that to examine the database and make sure the db is as you expect it.
Just a few thoughts for the "no such table" error.
Here is link for creating, Open , inserting, and retrieve data from the SQLite database . It will help you.
SQLite Datase Create,Insert and Retrieve from the database Click here
jonty to deal with the database its compulsory that first we open the database and then we makes changes in database
and if it giving the error No such table then i recommend you check the existence of table in database i.e. such table created or not.
Try this code,
if(sqlite3_open([YourDatabasePath UTF8String],&db) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"insert into Limittabel (limitAmt,Profileid) Values (?,?)"];
char *errmsg=nil;
if(sqlite3_exec(db, [querySQL UTF8String], NULL, NULL, &errmsg)==SQLITE_OK)
{
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
}
sqlite3_close(db);
If this code doesn't work then there is a problem in your query, check your query again. this code works at my side.

iPhone SQLite commands with apostrophes

I'm writing an application for the iPhone that communicates with a SQLite database but I'm running into a small problem. Whenever I try to query information based on a condition that contains an apostrophe, no results are returned.... even if a result that matches the requested condition exists. Let me give some specifics...
SQLite Table
Row--Column1--Column2---------
Test Data - 001
User's Data - 002
Objective-C Code
//Create the sql statement
sqlite3_stmt *sqlStatement;
//Create the name of the category that will be passed in
NSString *categoryName = #"User's Data";
//Create the rest of the SQL query
NSString *sqlQuery = "SELECT * FROM theTableName WHERE Column1 = ?";
//If there are no errors in the SQL query
if (sqlite3_prepare_v2(theDatabase, sqlQuery, -1, &sqlStatement, nil) == SQLITE_OK)
{
//Bind the category name to the sql statement
sqlite3_bind_text(sqlStatement, 1, [categoryName UTF8String], -1, SQLITE_TRANSIENT);
//While there are rows being returned
while (sqlite3_step(sqlStatement) == SQLITE_ROW)
{
//Retrieve row data
}
}
else
{
//Save error message to the application log and terminate the app
NSAssert1(0,#"Error: Failed to prepare the SQL statement with message '%s'.", sqlite3_errmsg(database));
}
//Reset the sql statement
sqlite3_reset(sqlStatement);
I'm semi-new to objective C, so my first thought when writing this code was to sanitize the user inputs. But after doing some research, I read that the sqlite3_bind calls do the necessary sanitation for you. But whenever the code runs, the while loop is skipped right over because there are no rows being returned. It should return the second row from the database table. If I copy/paste the exact same SQL query into a SQL managing program (I use SQLite Manager) (and with the necessary query sanitation of course), it returns the correct data.
I've spent a long time trying to debug this myself and even a greater amount of time trying to search online for a similar problem being explained and resolved, but to no avail. As of now, I just disabled the user's ability to key in an apostrophe on the iPhone's virtual keyboard. But this is a feature I'd love to include in my finished product. Can anyone here offer me any helpful tips? Any kind of help would be greatly appreciated.
For sqlite your request will be (as you can see it is even wrong highlighted):
SELECT * FROM theTableName WHERE Column1 = User's data
And it will wait for the closing ' symbol
You should echo ' symbol, for example in following way:
NSString *sqlQuery = [NSString stringWithFormat:#"SELECT * FROM tableName WHERE Column1=\"%#\"", categoryName];
In this case query will be
select * from theTableName where column1="User's data"
that is completely legal query.
In this case you don't need binding any more and final code will look like:
if (sqlite3_prepare_v2(database, [sqlQuery UTF8String], -1, &sqlStatement, nil) == SQLITE_OK)
{
//While there are rows being returned
while (sqlite3_step(sqlStatement) == SQLITE_ROW)
{
//Retrieve row data
}
}
else
{
//Save error message to the application log and terminate the app
NSAssert1(0,#"Error: Failed to prepare the SQL statement with message '%s'.", sqlite3_errmsg(database));
}
The official character is ''
sanitize with:
NSString *stringToSanitize = #"This is the value with ' character";
NSString *sanitized = [stringToSanitize stringByReplacingOccurrencesOfString:#"'"
withString:#"''"];
Then you can use it on your querys

sqlite delete problem on iPhone

In my iPhone app, I'm trying to delete a row from an SQLite database. After the delete statement is executed the row seems to be deleted correctly, but after I restart the application the row is still there.
I'm using the code blow to delete the record. Any idea what could be the problem?
NSString *deleteSQL = [NSString stringWithFormat:#"DELETE FROM table1 WHERE actId=%d", actId];
char *errorMsg;
if (database == nil) {
NSLog(#"ERROR db not initialized but trying to delete record!!!");
}else{
if (sqlite3_exec(database, [deleteSQL UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK){
NSAssert1(0, #"Error updating tables: %s", errorMsg);
sqlite3_free(errorMsg);
return NO;
}
}
NSLog([NSString stringWithFormat:#"DELETE Successful"]);
I've solved this problem. Although I don't understand exactly all the details. The problem was the in my 'loading code' I forgot to call sqlite3_finalize for the statements. Not sure why but this influenced somehow future inserts and deletes. Adding sqlite3_finalize to the data loading method solved the problem.

Some changes to SQLite database are not persisting after app close and relaunch

I've got an iPhone app I'm developing and when the app launches I open an SQLite database connection, and I close it when the application terminates. The database is in the application documents folder.
During the lifetime of the app I run several INSERT and UPDATE statements. However, for some reason my UPDATE statements are not saving properly once the application is closed and then restarted. I am calling sqlite3_prepare_v2, sqlite3_step and sqlite3_finalize properly so I'm sure the transactions should be finalized. I've added breakpoints on all those 3 functions and they are all being hit okay and all returning the correct values.
When I close the application after an update and look in the documents directory I can see another database file with -journal after it. Does this mean something's not working properly transaction wise?
I've also noticed that in my applicationWillTerminate: method where I close the connection using sqlite3_close(), that it is returning SQLITE_BUSY. Why could this be?
I've been struggling for a whole day now so I really hope someone can point me in the right direction!
Here's my code to perform my update queries:
// Update statement
sqlite3_stmt *stmt;
char *query = "UPDATE records SET fielda = ? WHERE pkfield = ?;";
if (sqlite3_prepare_v2(database, query, -1, &stmt, nil) == SQLITE_OK &&
// Bind
sqlite3_bind_text(stmt, 1, [myNSStringVar UTF8String], -1, nil) == SQLITE_OK &&
sqlite3_bind_int(stmt, 2, recordID) == SQLITE_OK) {
// Execute
int ret = sqlite3_step(stmt);
if (ret == SQLITE_DONE) {
sqlite3_finalize(stmt);
}
}
Ah... I figured it out! One of my obscure finalize statements never actually got reached! As it was only a SELECT statement I didn't check it over because it has nothing to do with any data manipulation or transactions! That's a day's worth of development out of the window! But I won't make that mistake again!
Thanks for your help anyway guys!
Looks like you need to let sqlite finish up it's current task(s) before killing your app - SQLITE_Busy means that "the database file is locked", so following the docs here should set you on the right path.
If you are reusing the update statements you should call sqlite3_reset() on the statement right after use, a call to sqlite3_clear_bindings() might also be appropriate to make sure the assigned parameters are reset. You should then call sqlite3_finalize only when cleaning up. This might be your problem because if the statement is still being executed and you call sqlite3_finalize on it then execution will be interrupted. That said, you should most probably be reusing statements for efficiency if you are not already. For me it works like so:
static sqlite3_stmt *update_statement = nil;
-(void)performUpdateOnRow: (NSInteger)primaryKey {
if (update_statement == nil){
const char *sql = "UPDATE foo SET bar=?,baz=? WHERE pk=?";
if( sqlite3_prepare_v2(database, sql, -1, &update_statement, NULL) != SQLITE_OK ){
// Insert some serious error handling here!
}
}
sqlite3_bind_text(update_statement, 1, #"first", -1,SQLITE_TRANSIENT);
sqlite3_bind_text(update_statement, 2, #"second", -1,SQLITE_TRANSIENT);
sqlite3_bind_int(update_statement, 3, primaryKey);
sqlite3_step(update_statement);
sqlite3_reset(update_statement);
}
Are you sure saving lots of stuff to your SQLite DB during the app usage is best for performance?
I tend to store changes etc in an NSMutableArray during runtime, setting a "dirty" flag to YES each time an object is updated.
Then in my applicationWillTerminate method I call the following:
[todos makeObjectsPerformSelector:#selector(dehydrate)];
My "dehydrate" method (this is based on Apple's own guide for manipulating SQLite databases) is then essentially this:
- (void) dehydrate {
if (dirty) {
if (dehydrate_statement == nil) {
const char *sql = "UPDATE todo SET text=?,priority=?,complete=?,detail=? WHERE pk=?";
if (sqlite3_prepare_v2(database,sql,-1,&dehydrate_statement,NULL) != SQLITE_OK) {
NSAssert1(0,#"Error: failed to prepare statement with message '%s'.",sqlite3_errmsg(database));
}
}
sqlite3_bind_int(dehydrate_statement, 5, self.primaryKey);
sqlite3_bind_text(dehydrate_statement, 4, [self.detail UTF8String],-1,SQLITE_TRANSIENT);
sqlite3_bind_int(dehydrate_statement, 3, self.status);
sqlite3_bind_int(dehydrate_statement, 2, self.priority);
sqlite3_bind_text(dehydrate_statement, 1, [self.text UTF8String],-1,SQLITE_TRANSIENT);
int success = sqlite3_step(dehydrate_statement);
if (success != SQLITE_DONE) {
NSAssert1(0,#"Error: failed to save changes with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_reset(dehydrate_statement);
dirty = NO;
}
}
Does this help at all?