iOS SQLite3 multiple prepare statements - ios

just an easy question.
I got an app that uses archaic code (I'm not the one who started the app :D)
Anyhow, it uses SQLite3....yeah....
So my SQlite3 is a bit rusty but when we have multiple query like so:
const char *query1 = "SELECT ... ";
if (sqlite3_prepare_v2(_database, query1, -1, &statement, nil) == SQLITE_OK)
{
...
}
const char *query2 = "UPDATE ... ";
if (sqlite3_prepare_v2(_database, query2, -1, &statement, nil) == SQLITE_OK)
{
...
}
Do I need to use:
sqlite3_reset(statement);
Before I call;
if (sqlite3_prepare_v2(_database, query2, -1, &statement, nil) == SQLITE_OK)
In the above example or does SQLite3 automatically call sqlite3_reset() function each time we call prepare statement?

When you have called sqlite3_prepare_v2(), you must call sqlite3_finalize() to free the resources allocated for the statement.
This must be done before the statement variable is reused, or when you no longer need the statement.
sqlite3_reset() is needed only if you want to execute the same prepared statement another time.

Yes, if you want to use sqlite3_prepare_v2 statement, then sqlite3_reset(statement) statement is compulsory, otherwise there are chances to throw exception.
Here, you can get more idea about importance for sqlite3_reset(statement).
Enjoy Coding !!

Related

Why I am Not able to create and add data to the sqlite file at the same time?

In My current ios application I have to add tables and insert data to the added table for new version.
By taking Upgrade into consideration I did it through the code itself Like below
-(void)lessThan100TableQuery
{
NSString *query=[NSString stringWithFormat:#"CREATE TABLE 'Table_Name' ('item_id' INTEGER PRIMARY KEY NOT NULL , 'item_section' INTEGER, 'item_no' INTEGER, 'bullet_no' VARCHAR, 'heading' INTEGER, 'hide_controls' INTEGER, 'description' VARCHAR);INSERT INTO 'Table_Name' VALUES(1,1,0,'',1,1,'Condition/adequacy of distributor''s/supply intake equipment');"
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
if(sqlite3_step(statement) != SQLITE_DONE) {
return NO;
}
sqlite3_finalize(statement);
}
}
(like above I add 100 rows I skipped them here)
But by calling the above method only the table get added without the values
I cross checked it by running the above query in sqlitemanager and working fine without any issue. It is not working in code.
Help me out folks
The sqlite3_prepare_v2() documentation says:
These routines only compile the first statement in zSql
To execute multiple statements, you have to use a loop, and use pzTail to skip over the previously-executed statement.

Using NSString/parameters into SQLite statement iOS

I have my code below. My values _emailVaue _passwordValue and _nameValue are taken from UITextFields in my app. I was under the impression that passing these values into parameters in my SQLite code would allow me to have special characters in those values such as double quotation marks ( " ), however, if I put them in, the SQLite crashes. Is there something I'm doing wrong?
I'm aware that it's probably best to use something like FMDB, but I was hoping that there might be a quicker fix to get me through an upcoming demo.
I'd appreciate any help, thanks!
if (sqlite3_open(dbpath, &_contactDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:
#"INSERT INTO CONTACTS (email, password, name) VALUES (\"%#\", \"%#\", \"%#\")",
_emailValue, _passwordValue, _nameValue];
NSLog(insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_contactDB, insert_stmt,
-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
I hope it's OK to answer my own question if it seems to work. Hopefully someone will find it useful. Would appreciate any feedback on where I might be going wrong.
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
const char *insertSQL;
if (sqlite3_open(dbpath, &_contactDB) == SQLITE_OK)
{
insertSQL = "INSERT INTO CONTACTS (email, password, name) VALUES (?, ?, ?)";
if(sqlite3_prepare_v2(_contactDB, insertSQL, -1, &statement, NULL) == SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [_emailValue UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [_passwordValue UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [_nameValue UTF8String], -1, SQLITE_TRANSIENT);
}
if (sqlite3_step(statement) == SQLITE_DONE)
{
//worked
} else {
//didn't work
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
I'll try to explain what happened with your code and how it could be improved so that the crash would not occur. I totally agree with the usage of bound arguments, this answer is posted only as it represents an answer to how your crash can be fixed, and might help people that don't have the time to switch to bound statements.
Here's what happened:
sqlite3_prepare_v2() failed as your query string was invalid due to the fact that your strings contained the " characted
due to the above, statement was either NULL or contained a garbage value
sqlite3_step() crashed as an invalid pointer was passed as argument.
Here's the fix:
escape all your strings, by replacing " by \", this will generate a valid query; if you were using ' in your query, then you would have to replace ''s by \'
Example for email:
NSString *escapedEmail = [_emailValue stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
even if you're sure the query is correct, is still mandatory to check the result of sqlite3_prepare_v2() before using the statement in any other sqlite calls.
As a general note, you need to code very defensively when dealing with C API's as C doesn't forgive you if you forget to check for NULL pointers. Objective-C is more soft, as it allows you to send messages to nil objects.

Error with SQL update Statement

I want to update something in a sql database, but every time it gives me an error ...
This is my code:
// UPDATE SQL
- (void)sqlId:(int)sqlId text:(NSString *)text time:(NSString *)time preis:(NSString *)preis
{
[self openDb];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *insertSQL = [NSString stringWithFormat:
#"UPDATE `webdesign` SET data='%#', time='%d', preis='%#' WHERE id='%d')",
text, [time intValue], preis, sqlId];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"updated");
} else {
NSLog(#"Error");
}
sqlite3_finalize(statement);
}
[self closeDb];
}
The console says:
2013-08-31 12:07:21.366 Webdesign[6519:a0b] database opened
2013-08-31 12:07:21.367 Webdesign[6519:a0b] Error
2013-08-31 12:07:21.367 Webdesign[6519:a0b] database closed
maybe it's a simple problem, but I can't find it.
without knowing the table structure of your SqLite3 database, it's not possible to provide you with a 100% correct answer, but I suspect the line
UPDATE `webdesign` SET data='%#', time='%d', preis='%#' WHERE id='%d')
to be erroneous. In fact, you put decimals between single quotes, you put the name of the table between single quotes, ...
I tend to use an NSLog to write out the created statement, and copy/paste that statement in my sqlite3 command line tool (or in Valentina Studio, which I use often) to check if the created statement is correct. This has saved me lots of time.
Kind regards,
PB
DAMN I've found the error ...
#"UPDATE `webdesign` SET data='%#', time='%d', preis='%#' WHERE id='%d')"
The ")" is the mistake ! :D
always such a small error -.-

Not inserting rows in sqlite database in iOS

I have a method intended to insert in my sqlite database from a custom object:
- (void)insertCustomEntity:(CustomEntity *)customEntity
{
NSString *filePath = [FileMngr copyDatabaseToDocuments];
sqlite3 *database;
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "INSERT OR REPLACE INTO Entities (id, type, timestamp, result) VALUES (?, ?, ?, ?)";
sqlite3_stmt *compiledStatement;
NSLog(#"Could not prepare statement: %s\n", sqlite3_errmsg(database));
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_int(compiledStatement, 1, customEntity.id);
sqlite3_bind_int(compiledStatement, 2, customEntity.type);
sqlite3_bind_int64(compiledStatement, 3, customEntity.timestamp);
sqlite3_bind_int(compiledStatement, 4, customEntity.result);
}
if(sqlite3_step(compiledStatement) == SQLITE_DONE) {
}
else {
NSLog(#"Step: %d\n", sqlite3_step(compiledStatement));
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
I've been doing tests for a while and data was being inserted, but suddenly it stopped to do and I'm now getting a 5 step code at my second NSLog. Why does this happen, if it was working previously? I tried several options I found in some posts, like placing the sqlite3_step(compiledStatement) inside the sqlite3_prepare_v2 but I keep being unable to insert. What I'm doing wrong?
Thanks in advance
I am not sure but it looks like some of your braces are mis-matched? Anyways, error code 5 indicates that your database is locked.
http://www.sqlite.org/c3ref/c_abort.html
Check if something else is accessing your database ( or your database is not getting closed in some situation in which case your code needs to change). Try the following solution to resolve it :-
sqlite3 database is getting locked

Sqlite Database locked in some case while inserting data

I have a problem in my Iphone application.
Some time my Application run successfully,But in some cases it give "databse is locked exception"thats why i am unable to read or insert data from sqlite datase.
Please suggest me if any one have some solution.
This is my code of inserting data into databse
Thanks.
-(void)insertDataIntoDatabase
{
NSLog(#"insertDataIntoDatabase-----1");
#try{
tUserName=userNameTf.text;
tLevel=[NSString stringWithFormat:#"%d",level];
tMoves=[NSString stringWithFormat:#"%d",moves];
NSLog(#"tLevel;;;%#",tLevel);
// NSString *tdatabaseName = #"FlipScoreBord.sqlite";
sqlite3_stmt *addStatement;
// NSArray *tdocumentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *tdocumentsDir = [tdocumentPaths objectAtIndex:0];
// NSString *tdatabasePath = [tdocumentsDir stringByAppendingPathComponent:tdatabaseName];
NSString *insertQuery = [NSString stringWithFormat:#"INSERT INTO Moves (User_Name,User_Label,User_Moves) VALUES('%#','%#','%#')",tUserName,tLevel,tMoves];
const char *sql = [insertQuery cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_prepare_v2(tdatabase, sql, -1, &addStatement, NULL) != SQLITE_OK)
{
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(tdatabase));
}
sqlite3_bind_text(addStatement, 0, [tUserName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStatement, 1, [tLevel UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStatement, 2, [tUserName UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(addStatement))
{
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(tdatabase));
sqlite3_reset(addStatement);
}
sqlite3_close(tdatabase);
}
#catch (NSException *r)
{
NSLog(#"Exception---- %#",r);
}
NSLog(#"insertDataIntoDatabase-----2");
}
I have to confess that I use FMDB (a SQLite wrapper that insulates me from the SQLite functions), but a couple of things look odd:
If you sqlite3_prepare_v2() a statement, don't you need your sqlite3_finalize()?
It looks like you're closing the db here, but not opening it. Seems like that opens the possibility that your sqlite3_open() statements and your sqlite3_close() calls are not balanced. Are you 100% confident that this is not the problem? I'd try putting in NSLog's at the open and close statements and make sure they're balanced.
The combination these two issues make me wonder if you meant sqlite3_finalize() where you currently have sqlite3_close().
Just a few ideas.
This link lists the reasons how a database lock error can be triggered:
http://www.sqlite.org/cvstrac/wiki?p=DatabaseIsLocked
Quoting one of the reasons:
Trying to write to a table while a SELECT is active on that same table.
Since you did not call the sqlite3_finalize on your statement, it is possible that a previous 'SELECT' statement is blocking your 'INSERT'. Try adding an sqlite3_finalize before you call the sqlite3_close.

Resources