Objective - C And SQLite - Database Locked - ios

What motivates the occurs "Error database is locked" when ever I open and close the database and also finalize all statement?
Code:
//Opening database
if (sqlite3_open([[self filePath] UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Database failed to open.");
}else{
NSLog(#"Database opened.");
}
//Performing operation
char * err;
if(sqlite3_exec(database, [sql UTF8String], NULL, NULL, &err) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"----> Could not perform operation on table people. Error %# <----", [NSString stringWithUTF8String:err]);
} else {
NSLog(#"----> Operation performed on table people <----");
}
sqlite3_close(database);

Related

Implementation of NSOperationQueue by sending request & Storing response in Database parallely

I have implemented NSOPERATIONQUEUE By sending request and i can able to download response from server but the problem is i cant able to parallely process the sqlite to insert/update the response,i am getting Database Locked Error.So Can anyone suggest me a solution to work with database for insertion/updation of my downloaded response??
I have created a NSOperation Class as PageLoadOperation and i will pass request 7 times to that NSOperation class and add it to queue as below
PageLoadOperation *pageLoad=[[PageLoadOperation alloc]initWithRequest:theRequest];
[queue addOperation:pageLoad];
In Main i can able to send request by below NSURLConnection
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
[self openConnection];
[self doSomethingWithData:data];
[self closeConnection];
}];
and in doSomethingWithData method i will insert/update the response by converting data to NSString I have separately created method for opening the database connection and once insertion/updation completed i will closeconnection by following methods
-(BOOL)openConnection
{
database=nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
documentsDir = [paths objectAtIndex:0];
if(sqlite3_open([[documentsDir stringByAppendingPathComponent:#"DataStore"] UTF8String], &database)==SQLITE_OK)
{
NSLog(#"DB Connection Established successfully");
return YES;
}
else
{
NSLog(#"DB not connected");
return NO;
}
}
-(BOOL)closeConnection
{
NSLog(#"%#",documentsDir);
if(sqlite3_close(database)==SQLITE_OK)
{
NSLog(#"DB Connection closed successfully");
return YES;
}
else
{
NSLog(#"Error Failed to close DB because %s",sqlite3_errmsg(database));
return NO;
}
}
My Insertion Method is :
- (void) addToDatabase :(NSString*) sqlstmt :(NSArray *)params
{
sqlite3_stmt *addStmt;
if(sqlite3_prepare_v2(database, [sqlstmt UTF8String], -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
else
{
for (i=1; i<=[params count]; i++)
{
sqlite3_bind_text(addStmt, i,[[params objectAtIndex:i-1] UTF8String], -1, SQLITE_TRANSIENT);
}
}
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog(#"%lld",sqlite3_last_insert_rowid(database));
sqlite3_finalize(addStmt);
}
While adding to database i am getting database locked error because while one response is open the database and inserting into database parallely another response try to open the database connection,so how can i resolve this problem?

Sqlite inserting issue in iOS

I need to store user doubleTap count in db. Its working fine.
If i am doing very fast double tapping to insert, issues will appear (database is locked, no such table: and out of memory). How to handle that issue?
Thanks in Advance
I tried this, FYI:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void)
{
#try {
if([self openAppDatabase] == YES) //If DB open success...
{
sqlite3_stmt *statement = nil;
NSString *queryString = [NSString stringWithFormat:#"INSERT INTO %# (%#,%#) values (?,?)",Tables_Count,lkt_TO,ttt_TIME];
BOOL prepareStatementResult = sqlite3_prepare_v2(databaseObj, [queryString UTF8String], -1, &statement, NULL);
if(prepareStatementResult == SQLITE_OK) {
sqlite3_bind_text(statement, 1, [contactNo UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [sentDate UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) != SQLITE_DONE) {
DLog(#"Can't insert ---- Error");
}
}
else {
// In the database cannot be opened then show the error message on the debugger.
DLog(#"%s", sqlite3_errmsg(databaseObj));
}
// Release the compiled statement from memory.
sqlite3_finalize(statement);
}
[self closeAppDatabase]; //If DB not opened will close it here...
}
#catch (NSException *exception) {
DLog(#"#Exception --- %#",exception.reason);
}
}
The dispatch queue you are using is a concurrent queue, not a series queue. The result is that too many requests are being made to the dB at a time. You should be ok if you change your code to use dispatch_barrier_async but I've never used it on system queues.
Additionally, you're code could use some cleanup. The try is unnecessary since this code does not throw exceptions. Contrary to Java, Objective Chicago very rarely throws exceptions.
Lastly, you may consider using a Objective C SQLite wrapper, like FMDatabase. It cleans things up quite a bit.

Can't open SQLite database due out of memory error

I'm having an issue opening my sqlite database for an iPhone app I'm writing. I thought I followed the tutorials verbatim but for some reason I am getting an "Out of memory" error.
-(NSString *) filepath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0] stringByAppendingPathComponent:#"db.sqlite"];
}
-(sqlite3*)openDB{
if(db == NULL){
sqlite3 *newDBConnection;
if(sqlite3_open([[self filepath] UTF8String], &newDBConnection) != SQLITE_OK){
sqlite3_close(db);
NSLog(#"%s SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
db = NULL;
}
else{
NSLog(#"db opened");
}
}
return db;
}
DB is an ivar and I am calling db = [self openDB]; in the initialization method.
The sqlite3_open is failing because you are using NSDocumentationDirectory instead of NSDocumentDirectory.
The reason you're receiving the "Out of memory" error is that sqlite3_open is updating newDBConnection, but the sqlite3_errmsg is trying to use db (which is still NULL). And whenever you call sqlite3_errmsg with a NULL for the sqlite3 pointer, SQLite somewhat confusingly returns an "Out of memory" message.
Also note that even if you fix the two above issues, note that you are calling sqlite3_errmsg after performing sqlite3_close. Make sure to get your error message before you call sqlite3_close.
E.g. I would suggest:
- (BOOL)openDB {
if (db == NULL) {
int rc;
if ((rc = sqlite3_open([[self filepath] UTF8String], &db)) != SQLITE_OK) {
NSLog(#"%s SQL error '%s' (%d)", __FUNCTION__, sqlite3_errmsg(db), rc);
sqlite3_close(db);
db = NULL;
return false; // open failed
} else {
NSLog(#"db opened");
return true; // open successful
}
}
return true; // already open
}
Note, a minor point, given that sqlite3_open returns the error code, I would just save that directly, rather than calling sqlite3_errcode to get the code that was just returned.

Running an iOS SQLite Updates

I'm using this to do an Update statement in a test iOS App, the log outputs 'Success' but theres no change in the database. Could anyone point me in the right direction? It'd be greatly appreciated.
I'm brand new to this so please forgive my probably appallingly written code.
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"chars.sqlite3"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "UPDATE characters SET level = 'testing' WHERE id='1'";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
if (sqlite3_step(sqlStatement) == SQLITE_DONE){
NSLog(#"Success");
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
}
The problem is that you're opening the database from the bundle, which is read-only. You should
Check for the existence of the database in the Documents folder.
If not there, copy the database from the bundle to the Documents folder.
Now, open the database from the Documents folder.

SQLcipher how to create cypted database?

I'm trying to follow this tutorial: http://sqlcipher.net/ios-tutorial/
I create a database called "sqlcipher.db" then I recreate this
When I execute this code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
stringByAppendingPathComponent: #"encrypted.db"];
sqlite3 *db;
if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) {
const char* key = [#"secret" UTF8String];
int sqlite3_key(sqlite3 *db, const void *pKey, int nKey);
sqlite3_key(db, key, strlen(key));
if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM t1;", NULL, NULL, NULL) == SQLITE_OK) {
// password is correct, or, database has been initialized
NSLog(#"Hello 1");
} else {
// incorrect password!
NSLog(#"Hello 2");
}
sqlite3_close(db);
} else {
NSLog(#"Hello 3");
}
}
It allways outs "Hello 2".
When I try to reproduce the steps to crate an encrypted db described here http://zetetic.net/blog/2009/12/29/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher.html#disqus_thread I can't get it encrypted, I believe that it is beacause I am using sqlite3 mac command.
So I saw in the comments that S Lombardo says that I have to compile a command line sqlcipher executable but the link doesn't works.
How should I encrypt my database to use it with SQLcipher?
Did anyone have success using sqlicipher in iOS?
After one hour Googling i've found how to compile sqlcipher command line for OSX:
I hope this could help somebody.
https://groups.google.com/forum/#!msg/sqlcipher/bd1R13RpZHQ/SEPK8YrRt1gJ

Resources