Objective-C Issue with deleting data from SQLITE database - result code 5 - iphone

I am experiencing issues with deleting a row / data record from an SQLite database located on the iPhone. I followed advice given in the following post, but the result code from SQLite is 5. From the SQLite reference manual, 5 means:
SQLITE_BUSY 5 /* The database file is locked */
Has anyone else come across this problem or have any ideas why this would be the case?
Here is an excerpt of my code (dbrc is set to 5):
NSString *retrievedContactID = [archivedContact objectForKey:#"contact_id"];
sqlite3 *database = [FollowUPAppDelegate checkAndCreateDatabase];
NSString *deleteSQL = [NSString stringWithFormat:#"DELETE FROM Contacts WHERE contact_id = %#", retrievedContactID];
const char *delete_stmt = [deleteSQL UTF8String];
sqlite3_stmt *compiledStatement;
int dbrc; //database return code
dbrc = sqlite3_prepare_v2(database, delete_stmt, -1, &compiledStatement, NULL);
dbrc = sqlite3_step(compiledStatement);
sqlite3_finalize(compiledStatement);
compiledStatement = NULL;
if (dbrc != 101) { //anything except 101 (SQLITE_DONE for delete, *not* SQLITE_OK)
NSLog(#"Error deleting contact from database: result code %i", dbrc);
return;
}
else {
NSLog(#"deleted the customer from datasets");
}
sqlite3_close(database);

This means. your database is being used by some other process. you have to stop the other process and proceed.
I can give you an example. when you are accessing a database from your app and if you try to change the content using some external sqlite manager you would get this busy error. The solution to this problem is,stop your app and try.
You problem is similar. Your database is locked by some other process.

Related

sqlite3 query works on cmd line but returns no data in iOS 6 SImulator

I have this sqlite3 table used in an iOS 6 app for iPad:
CREATE TABLE notes(id INTEGER PRIMARY KEY, note TEXT, noteDate TEXT, wasUploaded INTEGER);
from the sqlite3 command line this query works:
sqlite> Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `wasUploaded`=0;
1|Well|2012-10-04 22:46:23|0
On iOS iPad 6.0 Simulator each of these queries returns the exact same data as above:
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `id`=1";
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `note`='Well'";
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `noteDate`='2012-10-04 22:46:23'";
But this query which worked fine on the command line now returns no data:
const char *sqlStatement = "Select `id`,`note`,`noteDate`,`wasUploaded` FROM `notes` WHERE `wasUploaded`=0";
Has me baffled. Why is that last query not working? Do I need to make that column an index or something? The other two non-indexed columns work but not this.
No errors. The last query that returns no data gives a normal return code of 101 (sqlite3_step() has finished executing) and a query without the where clause returns the same data as for the other three queries.
Edit: here is the complete code
- (NSString *)getNotesToBeUploaded {
sqlite3 *stuDb;
NSString *thisNote;
NSMutableString *notes = [[NSMutableString alloc]init];
if (self.filePath == #"empty") {
[self setDatabaseFilePath];
}
if (sqlite3_open([self.filePath UTF8String], &stuDb) == SQLITE_OK)
{
// this is the query line that get changed to show stackoverflow the different results:
const char *sqlStatement = "Select `id`,`note`,`noteDate` FROM notes WHERE `wasUploaded`=0";
sqlite3_stmt *compiledStatement;
int nResult = sqlite3_prepare_v2(stuDb, sqlStatement, -1, &compiledStatement, NULL);
if ( nResult == SQLITE_OK)
{
int nret; // diagnostic used to watch return vaues when single stepping
while ((nret = sqlite3_step(compiledStatement)) == SQLITE_ROW)
{
int id = sqlite3_column_int(compiledStatement, 0);
const unsigned char *note = sqlite3_column_text(compiledStatement, 1);
const unsigned char *noteDate = sqlite3_column_text(compiledStatement, 2);
int wu = sqlite3_column_int(compiledStatement, 4);
if (strlen((const char *)note) > 0 && strlen((const char *)noteDate) > 0)
{
thisNote = [NSString stringWithFormat:#"%d,%s,%s,%d\n",id, noteDate, note, wu];
[notes appendString:thisNote];
}
}
} else {
sqlite3_finalize(compiledStatement);// prevent small memory leaks
sqlite3_close(stuDb);
thisNote =
[NSString stringWithFormat:#"prepare failed with status:%d in %s at line %d path was %#,0,0\n",nResult,__FILE__,__LINE__,self.filePath];
[notes appendString:thisNote];
[notes appendString:#"\n"];
return (NSString *)notes;
}
sqlite3_finalize(compiledStatement);
sqlite3_close(stuDb);
}
Are you checking the return codes from your sqlite3 calls? And, if you're not getting SQLITE_OK or SQLITE_ROW, as appropriate, you should check the sqlite3_errmsg results to diagnose what's going on. You really should share your code if you want us to help you.
But the most common problems in the first-time iOS SQLite apps are
Failing to include the database in your app's bundle. Check your Target settings and make sure you've included the database in the Build Phases. You can also confirm this by looking at your app's bundle in the simulator in the ~/Library/Application Support/iPhone Simulator folder. If you want to do that, you may want to unhide your ~/Library folder if you haven't by typing in chflags no hidden ~/Library in the Terminal command line interface.
If you're planning on updating your database from the app, failing to first copy the database from the bundle to the Documents folder before you try to start using it.
Using sqlite3_open and interpreting a successful return code as evidence that the database was opened successfully ... but if it didn't find the database, the sqlite3_open function annoyingly will create a new blank database ... I always suggest that people use sqlite3_open_v2 instead, in which you can omit the parameter to create a blank database if it's not found if that's not what you want.
Certainly, there can be a ton of code-related issues (order that the functions are called, failing to check return codes, etc.), too. It's impossible to comment further without seeing the code.
And I feel obliged to share my final SQLite programming advice that it's worth checking out FMDB Objective-C SQLite wrapper library, which greatly simplifies SQLite programming in iOS.
Update:
Having looked at your code, it looks fine. I just ran it (only tweaked to just NSLog rather than appending notes):
- (void)test2
{
sqlite3 *stuDb;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *databaseName = [documentsDirectory stringByAppendingPathComponent:#"test.db"];
if (sqlite3_open([databaseName UTF8String], &stuDb) == SQLITE_OK)
{
// this is the query line that get changed to show stackoverflow the different results:
const char *sqlStatement = "Select `id`,`note`,`noteDate` FROM notes WHERE `wasUploaded`=0";
sqlite3_stmt *compiledStatement;
int nResult = sqlite3_prepare_v2(stuDb, sqlStatement, -1, &compiledStatement, NULL);
if ( nResult == SQLITE_OK)
{
int nret; // diagnostic used to watch return vaues when single stepping
while ((nret = sqlite3_step(compiledStatement)) == SQLITE_ROW)
{
int id = sqlite3_column_int(compiledStatement, 0);
const unsigned char *note = sqlite3_column_text(compiledStatement, 1);
const unsigned char *noteDate = sqlite3_column_text(compiledStatement, 2);
int wu = sqlite3_column_int(compiledStatement, 4);
if (strlen((const char *)note) > 0 && strlen((const char *)noteDate) > 0)
{
// thisNote = [NSString stringWithFormat:#"%d,%s,%s,%d\n",id, noteDate, note, wu];
// [notes appendString:thisNote];
NSLog(#"%d,%s,%s,%d\n",id, noteDate, note, wu);
}
}
} else {
//sqlite3_finalize(compiledStatement);// prevent small memory leaks, not needed if the prepare failed
sqlite3_close(stuDb);
NSLog(#"prepare failed with error %s", sqlite3_errmsg(stuDb));
return;
}
sqlite3_finalize(compiledStatement);
sqlite3_close(stuDb);
}
}
And I got results:
2012-10-05 15:44:06.075 test8[1574:c07] 1,2012-10-05 19:43:37,ABC,0
2012-10-05 15:44:06.076 test8[1574:c07] 2,2012-10-05 19:43:46,XYZ,0
So the problem must be in the database itself. Judging from your last comment, it sounds like rebuilding the database did it for you. That's great.

Table still exists after DROP TABLE

My iPhone application has a code like this to delete a table and re-create it.
const char *sql = [#"DROP TABLE mytable" cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_step(statement);
NSLog(#"dropped.");
} else {
NSLog(#"error. %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
// ...
// DO SQL LIKE `CREATE TABLE mytable` here.
In most cases, this code works.
But error reports say, the table still exist after the first SQL (DROP TABLE mutable) ran without an error in some rare cases. And I have never experienced that case on my devices.
Has anyone experienced this? or any information?

data is not being inserted from this insert query

I am using this code to insert the data in my database
but it is not working..
My data is not being inserted in the table ..
what can be the problem??
in function.h
+(BOOL)insertStudentinfoData:(NSString *)first_name last_name:(NSString *)last_name phone_num:(NSString *)phone_num;
in function.m
+(BOOL)insertStudentinfoData:(NSString *)first_name last_name:(NSString *)last_name phone_num:(NSString *)phone_num
{
NSString *sql = [NSString stringWithFormat:#"insert into add_data
values(NULL,'%#','%#','%#')",first_name,last_name,phone_num];
return [DBOperation executeSQL:sql];
}
And I am giving the data from this
[Function insertStudentinfoData:#"hello" last_name:#"w3qrq" phone_num:#"efew"];
but my data is not being inserted in the table
////In DBOperation.h
+(BOOL) executeSQL:(NSString *)sqlTmp {
if(conn == SQLITE_OK) {
NSLog(#"\n\n%#",sqlTmp);
const char *sqlStmt = [sqlTmp cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *cmp_sqlStmt1;
int returnValue = sqlite3_prepare_v2(database, sqlStmt, -1, &cmp_sqlStmt1, NULL);
returnValue == SQLITE_OK ? NSLog(#"\n Inserted \n") :NSLog(#"\n Not Inserted \n");
sqlite3_step(cmp_sqlStmt1);
sqlite3_finalize(cmp_sqlStmt1);
if (returnValue == SQLITE_OK) {
return TRUE;
}
}
return FALSE;
}
I guess you are passing the NULL value for PRIMARY KEY, first reset the simulator
if you are not specifying the column name and inserting the values then you should pass the value for each column in particular order of column created otherwise its a good idea to specify column
NSString *sql = [NSString stringWithFormat:#"INSERT INTO add_data
(first_name,last_name,phone_num) VALUE('%#','%#','%#')",first_name,last_name,phone_num];
or
NSString *sql =[NSString stringWithFormat:#"INSERT INTO add_data
(first_name,last_name,phone_num,email,address,city,zip) VALUES
('%#','%#','%#','%#','%#','%#','%#');",first_name,last_name,phone_num,email,addr‌​ess,city,zip];
are you sure that the database is initialized correctly? I always had trouble with the DB not actually there. Which DB Framework are you using?
[EDIT] do you see this log statement?
NSLog(#"\n\n%#",sqlTmp);
Did you write the DBOperations class yourself? I think there is some issue there with the static variable you're using. I'd suggest to either use an existing db framework like fmdb or something, or else modify your class so that it uses the Singleton Pattern.
Oh, and one thing: Are you calling all methods from the same thread? SQlite DBs are not thread safe!
[edit2] You can use the link provided here: SQLite3 error - iOS to check what the value in returnValue actually states - and then figure out the underlying error.
It's probably best for now to modify your not inserted statement like this:
returnValue == SQLITE_OK ? NSLog(#"\n Inserted \n") :NSLog(#"\n Not Inserted with code: %i\n",returnValue);
What if you provide the names of the columns to be inserted:
insert into T (foo, bar, baz)
values( ....)
Try it this way to see full error code and message:
The sql comes as NSString *, do not convert it into a cstring.
int rc;
sqlite3_stmt *sel;
if ((rc = sqlite3_prepare_v2(db_handle, [sql UTF8String], -1, &sel, NULL)) != SQLITE_OK) {
NSLog(#"cannot prepare '%#': %d (%s)", sql, rc, sqlite3_errmsg(db_handle));
return;
}
if (sqlite3_step(sel) != SQLITE_DONE) {
NSLog(#"error insert/update: '%s'", sqlite3_errmsg(db_handle));
...

Select Query Is Not Being Prepared

Here i am implementing a select query to fetch data from table but no any row is been returned by my query.
below is my code that i am using:
if ((sqlite3_open([[self dataFilePath] UTF8String], &database))==SQLITE_OK)
{
NSLog(#"DataBase OpeneD..!!");
imageId=[[NSMutableArray alloc] init];
const char *slectImageIdQuery="SELECT * from ts_Gallary;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, slectImageIdQuery, -1, &statement, nil)==SQLITE_OK)
{
NSLog(#"Query CREATED..!!");
while (sqlite3_step(statement)==SQLITE_ROW)
{
int iId=sqlite3_column_int(statement, 0);
NSString *imgTtl=[NSString stringWithFormat:#"%d",iId];
NSLog(#"image id in while=%d",iId);
[imageId addObject:[NSString stringWithFormat:#"%#",imgTtl]];
}
}
else
{
NSLog(#"query could not be prepared");
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
My console display:
2011-04-06 17:44:33.381 Tuscany[4680:207] DataBase OpeneD..!!
2011-04-06 17:44:33.382 Tuscany[4680:207] query could not be prepared
Note: Here dataFilePath is method which return path of my database and database is sqlite3 object
No Error or exception is been thrown by my application.
What problem can there be and how can I detect the problem as well as solve that?
Thanks.
No Error or exception is been thrown
by my application.
Well, yeah, there is. Your call to sqlite3_prepare_v2() fails; it doesn't return SQLITE_OK.
What happens when you run this statement at your database's sqlite prompt?
SELECT * from ts_Gallary;
Try replacing this line
NSLog(#"query could not be prepared");
with something that will give you more information about the error. Include a call to sqlite3_errmsg().
Remove the semicolon(;) from const char *slectImageIdQuery="SELECT * from ts_Gallary;"
like const char *slectImageIdQuery="SELECT * from ts_Gallary"
and its work properly.

SQLite database - cannot see updates

I have a sqlite database and I am adding to it new words. The problem is that I can see them added to a table only after restarting application. The "SELECT" statement doesn't "see" newly added elements before restarting application.
Why may this happen?
I am creating some kind of a dictionary. Here is how I add new items:
const char *sql_query = "INSERT INTO words(word) VALUES(?)";
if(sqlite3_prepare_v2(database, sql_query, -1, &addWordsStmt, NULL) != SQLITE_OK)
{
return FALSE;
}
sqlite3_bind_text(addWordsStmt, 1, [ word UTF8String], -1, SQLITE_TRANSIENT);
if( sqlite3_step(addWordsStmt) != SQLITE_DONE)
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
sqlite3_reset(addWordsStmt);
sqlite3_finalize(addWordsStmt);
And here is my retrieval code:
const char *sql_query = "SELECT word FROM words WHERE id=?";
if(sqlite3_prepare_v2(database, sql_query, -1, &getWordsStmt, NULL) != SQLITE_OK)
{
return;
}
sqlite3_bind_int(getWordsStmt, 1, wordid);
if( sqlite3_step(getWordsStmt) != SQLITE_ROW)
{
NSLog(#"Error while getting data. '%s'", sqlite3_errmsg(database));
sqlite3_reset(getWordsStmt);
return;
}
NSString *word = [NSString stringWithUTF8String:(char *)sqlite3_column_text(getWordsStmt, 0)];
sqlite3_reset(getWordsStmt);
sqlite3_finalize(getWordsStmt);
My guess is that you are in a transaction. There must be some other calls during your open and close routines that are wrapping your calls in a transaction and not displayed in your code fragments.
That is why you don't see the new words until you application exits
There's your problem:
const char *sql_query = "SELECT word FROM words WHERE id=?";
This isn't how you use SQL. Instead, you should be using SELECT word FROM words; and stepping to get each row as long as you're getting SQLITE_ROW until you get SQLITE_DONE. That will get you all your words. How are you going to find a word by id when you don't know the id of newly added words?