How to rollback what an action did on sqlite database using objective-c - objective-c

I am updating a database table before requesting some json data from a web service. Some times response fail. If this type of occasion ho can i rollback update operation using objectivec.
-(void)syncPhoneDBWithData:(NSData *)data{
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:data];
if ([dictionary count]!= 0) {
NSArray *ticketsArray = [dictionary objectForKey:#"tickets"];
for (NSDictionary *ticketDict in ticketsArray) {
Ticket *ticketToStore = [[Ticket alloc]init];
ticketToStore.ticketID = [ticketDict objectForKey:#"ticketID"];
ticketToStore.ticketTitle = [ticketDict objectForKey:#"ticketTitle"];
ticketToStore.numberOfAdults = [ticketDict objectForKey:#"numberOfAdults"];
ticketToStore.numberOfChildren = [ticketDict objectForKey:#"numberOfChildren"];
ticketToStore.redeemed = [ticketDict objectForKey:#"redeemed"];
ticketToStore.syncStatus = [NSNumber numberWithInt:1];
if ([DBConnect isExistingTicket:ticketToStore.ticketID]) {
[DBConnect updateTicketRedeemStatus:ticketToStore];
}else{
[DBConnect insertNewTicket:ticketToStore];
}
}
}else{
NSLog(#"======================Empty============================");
}
}
+ (NSString *)insertNewTicket:(Ticket *)ticket{
NSString *lastInsertedTicketId = #"";
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:dbName];
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "insert into tickets (ticket_id , ticket_title , adults , children , redeem_status , sync_status, redeemed_dateTime ) VALUES (?,?,?,?,?,?,?)";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text ( compiledStatement, 1, [ticket.ticketID UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text ( compiledStatement, 2, [ticket.ticketTitle UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int ( compiledStatement, 3, [ticket.numberOfAdults intValue] );
sqlite3_bind_int ( compiledStatement, 4, [ticket.numberOfChildren intValue]);
sqlite3_bind_text ( compiledStatement, 5, [ticket.redeemed UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int ( compiledStatement, 6, [ticket.syncStatus intValue] );
sqlite3_bind_int ( compiledStatement, 7, [ticket.redeemedDate timeIntervalSince1970]);
}
if(sqlite3_step(compiledStatement) != SQLITE_DONE ) {
NSLog( #"add new Ticket Error: %s", sqlite3_errmsg(database) );
}else{
lastInsertedTicketId = [NSString stringWithFormat:#"%lld",sqlite3_last_insert_rowid(database)];
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return lastInsertedTicketId;
}

Use CoreData (wrapped into MagicalRecord) and undo. :)

Related

sqlite3_prepare_v2 failing

Could anyone explain to me why this if statement is not triggering? The database opens just fine, it's just that I can't retrieve any values from the database. Also, the table name is correct as well.
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int uniqueId = sqlite3_column_int(statement, 0);
char *nameChars = (char *) sqlite3_column_text(statement, 1);
char *addressChars = (char *) sqlite3_column_text(statement, 2);
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
NSString *address = [[NSString alloc] initWithUTF8String:addressChars];
PersonInfo *info = [[PersonInfo alloc] initWithUniqueID:uniqueId name:name address:address];
[returnArray addObject:info];
}
sqlite3_finalize(statement);
}
return returnArray;
}

Delete data in SQLite

I want to delete record from database,
I define in file.h the database, and in the file.m the insert data and read data it's work, but the delete was not work.
this is the file.h
#import "sqlite3.h"
#define DATA_FILE #"prova12"
#define TABLE_NAME #"password"
#define FIELDS_NAME_SID #"pass"
#define FIELDS_NAME_SNAME #"foto"
#define FIELDS_NAME_SCLASS #"studentClass"
#define FIELDS_NAME_PROVA #"provaClass"
{sqlite3 *db;
}
in the file.m
for the path:
-(NSString *)dataFilePath {
NSArray * myPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask, YES); NSString * myDocPath = [myPaths objectAtIndex:0];
NSString *filename = [myDocPath stringByAppendingPathComponent:DATA_FILE];
return filename;
for read:
-(NSMutableArray*)selectAll
{
NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:nil];
NSString *filename = [self dataFilePath];
NSLog(#"%#",filename);
if (sqlite3_open([filename UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO,#"no");
} else {
NSString *qsql = [NSString stringWithFormat: #"SELECT %# FROM %#", FIELDS_NAME_SID, TABLE_NAME];
NSLog(#"qui%#",qsql);
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_text(statement, 1, [inserisci.text UTF8String], -1, NULL);
while (sqlite3_step(statement) == SQLITE_ROW) {
char *field1 = (char *) sqlite3_column_text(statement, 0);
NSString *field1Str = [[NSString alloc] initWithUTF8String: field1];
//studentId.text = field1Str;
//[field1Str release];
[list addObject:field1Str];
NSLog(#"%d",list.count);
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
return list;
}
and this for save:
-(IBAction) save {
NSString *filename = [self dataFilePath];
if (sqlite3_open([filename UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(NO,#"no");
} else {
NSString *sqlStr = [NSString stringWithFormat: #"INSERT OR REPLACE INTO %# (%#, %#, %# ,%#) VALUES (?,?,?,?)",
TABLE_NAME, FIELDS_NAME_SID, FIELDS_NAME_SNAME, FIELDS_NAME_SCLASS, FIELDS_NAME_PROVA];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {
NSLog(#"quiiiiddddd %#", filename);
sqlite3_bind_text(statement, 1, [inserisci.text UTF8String], -1, NULL);
sqlite3_bind_text(statement, 2, [immagine UTF8String], -1, NULL);
sqlite3_bind_text(statement, 3, [inserisci.text UTF8String], -1, NULL);
sqlite3_bind_text(statement, 4, [inserisci.text UTF8String], -1, NULL);
if (sqlite3_step(statement) != SQLITE_DONE) {
NSAssert(0, #"no");
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
}
but I don't have an idea to delete data, can anyone please help me?
you want to delete all record ore selected
-(bool)deleteEvent:(int)eventID
{
DBSettings *dbSettings = [[DBSettings alloc]init];
[dbSettings checkAndCreateDatabase];
DatabaseName=dbSettings.DBName;
DatabasePath=dbSettings.DBPath;
[dbSettings release];
sqlite3 *database;
if(sqlite3_open([DatabasePath UTF8String], &database) == SQLITE_OK)
{
const char *sqlStatement;
NSString *query = [NSString stringWithFormat:#"%#'%i'",kDeleteQuery,eventID];
//Convert NSString to char pointer for execution
sqlStatement=[query UTF8String];
if(sqlite3_prepare_v2(database, sqlStatement, -1, &deleteStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
if(SQLITE_DONE != sqlite3_step(deleteStmt))
{
NSAssert1(0, #"Error while deleting data. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(deleteStmt);
sqlite3_close(database);
return YES;
}
return NO;
}
kDeleteQuery "Is your query for all record or selected"
-(void)deleteDetails:(int *)detailId
{
if (sqlite3_open([filename UTF8String], &db) != SQLITE_OK)
{
sqlite3_close(db);
}
else
{
sqlite3_stmt *statement;
NSString *strSQL =[NSString stringWithFormat:#"DELETE FROM tablename WHERE id = %d", detailId];
mainSql = [strSQL UTF8String];
if(sqlite3_prepare_v2(db, mainSql , -1, &statement, NULL)==SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"Records are deleted");
}
}
else
{
NSLog(#"Error : -------'%s'", sqlite3_errmsg(db));
}
}
sqlite3_reset(statement);
sqlite3_finalize(statement);
sqlite3_close(db);
}

SQLite, Objective C: method returns int max value

-(int)countTheNumberOfDublicatesForType:(int)typeID
{
NSInteger quantity=0;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:user_data];
sqlite3* database = NULL;
sqlite3_stmt *statement;
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
const char *sqlQuery=sqlite3_mprintf("SELECT COUNT(refID)\
FROM dublicates\
WHERE typeREF=%i",typeID);
if(sqlite3_prepare_v2(database, sqlQuery,-1, &statement, NULL) == SQLITE_OK)
sqlite3_bind_int(statement, 1,typeID);
if(sqlite3_step(statement) == SQLITE_ROW)
{
quantity = sqlite3_column_int(statement, 0);
}
sqlite3_finalize(statement);
sqlite3_free((char*)sqlQuery);
sqlite3_close(database);
}
else
{
//
}
return quantity;
}
The math in this method returns the max value of int. Where's the mistake and how to manage it the way it would return the real values from db? Thank you in advance.
EDIT:
You have no error handling, you are binding to a nonexistent parameter, the code is indented wrong, and you are reading with a wrong data type.
Use something like this:
if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
sqlite3_errmsg(database); // log or print this
sqlite3_close(database);
return 0;
}
if (sqlite3_prepare_v2(database,
"SELECT COUNT(refID) FROM dublicates WHERE typeREF=?",
-1, &statement, NULL) != SQLITE_OK) {
sqlite3_errmsg(database); // log or print this
sqlite3_close(database);
return 0;
}
sqlite3_bind_int(statement, 1, typeID);
if (sqlite3_step(statement) != SQLITE_ROW)
sqlite3_errmsg(database); // log or print this
else
quantity = sqlite3_column_int(statement, 0);
sqlite3_finalize(statement);
sqlite3_close(database);

Xcode crash caused by sqlite3_bind_text function in objective C

I am trying to take text that the user inputs in a text view section (outlet named viewNotes) and put it into a DB after clicking a submit button. When I run the app it works fine until I hit submit and then I get a crash (breakpoint) on the sqlite3_bind_text function. I can't figure out what I'm doing wrong. Here is the action code:
- (IBAction)submitNotes:(id)sender {
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDir stringByAppendingPathComponent:#"highpeaks.db"];
sqlite3 *database;
sqlite3_stmt *theNewStmt;
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
const char *sql = "UPDATE Peaks SET notes=? WHERE ID=?";
if(sqlite3_prepare_v2(database, sql, -1, &theNewStmt, NULL) != SQLITE_OK)
NSLog(#"Error while creating update statement. %s", sqlite3_errmsg(database));
}
NSLog(#"%#",self.viewNotes.text);
sqlite3_bind_text(theNewStmt, 1, [self.viewNotes.text UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(theNewStmt, 2, [self.detailItem ID]);
char* errmsg;
sqlite3_exec(database, "COMMIT", NULL, NULL, &errmsg);
if(SQLITE_DONE != sqlite3_step(theNewStmt))
NSLog(#"Error while updating. %s", sqlite3_errmsg(database));
sqlite3_finalize(theNewStmt);
sqlite3_close(database);
}
I am not entirely sure what was wrong with the above code, but this code works just fine:
sqlite3_stmt *stmt=nil;
sqlite3 *cruddb;
//insert
const char *sql = "UPDATE Peaks SET notes=? where ID=?";
//Open db
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *cruddatabase = [docsDir stringByAppendingPathComponent:#"highpeaks.db"];
sqlite3_open([cruddatabase UTF8String], &cruddb);
sqlite3_prepare_v2(cruddb, sql, -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, [self.viewNotes.text UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, [self.detailItem ID]);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_close(cruddb);

Count Number of Rows in a SQLite Database

I'm trying the following code to count the number of rows in my SQLite database table, but it throws an exception. Is these a simpler way to do this?
- (void) countRecords {
int rows = 0;
#try {
NSString *dbPath = [self getDBPath];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *strSQL;
strSQL = #"SELECT COUNT(*) FROM MYTABLE";
const char *sql = (const char *) [strSQL UTF8String];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK) {
// THIS IS WHERE IT FAILS:
if (SQLITE_DONE!=sqlite3_step(stmt) ) {
NSAssert1(0,#"Error when counting rows %s",sqlite3_errmsg(database));
} else {
rows = sqlite3_column_int(stmt, 0);
NSLog(#"SQLite Rows: %i", rows);
}
sqlite3_finalize(stmt);
}
sqlite3_close(database);
}
}
#catch (NSException * e) {
NSLog(#"Error Counting");
}
}
I came across a solution, using my code above, just replacing the step statement with the code below:
if (sqlite3_step(stmt) == SQLITE_ERROR) {
NSAssert1(0,#"Error when counting rows  %s",sqlite3_errmsg(database));
} else {
rows = sqlite3_column_int(stmt, 0);
NSLog(#"SQLite Rows: %i", rows);
}
This usually works for me
- (NSInteger )numberRecordsForTable:(NSString *)table {
NSInteger numTableRecords = -1;
if (sqlite3_open([self.dbPath UTF8String], &database) == SQLITE_OK) {
NSString *sqlStatement = [NSString stringWithFormat: #"select count(*) from %#", table];
const char *sql = [sqlStatement cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_prepare_v2(database, sql, -1, &sqlClause, NULL) == SQLITE_OK) {
while(sqlite3_step(sqlClause) == SQLITE_ROW) {
numTableRecords = sqlite3_column_int(sqlClause, 0);
}
}
else {
printf("could not prepare statement: %s\n", sqlite3_errmsg(database));
}
}
else {
NSLog(#"Error in Opening Database File");
}
sqlite3_close(database);
return numTableRecords;
}
HTH
There is no SQL expression to count rows in a database: you can count rows in a every table and then add them up.
I thought I'd trow in my two cents here as there is an expression to count rows in a database, I use it when dealing with MySQL databases using php scripts all the time. and I tested it in an ios app it's available in there too behold:
sqlite3 *database;
if(sqlite3_open([dbpath UTF8String], &database) == SQLITE_OK)
{
NSString *sql = #"select count(*) from today";
sqlite3_stmt *selectStatement;
int returnValue = sqlite3_prepare_v2(database, [sql UTF8String], -1, &selectStatement, NULL);
if (returnValue == SQLITE_OK)
{
if(sqlite3_step(selectStatement) == SQLITE_ROW)
{
numrows= sqlite3_column_int(selectStatement, 0);
}
}
sqlite3_finalize(selectStatement);
sqlite3_close(database);
}
no need for a fancy loop counter thing. btw if your using an auto increment int for the primary key. it works just slightly different then an array's key. where as in an array that is n items long the valid array elements are from 0 to n-1 in a database the key field is from 1 to n simple enough to work around if you just keep that in mind.
-(void)databaseRecordCount{
int rows = 0;
#try {
sqlite3 *database;
NSString *filePath = [self databaseDocumentsFilePath];
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
NSString *query = #"SELECT * FROM MYTABLE";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &compiledStatement, NULL) != SQLITE_OK)
NSLog(#"Error while creating detail view statement. '%s'", sqlite3_errmsg(database));
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &compiledStatement, nil) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
rows++;
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
}
#catch (NSException * e) {
NSLog(#"Error Counting");
}
NSLog(#"SQLite Rows: %i", rows);
NSUserDefaults *userDefaults;
userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:rows forKey:#"databaseRecordCount"];
[userDefaults synchronize];
}
You'll have to count of each table individually. Some pseudo code:
sql = "SELECT name FROM sqlite_master" WHERE type = 'table'
tables() = GetRows(sql)
Dim total As Integer
For Each t As String in tables
sql = "SELECT COUNT(*) FROM " + t
total = total + GetValue(sql)
Next
Show(total)