Rows not updating sqlite3 - ios

The following code is suppose to update 2 columns (HoursWorked and TotalEarned) in the row where Date(Primary Key) = todays date which is stored in the string dbDate. I think my update string might be written wrong. The alert view is being triggered.
sqlite3_stmt *newstatement;
sql =[NSString stringWithFormat:#"UPDATE HourLog SET HoursWorked = '%#', TotalEarned = '%#' WHERE Date ='%#'", HoursWorked, TotalEarned, dbDate];
if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &newstatement, nil)==SQLITE_OK){
NSLog(#"details updated");
UIAlertView *alertDialog;
alertDialog = [[UIAlertView alloc]
initWithTitle:#"Title"
message:#"Details Updated!"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles: nil];
[alertDialog show];
sqlite3_step(newstatement);
}
sqlite3_finalize(newstatement);
sqlite3_close(db);

A couple of issues:
The UPDATE syntax is not correct. The individual fields being updated must be separated by a comma, not the word AND.
You probably shouldn't report that the update succeeded until you confirmed the result of sqlite3_step.
In case you're not getting a hit on your WHERE clause, I might suggest determining how many rows were updated, so you can confirm that the WHERE clause succeeded.
And, as always, report sqlite3_errmsg if your SQLite calls fail or else you're flying blind.
Thus:
sqlite3_stmt *statement;
int originalTotalCount = sqlite3_total_changes(db);
NSString *sql = [NSString stringWithFormat:#"UPDATE HourLog SET HoursWorked = %# , TotalEarned = %# WHERE Date='%#'", HoursWorked, TotalEarned, dbDate];
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) != SQLITE_OK) {
NSLog(#"%s: prepare failed: %s", __FUNCTION__, sqlite3_errmsg(db));
} else {
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(#"%s: step failed: %s", __FUNCTION__, sqlite3_errmsg(db));
} else {
int rowsUpdated = sqlite3_total_changes(db) - originalTotalCount;
NSString *message;
if (rowsUpdated == 1)
message = #"Updated one row";
else if (rowsUpdated == 0)
message = #"No rows updated";
else
message = [NSString stringWithFormat:#"Updated %d rows", rowsUpdated]; // should never happen
NSLog(#"%#", message);
UIAlertView *alertDialog = [[UIAlertView alloc] initWithTitle:nil
message:message
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alertDialog show];
}
sqlite3_finalize(statement);
}
I personally wouldn't use the single quotes around the numeric values for HoursWorked and TotalEarned. And you might consider storing the date in one of the established SQLite date formats.

Related

iOS SQLite Blob data is saving NULL

I am trying to insert a BLOB data of SignatureView using this code but when i actually browse the database there is null instead of data.
My signature table schema is given below.
create table sign(id integer primary key AUTOINCREMENT, image blob,invoiceid integer);
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
sqlite3 *contactDB;
sqlite3_stmt *statement;
NSLog(#"%#",dbPath);
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
int invoiceIDINT = (int)invoiceID;
//
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO sign (image,invoiceid) VALUES (?,%d)", invoiceIDINT];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_bind_blob(statement, 2, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_step(statement);
} else {
const char *Error = sqlite3_errmsg(database);
NSString *error = [[NSString alloc]initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc]initWithTitle:#"Error2" message:[NSString stringWithFormat:#"Last inserted ID: %#",error] delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
Always check the result of sqlite3_prepare_v2. If it fails, log the problem using sqlite3_errmsg.
Only call sqlite3_finalize if sqlite3_prepare_v2 succeeds.
You get NULL for the blob because your call to sqlite3_bind_blob is passing the wrong column index. It should be 1, not 2 since your want to bind to the first ? in your INSERT statement.
Why the inconsistency? Why do you use stringWithFormat to set the value for the invoiceid column and then use sqlite_bind_xxx for the image column? You should bind both. Never use stringWithFormat to build a query.
You call sqlite3_step twice. Only call it once and bind your values before you call it.
You appear to be writing to a database inside your app's resource bundle. You can't do that on a real device. It works in the simulator but not on real iOS devices. You need to put your database file in the Documents folder.
Given all of the above, your code should be something like this:
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
// This is wrong - you need to update this to use the Documents folder
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
NSLog(#"%#",dbPath);
sqlite3 *contactDB;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
const char *insert_stmt = "INSERT INTO sign (image, invoiceid) VALUES (?, ?)";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_blob(statement, 1, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, (int)invoiceID);
if (sqlite3_step(statement) == SQLITE_DONE) {
// Row inserted successfully
} else {
const char *Error = sqlite3_errmsg(contactDB);
NSString *error = [[NSString alloc] initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc] initWithTitle:#"Error2" message:[NSString stringWithFormat:#"Last inserted ID: %#",error] delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
} else {
NSLog(#"Unable to prepare statement %s: %s", insert_stmt, sqlite3_errmsg(contactDB));
}
sqlite3_close(contactDB);
} else {
NSLog(#"Unable to open database at path %#: %s", dbPath, sqlite3_errmsg(contactDB));
}
}

how to check item already exits in sqlite objective c

This the my code
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
// [self.dbManager executeQuery:query1];
// -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable
NSLog(#"q1--%#",query1);
BOOL recordExist = [self.dbManager recordExistOrNot:query1];
NSLog(#"------%d",recordExist);
if (!recordExist)
{
NSString *query;
if (self.recordIDToEdit == -1) {
query = [NSString stringWithFormat:#"insert into c values(null,'%#','%d','%d',%d)",item_name.text,a,p,c];
NSLog(#"query---%#",query);
}
// Execute the query.
[self.dbManager executeQuery:query];
// If the query was successfully executed then pop the view controller.
if (self.dbManager.affectedRows != 0) {
NSLog(#"Query was executed successfully. Affected rows = %d", self.dbManager.affectedRows);
// UIAlertView *alert=[[UIAlertView alloc]initWithTitle:Nil message:#"Successfully Added to The Cart" delegate:Nil cancelButtonTitle:#"ok" otherButtonTitles:Nil, nil];
// [alert show];
[self loadData];
}
else{
NSLog(#"Could not execute the query.");
}
}
else
{
NSLog(#"item already exits....");
}
- (BOOL)recordExistOrNot:(NSString *)query1{
sqlite3 *sqlite3Database;
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
sqlite3_stmt *compiledStatement;
BOOL recordExist=NO;
if(sqlite3_open([databasePath UTF8String], &sqlite3Database) == SQLITE_OK)
{
// sqlite3_stmt *statement;
if (sqlite3_prepare_v2(sqlite3Database,[query1 UTF8String], -1, &compiledStatement, NULL)==SQLITE_OK)
{
if (sqlite3_step(compiledStatement)==SQLITE_ROW)
{
recordExist=YES;
}
else
{
//////NSLog(#"%s,",sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
sqlite3_close(sqlite3Database);
}
}
return recordExist;
}
actually i want to be check string value in the table like "select * from table name where item_name=tea"
but this code is checking integer value but i want check string value.please help me
You are missing the single quotes in you select statement. first line.
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
to
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name='%#'",trimmedString];
i'll assume that item_name is unique then you might be better served with doing insert or ignore.
i.e.
insert or ignore into tablename (item_name) values ('something')
thsi will ignore doing the insert if that value for your key exists

implementing WAL in iOS?

The code I placed below works. So my scenario is I have the code below in a class. I use this class simply for merging tables and updating one table. When I call the object that this code lives in the app delegate for example, it works great! But when I call the same object after clicking a button in a tableview controller, I get a database lock error. So here's what I am wondering. After reading sqlite documentation WAL: http://www.sqlite.org/wal.html I am thinking that I cannot read and update concurrently to the sqlite db, right? I am unsure of a solution around this, so what would be a good suggestion around my problem. Remember, keep in mind this code works just fine in the app delegate, it does not work in my tableview controller when I call it using action upon clicking the button. Note: I SELECT data from the SQLITE database to display table cell names etc. Thanks ahead of time!
//Allocates a filemanager object. Ideally, this object is used for searching through the applications context
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL dbErr = NO;
//Boolean variable to tell if the database exists
BOOL error,mainDbError;
//Looks through all the databases. If there is a database that does not exist, the following error message will appear to the user. If all the databases exist on the system, the database opens respectively
error = [self checkAndOpenSyncDB];
mainDbError = [self checkAndOpenMainDB];
if (!error&&mainDbError) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"We didn't mean for this to happen. Looks like there was a problem loading the sync database. Contact technical support for further assistance."
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
else{
//This is I think to check when the last time the sync occured on the system.. not quite sure though1
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Erorr syncing the database: Code: %d, message: '%s'", error,sqlite3_errmsg(syncOpenHandle));
char *errorMessage;
int errorNum = 0;
//Atataching the sync db to the master db
NSString *attachSQL = [NSString stringWithFormat:#"ATTACH DATABASE \'%#\' AS sync_db", self->pathForSync];
NSLog(#"PATH FOR SYNC !!!!!!! %#", pathForSync);
NSLog(#"Here's the arratch string: %#", attachSQL);
//
if (sqlite3_exec(syncOpenHandle, [attachSQL UTF8String], NULL, NULL, &errorMessage) == SQLITE_OK) {
NSString *masterQuery = [NSString stringWithFormat:#"SELECT name FROM sqlite_master WHERE type='table';"];
const char *masterStmt = [masterQuery UTF8String];
sqlite3_stmt *statement;
BOOL loopErr;
loopErr = sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL);
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL)==SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString * currentTable = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"Here's the current table: %#",currentTable);
//This is where the magic happens. If there are any keys matching the database, it will update them. If there are no current keys in the database, the query will insert them.
if ([currentTable isEqualToString:#"USER_DATA"] == NO && [currentTable isEqualToString:#"USER_ACTIVITY"]== NO && [currentTable isEqualToString:#"USER_ITINERARY"] == NO) {
NSString *tblUpdate = [NSString stringWithFormat:#"INSERT or REPLACE INTO main.%# SELECT * FROM sync_db.%#;",currentTable, currentTable];
const char *updateStmt = [tblUpdate UTF8String];
//sqlite3_busy_timeout (mainOpenHandle, 60000);
bool update;
update = sqlite3_exec(syncOpenHandle, updateStmt, NULL, NULL, &errorMessage)== SQLITE_OK;
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
if (sqlite3_exec(syncOpenHandle, updateStmt, NULL, NULL, &errorMessage)== SQLITE_OK) {
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
if (errorNum == 1) {
//A database reset is needded
//self->isResetDataBase = YES;
}
dbErr = YES;
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
}
NSLog(#"Here's the error num %d", errorNum);
NSLog(#"Erorr syncing the database: Code: %d, message: '%s'", error,sqlite3_errmsg(syncOpenHandle));
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
sqlite3_finalize(statement);
//Detaching the database from the mainDB
NSString *detachSQL = [NSString stringWithFormat:#"DETACH DATABASE sync_db"]; // reference sync db
if ((errorNum = sqlite3_exec(syncOpenHandle, [detachSQL UTF8String], NULL, NULL, &errorMessage))!= SQLITE_OK) {
NSLog(#"Detatched syncDb Failed. ErrorMessage = %s ", errorMessage);
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
//Closing the database when finished.
if (syncOpenHandle!=nil) {
sqlite3_close(syncOpenHandle);
NSError *err;
int success = [fileManager fileExistsAtPath:pathForSync];
if (success) {
[[NSFileManager defaultManager]removeItemAtPath:pathForSync error:&err];
}
}

Ios Adding Value in loop in sqlite

Hey my code is very simple , i have crated a sqlite table with one column id and message.
my sqlite table is created successfully. i want to insert 5 string value in message column .my code for insert string value
- (IBAction)addTextToDatabase:(id)sender
{
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &myDatabase) == SQLITE_OK) {
NSString *insertSQL = [NSString stringWithFormat:
#"INSERT INTO SAMPLETABLE (MESSAGE) VALUES (\"%#\")",
self.textField.text];
const char *insert_stmt = [insertSQL UTF8String];
for (int k = 0; k < 5; k++) {
sqlite3_prepare_v2(myDatabase, insert_stmt,
-1, &statement, NULL);
sqlite3_finalize(statement);
}
// sqlite3_prepare_v2(myDatabase, insert_stmt,
// -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
statusOfAddingToDB = [NSString stringWithFormat:#"Text added -- %#",
textField.text];
} else {
statusOfAddingToDB = #"Failed to add contact";
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"DB Status"
message:statusOfAddingToDB delegate:nil cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
// sqlite3_finalize(statement);
sqlite3_close(myDatabase);
}
}
but when i check my database only one value is added to it.please help how to achieve this?
Write sqlite3_step statement within for loop before sqlite3_finalize statement
You have to run this statement:
sqlite3_step(compiledStatement) == SQLITE_DONE
after each insertion.

Deleted record successfully but message can't be printed

I have put my code here i am not getting ,what is the issue with alert message.
NSString *deleteSQL = [NSString stringWithFormat:#"DELETE FROM FAVOURITE WHERE ID = %#", self.arrayID[[sender tag]]];
const char *delete_stmt = [deleteSQL UTF8String];
NSLog(#"insert query is %#",deleteSQL);
NSLog(#"insert statement is %s",delete_stmt);
sqlite3_prepare_v2(favouriteDB, delete_stmt, 1, &statement, NULL);
NSLog(#"akh:%d",sqlite3_prepare_v2(favouriteDB, delete_stmt, -1, &statement, NULL));
NSLog(#"akhdadsa:%d",SQLITE_DONE);
sqlite3_step(statement);
NSLog(#"this %d", sqlite3_step(statement));
if (sqlite3_step(statement)==SQLITE_DONE)
{
UIAlertView *myAlert1 = [[UIAlertView alloc]initWithTitle:#"Message"
message:#"Successfully Remove From Favourite List"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[myAlert1 show];
}
You are calling sqlite3_step twice.
The first call deletes the record, the second one then fails.
you have executed statement twice.
sqlite3_step(statement);
NSLog(#"this %d", sqlite3_step(statement));
if (sqlite3_step(statement)==SQLITE_DONE)
It should be
//sqlite3_step(statement);//delete this line
NSLog(#"this %d", sqlite3_step(statement));
if (sqlite3_step(statement)==SQLITE_DONE)

Resources