Sqlite Database locked in some case while inserting data - ios

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.

Related

adding a record to SQLite cause extra random records to be added

I am writing an application with iOS and SQLite database.
I have a tableView that displays a list of workshops with information i.e:Title, presenters' names. when the user clicks Add button a new view is presented modally. the new view contains a list of names. The user can choose the workshop presenters by tabbing on some names from this list, and then the selected name get a checkmark besides them. after user clicks save the records are added to the Database correctly and the view is dismissed.
However, after I return to the view with the list of workshops I find that the newly added workshop has more presenters than I actually added.
When I check the database file I find that the extra records are actually added in the database which means that it is not a semantic error in the code that causes the extra names to be added.
Also, I debugged my code where the insert query is placed. It explicitly states that only the checked names are added to the database, and I NSLog the result of the query, it prints out the selected names only.
I don't know where exactly the extra names are added. I tried to find a pattern but every time different names are being added as extra in the database.
The odd thing is that this problem does not occur always.
UPDATE:
here is a snippet of my code in the Database.m file. I am assuming that I added two presenters to the workshop form my addWorkshop view controller
-(void)addWorksopWithTitle:(NSString *)title presenters:(NSMutableArray *)presenters date:(NSDate *)date time:(NSString *)time bld:(NSString *)bld floor:(int)floor room:(NSString *)room manadatory:(BOOL)manadatory
{
[self openConnection];
const char *SqlStatement = "insert into Workshop (wid,title,manadatory,date,time,bld,floor,room,wsdate,dateD) values(null,?,?,?,?,?,?,?,?,?)";
//end of edited code
sqlite3_stmt *compileStatement1;
int success;
if (sqlite3_prepare_v2(database, SqlStatement, -1, &compileStatement1, NULL) == SQLITE_OK)
{
NSLog(#"insert WS prepair");
sqlite3_bind_text(compileStatement1, 1, [title UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(compileStatement1, 2, manadatory);
sqlite3_bind_text(compileStatement1, 3, [#"Feb 15, 2014" UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compileStatement1, 4, [time UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compileStatement1, 5, [bld UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(compileStatement1, 6, floor);
sqlite3_bind_text(compileStatement1, 7, [room UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(compileStatement1, 8, [date timeIntervalSince1970]);
sqlite3_bind_double(compileStatement1, 9, [date timeIntervalSince1970]);
success = sqlite3_step(compileStatement1);
NSLog(#"sucess insert ws msg:%d",success);
}else
{
NSLog(#"insert WS NOT success");
NSAssert1(0, #"Error: failed to prepare statement with message '%s'. ", sqlite3_errmsg(database));
}
sqlite3_finalize(compileStatement1);
if (success == SQLITE_ERROR)
{
NSAssert1(0, #"Error: failed to insert into the database with message '%s'.", sqlite3_errmsg(database));
}
//get the last inserted workshop id
int wid = (int) sqlite3_last_insert_rowid(database);
//NSLog statement to get the number of presenters to be added. it returns 2
NSLog(#"#presenters to add: %lu",(unsigned long)[presenters count]);
//insert presenters in Present table
for (Faculty *presenter in presenters) {
const char *SqlStatement2 = "insert into Presents(pid,wid,fid) values(null,?,?)";
sqlite3_stmt *compileStatement2;
int success2;
if (sqlite3_prepare_v2(database, SqlStatement2, -1, &compileStatement2, NULL) == SQLITE_OK)
{
sqlite3_bind_int(compileStatement2, 1, wid);
sqlite3_bind_int(compileStatement2, 2, [presenter fid]);
success2 = sqlite3_step(compileStatement2);
NSLog(#"insert to present,sucess msg:%d",success2); //success message prints 101. which according to SQLite documentation means the sqlite3_step() has finished executing
}else
{
NSLog(#"insert to present NOT success");
NSAssert1(0, #"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_finalize(compileStatement2);
if (success2 == SQLITE_CONSTRAINT)
{
NSAssert1(0, #"Error: failed to insert into the database with message '%s'.", sqlite3_errmsg(database));
}
}
[self closeConnection];
}
this code add extra records only sometimes

Change Data of database

I'm developing for iOS and I have a previous database really poorly constructed. Now there is already 140 sealed but in my update I make a new database but I can not delete the data... How can I change the data from database A to database B ? I use sqlite3 in xCode 5
Here is an example code altering a column in a database table:
- (void)alterDB {
sqlite3_stmt *statement;
sqlite3_stmt *selectStmt;
const char *columnExists = "select callCount from lastCall";
//Alter the table ONLY IF column we want doesn't exist
if (sqlite3_prepare_v2(database, columnExists, -1, &selectStmt, NULL) != SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat:#"ALTER TABLE lastCall ADD COLUMN callCount INTEGER"];
const char *update_stmt = [updateSQL UTF8String];
sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"DATABASE ALTERED");
} else {
NSLog(#"error altering database");
}
}
}
I hope this gives you an idea.
Write migration code,
that will select the data from Database A and will insert it into Database B.
When dealing with different schemas, I have a method that I always call when opening the database that checks the schema version in a table set aside for that purpose and then doing any alterations as needed to the schema.
- (void) checkSchema {
if([[self preferenceForKey:#"SchemaVersion"] isEqualToString: #"1"]) {
[db sqlExecute:#"create table Documents(documentID int, description text, type text, url text, modifiedDate text, read int, fileName text, needsUpdate int, primary key(documentID,type));"];
[self setPreference:#"2" ForKey:#"SchemaVersion"];
}
// etc.
}
So while developing, I can add schema changes and no matter what version of the app someone is using, when they upgrade they will get the latest schema changes.
It is because of this, and the work of changing all my accessor methods to the database that I am now using SimpleDB (https://github.com/AaronBratcher/SimpleDB), a key/value db I wrote. Completely different way of accessing data that makes things a lot simpler.

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

Inserting into sqlite table

I'm working on an iPhone App which uses sqlite. I am trying to insert a record on a table. My code runs fine but it does not populate the table. My code is as shown below. Can someone help on what is wrong with the method. Thanks for the help:
- (void) saveProductDetails: (int)pklItemID :(NSString*)sItemDescription :(NSString*)barcodeValue :(int)lRemainingItems :(float)lCostPrice :(float)lSellingPrice
{
// The array of products that we will create
// NSMutableArray *products = [[NSMutableArray alloc] init];
NSLog(#"The ItemID in DBMethod is %d",pklItemID);
NSLog(#"The Selling Price in DBMethod is %f",lSellingPrice);
NSLog(#"The Cost Price in DBMethod is %f",lCostPrice);
NSLog(#"The Stock Quantity in DBMethod is %d",lRemainingItems);
NSDate* now = [NSDate date];
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO Spaza_Inventory (fklSpazaID,fklItemID,lRemainingItems,lCostPrice,lSellingPrice,fklUserID,fklSalesID,fklOrderListID,dtCostEffective,dtPriceEffective)\
VALUES ('%d','%d',' %d','%.02f','%.02f','%d','%d','%d','%#','%#')",0,pklItemID, lRemainingItems, lCostPrice, lSellingPrice,0,0,0,now, now];
NSLog(#"The SQl String is %#",insertSQL);
const char *sql = [insertSQL UTF8String];
//To run the above SQL in our code, we need to create an SQLite statement object. This object will execute our SQL against the database.
// The SQLite statement object that will hold the result set
sqlite3_stmt *statement;
// Prepare the statement to compile the SQL query into byte-code
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
//After preparing the statement with sqlite3_prepare_v2 but before stepping through the results with sqlite3_step, we need to bind the parameters. We need to use the bind function that corresponds with the data type that we are binding.
sqlite3_bind_int(statement, 2, pklItemID);
sqlite3_bind_int(statement, 3, lRemainingItems);
sqlite3_bind_double(statement, 4, lCostPrice);
sqlite3_bind_double(statement, 5, lSellingPrice);
//sqlite3_bind_int(statement, 5, pklItemID);
//If the result is SQLITE_OK, we step through the results one row at a time using the sqlite3_step function:
if ( sqlResult== SQLITE_OK) {
// Step through the results - once for each row.
NSLog(#"Record Updated");
// Finalize the statement to release its resources
sqlite3_finalize(statement);
}
else {
NSLog(#"Problem with the database:");
NSLog(#"%d",sqlResult);
}
//return products;
}
sqlite3_step(statement);
Add above statement after binding.
From what I am seeing, you are preparing the query, but never actually executing it...
To execute the query you need to call sqlite3_step. Do this after binding all of the variables.
You should also check the result of sqlite3_prepare_v2 right away, before calling any of the bind statements.

Resources