perhaps I'm blind but I cant figure out what I am doing wrong.
after the 2 runs (there are only 2 values in the database) I get 2 different values like it should be. Then I write it into the NSMutableArray.
But there is only the 2nd value twice. Shouldnt it add to the end of the array? What do I do wrong?
- (NSMutableArray *)getItemsFromDatabaseWithName:(NSString *)databaseName fromTable:(NSString *)tableName andConstraint:(NSString *)constraint
{
NSString *absolutePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:databaseName];
NSLog(#"%#", absolutePath);
//Datenbank öffnen --- "**" bedeuten "&" verwenden
sqlite3_open([absolutePath UTF8String], &_database);
//check if there is a constraint and if not take 2nd statement
if (![constraint isEqualToString:#""])
{
_statement = [NSString stringWithFormat:#"select * from %# where %#",tableName, constraint];
}
else
{
_statement = [NSString stringWithFormat:#"select * from %#",tableName];
}
const char *charStatement = [_statement cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *results;
//new array to return values
_mutableItemArray = [NSMutableArray new];
//new ItemModel
ItemModel *tmpItem = [ItemModel new];
if (sqlite3_prepare_v2(_database, charStatement, -1, &results, NULL)== SQLITE_OK)
{
while (sqlite3_step(results) == SQLITE_ROW)
{
_charItemName = (char *)sqlite3_column_text(results, 1);
[tmpItem setItemName:[NSString stringWithUTF8String:_charItemName]];
_charItemDescription = (char *)sqlite3_column_text(results, 2);
[tmpItem setItemDescription:[NSString stringWithUTF8String:_charItemDescription]];
_charItemYear = (char *)sqlite3_column_text(results, 3);
[tmpItem setItemYear:[_dateFormat dateFromString:[NSString stringWithUTF8String:_charItemYear]]];
_charItemRecommendedBy = (char *)sqlite3_column_text(results, 4);
[tmpItem setItemRecommendedBy:[NSString stringWithUTF8String:_charItemRecommendedBy]];
_charItemImage = (char *)sqlite3_column_text(results, 5);
[tmpItem setItemImage:[NSString stringWithUTF8String:_charItemImage]];
[_mutableItemArray addObject:tmpItem];
#warning here I get the 2 items correct
NSLog(#"ItemName: %#",[tmpItem getItemName]);
NSLog(#"ItemName: %#",[tmpItem getItemDescription]);
}
}
sqlite3_close(_database);
#warning here I get 2 times the same item ???
NSLog(#"ItemName: %#",[_mutableItemArray objectAtIndex:0]);
NSLog(#"ItemName: %#",[_mutableItemArray objectAtIndex:1]);
return _mutableItemArray;
}
You just create one object tmpItem.
This will be added to the array and in the next run of the while loop you're not creating a new tmpItem but modifying the old one and add it to the array.
Therefore you will end up with an Array containing two pointers to the same object tmpItem (with the latest state).
Solution: create your tmpItem within the while loop.
If you go through your code you will see inside the while loop you are setting the same object (tmpItem) again and again,that is why your array has last updated values of the same object.
Now see below code you will notice in the while loop, we are creating new object and storing it in an NSArray.
- (NSMutableArray *)getItemsFromDatabaseWithName:(NSString *)databaseName fromTable:(NSString *)tableName andConstraint:(NSString *)constraint
{
NSString *absolutePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:databaseName];
NSLog(#"%#", absolutePath);
//Datenbank öffnen --- "**" bedeuten "&" verwenden
sqlite3_open([absolutePath UTF8String], &_database);
//check if there is a constraint and if not take 2nd statement
if (![constraint isEqualToString:#""])
{
_statement = [NSString stringWithFormat:#"select * from %# where %#",tableName, constraint];
}
else
{
_statement = [NSString stringWithFormat:#"select * from %#",tableName];
}
const char *charStatement = [_statement cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *results;
//new array to return values
_mutableItemArray = [NSMutableArray new];
//new ItemModel
if (sqlite3_prepare_v2(_database, charStatement, -1, &results, NULL)== SQLITE_OK)
{
while (sqlite3_step(results) == SQLITE_ROW)
{
ItemModel *tmpItem = [ItemModel new];
_charItemName = (char *)sqlite3_column_text(results, 1);
[tmpItem setItemName:[NSString stringWithUTF8String:_charItemName]];
_charItemDescription = (char *)sqlite3_column_text(results, 2);
[tmpItem setItemDescription:[NSString stringWithUTF8String:_charItemDescription]];
_charItemYear = (char *)sqlite3_column_text(results, 3);
[tmpItem setItemYear:[_dateFormat dateFromString:[NSString stringWithUTF8String:_charItemYear]]];
_charItemRecommendedBy = (char *)sqlite3_column_text(results, 4);
[tmpItem setItemRecommendedBy:[NSString stringWithUTF8String:_charItemRecommendedBy]];
_charItemImage = (char *)sqlite3_column_text(results, 5);
[tmpItem setItemImage:[NSString stringWithUTF8String:_charItemImage]];
[_mutableItemArray addObject:tmpItem];
NSLog(#"ItemName: %#",[tmpItem getItemName]);
NSLog(#"ItemName: %#",[tmpItem getItemDescription]);
}
}
sqlite3_close(_database);
NSLog(#"ItemName: %#",[_mutableItemArray objectAtIndex:0]);
NSLog(#"ItemName: %#",[_mutableItemArray objectAtIndex:1]);
return _mutableItemArray;
}
Related
I am working on SQLite but when I replace the data it adds again and again to my database, basically I want to store the alarm name, alarm type and alarm tune path, there is should be only 6 rows in NotiType because I am inserting exactly the 6 elements in every column. But the problem here is when I am replacing the data when there is change in alarm names types and tunes everyday, but the data is being inserted in every column below the and counting when ever the table is calling replace data function.
if([fileManager fileExistsAtPath:_dbPath] == YES) {
const char *dbPathagain = [_dbPath UTF8String];
if(sqlite3_open(dbPathagain, &_DB) == SQLITE_OK ) {
NSLog(#"database is open");
char *errorMessage;
const char *sql_statement = "CREATE TABLE IF NOT EXISTS NotiType(Alarm TEXT, Type TEXT, TPath TEXT)";
NSLog(#"created table success");
// sqlite3_stmt *statement = NULL;
// const char *dbPathagain = [ _dbPath UTF8String];
if([fileManager fileExistsAtPath:_dbPath] == YES) {
sqlite3_stmt *statement = NULL;
const char *dbPathagain = [_dbPath UTF8String];
if(sqlite3_open(dbPathagain, &_DB) == SQLITE_OK ) {
for(int itemIndex = 0; itemIndex < [azanst count];itemIndex++){
NSString *myname = [azanst objectAtIndex:itemIndex];
NSString *mytype = [alarmsstype objectAtIndex:itemIndex];
NSString *mytunepath = [alarmtune objectAtIndex:itemIndex];
NSString *insertSQLData = [NSString stringWithFormat:#"REPLACE INTO NotiType(Alarm, Type, TPath) VALUES (\"%#\", \"%#\",\"%#\")", myname, mytype, mytunepath];
NSLog(#"here is alarm names %#", myname);
NSLog(#"here alarm types %#", mytype);
NSLog(#"here alarm tune path %#", mytunepath);
const char *insert_statement = [insertSQLData UTF8String];
sqlite3_prepare_v2(_DB, insert_statement, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"data added successfully");
}
else {
NSLog(#"could not add timings");
}
}
sqlite3_finalize(statement);
sqlite3_close(_DB);
}
}
if (sqlite3_exec(_DB, sql_statement, NULL, NULL, &errorMessage) != SQLITE_OK) {
NSLog(#"failed to insert in table");
}
sqlite3_close(_DB);
}
else {
NSLog(#"failed to open db or cretate table");
NSLog(#"Database Error Message : %s", sqlite3_errmsg(_DB));
}
}
UPDATE
I am doing something like this
for (i=0, i<= ID.count, i++) {
NSString *insertSQLData = [NSString stringWithFormat:#"UPDATE NotiType SET Alarm =" + myname "," + "Type =" + mytype "," + "Tpath =" mytunepath + " where ID == i"];
}
You forgot to provide a WHERE statement :
NSString *insertSQLData = [NSString stringWithFormat:#"REPLACE INTO
NotiType(Alarm, Type, TPath) VALUES (\"%#\", \"%#\",\"%#\")", myname,
mytype, mytunepath];
you should add something like WHERE _id = %#, myAlarmUniqIdentifier to make sureyou only change the one that is beeing edited
edit : Come to think of it I also recommand using UPDATE, I'm not sure if REPLACE is what you want here..
UPDATE {table} SET {column1} = {editedObject.value1}, {column2} = {editedObject.value2} WHERE {uniqueIdField} = {editedObject.identifier};
EDIT 2 :
following your edit, update your for loop like this :
NSString *myname = [azanst objectAtIndex:i];
NSString *mytype = [alarmsstype objectAtIndex:i];
NSString *mytunepath = [alarmtune objectAtIndex:i];
NSNumber *myid = [ID objectAtIndex:i]; //<-- get the unique identifier for the item number ‘i‘
[NSString stringWithFormat:#"UPDATE NotiType SET Alarm=%#, Type=%#, Tpath=%# where ID=%#", myname, mytype, mytunepath, myid];
I am trying to retrieve some data from my sqlite table base on a date, but I am getting EXC_BAD_ACCESS(code=EXC_1386_GPFLT) error. Here is my method to fetch data-
-(NSMutableArray*)fetchDataFromTable:(NSString*)tableName whenDate:(NSString*)activeDate{
NSMutableArray *resultArray=[[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"select * from %# where ActiveDate = \"%#\"", tableName, activeDate];
if ([self canOpenDatabase]) { //checks if database can be openned
sqlite3_stmt *statement=nil;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
NSMutableArray *fetchedResults=[[NSMutableArray alloc]init];
int numberOfColumns = sqlite3_column_count(statement);
for (int i=0; i< numberOfColumns; i++){
char *dataAsChars = (char *)sqlite3_column_text(statement, i);
if (dataAsChars != NULL) {
NSString *dataString = [[NSString alloc] initWithUTF8String:dataAsChars];
[fetchedResults addObject:dataString];
}
}
[resultArray addObject:fetchedResults];
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
else{
NSLog(#"Data can not be retrived");
}
return resultArray;
}
else{
return resultArray;
}
}
I also trying printing the query. It shows
select * from Time_table where ActiveDate = "2016-01-01"
Please Help me out.
There are several issues.
Pair the call to sqlite3_close with the success of opening the database.
Pair the call to sqlite_finalize with the success of preparing the statement.
Don't close the database or finalize the statement inside the loop.
Don't build queries using stringWithFormat. Properly bind values into the prepared statement.
The issue was very obvious yet very intuitive. I am glad that I faced this issue. At least I won't do it again. So, here is the simple fix and the reason behind it-
In case of database object fetching, EXC_BAD_ACCESS normally happens when -
An object is not initialised or
An object is already released untimely
So, in case, I were never to use the prepared statement or completely done working with the statement, I should use sqlite_finalize. In may method, I used the statement after I finalised the statement.
So the easy fix was to finalise after the while statement-
-(NSMutableArray*)fetchDataFromTable:(NSString*)tableName whenDate:(NSString*)activeDate{
NSMutableArray *resultArray=[[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"select * from %# where ActiveDate = \"%#\"", tableName, activeDate];
if ([self canOpenDatabase]) {
sqlite3_stmt *statement=nil;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
NSMutableArray *fetchedResults=[[NSMutableArray alloc]init];
int numberOfColumns = sqlite3_column_count(statement);
for (int i=0; i< numberOfColumns; i++){
char *dataAsChars = (char *)sqlite3_column_text(statement, i);
if (dataAsChars != NULL) {
NSString *dataString = [[NSString alloc] initWithUTF8String:dataAsChars];
[fetchedResults addObject:dataString];
}
}
[resultArray addObject: fetchedResults];
}
sqlite3_finalize(statement);
}
else{
NSLog(#"Data can not be retrived");
}
sqlite3_close(database);
return resultArray;
}
else{
return resultArray;
}
}
I am trying to create loop for reading from sqlite DB, but the column count always return zero. columns=0
sqlite3_stmt *statement;
NSString *querySQL = #"SELECT * FROM Animations";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(localDB,query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
int columns = sqlite3_data_count(statement);
NSLog(#"Columns: %d",columns);
while(sqlite3_step(statement) == SQLITE_ROW)
{
for (int i=1;i<columns;i++)
{
NSString *st0 = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, i)];
NSLog(#"%#",st0);
}
}
}
else
{
NSLog(#"%s","Error on SQLITE_OK");
}
https://www.sqlite.org/c3ref/data_count.html
The sqlite3_data_count(P) routine returns 0 if the previous call to sqlite3_step(P) returned SQLITE_DONE.
Try putting the data count after your sqlit3_step statement (inside your while loop)
I have two database(customerDB & s-customerDB) in my app. I want to transfer customerDB info to s-customerDB.
I am using the below steps,
1.Open the s-customerDB.
2.The Attach and insert statement return the success resultCode.
But the "select" query returns the 0 object.
Kindly guide me what I have done wrong.
NSString *tempString = [[NSString alloc]initWithString:#" attach DATABASE 'customerDB.db' as customer "];
int resultCode = sqlite3_exec(_database, [tempString UTF8String], NULL, NULL, NULL);
[tempString release]; tempString = nil;
if (resultCode == SQLITE_OK) //Working
{
NSString *table = [[NSString alloc]initWithString:#"Employee"];
tempString = [[NSString alloc]initWithString:#"INSERT INTO"];
tempString = [tempString stringByAppendingFormat:#" %# select * from customer.%# ",table,table];
sqlite3_stmt *stmt_version = 0x00;
resultCode = sqlite3_prepare_v2(_database, [tempString UTF8String], -1, &stmt_version, NULL);
[tempString release]; tempString = nil;
sqlite3_finalize(stmt_version);
NSArray *tempArraty = [self executeSelectSqlQuery:#"select * from Employee" error:nil];
if (resultCode == SQLITE_OK) //Working
{
return YES;
}
I have found the problem on my code. I have to execute the insert query using sqlite3_exec instead of sqlite3_prepare_v2.
i have array namely _twoArray it contains data something like below
ha ha 2d array(
(
"Anand Kapadiya",
"Alok Darji",
"Akash Parikh",
"Ajay Desai",
"Aysu Can",
"Ayegba James",
"Ashish Modi",
"Arks Patel",
"Archit Patel",
"Anzey Khodorovskyy"
),
(
"12/01",
"08/13/1990",
"12/09/1989",
"05/22/1988",
"04/14/1992",
"12/15/1905",
"09/08",
"05/27/1990",
"05/22/1990",
"02/06"
)
)
i have database with one table and 2 fields one is Names and another is birth dates how can i add birth dates and names in database from this 2d array i am trying following code
for (id obj in _twoArray)
{
sqlite3_stmt *stmt;
int x;
char *update = "insert into PersonNamesAndBirthDates (Names,Birthdates) values(? ?);";
x = sqlite3_prepare_v2(database1, update, -1, &stmt, nil);
if (x == SQLITE_OK)
{
NSLog(#"PersonNamesAndBirthDates is -->%#",[NSString stringWithFormat:#"%#",obj]);
sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:#"%#",obj] UTF8String],-1, NULL);
sqlite3_bind_text(stmt, 2, NULL,-1, NULL);
}
if (sqlite3_step(stmt) != SQLITE_DONE){}
NSLog(#"Error: ");
sqlite3_finalize(stmt);
}
plz suggest me something or if this is not possible then tell me how can i add 2 different array in table at same time
Your _twoArray contains two object which are in turn NSArray. Now it is fixed that you will have always two array within one array, then try this
NSArray *nameArr = [_twoArray objectAtIndex:0];
NSArray *bdArr = [_twoArray objectAtIndex:1];
if (sqlite3_open([databaseFilePath UTF8String], &database1) == SQLITE_OK)
{
for (int i = 0; i< [nameArr count]; i++)
{
sqlite3_stmt *stmt;
int x;
char *update = "insert into PersonNamesAndBirthDates (Names,Birthdates) values(? ?);";
x = sqlite3_prepare_v2(database1, update, -1, &stmt, nil);
if (x == SQLITE_OK)
{
NSLog(#"PersonName is -->%#",[NSString stringWithFormat:#"%#",[nameArr objectAtIndex:i]]);
NSLog(#"BirthDates is -->%#",[NSString stringWithFormat:#"%#",[bdArr objectAtIndex:i]]);
sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:#"%#",[nameArr objectAtIndex:i]] UTF8String],-1, NULL);
sqlite3_bind_text(stmt, 2, [[NSString stringWithFormat:#"%#",[bdArr objectAtIndex:i]] UTF8String],-1, NULL);
}
if (sqlite3_step(stmt) != SQLITE_DONE){}
NSLog(#"Error: ");
sqlite3_finalize(stmt);
}
sqlite3_close(database1);
}
Your array contain two objects which are array type.
for (int i=0;i<[[_twoArray objectAtIndex:0] count];i++)
{
sqlite3_stmt *stmt;
int x;
char *update = "insert into PersonNamesAndBirthDates (Names,Birthdates) values(? ?);";
x = sqlite3_prepare_v2(database1, update, -1, &stmt, nil);
if (x == SQLITE_OK)
{
NSLog(#"PersonName:%# BirthDate:%#",[[NSString stringWithFormat:#"%#",[[_twoArray objectAtIndex:0] objectAtIndex:i]],[[NSString stringWithFormat:#"%#",[[_twoArray objectAtIndex:1] objectAtIndex:i]]);
sqlite3_bind_text(stmt, 1, [[NSString stringWithFormat:#"%#",[[_twoArray objectAtIndex:0] objectAtIndex:i]] UTF8String],-1, NULL);
sqlite3_bind_text(stmt, 2, NULL,-1, NULL);
}
if (sqlite3_step(stmt) != SQLITE_DONE){}
NSLog(#"Error: ");
sqlite3_finalize(stmt);
}
You can't do it in the way you are trying to, as your for loop is providing you a array at a time not the variables. You can use following two ways:
create two arrays name and dob and add records respectively on same index then use for loop for the index of any array and use 2 string variable to store data of same index and then use these to create query
Or you can create a NSDictionary in which you can store, name and dob, such as
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:0];
while (records) {
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"Mr. X", #"name"
#"13/12/82", #"dob"
nil];
[array addObject:dictionary];
records--;
}
And then create each query for index. to retrieve dictionary, values and to create query you use following code,
for (NSDictionary *dict in array) {
NSString *userName = [dict valueForKey:#"name"];
NSString *dateOfBirth = [dict valueForKey:#"dob"];
//write query here
}