FMDB not inserting into DB - iphone

I am trying to use FMDB to insert a few queries into the DB.
When I check the query for insert it is saying that it is inserting.
Later I can actually read the data from the Tables.
But what happens is that if I try to read the information from the DB, it comes back as null. When I checked the DB in the Xcode Project, not seems to have updated.
It kind of confusing me. Any suggestion what the problem could be?

Your code is wrong. This is what I use to write:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"db.sqlite"];
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
[db open];
[db executeUpdate:#"INSERT INTO foo (bar) VALUES (?)", bar];
[db close];
And to read:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"db.sqlite"];
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
[db open];
NSMutableArray *bar = [[[NSMutableArray alloc] init] autorelease];
FMResultSet *s = [db executeQuery:#"select * from foo"];
while ([s next]) {
[bar addObject:[s stringForColumn:#"bar"]];
}
NSLog(#"%#", bar);
[db close];
Also checkout where I located the db. I think doing your way will work on simulator but not on the device because of sandboxing and all.
Good luck!
EDIT:
Put this in your app delegate:
- (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:#"db.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:#"db.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
And run that method from application:didFinishLaunchingWithOptions with:
[self performSelector:#selector(createEditableCopyOfDatabaseIfNeeded) withObject:nil];
Be sure that you put your database in your projecttree first.

Related

sqlite3_open - Can't open database

I have the following statement in my code:
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"Notebook.sqlite"]];
NSFileManager *fileMgr = [NSFileManager defaultManager];
const char *dbpath = [databasePath UTF8String];
NSLog(#"open sqlite at %s",dbpath);
if (sqlite3_open(dbpath, &noteDB)==SQLITE_OK)
the output of NSLog is
/Users/GinLin/Library/Application Support/iPhone Simulator/7.0/Applications/CE1BAB1C-3DEC-4A1D-A083-537B0B51C99D/Library/Documentation/Notebook.sqlite
but it doesn't seem to be opening my database.
And I cannot find the folder "Documentation" under "/CE1BAB1C-3DEC-4A1D-A083-537B0B51C99D/Library/".
Could anyone help?
I believe you meant to use NSDocumentDirectory not NSDocumentationDirectory, e.g.:
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
First you must check if the DB path contains de file, else, copy the DB
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString* resourcePath=[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database.db"];
//Destination path
NSString *dbPath = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"database.db"];
//Find file
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(success==YES){
NSLog(#"File found");
}else{
NSError* error;
if(![fileMgr copyItemAtPath:resourcePath toPath:dbPath error:&error]){
NSLog(#"Can't copy");
}else{
NSLog(#"That's all :D");
}
}

SQLite Not Importing Properly into iOS

It appears that when I copy a .sqlite3 file into iOS, and use FMDB to access it, the database is empty. I just drag and drop it into Xcode. When I run:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"db.sqlite3"];
FMDatabase *db = [FMDatabase databaseWithPath:writableDBPath];
FMResultSet *results = [db executeQuery:#"SELECT * FROM tableName"];
results returns nil. Looking at [db lastErrorMessage], it says my table does not exist. When I open up the .sqlite file in the command line (the one that is stored in the iPhone Simulator), I get an empty database. Is there a specific way to import a SQLite database into iOS? If so, how?
I see two likely problems:
First, make sure the .sqlite file is included in your project target. Select your file in the File Navigator; open the Utilities panel (the right hand panel icon in the section that says "View"), and look for a section titled "Target Membership". If the box for your desired target (you probably only have one) is not checked, your database file is not being copied into the bundle.
Second, you are attempting to find the database in your documents directory. However, you must manually copy it from your bundle to that directory before you can open it as a writable file:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"db.sqlite3"];
NSURL *dbURL = [NSURL fileURLWithPath:dbPath];
// copy a database from the bundle if not present
// on disk
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:dbPath]) {
NSURL *bundlePath = [[NSBundle mainBundle] URLForResource:#"db" withExtension:#"sqlite3"];
NSError *error = nil;
if (!bundlePath || ![fm copyItemAtURL:bundlePath toURL:dbURL error:&error]) {
NSLog(#"error copying database from bundle: %#", error);
}
}
I think that you can also your original code. You just need to open the "db"
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDirectory = [paths objectAtIndex:0];
//NSString * documentDirectory = #"/Users/cefitdept/Documents/ImportDB/";
NSString * dbPath = [documentDirectory stringByAppendingPathComponent:#"ImportDB.sqlite"];
FMDatabase * db = [FMDatabase databaseWithPath:dbPath];
if (![db open]) {
return;
}
FMResultSet * results = [db executeQuery:#"SELECT * FROM main"];
while ([results next]) {
NSData * data = [results dataForColumn:#"engs"];
NSString * string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

[NSBundle mainBundle]pathForResource returns nil

I'm trying to connect my app to SQLite database but I get messages that tell me that the database is created but there are no tables.
I debugged the program and discovered that
[[NSBundle mainBundle] pathForResource] always returns nil
NSString* file = [[NSBundle mainBundle]pathForResource:_databaseName ofType:_databaseType];
Why is this happening?
Please help me!
First : make sure your database is in the app bundle.
Then you need to implement methods to copy the path to the documentary Directory .as these
-(NSString *) getDBPath:(NSString*)databaseName {
// search for the existed paths
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:databaseName];
}
- (void) InstantiateYourDatabase:(NSString *)DatabaseName {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dpname=DatabaseName;
_dbPath = [self getDBPath:dpname];
BOOL success = [fileManager fileExistsAtPath:_dbPath];
NSLog(#"success == %i",success);
if( !success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:DatabaseName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:_dbPath error:&error];
}
}
Tell me if it helps!
try below code for find database path
NSString *databaseName = #"your_db_name.sql";
NSString *databasePath;
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"Database Path is: %#",databasePath);
You want More Detail about Sqllite Database Connectivity in iOS try this tutorial
Welcome!
If you created a sqlite db file and drag it to your project in xcode3, it's in application document folder while its running.
NSString *databaseName = #"cartoon.db";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentDir stringByAppendingPathComponent:databaseName];
Whenever you are using the database you have to use the Documents Directory

how do we open an already existing database fmdb and where to include it?

I am using fmdb but i am not knowing where to add the db file.
I found this old answer that i think it doesn't fit for xcode 4.2 (since we dont have 'Resources' folder anymore).
I created a database in 'Lita', added the extension .sqlite and added the db file as follows :
then tried to use the following
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"db.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
[database open];
FMResultSet *results = [database executeQuery:#"select * from tbl"];
printf("hi");
while([results next]) {
printf("hi2");
NSString *name = [results stringForColumn:#"clm1"];
NSString *text = [results stringForColumn:#"clm2"];
NSLog(#"test: %# - %#",name, text);
}
printf("done");
i am getting the 'hi' 'done' but never 'hi2'...
anyone can help?
You want to add the (compiled) database to the project as a resource, and then copy it into the documents folder of the app on first start-up.
Here is an example method that does the work, call it from the applicationDidFinishLaunching and use the resultant FMDatabase * for all you queries.
- (FMDatabase *)openDatabase
{
NSFileManager *fm = [NSFileManager defaultManager];
NSString *documents_dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *db_path = [documents_dir stringByAppendingPathComponent:[NSString stringWithFormat:#"database.s3db"]];
NSString *template_path = [[NSBundle mainBundle] pathForResource:#"template_db" ofType:#"s3db"];
if (![fm fileExistsAtPath:db_path])
[fm copyItemAtPath:template_path toPath:db_path error:nil];
FMDatabase *db = [FMDatabase databaseWithPath:db_path];
if (![db open])
NSLog(#"Failed to open database!");
return db;
}
I am working with the same issues right now. But to answer your question: the documents folder is the folder that is to be used in the device.
Put the database in the the supporting files folder.
Here is what works for me:
//hide status bar for full screen view
[[UIApplication sharedApplication]setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
//set reference to database here
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.databasePath = [documentDir stringByAppendingPathComponent:#"RPRA.sqlite"];
[self createAndCheckDatabase];
// Override point for customization after application launch.
return YES;
}
//method used to create database and check if it exists
-(void) createAndCheckDatabase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:self.databasePath];
if(success) return;
//else move database into documents folder
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"RPRA.db"];
[fileManager copyItemAtPath:databasePathFromApp toPath:self.databasePath error:nil];
}
- (void)ensureDBFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"retails.sqlite"]];
NSLog(#"Database Filepath Delgate = %#", dbFilePath);
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL dbFileExists = [fileManager fileExistsAtPath:dbFilePath];
if(!dbFileExists){
//Copy the db file if it didn't exist
NSString *bundledDbPath = [[NSBundle mainBundle] pathForResource:#"retails" ofType:#"sqlite"];
if (bundledDbPath != nil) {
BOOL copiedDbFile = [fileManager copyItemAtPath:bundledDbPath toPath:dbFilePath error:nil];
if (!copiedDbFile) {
NSLog(#"Error: Couldn't copy the db file from the bundle");
}
}
else {
NSLog(#"Error: Couldn't find the db file in the bundle");
}
}
self.db = [FMDatabase databaseWithPath:dbFilePath];
[self.db setShouldCacheStatements:NO];
[self.db open];
if([self.db hadError]) {
NSLog(#"Database Error %d: %#", [self.db lastErrorCode], [self.db lastErrorMessage]);
}
}

iPhone SDK: SQLite error: no such table:, even though a terminal query returns successful

I have a problem with sqlite database integration in my app.
My app uses a translator style function, whereby a users text entry is converted into another way of wording the same word, the word alternatives are listed in a SQLite database.
Basically the code is designed to take text, split it into individual words, and search for them on the database, and return the result for each word, however, the application ends up not returning results and I get the error "error: no such table: dictionary" Even though a query on terminal returns results successfully.
Can anyone give me a hand in identifying what's been done wrong? Thanks
This is the code I used:
-(void)translate{
//take input and break into an array
NSString *clearText = [[NSString alloc] init];
clearText=inputBox.text;
NSArray *words = [[NSArray alloc] init];
words= [clearText componentsSeparatedByString:#" "];
numOfWords=words.count;
NSString *newText=#"";
//open database
sqlite3 *db = [self getNewDBConnection];
//loop through array
for(i=0;i<numOfWords;i++){
sqlite3_stmt *resultStatement= nil;
NSString *res = [NSString stringWithFormat:#"select * from dictionary where plain='%#'",[words objectAtIndex:i]];
if((sqlite3_prepare_v2(db, [res UTF8String], -1, &resultStatement, nil))!=SQLITE_OK){
NSLog(#"Error getting result, maybe word not found\n");
//NSLog(#"tried query:%#",res);
NSLog(#"error: %s", sqlite3_errmsg(db));
}
else{
if(sqlite3_step(resultStatement)==SQLITE_ROW){
//in the line below, 1 is the column number of the replacement word
NSString *add = [[NSString alloc] initWithUTF8String: (char*)sqlite3_column_text(resultStatement,1)];
newText=[newText stringByAppendingString:add];
[add release];
}
}
sqlite3_finalize(resultStatement);
}
//output result
outputBox.text=newText;
sqlite3_close(db);
}
-(sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data9.sqlite"];
if (sqlite3_open([path UTF8String], &newDBconnection) == SQLITE_OK) {
NSLog(#"Database Successfully Opened");
} else {
NSLog(#"Error in opening database");
}
return newDBconnection;
}
This is the code used to copy the database:
- (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:#"data9.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:#"data9.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Based on the missing table, it looks like it is creating a new database at the path. So either the path is wrong, or it is possible that you might not have copied the master database to that location. The SQLite file is usually in the bundle and needs to be copied first.
Major issues from my perspective.
I went so far as to delete the entire database capability and then ran the app and it still opened the database.
I have this code in applicationDidFinishLaunchingWithOption in the appDelegate. It is designed for start-up to check a valid database is avaailable, so mostly it is never executed. I removed the conditional statement around the copy, and inserted a removeItemAtPath statement to delete the file. Ran it once, and my problem all went away (or at least those with the database, by biggest problem is still user error :-))
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"languageDB.sqlite"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
NSError *error;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"language.sqlite"];
NSString *writableDBPath = [docsDir stringByAppendingPathComponent:#"languageDB.sqlite"];
if ([filemgr fileExistsAtPath: databasePath ] == NO){
[filemgr copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
NSLog(#"copy error %#",error);
}
Something else you might want to make sure of if you're adding a table to an existing database and then trying to re-add it to your project is that you delete the copy of the database in the location where Xcode is copying it prior to loading your app in the simulator. For instance, when I was having this problem, I had to go into /Users/<user>/Library/Application Support/iPhone Simulator/6.0/Applications/1234DFE1-5AA9-4CFF-0235-3D98961E9281/Documents/ to delete the database there. When I cleaned and re-ran the simulator, it found my new table just fine.