What is Fastest way to load text from sqlite database in ios? - ios

I have an sqlite database which has a 6000 rows in it. I need to import the text from it .It successfully imports the text but takes lot of time . I dont need to import all the rows at a time , It should display the 100-300 rows in UITextView when i clicked each cell in UITableView . the code Iam using is as follows :
#try
{
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"MyDatabase.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
const char *sql = "SELECT ID, MyText FROM MyTable ";
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
string = [[NSMutableString alloc]init];
MyTextView.text=#"";
while (sqlite3_step(sqlStatement)==SQLITE_ROW)
{
DetailsIDs *MyDetails = [[DetailsIDs alloc]init];
MyDetails.MyText = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
[MyTextView setText:[NSString stringWithFormat:#"%# \n%#", MyTextView.text,MyDetails.MyText]];
}
}
#catch (NSException *exception)
{
NSLog(#"An mmmm exception occured: %#", [exception reason]);
}
#finally
{
}
}
I need a fastest way to retrive the text from database,
Iam stuck ! plz help me , Thanks !

Here is your performance problem:
[MyTextView setText:[NSString stringWithFormat:#"%# \n%#", MyTextView.text,MyDetails.MyText]];
You should probably use an NSMutableString and append to it, if you really want everything in one long string like that.

Related

Update query run without error but do not update database ios sqlite objective C

I am running SQLite query on my database. The select query is working fine, but when I am running SQLite query no error is generated, but it is still not updating my database values.
The function is as follows :
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"bikeapp.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
NSString *query = [NSString stringWithFormat:#"UPDATE bikes SET to_show = 0 where id = %ld",(long)bikeId];
//const char *sql = "UPDATE bikes SET to_show = 0 where id = 3";
const char *sql = [query UTF8String];
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
if(sqlite3_step(sqlStatement))
{
return YES;
}else
return NO;
//
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
The code runs through without any error or exception but it is not updating the values inside the database. The query when run directly on database shows the changes being done. If anybody can help me out here I would appreciate it. Thanks.

How to close database in sqlite in ios?

I am using SqliteDatabase in my project.I am calling a function for data manuplation.
-(void)updateInspectionMapData2:(NSString *)clientid : (NSString *)inspectionid : (NSString *)status
{
NSLog(#"EIGHT");
NSLog(#"inside update data");
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSArray *checkVal = [self getSubClientDataByInspectionId:inspectionid :clientid];
NSLog(#"check is %#",checkVal);
if(checkVal == nil || [checkVal count] == 0)
{
NSString *querySql=[NSString stringWithFormat:
#"UPDATE inspectioninspectormap SET status=\"%#\" where inspectionid = \"%#\" and clientid =\"%#\" and (status = \"1\" or status = \"2\")",status,inspectionid,clientid];
NSLog(#"sql is %#",querySql);
const char *sql=[querySql UTF8String];
if(sqlite3_prepare_v2(database,sql, -1, &statement, NULL) == SQLITE_OK)
{
if(SQLITE_DONE != sqlite3_step(statement))
{
NSLog(#"Error while updating. '%s'", sqlite3_errmsg(database));
}
else
{
sqlite3_reset(statement);
NSLog(#"Update done successfully!");
}
}
sqlite3_finalize(statement);
}
}
sqlite3_close(database);
}
Please tell me is this the right way to close sqlite database.I am not sure i am right because later i get error unable to open database.?
There are many problems with your code. Here's what I see after just a quick glance:
You try to close the database even if it doesn't open.
You try to finalize the prepared statement even if the statement can't be prepared.
You needlessly call sqlite3_reset on the prepared statement.
You build your query using stringWithFormat: instead of properly binding values into the prepared statement.
You are using sqlite3_open instead of sqlite3_open_v2.
You don't log an error if sqlite3_open or sqlite3_prepare_v2 fail.
There is an issue in your code:
This code:
}
sqlite3_finalize(statement);
}
}
sqlite3_close(database);
should be changed to:
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
Closing the sqlite should happen right after you finish your work with database, and also within the open connection if loop, but not after the open connection!!!!
When using sqlite, opening and closing should be taken care, else it could lead to lock the database. The problem occurs when you try to open another connection to sqlite without closing the previous one, then your database will be locked .To avoid this, you need make sure that every open connection should have the close connection at the end.
You can try FMDB which is an sqlite wrapper. By using the FMDB,you can simply create the sqlite database using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"database.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
and you can open the database connection by:
[database open];
and close it by:
[database close];
and to execute a simple statement:
[database executeUpdate:#"create table user(name text primary key, age int)"];
There is a good tutorial out there:
+ (NSString*)setupDatabase
{
NSError *error;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *dbFilePath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", DATABASENAME, DATABASETYPE]];
if (! [[NSFileManager defaultManager] fileExistsAtPath:dbFilePath])
{
// if installing the application very first time didn't find db, need to copy
NSString *backupDbPath = [[NSBundle mainBundle] pathForResource:DATABASENAME
ofType:DATABASETYPE];
BOOL copiedBackupDb = [[NSFileManager defaultManager] copyItemAtPath:backupDbPath
toPath:dbFilePath
error:&error];
if (! copiedBackupDb)
{
// copying backup db failed
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
return nil;
}
}
return dbFilePath;
}
+ (NSString *)getDataBaseFilePath
{
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbFilePath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", DATABASENAME, DATABASETYPE]];
return dbFilePath;
}
+(NSString*)selectItem:(NSString*)itemID
{
NSString *name=nil;
NSString* _dataBasePath = [self getDataBaseFilePath];
sqlite3 *database;
if (sqlite3_open([_dataBasePath UTF8String], &database) == SQLITE_OK) {
NSString *query;
query= [NSString stringWithFormat:#"select ITEM_id from Table where IF ITEM_id='%#' ",itemID];
const char *sql=[query UTF8String];
sqlite3_stmt *selectstmt;
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL)==SQLITE_OK) {
while (sqlite3_step(selectstmt)==SQLITE_ROW) {
if (sqlite3_column_text(selectstmt, 0))
name=[NSString stringWithUTF8String:(char*) sqlite3_column_text(selectstmt, 0)];
}
sqlite3_finalize(selectstmt);
}
}
sqlite3_close(database);
return (name) ;
}
+(BOOL)updateITEM:(ItemObj*)itemObj;
{
NSString* _dataBasePath = [self getDataBaseFilePath];
sqlite3 *database;
if (sqlite3_open([_dataBasePath UTF8String], &database) == SQLITE_OK) {
NSString *qs=[NSString stringWithFormat:#"UPDATE ITEM set User_ID = '%#',User_Name = '%#',Item_id = '%#',User_Status = '%#' WHERE Item_id = '%#'", itemObj.usersid, itemObj.user_name, itemObj.user_id, itemObj.user_status, itemObj.user_id];
const char *sql=[qs UTF8String];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) != SQLITE_OK)
return FALSE;
int result = sqlite3_step(selectstmt);
if(result != SQLITE_DONE) return FALSE;
sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
return TRUE;
}

SQLite "file is encrypted or is not a database"

I guess this should be fairly simple, since I an new to Xcode, Objective-C and SQLite, and I am just trying to get a simple tutorial to work.
I copied the "sampled.sql" file to the directory and this is the code that connects:
-(NSMutableArray *) authorList {
theauthors = [[NSMutableArray alloc] initWithCapacity:10];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"sampledb.sql"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "SELECT * FROM verb";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement 1: %s", sqlite3_errmsg(db));
} else {
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
Author * author = [[Author alloc] init];
author.verb_nutid = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
//author.title = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
[theauthors addObject:author];
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement 2: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
return theauthors;
}
}
DATABASE FILE:
BEGIN TRANSACTION
CREATE TABLE "verb" ('ID' INTEGER PRIMARY KEY AUTOINCREMENT, 'verba' TEXT, 'verbb' TEXT);
INSERT INTO 'verb' VALUES …
And so on...
But I get the error:
Problem with prepare statement 1: file is encrypted or is not a database
Help would be much appreciated! (-:
Try to write your sampledb.sql into the documents directory instead of the bundle directory :
// Getting the documents directory path
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Getting your db's path
NSString *dbPath = [docsDir stringByAppendingPathComponent:#"sampledb.sql"];
There's no way to write into the bundle directory because it's code signed with SSL certificate. But the documents directory's not.

Update row in sqlite isn`t updating

I am trying to update just one cell in row but I can`t get it work. Method for updating:
- (void) UpdateQuestionShownParameter:(int)QuestionId :(BOOL)QuestionShown{
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"Milionar.sqlite"];
const char *sql = "UPDATE Questions set Show = ? WHERE id = ?";
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)
{
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) == SQLITE_OK)
{
NSInteger shownInteger = (QuestionShown ? 1 : 0);
sqlite3_bind_int(sqlStatement, 1, shownInteger);
sqlite3_bind_int(sqlStatement, 2, QuestionId);
if (sqlite3_step(sqlStatement) != SQLITE_DONE)
{
NSLog(#"Error while updating. '%s'", sqlite3_errmsg(db));
}
sqlite3_finalize(sqlStatement);
}
else
{
NSLog(#"Problem with prepare statement");
}
}
else
{
NSLog(#"An error has occured while opening database.");
}
sqlite3_close(db);
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
}
Trying in ViewDidLoad:
- (void)viewDidLoad
{
ListOfQuestions *listQuestions =[[ListOfQuestions alloc] init];
self.Questions = [listQuestions getQuestions];
Question *generatedQuestion = (Question *) [self.Questions objectAtIndex:0];
[listQuestions UpdateQuestionShownParameter:generatedQuestion.id :TRUE];
[self.Description setText:(generatedQuestion.Description)];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Everytime when I tried to run app I get 0 in Shown column. But I don`t have any errors. So am I doing something wrong or everytime when I tried to run app in emulator I get recreate database from project database?
Thanks
You are opening the database in the bundle, which is read-only. You should be copying the database from bundle to Documents folder if the database doesn't already exist in Documents folder:
NSString *filename = #"Milionar.sqlite";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:filename];
NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *documentsPath = [documentsFolder stringByAppendingPathComponent:filename];
if (![fileManager fileExistsAtPath:documentsPath]) {
NSError *error = nil;
BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error];
NSAssert(success, #"Unable to copy database: %#", error);
}
if (sqlite3_open([documentsPath UTF8String], &db) != SQLITE_OK) {
NSLog(#"Open failed");
} else {
// ...
}
For more information about where documents belong, see the File System Programming Guide.
By the way, if you're looking for the Documents folder for your simulator, that's located in ~/Library/Application Support/iPhone Simulator (in Xcode 6, this is now ~/Library/Developer/CoreSimulator/Devices). If you don't see the "Library" folder, you can unhide it by typing the following command into your Terminal command line interface:
chflags nohidden ~/Library

sql and UIPickerView

I need to develop a sql statement based on values picked on a UIPickerView. If you need a visual idea, here's a link to the screenshot (sorry not enough reputation to post pics yet) . I haven't been able to find any documentation on this and want to make sure I'm on the right track before I dig into it.
Each component (kTypeComponent, kDifficultyComponent, kDescriptionComponent) has three rows to select from (ex. kTypeComponent row1=bike, row2=run, row3=swim)
My thought would be that the sql statement would look something like this
sqlite3_stmt *pickerStatement;
//This would give back a string of the row selected (i.e bike, run, swim)
NSInteger getTypeSelected = [pickerView selectedRowInComponent:kTypeComponent];
NSString typeSQL = [rowOneItems objectAtIndex:getTypeSelected];
const char *pickerSQL = "SELECT description FROM workoutTbl WHERE (type = typeSQL) AND ...
Is this possible to do with a sql statement? I'm only familiar with basic SQL, so I'm not sure
Would the SQL statement go in the action (button) or where I set up my NSMutableArray and open the database? Should it go into a different class?
Edit - Solution
In case anyone comes around with the same problem, here is the solution to it
- (NSArray *)getWorkoutListwithType:(NSString *)workoutType withDifficulty:(NSString *)difficulty withLength:(NSString *)length {
NSMutableArray *workouts;
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"workoutList.sqlite"];
// NSLog(#"Db path is %#",dbPath);
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if (!success){
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"error with message '%s'.", sqlite3_errmsg(db));
}
// only alloc/init the array if the SQL database opens properly
workouts = [[NSMutableArray alloc] init];
sqlite3_stmt *sqlStatement;
// add "%%" as a wildcard so the query will say "difficulty LIKE '>30%' and match >30 MINS, >30 HOURS, etc.
NSString *sqlString = [NSString stringWithFormat: #"SELECT description FROM workoutTbl WHERE type LIKE '%#%%' AND difficulty LIKE '%#%%' AND duration LIKE '%#%%'", workoutType, difficulty, length];
NSLog(#"query: %#", sqlString);
const char *sql = [sqlString UTF8String];
if (sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
}
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
[workouts addObject:[NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)]];
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally {
sqlite3_close(db);
}
// Pass back an immutable copy of the array. if the array is nil, then the database never opened and there will be an error
return [workouts copy];
}
What do you mean by 'three rows to select'? Do you mean 'three fields (columns) to select'? If you want to specify field values, then a statement should like
NSString* sqlStatement = [NSString stringWithFormat:#"SELECT * FROM workoutTbl WHERE type = '%#' AND id = '%i'", typeSQL,idNumber];

Resources