Inserting array of value in Sqlite3 i-phone - iphone

I am trying to insert a set of values in an sqlite table using a for loop. It is inserting only one set of value. I am posting here my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"myDatabase.sql"];
for(int i=0;i<[arr count];i++)
{
sqlite3 *database;
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"\n inserting data \n");
sqlite3_exec(database, [[NSString stringWithFormat:#"INSERT INTO AnswerConnect VALUES('%#')",[arr objectAtindex:i] ] UTF8String], NULL, NULL, NULL);
//sqlite3_finalize(compiledStatement);
sqlite3_close(database);
}
}
Thanks in advance.

You have to first prepare a sqlite statement to insert data in table.Try this :
sqlite3_stmt *statement = nil
const char *sql = "insert into tablename (col1,col2) Values( ?, ?)";
if(sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
for(int i=0;i<[arr count];i++)
{
sqlite3_bind_text(statement, 1,[[arr objectAtindex:i] UTF8String] , -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(add_statement))
{
NSLog(#"Error while inserting result data. '%s'", sqlite3_errmsg(database));
}
//Reset the add statement.
sqlite3_reset(statement);
}

Don't do like that! Don't open/close SQLite connection in loop like that! Open handle to database outside from loop and than just use pointer on it. In this kind of request it's unsafe to insert format, because SQL statement may be compiled with some kind of injection code. Use sqlite3_stmt instead and bind values to it. Also if you compile only one instance of sqlite3_stmt and reuse it, this will give you better performance than compiling new statements all the time.
How many columns in each data set? Does it insert only one value from single data set like string?

Related

UITableViewController not always consistent with actual SQLite database until after restarting app

In my "viewWillAppear" callback I attempt to populate a UITableViewController with data from SQLite database for the user to see.
However, what I noticed was if I switch to another tab, commit a new row of data into SQLite and switch back to the UITableViewController it does not update with the new row I just added to the database. I have to quit out of the app completely and navigate back to the UITableViewController in order to see the new row reflected on the table view.
How do I get around this problem (i.e. how do I force always showing the very latest information in SQLite on the UITableViewController after switching back and forth a bunch of times?)
Would appreciate all / any advice.
Here is the code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"viewwillappear");
//[[self tableView] reloadData];
int rc=-1;
if (databasePath == nil) {
NSLog(#"database path is NIL. Trying to set it");
databaseName = #"mymemories.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
return;
}
rc = sqlite3_open([databasePath UTF8String], &database);
if(rc == SQLITE_OK) {
memoriesArray = [[NSMutableArray alloc]init ];
sqlite3_stmt *statement = nil;
NSString *fullQuery = #"SELECT * FROM memories";
const char *sql = [fullQuery UTF8String];
if(sqlite3_prepare_v2(database, sql, -1, &statement, NULL)!=SQLITE_OK)
NSAssert1(0, #"Error preparing statement '%s'", sqlite3_errmsg(database));
else
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *place= [NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 4)];
//[User setName:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 1)]];
//[User setAge:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 2)]];
[memoriesArray addObject:place];
//[currentUser release];
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
Also in case this is relevant, here is the code that commits to the SQLite database:
NSData * blob = [NSData dataWithContentsOfURL:recordedTmpFile];
int rc=-1;
rc = sqlite3_open([databasePath UTF8String], &database);
if(rc == SQLITE_OK) {
sqlite3_exec(database, "BEGIN", 0, 0, 0);
NSLog(#"Connected To: %#",databasePath);
sqlite3_stmt *updStmt =nil;
const char *sql = "INSERT INTO memories (data,place) VALUES (?,?);";
rc = sqlite3_prepare_v2(database, sql, -1, &updStmt, NULL);
if(rc!= SQLITE_OK)
{
NSLog(#"Error while creating update statement:%#", sqlite3_errmsg(database));
}
sqlite3_bind_text( updStmt, 2, [[tags text] UTF8String], -1, SQLITE_TRANSIENT);
rc = sqlite3_bind_blob(updStmt, 1, [blob bytes], [blob length] , SQLITE_BLOB);
if((rc = sqlite3_step(updStmt)) != SQLITE_DONE)
{
NSLog(#"Error while updating: %#", sqlite3_errmsg(database));
sqlite3_reset(updStmt);
}
sqlite3_exec(database, "COMMIT", 0, 0, 0);
//rc = sqlite3_reset(updStmt);
sqlite3_close(database);
}
As an extension of an explanation of Darren's answer.
First off his answer is correct.
Secondly you need to use an NSMutableArray to ensure consistency, this is where you are going wrong by not updating it as you should
The steps you should be taking to ensure consistency are the following:
Loading Data into Table
In viewDidLoad, call your SQL statement and load it into your array
in viewWillAppear ensure that your array contains data, if not display a notice that no results were returned
Saving Data into Database
Update the change to the array (or datasource)
Update the Database with the updated datasource to ensure consistency
Update the table with one of the 4 UITableView reloading methods
Using the NSMArray to ensure consistency between updates and app loads is fairly common practise has be recommended to me in the past by fellow co workers with decades of experience.
Note:
You will need to synchronise the datasource to ensure that 1 thread is accessing it at any 1 time otherwise you will get a crash.
Assuming you read your SQL data into an array, then use this array to build the UITableView, when you add a record to your SQL database, you either need to also add it to the array used to build the table, or re-read the data from the database into the array.

how to inserting data after completion of inserting and updating the data

I am developing one application. In that iam facing the problem at inserting the data into database. First insert and update will be performed very well. After updating if i want to perform insert operation then app will be crashed. My code for inserting and updating were like below
+(BOOL)update:(CalendarInfo*)clInfo
{
NSString *query = [NSString stringWithFormat:#"UPDATE ABC set A = '%#' where B =%d and C=%d",clInfo.a,clInfo.b,clInfo.c];
sqlite3_stmt *stStatement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &stStatement, nil)==SQLITE_OK)
{
if(SQLITE_DONE == sqlite3_step(stStatement))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog(#"updation Successful");
}
return 0;
}
+(BOOL)insert:(CalendarInfo*)clInfo{
sqlite3_stmt *addStmt = nil;
sqlite3 *contactDB;
NSArray *docPathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *destPath = [NSString stringWithFormat:#"%#/example.sqlite",[docPathArr objectAtIndex:0]];
if (sqlite3_open([destPath UTF8String], &contactDB)==SQLITE_OK) {
NSString *query2 = [NSString stringWithFormat:#"INSERT INTO ABC(C,B,A) VALUES(%d,%d,'%#')",clInfo.c,clInfo.b, clInfo.a];
if(sqlite3_prepare_v2(database, [query2 UTF8String], -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog(#"Insertion Successful");
sqlite3_reset(addStmt);
return 0;
}
So please tell me how to solve my problem.
From the limited code you've posted, I think the answer has to do with that you have two different sqlite3 instances here. Was this intentional?
You call sqlite3_open([destPath UTF8String], &contactDB);
and then attempt to get an error result off another sqlite instance:
sqlite3_errmsg(database)
Either use database or contactDB and you should be all set.

Sqlite3 in iPhone gives Database Locked Exception

I am newbiee in iphone and sqlite and doing some tutorials.
I have created one method which stores some temperory informartion into my database.
Now when i am on firstView controller of my Application i called that method twice. It stores the data twice into the particular table. Now i went to SecondViewController and in there i have a new sqlite3 object in the header file and i again copy paste that method into the SecondViewController. Now when i call that method on Second ViewController it gives me following error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while inserting data. 'database is locked''
my Code is:
-(void)storeTemp
{
SchoolFocusIPadAppDelegate *delegate = (SchoolFocusIPadAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"sfocusDB.sqlite"];
if(sqlite3_open([path UTF8String], &databases) == SQLITE_OK){
//const char *sql = "select * from animal";
const char *sql = "insert into groups(id, groupid, name, desc , createdon,createdby) Values(?,?,?,?,?,?)";
sqlite3_stmt *add;
if(sqlite3_prepare_v2(databases, sql, -1, &add, NULL) == SQLITE_OK){
NSLog(#"Connection Successful");
NSLog(#"***Storing START on Database ***");
sqlite3_bind_text(add, 2, [[NSString stringWithFormat:#"Temp Group Dont Open"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 3, [[NSString stringWithFormat:#"kjhasd"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 4, [[NSString stringWithFormat:#"asdas"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 5, [[NSString stringWithFormat:#"asdsa"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 6, [[NSString stringWithFormat:#""] UTF8String], -1, SQLITE_TRANSIENT);
NSLog(#"***Storing END on Database ***");
if(SQLITE_DONE != sqlite3_step(add))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(databases));
else {
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
}
sqlite3_finalize(add);
}
sqlite3_close(databases);
}
Please Help me friends. M really stucked.
Thanks alot
here lots of chances to kill
1.if your id is not null in DB it will kill with constraint failed error
if you don't want to insert any value to id remove from list
like
const char *sql = "insert into groups( groupid, name, desc , createdon,createdby) Values(?,?,?,?,?)";
and change that number 1-5 instead of 2-6
I've had some problems with sqlite3_close following an if/else (not sure why) but when I also put the finalize and close calls inside the if, it'd work out. I started following every open and close with an NSLog of the same (numbered so I knew which one was which) and you can then see which step left the DB open (and therefore locked)
Have you copied the database to the writable doc-dir?
Your prepare-call needs a little change:
From if(sqlite3_prepare_v2(databases, sql, -1, &add, NULL) == SQLITE_OK){
To if(sqlite3_prepare_v2(databases, [sql UTF8String], -1, &add, NULL) == SQLITE_OK){
(but that's nit the reason for the database locked).

SQLite iPhone - Insert Fails

I am trying to insert a value to a SQLite db, but everytime I try my program simply crashes with no error message at all.
Here is my code:
- (void) insertToDatabase:(NSString *) refName {
// The Database is stoed in the application bundle
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"staticdata.sqlite"];
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK){
const char *sql = "Insert into usersDates(dateDescription) VALUES (?)";
sqlite3_stmt *init_statement;
sqlite3_bind_text(init_statement, 1, [refName UTF8String], -1, SQLITE_TRANSIENT);
if(!sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) == SQLITE_OK){
NSAssert1(0, #"Failed to insert to database file with message '%s'.", sqlite3_errmsg(database));
}
if(sqlite3_step(init_statement) != SQLITE_DONE ) {
NSLog( #"Error: %s", sqlite3_errmsg(database) );
} else {
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
}
sqlite3_finalize(init_statement);
} else {
sqlite3_close(database);
NSAssert1(0, #"Failed to open database file with message '%s'.", sqlite3_errmsg(database));
}
}
The error seems to occur on the bind statement. I have confirmed the database is actually being opened, and refname is correctly being passed to my method.
Can anyone help? I would normally use core data, however this is a bug fix to an existing project, and I simply do not have the time to allocate to making the move to core data.
The order of your statements is incorrect. bind_() is used after prepare()
SQLite bind() documentation
The first argument to the sqlite3_bind_*() routines is always a pointer to the sqlite3_stmt object returned from sqlite3_prepare_v2() or its variants.
const char *sql = "Insert into usersDates(dateDescription) VALUES (?)";
sqlite3_stmt *init_statement;
if(!sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) == SQLITE_OK){
NSAssert1(0, #"Failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_bind_text(init_statement, 1, [refName UTF8String], -1, SQLITE_TRANSIENT);
sqlite_step(init_statement);

Difficulty deploying database with my iphone app

I have an application that needs a database. The application is running fine in the simulator. But when i try to deploy it onto the iphone then it gives me the error that 'no such table animal'. Where is the problem? I am providing the code for better understanding
(void)viewDidLoad
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"AnimalDatabase.sql"];
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
const char *sqlStatement = "insert into animal (id, name) VALUES (?, ?)";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
//NSLog(filePath);
sqlite3_bind_int(compiledStatement, 1, 12);
//NSLog(#"A");
sqlite3_bind_text( compiledStatement, 2, [#"abc" UTF8String], -1, SQLITE_TRANSIENT);
//NSLog(#"B");
if(sqlite3_step(compiledStatement) != SQLITE_DONE )
{
//NSLog(#"C");
NSLog( #"Error: %s", sqlite3_errmsg(database) );
}
else
{
//NSLog(#"D");
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
}
}
else
{
NSAssert1(0, #"Error while creating insert statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
}
else
{
NSLog(#"Error Occured");
}
sqlite3_close(database);
[super viewDidLoad];
}
I think you need to look at what is being transfered to your iPhone. I had issues with this, there are some strange issues around how the database is created or not created on the actual iPhone. I think what is happening in your case is that no database is being transfered, and then your call to
sqlite3_open
is actually creating the database so you don't receive an error until you call a select statement.
Check your documentation on where to place the db in your resources to ensure it is copied to your iPhone when building.
The most likely reason is that the AnimalDatabase.sql file doesn't exist so there is no Animal table to insert into.