iPhone app crashes with sqlite3_bind_text() - iphone

I'm attempting to make a simple app that stores and displays flash cards, however I'm having an awful time getting my SQLite to work. The database connection is fine, but when I try an insert, it crashes and gives no indication of what went wrong. This is the code I am using to insert the flash card into the table.
const char *insert = "INSERT OR REPLACE INTO LIST (TERM, DEFINITION) VALUES (?, ?);";
sqlite3_stmt *statement;
sqlite3_prepare_v2(database, insert, -1, &statement, nil);
sqlite3_bind_text(statement, 1, [term UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [def UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
I've determined that the bind text method is the weak link with some NSLog() methods I placed earlier. In this example, term and def are NSStrings that do hold the correct value (I know that much for sure). Any help would be appreciated. I haven't quite mastered portable c.

Not 100% why its not working but I have a few things to suggest:
Get rid of the ; at the end of the insert statement, I've never had it in mine.
Put the prepare and step into an if statement like so
if(sqlite3_prepare_v2(db, sql, -1, &statement, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(db));
}
if (SQLITE_DONE != sqlite3_step(statement)) {
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(db));
}
None of this might help but it might get you closer as to whats wrong.
Also, one thing that might help. When I've been working with SQLite its been an utter pain if I make a change to the db or if I'm not putting correct data in. I've spent a lot of time resetting the iPhone simulator and cleaning the build

Related

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.

sqlite error 14 [unable to open database file] iphone xcode

Hi i am using database in iphone. After along time, My application gave this error
sqlite error 14 [unable to open database file]
My application is going good but some times it generates the above error.What is the solution?
There is the code:
[lovkid openDatabase:[appDelegate getDBPath]];
NSString *Flag = [NSString stringWithFormat:#"%#", appDelegate.selectimage];
int recId = (int)appDelegate.Id;
NSLog(#"recID = %d",appDelegate.Id);
updateStmt1 = nil;
if(updateStmt1 == nil)
{
const char *sql ="UPDATE 'char' SET `Pic`=? WHERE `id`=?";
if(sqlite3_prepare_v2(database1, sql, -1, &updateStmt1, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database1));
}
sqlite3_bind_text(updateStmt1, 1, [Flag UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_int(updateStmt1, 2, recId);
if(SQLITE_DONE != sqlite3_step(updateStmt1))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database1));
else
NSLog(#"no error");
sqlite3_reset(updateStmt1);
sqlite3_finalize(updateStmt1);
...
well u need to try out my answer from the post
and make sure u write the two functions (of the post ) in ur application delgate that way ur app will open DB once
Let me Know if it worked
Cheers :)
The SQLite error 14 can be solved by changing the settings in the directory where the database file is stored.

SQLite Syntax (order by causing error)

Looking for some syntax help for SQLite, a very odd thing is happening. I am running the query on an iPhone.
Here is the query that fails: (Assume that the tables are correct, this runs great in the firefox sqlite plugin)
select tcodes.DisplayOrder, StatusText, StatusCode
from tcodes
join tcode_transitions on tcode_transitions.available = tcodes.UNID
where StatusCode = 'AAA'
order by tcodes.DisplayOrder
To get it to run, I have to remove the order by clause, which seems a bit strange.
Here is the call:
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
int rtn = sqlite3_prepare_v2(database, [sql UTF8String], -1, &compiledStatement, nil);
if(rtn != SQLITE_OK) {
NSLog(#"SQL Error: %d",rtn);
sqlite3_close(database);
}
}
in the above, rtn is == 1, which indicates a SQL error.
Again, the query runs great outside the phone. Is it possible that the SQL libraries on the iPhone have a different syntax for the order by?
Use sqlite3_errmsg (or sqlite3_errmsg16) to get more information about error.
Try adding DisplayOrder to select clause.
Some databases require that all columns in ORDER BY clause are also present in SELECT clause.

Why I am getting sqlite3error?

I am trying to reuse an sqlite statement in my application in a method. Here's the relevant code
if(getsets_statement == nil){
const char *sql = "SELECT DISTINCT num,roll FROM mytable WHERE cls like ? and divname like ?";
if(sqlite3_prepare_v2(database, sql, -1, &getsets_statement, NULL) != SQLITE_OK){
NSAssert1(0, #"Error: Failed to prepare stmt with message '%s'", sqlite3_errmsg(database));
}
}
sqlite3_bind_text(getsets_statement, 1, [cls UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(getsets_statement, 2, [divname UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(getsets_statement) == SQLITE_ROW){
setNumber= sqlite3_column_int(getsets_statement, 0);
roll = sqlite3_column_int(getsets_statement, 1);
[numArr addObject:[NSNumber numberWithInt:setNumber]];
[rollArr addObject:[NSNumber numberWithInt:roll]];
}
sqlite3_reset(getsets_statement);
The statement executes perfectly the first time it is called. But the next time I call this method, I get a sqlite3error. The values of divname and cls are present (did an NSLog and checked) but I don't understand why I am getting this error. I get the error at the first bind_text statement.
This is in the gdb console
Program received signal: “EXC_BAD_ACCESS”.
(gdb) where
#0 0x9041857f in sqlite3Error ()
#1 0x9041acea in vdbeUnbind ()
#2 0x9041b2c8 in bindText ()
Any help?
Make sure nothing else is actually the issue (is the database being closed somewhere else? Is the getsets_statement pointing to the same object? Has it been finalized?). Then try using NULL or SQLITE___STATIC instead of SQLITE_TRANSIENT. Since [NSString UTF8String] returns data that doesn't need to be freed (by you), it obviously doesn't need a destructor, and it will stay valid until after your function exits, at which time you're done running the statement anyway.
I believe you need to call sqlite3_reset and sqlite3_clear_bindings on the prepared statement before attempting to reuse it. Also, you should really check your return codes.

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?