I have a pre-populated SQLite db created with the Firefox SQLite Manager plugin.
I have included the DB to my project, added to the target and copied into destination group's folder. Then I created this function to copy the DB in the Documents folder:
-(void) createEditableDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *writableDB = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"DB.sqlite"];
success = [fileManager fileExistsAtPath:writableDB];
if (success){
return;
}
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"DB.sqlite"];
error = nil;
success = [fileManager copyItemAtPath:defaultPath toPath:writableDB error:&error];
if (!success){
NSAssert1(0, #"Failed to create writable database file:%#", [error localizedDescription]);
}
if (error){
NSLog(#"error = %#", [error localizedDescription]);
}
}
then I call this function in -(void)viewDidLoad and if I check in the simulator folder, a copy of the DB appears once I start the app.
The app runs fine, I can populate a UICollectionView with the data retrieved from the DB.
Then, when I try to insert some data, I receive no error but no data is added to the DB.
This is the code I use in MyViewController.h :
#property (nonatomic) NSString *DBPath;
#property (nonatomic) sqlite3 *myAppSQLITE;
This is the code I use in MyViewController.m :
-(IBAction)done:(id)sender{
DBPath = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"DB.sqlite"];
const char *dbpath = [DBPath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &myAppSQLITE) == SQLITE_OK){
NSString *querySQL = [NSString stringWithFormat:#"INSERT INTO myTable (name, age) VALUES('frank',30);"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(myAppSQLITE, query_stmt, -1, &statement, NULL) == SQLITE_OK){
sqlite3_finalize(statement);
}
sqlite3_close(myAppSQLITE);
}
}
I receive no error/warning but the data is never updated, even with a [self.collectionView reloadData];. If I run the same query with SQLite Manager in Firefox, everything works fine. If i open the DB inside the Simulator Documents folder with SQLite Manager, the DB is intact with no updated data. I have the same result running the app with my iPad.
How can I solve this?
Thank you in advance.
P.S: David's suggestion is right, this is a better way to create an editable DB:
- (void) createEditableDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"DB.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success){
return;
}
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"DB.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
P.S2: this could be an appropriate error checking, let me know if it's right or not.
int rc;
while ((rc = sqlite3_step(statement)) == SQLITE_ROW){
NSLog(#"ROW");
}
if (rc != SQLITE_DONE){
NSLog(#"%s: step error: %d: %s", __FUNCTION__, rc, sqlite3_errmsg(myAppSQLite));
}
You never actually execute the query by calling sqlite3_step.
You want:
if (sqlite3_prepare_v2(myAppSQLITE, query_stmt, -1, &statement, NULL) == SQLITE_OK){
sqlite3_step(statement); // add appropriate error checking
sqlite3_finalize(statement);
}
Related
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;
}
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;
}
In my app I am doing read ,write and delete on sqlite database(in db form) and it work fine in simulator but not working in actual device (giving error: No such table found).I try very hard to look for solution but couldn't find one or may be i misread something.
My db is in the
/users/My Name/library/developer/Core
simulator/devices/devicen-id/data/application/app-id/documents/My
database.
- (NSString *) getWritableDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:mydaatabase];
}
I am confuse where did i need to copy my database while running in the actual iOS device and what is the core problem.Any help regarding this will be very helpful
-(void)createEditableCopyOfDatabaseIfNeeded
{
BOOL success;
NSFileManager *fileManager1 = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:mydaatabase];
NSLog(#"=======%#", writableDBPath);
success = [fileManager1 fileExistsAtPath:writableDBPath];
if (success)
return;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:mydaatabase];
NSLog(#"=======%#", [NSBundle mainBundle]);
success = [fileManager1 copyItemAtPath:defaultDBPath
toPath:writableDBPath
error:&error];
if(!success)
{
NSAssert1(0,#"Failed to create writable database file with Message : '%#'.",
[error localizedDescription]);
}
}
Check your .sqlite file is added to your Copy Bundle Resources in Build Phases of your project. If it is not there, add it in your project.
Moreover, I can't find code for opening the database. So, in your ViewController.h file, declare Sqlite *database;
In your ViewController.m file,
-(void)databaseOpen
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory=[paths objectAtIndex:0];
NSString *myDBnew=[documentsDirectory stringByAppendingPathComponent:#"yourSqliteFile.sqlite"];
database =[[Sqlite alloc]init];
[database open:myDBnew];
NSLog(#"path: %#", myDBnew);
NSLog(#"Database opened");
}
and call it wherever you want as [self databaseOpen]; and then write your query.
Also, your -(void)createEditableCopyOfDatabaseIfNeeded should look something like this in your AppDelegate.m:
- (void)createEditableCopyOfDatabaseIfNeeded
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"yourSqliteFile.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"yourSqliteFile.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Call -(void)createEditableCopyOfDatabaseIfNeeded in didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[self createEditableCopyOfDatabaseIfNeeded];
return YES;
}
This should get you going.
Here are steps to working with SQLite Database.
Create your database in SQLite, add required table with well structure. and add it to your application.
Now, go to your app, select project from left panel, in middle panel -> General -> Linked Frameworks and Libraries(Last one) add libsqlite3.0.tbd (it is depend upon your Xcode version.)
Now, define below methods in your-object.h
#import <sqlite3.h>
+ (NSString *)getDBPath;
+ (void)copyDatabaseIfNeeded;
+ (void)openDatase;
Implement these in your-object.m
static sqlite3 *database;
#pragma mark - Copy and open databse
+ (NSString *)getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stirngByAppendingPathComponent:#"dbName.sqlite"];
}
+ (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:#"dbName.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
+ (void)openDatase
{
NSString *dbPath = [self getDBPath];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"Database Successfully Opened.");
}
else
{
NSLog(#"Error in opening database.");
}
}
Then call method in AppDelegate.m in application: didFinishLaunchingWithOptions:
[DataManager copyDatabaseIfNeeded];
Whenever you want to perform task with database, open it and check.
For inserting in database
+ (void)insertData
{
const char *dbpath = [[self getDBPath] UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *strSQL = [NSString stringWithFormat:#"INSERT INTO table name………………."];
const char *insertQuery = [strSQL UTF8String];
sqlite3_stmt *insert_stmt;
if (sqlite3_prepare_v2(database, insertQuery, -1, &insert_stmt, NULL) == SQLITE_OK)
{
if (sqlite3_step(insert_stmt) == SQLITE_DONE)
{
// Code
}
else
{
NSLog(#"error");
}
}
sqlite3_finalize(insert_stmt);
sqlite3_close(database);
}
}
7. Completed.... enjoy with database.
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
I have successfully used a .sqlite file when I store it in my project folder. I'm now trying to do the same thing, except pull the file from online instead of storing it locally. Any suggestions based on this code? I'm getting the error message "Problem with prepare statement" from the bottom of the code.
NSData *fetchedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"https://www.dropbox.com/s/zpcieluo2qv43vy/builds.sqlite?dl=1"]];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"builds.sqlite"];
[fetchedData writeToFile:filePath atomically:YES];
NSFileManager *fileMgr = [NSFileManager defaultManager];
BOOL success = [fileMgr fileExistsAtPath:filePath];
if (!success) {
NSLog(#"Cannot locate database file '%#'.", filePath);
}
if (!(sqlite3_open([filePath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"An error has occured.");
}
const char *sql = "SELECT * FROM builds";
sqlite3_stmt *sqlStatement;
if (sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"Problem with prepare statement");
}
Your dropbox URL will not work, you need to use:
https://www.dropbox.com/s/zpcieluo2qv43vy/builds.sqlite?dl=1
or you are just downloading a webpage...