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.
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 selecting data from sqlite database. Problem is that using following code it works some time. But lets say we call this method for any other table twice then it shows null select statement for other method. Is any thing wrong in method so that if we use same for other tables some time it works some time not.
-(void)getAssessmentNumber:(NSString *)dbPath{
appDelegate=[[UIApplication sharedApplication]delegate];
NSString*fileDBPath=[[NSBundle mainBundle] pathForResource:#"Database" ofType:#"sqlite"];
if (sqlite3_open([fileDBPath UTF8String], &database) == SQLITE_OK)
{
// NSLog(#"%#",[self getDBPath]);
NSString *querySQL = [NSString stringWithFormat:#"Select Am.AssessmentID , Am.AssessmentName From AssessmentMaster Am LEFT JOIN AssessmentDepartmentMapping M ON M.AssessmentID = Am.AssessmentID LEFT JOIN DepartmentListing d ON d.departmentID =M.departmentID where d.departmentID = '%#'",appDelegate.departmentID];
NSLog(#"%#",querySQL);
const char *sql = [querySQL UTF8String];
sqlite3_stmt *selectstmt;
NSError *error;
[appDelegate.assessmentNumberArray removeAllObjects];
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
while (sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
AssessmentListening *asmObj = [[AssessmentListening alloc] initWithPrimaryKey:primaryKey];
asmObj.assessmentID=[NSString stringWithFormat:#"%d",primaryKey];
asmObj.assessmentName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
[appDelegate.assessmentNumberArray addObject:asmObj];
}
}
else {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
// sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
}
Is this fine for getting the data from table?
Your code needs a little cleanup.
- (void)getAssessmentNumber:(NSString *)dbPath {
NSString *fileDBPath = [[NSBundle mainBundle] pathForResource:#"Database" ofType:#"sqlite"];
if (sqlite3_open([fileDBPath UTF8String], &database) == SQLITE_OK) {
appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.assessmentNumberArray removeAllObjects];
const char *sql = "Select Am.AssessmentID, Am.AssessmentName From AssessmentMaster Am LEFT JOIN AssessmentDepartmentMapping M ON M.AssessmentID = Am.AssessmentID LEFT JOIN DepartmentListing d ON d.departmentID = M.departmentID where d.departmentID = ?";
sqlite3_stmt *selectstmt;
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(selectstmt, 0, [appDelegate.departmentID UTF8String], -1, SQLITE_TRANSIENT);
while (sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
AssessmentListening *asmObj = [[AssessmentListening alloc] initWithPrimaryKey:primaryKey];
asmObj.assessmentID = [NSString stringWithFormat:#"%d", primaryKey];
asmObj.assessmentName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
[appDelegate.assessmentNumberArray addObject:asmObj];
}
sqlite3_finalize(selectstmt);
} else {
NSLog(#"Unable to prepare statement: %s", sqlite3_errmsg(database));
}
sqlite3_close(database);
} else {
NSLog(#"Unable to open the database from %#: %s", fileDBPath, sqlite3_errmsg(database);
}
}
Note all of the changes:
Only close the database if it is opened.
Only finalize the statement if it is prepared.
Don't build queries with stringWithFormat. Use the proper sqlite3_bind_xxx function to bind the values to the query. This ensures special characters are escaped and properly deals with quoting.
Use proper error checking. Use sqlite3_errmsg to get the error.
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;
}
}
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;
}
I am trying to read/write to a SQLite db but I keep getting errors. I've verified that the db exists in ...iPhone Simulator/Applications/5.1/app#/Documents/kipSQLDB.db
I've done INSERT and SELECT to it from Terminal.
But from the app it just errors out. (Additional question - is there a way with sqlite to get informative error messages like mysql_error in mysql? When I error in the app I get nothing but some symbols.
Here's my code:
.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface SQLiteController : NSObject {
//file management
NSFileManager *fileManager;
NSString *documentsDirectory;
//sqlite data
sqlite3* databaseHandle;
}
- (void) initSQLiteDB;
- (void) insertData : (NSString* ) fName : (NSString* ) lName : (NSString* ) companyName;
- (NSArray* ) getData;
#end
.m
- (void) insertData : (NSString* ) fName : (NSString* ) lName : (NSString* ) companyName {
NSString* insertStatement = [NSString stringWithFormat:#"INSERT INTO nameList (userFName, userLName, userCompany) VALUES (\"%#\", \"%#\", \"%#\")", fName, lName, companyName];
NSLog(#"%#", insertStatement);
char *error;
if ( sqlite3_exec(databaseHandle, [insertStatement UTF8String], NULL, NULL, &error) == SQLITE_OK) {
int recordID = sqlite3_last_insert_rowid(databaseHandle);
NSLog(#"A record was inserted into the database %# with the id of %i", databaseHandle, recordID);
} else {
NSLog(#"Error: %s", error);
}
}
- (NSArray* ) getData {
NSMutableArray* dataArray = [[NSMutableArray alloc] init];
NSString* getStatement = #"SELECT * FROM nameList";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(databaseHandle, [getStatement UTF8String], -1, &statement, NULL) == SQLITE_OK){
// Iterate over all returned rows
while (sqlite3_step(statement) == SQLITE_ROW) {
int recordID = sqlite3_column_int(statement, 0);
NSString* fNameFromDB = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
NSLog(#"%#", fNameFromDB);
}
} else {
NSLog(#"No soup for you!");
}
return 0;
}
#end
Use Try catch format and catch the error type of sql
Try this,i think it will help you some what
- (void) insertData : (NSString* ) fName : (NSString* ) lName : (NSString* ) companyName {
if(insertStatement == nil)
{
NSString* insertStatement = [NSString stringWithFormat:#"INSERT INTO nameList (userFName, userLName, userCompany) VALUES (\"%#\", \"%#\", \"%#\")", fName, lName, companyName];
NSLog(#"%#", insertStatement);
if(sqlite3_prepare_v2(database, insertSql, -1, &insertStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating insert statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(insertStatement, 1, [Gunameq UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insertStatement, 2, [Gpassq UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(insertStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog("Inserted");
//Reset the add statement.
sqlite3_reset(insertStatement);
insertStatement= nil;
- (NSArray* ) getData {
NSMutableArray* dataArray = [[NSMutableArray alloc] init];
NSString* getStatement = #"SELECT * FROM nameList";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(databaseHandle, [getStatement UTF8String], -1, &statement, NULL) == SQLITE_OK){
// Iterate over all returned rows
while (sqlite3_step(statement) == SQLITE_ROW) {
int recordID = sqlite3_column_int(statement, 0);
NSString* fNameFromDB = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
NSLog(#"%#", fNameFromDB);
}
} else {
NSLog(#"No soup for you!");
}
return 0;
}
#end
SQLite can be a little tricky. All access to it must be from the same thread. For every prepare statement there must be a finalize statement.
There is an example project for using SQLite here you can refer to: https://github.com/AaronBratcher/ABSQLite
It has classes for accessing SQLite in a more traditional database way that I feel makes it easier.