Error with SQL update Statement - ios

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 -.-

Related

iOS SQLite3 multiple prepare statements

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 !!

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.

SQLite update column if another column exists

Okay, so I'm not sure exactly how to name this question but I can explain what my issue is. I'm creating a webbrowser, and using an sqlite database to store the history. When the page finished loading my method:
-(void)addHistory:(NSString*)title address:(NSString*)url{
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_historyDB) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat:
#"UPDATE HISTORY SET title='%#' WHERE url='%#'", title, url];
const char *update_stmt = [updateSQL UTF8String];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(_historyDB, update_stmt, -1, &stmt, NULL)==SQLITE_OK) {
NSLog(#"Updated");
}else{
NSString *insertSQL =
[NSString stringWithFormat:
#"INSERT INTO HISTORY (title, url, visits, date, search) VALUES (\"%#\", \"%#\", \"%#\", \"%#\", \"%#\")",
title, url, #"todo", #"todo", [NSString stringWithFormat:#"%# %#", title, url]];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_historyDB, insert_stmt,
-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"Added Entry");
} else {
NSLog(#"Coundn't Add Entry");
}
sqlite3_finalize(statement);
}
sqlite3_close(_historyDB);
}
}
I assumed that if the update failed (because the url is not present in the table) it would move to the else statement and add the key. The main idea behind this is to update the title of the webpage, and once that is working, update other fields such as last visited, amount of times viewed and so on..
I've experimented with a variety of different methods but I just can't seem to achieve the desired results.
To execute the update statement, you must call sqlite3_step for that statement.
To find out how many records were updated, call sqlite3_changes.
And you must handle any errors returned by the sqlite3_prepare_v2 calls.
And you must call sqlite3_finalize for stmt.
And any website with ' in its URL or title will corrupt your SQL statements; to avoid SQL injection attacks, use parameters.
I ended up making the switch to FMDB, a brilliant Objective-C wrapper for SQLite. I then performed a SELECTstatement where the url matched the current one, if it returned a value I updated the database, if not, I simply added to it.

sqlite3 IOS query bugging table

i have this odd bug where i'm querying my table 'Children' with quite a complex query. It works fine, but for some reason it bugs a this other view from updating the database. You see this database holds stickers and one easy way to give them is to access this admin page, which is where its bugging. I can query the information fine, BUT ! when i update the table it hates and doesn't work. But its strange inside the core view controller it doesn't bug when i update the table there. I narrowed down the code to the cause of this problem:
-(void)leaderboardsystem
{
NSString *nexttargetsql = [NSString stringWithFormat:#"SELECT * FROM Children WHERE Completed > %d OR (Completed = %d AND Current_Stickers > %d) ORDER BY Completed ASC, Current_Stickers ASC LIMIT 1",completecount,completecount,stickercount]; //Queries table for the childs name and returns more data.
NSString *behindyousql = [NSString stringWithFormat:#"SELECT * FROM Children WHERE Completed < %d OR (Completed = %d AND Current_Stickers < %d) ORDER BY Completed DESC, Current_Stickers DESC LIMIT 1",completecount,completecount,stickercount];
nexttarget.text = [self leaderboardQuery:nexttargetsql];
behindyou.text = [self leaderboardQuery:behindyousql];
}
-(NSString*)leaderboardQuery:(NSString*)sql//does the querying
{
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(Childdb, [sql UTF8String], -1, &statement, nil)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
char *ffield1 = (char *) sqlite3_column_text(statement, 0);
NSString *ffield1Str = [[NSString alloc]initWithUTF8String:ffield1];
char *ffield2 = (char *) sqlite3_column_text(statement, 8);
NSString *ffield2Str = [[NSString alloc]initWithUTF8String:ffield2];
char *ffield3 = (char *) sqlite3_column_text(statement, 10);
NSString *ffield3Str = [[NSString alloc]initWithUTF8String:ffield3];
NSLog(#"Name:%#",ffield1Str);
NSLog(#"this is completecount: %#", ffield2Str);
NSLog(#"this is stickcount: %#",ffield3Str);
return ffield1Str;
}
}
return NULL;
}
whenever i call the method leaderboardsystem it causes this bug, but if i don't then it works fine ! funny enough, i was a little surprised to be honest. It surprises me because it affects a completely different view controller that has no connection to the main view. The table layout is:
[self createTable:#"Children" withField1:#"Name" withField2:#"Password" withField3:#"House" withField4:#"Sticker Collection" withField5:#"Tickets Gathered" withField6:#"Tickets Removed" withField7:#"Last Ticket Scanned" withField8:#"Current Tickets" withField9:#"Completed" withField10:#"Complete" withField11:#"Current_Stickers"];
This is the updating code that seems to fail when i include the leaderboard system in the main view(this is on a completely different view controller)
-(void)UpdateDatabase//update table, if value has been incremented
{
NSString *sql = [NSString stringWithFormat:#"UPDATE Children SET 'Current Tickets' = %d, 'Tickets Removed' = %d, 'Tickets Gathered' = %d WHERE Name = '%#'",[self.currenttickets.text integerValue], [self.removedtickets.text integerValue], [self.totaltickets.text integerValue], name];
[self updatetable:sql];
}
-(void)updatetable:(NSString*)sql
{
char *err;
if (sqlite3_exec(Childdb, [sql UTF8String], NULL, NULL, &err)!=SQLITE_OK) {
sqlite3_close(Childdb);
NSAssert(0, #"Could not update Table");
} else {
NSLog(#"Table updated");
}
}
I'm trying not to overload the description here and keeping it brief my program is quite large, if you require any more information let me know. BUT i guarantee that the leaderboard system is causing the problem. Thanks a million if you can solve this problem, been working on it all day ! :(
ALSO it also disturbs the place where i add records to the table, so the updating code is not causing it. Its that leaderboard query, no idea why :(
Okay, well i didn't want to do this. But instead of having a method to manage the query, i just repeated it twice, inside the method, but it worked ! Not sure what was wrong with it. Seems no one else could help me so, i'll just leave it to that.
You need to call sqlite3_finalize(Childdb). It would look something like the following:
-(NSString*)leaderboardQuery:(NSString*)sql//does the querying
{
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(Childdb, [sql UTF8String], -1, &statement, nil)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
...
}
}
sqlite3_finalize(Childdb);
return NULL;
}
This is a really simple example because there is no error handling. The documentation that describes this is the following (located here):
*ppStmt is left pointing to a compiled prepared statement that can be executed using sqlite3_step(). If there is an error, *ppStmt is set to
NULL. If the input text contains no SQL (if the input is an empty
string or a comment) then *ppStmt is set to NULL. The calling
procedure is responsible for deleting the compiled SQL statement using
sqlite3_finalize() after it has finished with it. ppStmt may not be
NULL.
This example code may help you: https://github.com/ccgus/fmdb/blob/master/src/FMDatabase.m#L519

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