I have a project that includes FMDB to manage SQLite databases. I imported and linked the FMDB wrappers, but problems is that no results are shown when I query the database :
The sqlite database created with Firefox SQLite manager (Ubuntu) and I copy it to Xcode .
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"db.sqlite"];
FMDatabase *db = [FMDatabase databaseWithPath:path];
[db open];
FMResultSet *fResult= [db executeQuery:#"SELECT * FROM mytable"];
while([fResult next])
{
NSLog(#"%#",[fResult stringForColumn:#"title"]);
}
[db close];
If you have copied your database into xCode then you should search for your database in your application's main bundle resource path first, then copy it into the Documents directory if it doesn't exist there yet, only then you can work with it. You might want to debug your FMDatabase object using lastErrorMessage and lastErrorCode messages.
FMDatabase *db = [FMDatabase databaseWithPath:path];
NSLog(#"database instantiated: %#", db];
[db open];
NSLog(#"Database has encountered an error with message: %#. And code: %d", db.lastErrorMessage, db.lastErrorCode];
FMResultSet *fResult= [db executeQuery:#"SELECT * FROM mytable"];
while([fResult next])
{
NSLog(#"%#",[fResult stringForColumn:#"title"]);
}
[db close];
The other problem might of course sound silly, but if your 'mytable' does not contain anything, the while loop expression will always be false. But my best guess - the database is not in the Documents directory.
Related
My program need to operate database, and now I used 'FMDB' framework and close the sandbox in my xcode project.
but I got a trouble, it's very strange: in myself computer, read/write operate are no problem. (after archive as app), but in the other computer, it can only read, canon't write, Why?
(The database is in this app's source folder).
The problem is not that the database file cannot be found, because I log the database path in other computer, It's right.
My system is "Mac OS 10.15", I'm using SDK that version '10.13' In Xcode.
Read operate: ↓
+ (charData *)getCharacteData:(NSString *)character
{
NSString *databasePath = [[NSBundle mainBundle] pathForResource:#"CN_Characters" ofType:#"DB"];
FMDatabase *db = [FMDatabase databaseWithPath:databasePath];
[db open];
FMResultSet *res = [db executeQuery:[NSString stringWithFormat:#"SELECT * FROM Proverbs WHERE character = '%#';",character]];
charData *charDta = [charData new];
if ([res next]) {
charDta.character = [NSString stringWithString:[res stringForColumn:#"character"]];
charDta.explanation = [NSString stringWithFormat:#"%#",[res stringForColumn:#"explanation"]];
} else {
return NULL;
}
[db close];
return charDta;
}
Write operate: ↓
+ (BOOL)saveCharacterDataWithCharacter:(NSString *)character Explanation:(NSString *)explanation
{
NSString *databasePath = [[NSBundle mainBundle] pathForResource:#"CN_Characters" ofType:#"DB"];
printf("databasePath: %s\n",databasePath.UTF8String);
FMDatabase *db = [FMDatabase databaseWithPath:databasePath];
[db open];
BOOL res = [db executeUpdate:[NSString stringWithFormat:#"UPDATE Proverbs SET explanation = '%#' WHERE character = '%#'",explanation,character]];
[db close];
return res;
}
Is it a permission problem?
When you run your app, you need to copy your file from the bundle into the documents directory.
if([[NSFileManager defaultManager] copyItemAtPath: databasePath
toPath:[documentsDirectory stringByAppendingPathComponent:#"CN_Characters.DB"]
error:&error]){
Otherwise it will be read only.
Problem: After long time running with no issues, my database is giving me a headache, it just wont stay at its place in the NSDocumentDirectory. The Database strangely disappears.
I never clear the documents-folder or delete anything. It only contains the database and saves some images in there which get downloaded if the user wants to keep them.
Has anybody an idea what could be going on?
after 3 days of struggling with this problem I can't come up with a possible solution, so please help me! :(
in my Database-Singleton I have the following init-Method
- (id)initWithName{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:kDatabaseName];
//kDatabaseName = nameOfDatabase.db
[self checkAndCreateDatabase];
return self;
}
and the checkAndCreateDatabase - method:
- (void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
NSURL *urlpath = [NSURL fileURLWithPath:databasePath];
NSError *error = nil;
[urlpath setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success && sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"database opened");
sqlite3_close(database);
return;
}
else{
sqlite3_close(database);
NSLog(#"Database was created");
}
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
//NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:databaseName ofType:#"sqlite3"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
if ([self createTables]){ //creates tables of DB, works fine
NSLog(#"Tables were created");
} else {
NSLog(#"Database failed to create and open");
}
}
This code worked for a year straight. and suddenly when i needed to do some updates, the database was not saved anymore.
After a lot of troubleshooting I found out the database is being created in the Documents folder, but when i try to access the exact same path (cause i don't touch the variables) it disappears, with it's tables.
I tried different versions of my repository, all of them seem to have the problem. I really am getting mad. :(
Are you persisting the databasePath between app launches? In iOS 8 the DocumentsDirectory (and all the others, Caches, tmp, etc) became dynamic - - their name changes in between every app launch. So if you're storing the absolute path anywhere in your app it will be invalid the next time the app launches. If this is the case, a good way to fix it is to store the path relative to the DocumentsDirectory and whenever you need it just call
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
and append your path to that.
Help this helps.
I have this function that takes results from a database query. I am using the FMDB Library to query the database. However, I have a feeling that I am not properly transferring the query results to my mutable array. Here is my fucntion
-(NSArray *)initializeGroupIDArray{
// Getting the database path.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *dbPath = [docsPath stringByAppendingPathComponent:#"itemList.db"];
FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
[database open];
NSString *sqlSelectQuery = #"SELECT DISTINCT GROUPID FROM ItemList";
// Query result
FMResultSet *resultsWithNameLocation = [database executeQuery:sqlSelectQuery];
while([resultsWithNameLocation next]) {
NSString *itemName = [NSString stringWithFormat:#"%#",[resultsWithNameLocation stringForColumn:#"GROUPID"]];
// loading your data into the array, dictionaries.
NSLog(#"GroupID = %#", itemName);
[groupArray addObject:itemName];
}
[database close];
NSArray *groupID;
[groupID = groupArray copy];
return groupID;
}
A warning comes up at the lines NSLog(#"GroupID = %#", itemName); and [groupArray addObject:itemName]; at it says that the local declaration of itemName hides instance variable. I have a feeling that this is the culprit behind me not being able to properly add the results to my array. What am I doing wrong?
The usage of itemName in the code you shared looks correct to me. The error message indicates that your class has an instance variable named itemName, which would make your usage of itemName in the NSLog and addObject: cases ambiguous (as two variables, one in your local scope, and one in your class scope, would be sharing the same variable name).
Fix this issue by choosing a new unique name for your NSString *itemName variable within this method.
I'm using FMDB in my project, I constructed the first sqlite3 database in terminal, and loaded it into my project. Later I made some changes to that database, so I deleted it from project (move to trash), and "add files" again. But the running result seems still accord to the previous database or sometimes just no query result. I also tried to remove the database and run project, it's still running with no error... Additionally, I imported a newer database with another name, it can't work either. So is there anything additional I need to do to totally remove a database in objective-c and reload one? Thanks!
My code shows as below:
- (IBAction)submitButton:(id)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"finalCarpool.db"];
FMDatabase* db = [FMDatabase databaseWithPath:writableDBPath];
NSLog(#"Is SQLite compiled with it's thread safe options turned on? %#!", [FMDatabase isSQLiteThreadSafe] ? #"Yes" : #"No");
if (![db open]) {
NSLog(#"Could not open db.");
}
FMResultSet *rs = [db executeQuery:#"select * from userinfo"];
int count=0;
while ([rs next]) {
count++;
NSLog(#"%i",count);
}
FMResultSet *rs2 = [db executeQuery:#"select id from userinfo where username = ? AND password= ?", usernameTextField.text,passwordTextField.text];
if ([rs2 next]) {
NSString *welcomeMessage=[[NSString alloc]initWithFormat:#"Welcome, %#",usernameTextField.text];
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:#"Successfully Login!"
message:welcomeMessage
delegate:nil
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[myAlert show];
[self.loginDelegate backToLaunch];
}
else {
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:#"Something is wrong..."
message:#"Your username and/or password doesn't match!Please try again!"
delegate:nil
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[myAlert show];
usernameTextField.text=Nil;
passwordTextField.text=Nil;
}
[usernameTextField resignFirstResponder];
[passwordTextField resignFirstResponder];
}
If you are testing on the simulator, the database path is
~/Library/Application Support/iPhone Simulator/<SIMULATOR-VERSION>/Applications/<APP-NAME>/Documents/finalCarpool.db
You can delete it from there.
Otherwise you can just delete the application from the simulator (in the same way you would do from the iPhone).
Go TO Ios Simulator> ResetContent and setting
I'm trying to open sqlite database from my documents directory:
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbFileName = [docDir stringByAppendingPathComponent:#"DatabaseName.sqlite"];
self.db = [FMDatabase databaseWithPath:dbFileName];
self.db.logsErrors = YES;
self.db = _db;
if ([self.db open]) {
NSLog(#"database opened");
}
NSLog(#"docDir = %#",[NSString stringWithFormat:#"%#%#",docDir,dbFileName]);
NSLog shows strange path docDir = /Users/userName/Documents/Users/userName/Documents/DatabaseName.sqlite instead of /Users/userName/Documents/DatabaseName.sqlite. While opening there are no errors or warnings.
After this I tried get count(*) from my table
NSString *queryString = [NSString stringWithFormat:#"SELECT count(*) FROM histories"];
FMResultSet *result = [self.db executeQuery:queryString];
NSLog(#"count = %i", [result intForColumnIndex:0]);
Database has more when 10k rows but NSLog shows 0. Application is not for iOS, only Command Line. Where can I find the problem?
You have
docDir = /Users/userName/Documents
dbFileName = /Users/userName/Documents/DatabaseName.sqlite
therefore in
NSLog(#"docDir = %#",[NSString stringWithFormat:#"%#%#",docDir,dbFileName]);
the docDir is printed twice (dbFileName already contains docDir).
Remark: The statement self.db = _db; looks suspicious, you might want to remove that.
Added: The FMDB documentation states:
You must always invoke -[FMResultSet next] before attempting to access
the values returned in a query, even if you're only expecting one.
So your code probably should look like this:
FMResultSet *result = [self.db executeQuery:queryString];
if ([result next]) {
NSLog(#"count = %i", [result intForColumnIndex:0]);
}