Weird problem with a sqlite3-database (Can only write once) - iphone

i have a huge problem with my sqlite3 database on the iphone sdk 4. I can only write/read the database once! With the iphone sdk 3.2 everything had just worked fine.
After the first try i get the errormessage "SQLITE_BUSY".
Here's a snippet of my code i use:
-(void) addFavoriteOdv:(Odv*)odv name:(NSString*)name;
{
#synchronized(self)
{
if(name == nil)
name = odv.name;
NSString* rowId = [self addOdv:odv];
int existing = [self numberOfFavoriteOdvs:rowId];
if(existing == 0)
{
sqlite3 *database = [self getOpenDatabase];
const char *insertStatement = [#"insert into favoriteodvs(odv, name) values (?, ?)" UTF8String];
int retCode = 0;
sqlite3_stmt *statement;
retCode = sqlite3_prepare_v2(database, insertStatement, -1, &statement, NULL);
if(retCode == SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [rowId UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [name UTF8String], -1, SQLITE_TRANSIENT);
if(sqlite3_step(statement)!= SQLITE_DONE)
{
NSLog(#"SQL Error: %s", sqlite3_errmsg(database));
NSLog(#"Inserting FavoriteOdv failed");
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
}
Has anybody an idea? I use the libsqlite3.dylib.
Thanks,
Sebastian

to reuse your prepared statement - you must call
sqlite3_reset(statement);
right after you're received "SQLITE_DONE" from sqlite3_step. After that you can bind another data and run your query again.
p.s. wrong:
const char *insertStatement = [#"insert into favoriteodvs(odv, name) values (?, ?)" UTF8String];
correct:
const char *insertStatement = "insert into favoriteodvs(odv, name) values (?, ?)";

Related

issue during insert data by using sqlite3 in to db iPhone

I have an issue where I am trying to insert data from NSMutableArray in to my database. Here is what I have so far:
- (void)insertList:(NSString*) strListName ArrayOfData:(NSMutableArray*) dataArray{
sqlite3 *database = nil;
sqlite3_stmt *addStmt = nil;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"customlists.sqlite"];
if(sqlite3_open([defaultDBPath UTF8String], &database) == SQLITE_OK)
{
for (int i = 0; i < dataArray.count; i++)
{
PageData *pageDta = [PageData new];
pageDta = [dataArray objectAtIndex:i];
if(addStmt == nil) {
const char *sql = "insert into NewList(ListName, PageName, PageNumber, id) Values(?, ?, ?, ?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1, [strListName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 2, [pageDta.strNamebyFilter UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 3, [pageDta.strPageNuber UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(addStmt, 4, i);
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
//SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
sqlite3_last_insert_rowid(database);
//Reset the add statement.
sqlite3_reset(addStmt);
}
}
else
{
NSLog(#"Error while opening database '%s'", sqlite3_errmsg(database));
}
sqlite3_close(database);
}
But after calling this function, the database is empty. Could someone help me to find the cause of this issue and potential remedies?
The main problem is simple - you are trying to write to a database in the app's bundle. This isn't allowed. An app's bundle is read-only on a real device (though it is writable in the simulator). The proper thing to do is copy the database from the resource bundle to a writable area of the app's sandbox the first time the app runs. Then every use of the database is done with the copy.
It would also be cleaner to prepare the statement before the for loop. No need to keep checking if it has been setup every loop iteration.
You make a call to sqlite3_last_insert_rowid but don't do anything with the value. What's the point?
You never finalize the statement after the loop is complete. You need to do that.
And you don't close the database when you are done.
change this line :
const char *sql = "insert into NewList(ListName, PageName, PageNumber, id) Values(?, ?, ?, ?)";
to :
NSString *insertSQL = [NSString stringWithFormat: #"NSString stringWithFormat: "INSERT INTO NewList(ListName, PageName, PageNumber, id) VALUES(\"%#\", \"%#\", \"%#\", \"%#\")" ,strListName, pageDta.strNamebyFilter, pageDta.strPageNuber, addStmt];
const char *sql = [insertSQL UTF8String];
I've rewrite function to:
if(sqlite3_open([defaultDBPath UTF8String], &database) == SQLITE_OK)
{
for (int i = 0; i < dataArray.count; i++)
{
PageData *pageDta = [PageData new];
pageDta = [dataArray objectAtIndex:i];
if(addStmt == nil) {
const char *sql = [[NSString stringWithFormat:#"INSERT INTO NewList (ListName, PageName, PageNumber) values('%#', '%#', '%#')",strListName,pageDta.strNamebyFilter, pageDta.strPageNuber] UTF8String];
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1, [strListName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 2, [pageDta.strNamebyFilter UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 3, [pageDta.strPageNuber UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
//Reset the add statement.
sqlite3_reset(addStmt);
}
sqlite3_finalize(addStmt);
}
else
{
NSLog(#"Error while opening database '%s'", sqlite3_errmsg(database));
}
sqlite3_close(database);
but result is the same :(

NULL data is inserted on the next index when original data is inserted

-(IBAction)btnAddToFavorite:(id)sender
{
[self insertDataToFavourites:[[tempDict objectForKey:#"pageid"]intValue]:[tempDict objectForKey:#"desc"]];
}
-(void)insertDataToFavourites:(int)pageid :(NSString *)description
{
sqlite3_stmt *insertStatement = nil;
NSString *sql;
int returnvalue;
sql = [NSString stringWithFormat:#"insert into AddFavorite (Id,Description) VALUES (?,?)"];
returnvalue = sqlite3_prepare_v2(database, [sql UTF8String], -1, &insertStatement, NULL);
NSLog(#"\nFavorite ID is:--> %d &\nDescription is:--> %#",[[tempDict valueForKey:#"pageid"] intValue] ,[tempDict valueForKey:#"desc"]);
if (returnvalue == 1){
NSAssert1 (0,#"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_bind_text(insertStatement, 1,[[tempDict objectForKey:#"pageid"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insertStatement, 2,[[tempDict objectForKey:#"desc"] UTF8String], -1, SQLITE_TRANSIENT);
if (SQLITE_DONE != sqlite3_step(insertStatement)){
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
}
else{
sqlite3_reset(insertStatement);
}
sqlite3_finalize(insertStatement);
}
This is a code to insert data into database. It is showing data like this, when i check database using select query.
Can anybody tell me where is the mistake ?
Thanks.
try to use the pageid method variable and not your dict, maybe the dict is wrong. On the other hand you insert for id
sqlite3_bind_text(insertStatement, 1,[[tempDict objectForKey:#"pageid"] UTF8String], -1, SQLITE_TRANSIENT);
i think this might be not correct.
For test case you can insert in SQLiteManager as sqlstatement
insert into AddFavorite (Id,Description) VALUES (1,'TestDescription');
to check if the statement is correct.
I would use this code to insert your values, if id is an int in your database
-(void)insertDataToFavourites:(int)pageid :(NSString *)description
{
sqlite3 *database;
if(sqlite3_open([self.databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "INSERT INTO AddFavorite (Id,Description) VALUES (?,?);";
sqlite3_stmt *compiled_statement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiled_statement, NULL) == SQLITE_OK) {
sqlite3_bind_int(compiled_statement, 1, pageid);
sqlite3_bind_text(compiled_statement, 2, [description UTF8String] , -1, SQLITE_TRANSIENT);
}
if(sqlite3_step(compiled_statement) != SQLITE_DONE ) {
NSLog( #"Error: %s", sqlite3_errmsg(database) );
} else {
NSLog( #"Insert into row id = %lld", sqlite3_last_insert_rowid(database));
}
sqlite3_finalize(compiled_statement);
}
sqlite3_close(database);
}

Iinsert/Replace data in SQLite

Why can't I update data to SQLite eventhought it print "yes yes", please help, here my code, it called from viewdidload:
-(void)updateData{
CryptTestAppDelegate *delegate=(CryptTestAppDelegate *)[[UIApplication sharedApplication] delegate];
sqlite3_stmt *stmt=nil;
NSString *dd = #"testing";
const char *sql = "Update ProvPuzz set desc2=?";
sqlite3_prepare_v2(delegate.db, sql, 1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, [dd UTF8String], -1, SQLITE_TRANSIENT);
if(sqlite3_step(stmt)){
NSLog(#"yes yes");
}else{
NSLog(#"no no");
}
sqlite3_finalize(stmt);
sqlite3_close(delegate.db);
}
It seems to pass every step, but my data not change at all. Any help please...
How should I call/code to be able to insert/replace these record in SQLite?
NSString *UpdateSql = [NSString stringWithFormat:#"Update ProvPuzz set desc2 = something"];
const char *sqlStatement = [UpdateSql UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(filesDB, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
if(sqlite3_step(compiledStatement) == SQLITE_DONE)
{
sqlite3_reset(compiledStatement);
}
}
// Release the compiled statement from memory
sqlite3_reset(compiledStatement);
sqlite3_finalize(compiledStatement);
sqlite3_close(filesDB);
and also check you db connection opened properly or not

Sqlite finalise and Db locking issue

I am using the below function in my app,and i have started using the sq-lite recently and i would like to get your opinion that i am going with that correctly or not.
Since i am facing db locked issue in my app when searched i found that i need to use sqlite3 finalise statement.
what i am not sure is do i need to place one finalise statement for each sqlite3 prepare statement
Please let me know
- ( BOOL ) addNewCate:(NSString*)dbPath:(NSString*)title:(NSString*)tierOneID:(NSString*)tierTwoID{
BOOL returnVal = NO;
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
const char *sql = "insert into storyboard_phrases(phrase) Values(?)";
sqlite3_stmt *addStmt;
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) == SQLITE_OK){
sqlite3_bind_text(addStmt, 1, [title UTF8String], -1, SQLITE_TRANSIENT);
}
if(sqlite3_step(addStmt) != SQLITE_DONE ) {
NSLog( #"Error: %s", sqlite3_errmsg(database) );
} else {
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
int ph_id = sqlite3_last_insert_rowid(database);
int sub_category_id = [tierTwoID intValue];
int main_category_id = [tierOneID intValue];
addStmt = nil;
sql = "insert into phrase_reference(phrase_id, sub_category_id,main_category_id) Values(?,?,?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) == SQLITE_OK){
sqlite3_bind_int(addStmt, 1, ph_id);
sqlite3_bind_int(addStmt, 2, sub_category_id);
sqlite3_bind_int(addStmt, 3, main_category_id);
}
if(sqlite3_step(addStmt) != SQLITE_DONE ) {
NSLog( #"Error: %s", sqlite3_errmsg(database) );
} else {
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
returnVal = YES;
}
}
sqlite3_finalize(addStmt);
}
sqlite3_close(database);
return returnVal;
}
hii you get the locked issues in log right, that means your database is open and you doing some changes in that database so close database and try again to run application and insert in table...
hope this will help you..

IPhone Development - sqlite3_bind_int not working

i'm trying to insert some data on a database using this code:
-(void)insertLocationOnDatabase:(LocationType *)aLocation {
sqlite3_stmt *stmt;
int location = [aLocation.locationID intValue];
NSLog(#"Location ID: %i", location);
const char *sql = "insert into tbl_location values (?,?,?,?)";
if (sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_int(stmt, 0, location);
sqlite3_bind_text(stmt, 1, [aLocation.Description UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [aLocation.isActive UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [aLocation.sequenceOrder UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) == SQLITE_DONE) {
NSLog(#"Location %# inserted on database",aLocation.Description);
}
else {
NSLog(#"Error on step: %i",sqlite3_errcode(database));
}
}
else {
NSLog(#"Error on prepare: %i",sqlite3_errcode(database));
}
}
the problem is on line:
sqlite3_bind_int(stmt, 0, location);
without this line and changing the sql, the code works fine, but when i put this line back, i get this error:
2010-09-17 10:24:01.032 StockControl[944:207] Error on step: 20
From sqlite3.h:
#define SQLITE_MISMATCH 20 /* Data type mismatch */
Somebody knows where is my mistake?
Regards,
Claudio
According to the docs for the binding methods in SQLite, the bindings count from one, not zero:
The second argument is the index of
the SQL parameter to be set. The
leftmost SQL parameter has an index of
1.
That might well lead to a type mismatch.
Why not use following methods?
NSString *sqlCmd = [NSString stringWithFormat:
#"insert into tbl_location values (%d,'%#','%#','%#')",
location,
aLocation.Description,
aLocation.isActive,
aLocation.sequenceOrder];
const char *sql = [sqlCmd UTF8String];
// ...
I use bind only for large data, for example an image file.