Copying SQLite Database from bundle to documents for writing? - ios

So I am trying to copy my database which is currently in the main bundle to the documents so I can write to it instead of just being able to read from it. Right now I have as follows and it just can't find the database, the NSLog("Found database"); does not show up, so therefore the copying isn't working. I've been working on this for a while however I just can't figure it out.Any help would be greatly appreciated.
UPDATED VERSION
- (IBAction)update:(id)sender {
#try {
/*
NSString *docsPath = [self applicationDocumentsDirectory];
NSString *dbPath = [docsPath stringByAppendingPathComponent:#"StayhealthyExercises-1.sqlite"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:dbPath];
*/
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* dbPath = [documentsPath stringByAppendingPathComponent:#"StayhealthyExercises-1.sqlite"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:dbPath];
if (!fileExists) {
NSLog(#"Didn't find database");
// get the source path to copy from
// NSString *dbSourcePath = [[NSBundle mainBundle] pathForResource:#"StayhealthyExercises-1" ofType:#"sqlite"];
NSString *dbSourcePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"StayhealthyExercises-1.sqlite"];
// copy db to documents
[[NSFileManager defaultManager] copyItemAtPath:dbSourcePath toPath:dbPath error:nil];
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "UPDATE stretchingexercises SET isFavorite = 'true' WHERE ID = '1'";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
if (sqlite3_step(sqlStatement) == SQLITE_DONE){
NSLog(#"Success");
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
}
}
OLD VERSION
- (NSString *)applicationDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
- (IBAction)update:(id)sender {
#try {
NSString *docsPath = [self applicationDocumentsDirectory];
NSString *dbPath = [docsPath stringByAppendingPathComponent:#"StayhealthyExercises-1.sqlite"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:dbPath];
if (!fileExists) {
NSLog(#"Found Database");
// get the source path to copy from
NSString *dbSourcePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"StayhealthyExercises-1.sqlite"];
// copy db to documents
[[NSFileManager defaultManager] copyItemAtPath:dbSourcePath toPath:dbPath error:nil];
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "UPDATE stretchingexercises SET isFavorite = 'true' WHERE ID = '1'";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}else{
if (sqlite3_step(sqlStatement) == SQLITE_DONE){
NSLog(#"Success");
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
}
}

Replace your code for getting dbPath in the first if block in - (IBAction)update:(id)sender with the code below:
NSString *dbPath = [[NSBundle mainBundle] pathForResource:#"StayhealthyExercises-1" ofType:#"sqlite"];

Try this code to check the file existence
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* foofile = [documentsPath stringByAppendingPathComponent:#"CopyFileNameFromMainBundle.db"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
This should return NO

Is it just a problem with having the wrong log? Seems to me it should be like this:
....
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:dbPath];
if (!fileExists) {
NSLog(#"Didn't Find Database in Documents Directory!");
...
} else {
NSLog(#"Found Database in Documents Directory.");
}
...

Related

how to update the sqlite database in ios

I am new to ios app development.This is the code for update the sqlite database i am using but its not updating it shows data base is locked.Any help.
-(BOOL) updateSignalCode:(NSString*)deviceString buttonType:(NSString*)name
{
const char *dbPath=[databasePath UTF8String];
if (sqlite3_open(dbPath, &database)==SQLITE_OK) {
NSLog(#"database Opened");
sqlite3_busy_timeout(database, 800);
NSString *insertSQL = [NSString stringWithFormat:#"update deviceDetail Set deviceId = '%#' where buttontype = '%#'",deviceString,name];
const char *insert_stmt = [insertSQL UTF8String];
if (sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL)==SQLITE_OK) {
NSLog(#"Query Executed");
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"Database Updated");
}
else {
NSLog(#"Error while updating.%d %s",sqlite3_errcode(database), sqlite3_errmsg(database));
}
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return nil;
}
You need to copy your sqlite file to document directory in appdelegate .
- (void)createCopyOfDatabaseIfNeeded {
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSLog(#"%#",[self getDBPath]);
success = [fileManager fileExistsAtPath:[self getDBPath]];
if (success){
return;
}
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"db.sqlite"];// replace name of sqlite here
success = [fileManager copyItemAtPath:defaultDBPath toPath:[self getDBPath] error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
-(NSString *)getDBPath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *dbPath = [docsPath stringByAppendingPathComponent:#"db.sqlite"]; // replace name of sqlite here
return dbPath;
}
In Appdelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self createCopyOfDatabaseIfNeeded];
return YES;
}

Read data from existing sqlite.db is working on simulator but not actual device (Objective C)

I don't know how to fix this error, I go to "Build Phases" and add sqlit.db file to Bundle resources but it still error.
Have anyone solve the problem this thing?.
Click Here to see code
-(void) initDatabase{
dbName = #"MBox_karaoke.db";
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writeableDBPath = [documentsDirectory stringByAppendingPathComponent:dbName];
success = [fileManager fileExistsAtPath:writeableDBPath];
if(success){
return;
}
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writeableDBPath error:&error];
if (!success) {
// NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
NSLog(#"Database created failed, %#",[error localizedDescription]);
}
else {
NSLog(#"Database created successfully");
}
}
As an error states resource file not found.
Make sure you copied the database file in bundle. When you drag database to project navigator, make sure that you have checked "Copy item if needed".
Following solution working for me.
-(void)initializeDatabase {
NSError *error;
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [docPaths objectAtIndex:0];
NSString *docPath = [docDir stringByAppendingPathComponent:#"Test.sqlite"];
NSString *template_path = [[NSBundle mainBundle] pathForResource:#"Test" ofType:#"sqlite"];
if (![fm fileExistsAtPath:docPath])
[fm copyItemAtPath:template_path toPath:docPath error:&error];
//-====
}
Your code is correct but some time database file doesn't select target membership that your database doesn't copy your path that it's this type error occur.
First Remove/Uninstall your install app.
Please, Select your database file in xcode and see your target membership is check or uncheck. Uncheck that select check. (See below image)
Run the project simulator and check your database available in your path. Database available that see your database browse contain is correct.
NSLog("Path: %#",defaultDBPath);
My answer
+ (NSString *)databasePath
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *sql_Path=[paths objectAtIndex:0];
NSString *dbPath=[sql_Path stringByAppendingPathComponent:#"MBox_karaoke.sqlite"];
NSFileManager *fileMgr=[NSFileManager defaultManager];
BOOL success;
NSError *error;
success=[fileMgr fileExistsAtPath:dbPath];
if (!success)
{
NSString *path=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"MBox_karaoke.sqlite"];
success=[fileMgr copyItemAtPath:path toPath:dbPath error:&error];
}
return dbPath;
}
Create Table and here My Table Name is Account
+ (void) createTableForAccount
{
char *error;
NSString *filePath =[self databasePath];
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
NSString *strQuery=[NSString stringWithFormat:#"CREATE TABLE IF NOT EXISTS Account(id TEXT,name TEXT);"];
sqlite3_exec(database, [strQuery UTF8String], NULL, NULL, &error);
}
else
{
NSAssert(0, #"Table failed to create");
NSLog(#"Account Table Not Created");
}
sqlite3_close(database);
}
Insert Data
+ (void)insertAccountDetails:(NSString *)id:(NSString *)name
{
NSString *dbPath=[self databasePath];
if(sqlite3_open([dbPath UTF8String],&database)==SQLITE_OK)
{
NSString *strQuery = [NSString stringWithFormat:#"INSERT into Account(id,name) values(?,?);"];
if(sqlite3_prepare_v2(database,[strQuery UTF8String] , -1, &stment, NULL)==SQLITE_OK)
{
sqlite3_bind_text(stment, 1, [[self checkEmpty:id] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stment, 2, [[self checkEmpty:name] UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_step(stment);
sqlite3_reset(stment);
}
sqlite3_finalize(stment);
}
sqlite3_close(database);
}
Fetch or Get Data from Table
+ (void)getAccountDetails
{
NSString *dbPath = [self databasePath];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
NSString *query = [NSString stringWithFormat:#"SELECT id,name from Account"];
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &stment, nil) == SQLITE_OK)
{
while (sqlite3_step(stment) == SQLITE_ROW)
{
NSString *idString = [[self charToString: (char *)sqlite3_column_text(stment, 0)]base64DecodedString];
NSString *nameString = [[self charToString: (char *)sqlite3_column_text(stment, 1)]base64DecodedString];
NSMutableArray *arrayId = [[NSMutableArray alloc]init];
NSMutableArray *arrayName = [[NSMutableArray alloc]init];
[arrayId addObject:idString];
[arrayName addObject:nameString];
}
sqlite3_reset(stment);
}
sqlite3_finalize(stment);
}
sqlite3_close(database);
}
Other Methods which called inside the db insert and fetch
insert
+ (NSString *)checkEmpty:(NSString *)check
{
if([check isEqual:[NSNull null]])
check = #" ";
return check;
}
Fetch method
+ (NSString*)charToString:(const char*)chart
{
NSString *string = #" ";
if(string)
{
chart = [self checkEmptyChar:chart];
string=[NSString stringWithUTF8String:chart];
}
return string;
}
+ (const char *)checkEmptyChar:(const char *)check
{
NSString *string = #" ";
if (check == NULL)
check = [string UTF8String];
return check;
}

how to import my.sqlite3 into my iPhone project in Xcode

I drag locationsWOW.sqlite3 file into my project and trying to load it in.The console did't show info about NSLog(#"failed to open database!"); but show NSLog(#"database open");
And even when I change the name of locationsWOW to be locations (#"locations" ofType:#"sqlite3"];)
which is not existing ,still the project successfully compiled and my .sqlite database didn't work.Any could help me a beginner.
Here is my code.
-(id)init{
if (self = [super init]) {
NSString *sqlite3DB = [[NSBundle mainBundle]pathForResource:#"locationsWOW" ofType:#"sqlite3"];
if (sqlite3_open([sqlite3DB UTF8String], &_database) != SQLITE_OK) {
NSLog(#"failed to open database!");
}
}
NSLog(#"database open");
return self;
}
As a beginer just do the following steps in your code
+(NSString *)databasePath
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *sql_Path=[paths objectAtIndex:0];
NSString *dbPath=[sql_Path stringByAppendingPathComponent:#"locationsWOW.sqlite"];
NSFileManager *fileMgr=[NSFileManager defaultManager];
BOOL success;
NSError *error;
success=[fileMgr fileExistsAtPath:dbPath];
if (!success) {
NSString *path=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"locationsWOW.sqlite"];
success=[fileMgr copyItemAtPath:path toPath:dbPath error:&error];
}
return dbPath;
}
After when create the Table
+(void)createTable
{
char *error;
NSString *filePath =[self databasePath];
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
NSString *strQuery=[NSString stringWithFormat:#"CREATE TABLE IF NOT EXISTS TableName(id TEXT,name TEXT);"];
sqlite3_exec(database, [strQuery UTF8String], NULL, NULL, &error);
}
else
{
NSAssert(0, #"Table failed to create");
NSLog(#"TableName Table Not Created");
}
sqlite3_close(database);
}

Always fail if (sqlite3_step(statement) == SQLITE_DONE)

This is the code that I have used in Appdelegate.m to copy the database
- (void) copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"LocalSongs.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
And this is used to get the DBPath
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"LocalSongs.sqlite"];
}
This is my playlist Insert method
-(NSString *)InsertPlaylist :(NSString *)PlaylistName
{
NSLog(#"passed");
NSString *status;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dbPath=[[NSString alloc]initWithString:[documentsDir stringByAppendingPathComponent:#"LocalSongs.sqlite"]];
NSLog(#"Database Path %#",dbPath);
sqlite3_stmt *statement;
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSLog(#"open");
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO LOCALPLAYLIST (PLAYLISTNAME,getdate()) VALUES (\"%#\")",PlaylistName];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
status=#"Playlist Created";
}
else
{
status=#"Error occured";
}
return status;
}
}
The problem I have is this prepare_v2 is always become notdone. It always execute the else part.
if (sqlite3_step(statement) == SQLITE_DONE)
What is the problem with this? Please help me
I think you have an error with your query: you are supposed to put a column name in the place you put getdate(), i.e. instead of
INSERT INTO LOCALPLAYLIST (PLAYLISTNAME,getdate()) VALUES (\"%#\")
you should use something like
INSERT INTO LOCALPLAYLIST (PLAYLISTNAME,MYDATECOLUMN) VALUES (\"%#\",getdate())
After sqlite3_prepare_v2 the statement pointer is NULL?
Compare the return values of sqlite3_prepare_v2 and sqlite3_step with the ones in http://www.sqlite.org/c3ref/c_abort.html to get a better insight on what's going wrong

Query statement is not executing of sqlite database in xcode

I am using sqlite database mathFActs in my project which i create through Sqlite Database Browser and add it to Xcode. following is my code from a view controller class
- (void)viewDidLoad
{ [super viewDidLoad];
[self copyDatabaseIfNeeded];
[self getInitialDataToDisplay:[self getDBPath]];
}
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPth = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPth];
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"mathFActs"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"mathFActs"];
}
-(void) getInitialDataToDisplay:(NSString *)databasePath{
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"open");
const char *sql = "select Question from math ";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
NSLog(#"prepare");
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSString *addressField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(selectstmt, 0)];
//address.text = addressField;
qstn.text=addressField;
sqlite3_finalize(selectstmt);
}}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
}
when i run the project it print open but not prepare means it's not executing query statement .. plz help me to solve my problem
Try this :-
-(void) getInitialDataToDisplay:(NSString *)databasePath
{
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"open");
const char *sql = "select Question from math ";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
NSLog(#"prepare");
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSString *addressField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(selectstmt, 0)];
//address.text = addressField;
qstn.text=addressField;
}
sqlite3_reset(selectstmt);
}
else
{
NSLog(#"Error: failed to select details with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_finalize(selectstmt);
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
}
EDIT :-
-(void)copyDatabaseIfNeeded
{
#try
{
NSFileManager *fmgr=[NSFileManager defaultManager];
NSError *error;
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *path=[paths objectAtIndex:0];
dbPath=[path stringByAppendingPathComponent:#"mathFActs.sqlite"];
if(![fmgr fileExistsAtPath:dbPath]){
NSString *defaultDBPath=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"Addict.sqlite"];
if(![fmgr copyItemAtPath:defaultDBPath toPath:dbPath error:&error])
NSLog(#"failure message----%#",[error localizedDescription]);
}
}
#catch (NSException *exception)
{
NSLog(#"Exception: %#", exception);
}
}
-(NSString *)getDBPath
{
//Search for standard documents using NSSearchPathForDirectoriesInDomains
//First Param = Searching the documents directory
//Second Param = Searching the Users directory and not the System
//Expand any tildes and identify home directories.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"mathFActs.sqlite"];
}
-(void)openDatabase
{
[self copyDatabaseIfNeeded];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
//Database Opened
NSLog(#"Database opened");
}
else
{
NSLog(#"Database cannot be opened");
}
}
-(void)closeDatabase
{
sqlite3_close(database);
}
Hope it helps you

Resources