Inexplicable EXC_BAD_ACCESS in the iPhone simulator - iphone

I'm trying to build a class for handling all sqlite3 work and I've encountered an EXC_BAD_ACCESS which I just can't explain. I am new to Objective-C development and memory management in general so I apologize if this is a stupid question.
When initializing the class I get the path to the database file and keep it around:
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
databasePath = [[[documentPaths objectAtIndex:0] stringByAppendingPathComponent:#"Database.sql"] retain];
Then I try to use it and it crashes on me:
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) { // crashes
The odd thing is that the exact same line in a different function works perfectly. I tried adding the variable initialization to above the line, but to no avail:
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
databasePath = [[[documentPaths objectAtIndex:0] stringByAppendingPathComponent:#"Database.sql"] retain];
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) { // crashes
In both cases the retain count is 2.
However, putting any form of static text in there works fine:
databasePath = #"I have a balloon";
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) { // fine
// or
if (sqlite3_open([#"APPLES!" UTF8String], &database) == SQLITE_OK) { // fine
A little more experimentation revealed that it was the UTF8String function that was crashing, but I don't understand why.
Edit: Even more experimentation resulted in me being able to call the UTF8String function but not even use the results:
const char * test = [databasePath UTF8String];
NSLog(#"%#", [NSString stringWithUTF8String:test]); // fine
if (sqlite3_open(test, &database) == SQLITE_OK) { // fails
Edit: Messed around even more and discovered that the problem was in a parameter that I was passing to the function. I had breakpoints all over the place so I was 100% sure that the point it fails is at the line I specified, a line which doesn't use the passed variable, but somehow it caused everything to fail. Sometimes. I have no idea how it went wrong, but I rewrote the entire thing, changed my function call and now it works.
Thanks to all who answered.

Have you checked the contents of the databasePath variable before the open call is made? Add an NSLog statement, or use the debugger, to find its value – it could be either NULL, which may not be handled by the sqlite3_open function, or it could even be that the crash is because the path is valid, and the database it points to is corrupt.

My guess is that the database variable is not declared properly. It doesn't seem to have anything to do with the path to the database.
Did you declare database like this?:
sqlite3 *database;

I suspect you are chasing the wrong problem. You haven't shown a crash dump but claim that opening "APPLES!" is 'fine' which sounds odd - surely you don't have a database with that name?
Are you sure you don't have a bad database file lying around - ie, the database file you are trying to open is corrupted in some way?

I think you have to post the crash log, your crash makes no sense. The code you posted should work.

Try a copy instead of a retain on the variable - it'll make an immutable copy of the string so it shouldn't go changing or disappearing.
EDIT::
What happens when you simply type
if (sqlite3_open[#"myDatabase.sqlite" UTF8String], &database) == SQLITE_OK) {
Also are you sure that the
NSArray * documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
databasePath = [[[documentPaths objectAtIndex:0]
stringByAppendingPathComponent:#"Database.sql"] retain];
is actually returning where the database is?
The code I use to grab the database from the app directory where kFilename is the database file is:
- (NSString *)dataFilePath{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
and then to use it I do:
if(sqlite3_open([[self dataFilePath] UTF8String], &database) != SQLITE_OK){
This works on both my iPod touch and the iPhone simulator.
EDIT2::
I've just used your above method and it seems to work here - I know it sounds stupid but have you tried rebooting? Its possible something strange is happening with the simulator

Related

Opening SQL with Objective-C

I have an sql file in my supporting files. How can I open this file so that I can start using SQL commands to get the information that I want? I've tried a couple different syntaxes, and the last time I tried I ended up screwing up the whole application because I couldn't remember what I had changed.
If you are using sqlite 3. Then,
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths lastObject];
NSString* dbPath = [documentsDirectory stringByAppendingPathComponent:#"database.sqlite"];
if(sqlite3_open([dbPath UTF8String], &dataBase) == SQLITE_OK)
{
NSLog(#"Opened Database");
//Your code
}
else
{
NSLog(#"Failed to open database");
sqlite3_close (database);
}

sqlite error database is locked

I am have a sqlite database in the iPhone application I am writing. I get an error with following code that I am running in a background thread. In the background thread, I call this method:
- (BOOL) songIsInDatabase:(NSString *)songTitle
{
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
//Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"Database.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if(sqlite3_open(dbpath, &DB) == SQLITE_OK){
NSString *insertSQL = [NSString stringWithFormat:#"select * from Bpm_Table where song_title = '%#'", songTitle];
const char *insert_stmt = [insertSQL UTF8String];
if(sqlite3_prepare_v2(DB, insert_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
return YES;
break;
}
}else{
NSLog(#"the error is %s", sqlite3_errmsg(DB));
}
sqlite3_finalize(statement);
}
[databasePath release];
return NO;
}
Then I call this method:
- (void) addSongToDatabase: (NSString *) songTitle andBPM: (int)bpm andGenre: (NSString *) genre
{
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
//Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"Database.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if(sqlite3_open(dbpath, &DB) == SQLITE_OK){
NSString *insertSQL = [NSString stringWithFormat:#"insert or replace into Bpm_Table (song_title, bpm, genre) values (\"%#\", \"%d\", \"%#\")", songTitle, bpm, genre];
const char *insert_stmt = [insertSQL UTF8String];
if(sqlite3_prepare(DB, insert_stmt, -1, &statement, NULL) == SQLITE_OK){
if(sqlite3_step(statement) == SQLITE_DONE)
{
} else {
NSLog(#"error: %s", sqlite3_errmsg(DB));
}
}sqlite3_finalize(statement);
}
[databasePath release];
}
If I run both these methods, one right after the other, I get an error that says database is locked. I added the sqlite3_finalize statements after poking around google in hopes that would fix the issue. If I comment out either of the methods, I don't get this error.
Does anyone know what's wrong?
you must always close the sqlite database after using it ... so add this line sqlite3_close(DB); just after sqlite3_finalize(statement);
Update -
You are returning YES in one of your while loop -
while (sqlite3_step(statement) == SQLITE_ROW)
{
return YES;
break;
}
so here you are nither finalizing nor closing the database.. you need to close if everytime you open it
But note that if you access the same SQLite DB from multiple threads, without some sort of separate synchronization (some way to know that you'll never have near-simultaneous accesses from multiple threads) then you're likely to get "database locked" errors even if you close everything correctly on each access.
SQLite does not provide any sort of "lock wait" mechanism.
Your basic options are:
Do all accesses from one thread.
Use a separate lock protocol around all accesses.
If you get a "database locked" error wait a brief period of time and retry.
your database is open close it using sqlite3_close(db)
if you dont close then the process which accessed your database will be running background
which will cause database is locked error.
if you want to remove database is locked error then follow these steps
1.copy your database file to some other location.
2.then replace the database with the copied database
3.this will dereference all processes which were accessing your database file
If you have tried sqlite3_close(DB) it's probably because your methods are trying to access the same database at the same time.
Try to place this line of code
sqlite3_busy_timeout(DB, 500);
somewhere between sqlite3_open and sqlite3_prepare_v2 in the method from where you get the "database is locked"-error message.
The database-connection in that method will then try to write/read in 500 milliseconds before it gives up, which is usually enough time to escape the locking.
Your database is open. Close it using sqlite3_close(db).
If you don't close, then the process accessing your database will be running background which will cause database is locked error.
For one thing, you're not closing the database connection with sqlite3_close() before you open a new connection
I just spent an hour with the same problem. The problem for me arose when i unwittingly killed a process by closing the shell (when the script was running a while loop and timer), while a db journal temp file was still opened. Windows does not kill the process even though you have killed it in Python, regardless if you have used db.close() or finalize in the script; if you exit all Python apps there will still be one running in the Task manager.
Hence you will need to end all Python processes in Windows Task Manager, restart them, and it should be fine(if that is actually the cause of the problem).
I had the same problem a while ago. I tried copying the database file itself, renamed it to different filename, then checked it - It actually WORKED!
I am using SQLite3.
I hope this will also work for you!

Odd NSString Behavior "warning: Unable to read symbols for..."

I have an object that handles database actions. It initiates with:
-(id)init{
databaseName = #"WhoPaidLast.sql";
// I think this one gets it from the app whereas the next one gets it from the phone
// databasePath = [[NSBundle mainBundle] pathForResource:#"WhoPaidLast" ofType:#"sql"];
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
self.databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
// Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase];
return self;
At the end of this I check the db:
-(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
success = [fileManager fileExistsAtPath:self.databasePath];
// If the database already exists then return without doing anything
if(success) return;
// 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];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:self.databasePath error:nil];
//[fileManager release];
}
After this, when I go to use databasePath I only seem to be able to use it once before it throws this error:
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.1 (8G4)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
I have a function that returns a bunch of values from the database. The first time detabasePath is used it works fine and outputs the intended value, the second time it throws the above error.
Here is the beginning of that function:
// Setup the database object
sqlite3 *database;
// Init groupsArray
groupsArray = [[NSMutableArray alloc] init];
NSLog(#"r- %#",self.databasePath);
NSLog(#"s- %#",self.databasePath);
// Open the database from the users filessytem
if(sqlite3_open([self.databasePath UTF8String], &database) == SQLITE_OK) {
If I remove the second NSLog function then it errors the next time databasePath is used. If I remove both it'll work for the sqlite3_open function but error on the next use.
If anyone knows the source of my error and/or what I might be doing wrong I'd very much appreciate your help.
Thanks.
There look to be a number of memory-management-related errors in the above code. I'm guessing that the debugger error you're seeing is due to a memory-related crash that the debugger isn't quite able to latch onto to give you a stack trace.
First off, your -init method never calls this on the superclass, which is not right. You need to have something like
if (!(self = [super init]))
{
return nil;
}
at the start of that method.
That alone should lead to all kinds of fun crashes. Beyond that, make sure that the databasePath property is set to use copy or retain (preferably copy, given that it's an NSString), or it won't hold on to the autoreleased object returned by [documentsDir stringByAppendingPathComponent:databaseName].
Also, I know you have it commented out, but don't use [fileManager release]. That's a shared instance you get back from [NSFileManager defaultManager] and you haven't retained it, so releasing that would lead to bad things.
You could try to enable breakpoints and turn NSZombie on to find your specific crash location, but I bet the cause is one of the factors I list above.
This is a bug of iOS/ Xcode 4
Enter the following 2 commands in Terminal
cd /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.1\ \(8G4\)/Symbols/
sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/Developer/ Developer
Clean (shift+cmd+k) the project before run it. And the problem should solved.
Ref: http://blog.damore.it/2011/04/xcode4-debugging-problem-warning-unable.html

Accessing a database through Obj-c

I am trying to find some source code on how to access and store variables from a database to my program via obj-c(iPhone). I have look for many hours now and no one has provided a sure fire way on how to go about this. If you have any advice or recommendations please post some source code or a link to it.
Thanks for the help.
If using the sqlite3 database which your program has access to on the phone for local database storage.
#import <sqlite3.h>
And create an openDatabase() method. Also add a variable for keeping the db around.
sqlite3 *db = nil;
Just make sure you call your open database method before using the database. Check this page out http://ved-dimensions.blogspot.com/2009/03/iphone-development-sqlite3-populating.html
Might give you something that you can use.
+(sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.sqlite"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &newDBconnection) == SQLITE_OK) {
NSLog(#"Database Successfully Opened :)");
} else {
NSLog(#"Error in opening database :(");
}
return newDBConnection;
}

warning: invalid receiver type +sqlite3

I am programming an Xcode iPhone app and utilizing sqlite. In an effort to delete all rows from a table, I receive the warning above when I build my code. Does anyone have any suggestions on how to fix this?
Thanks
- (void) deleteData {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory
stringByAppendingPathComponent:#"myDatabase.sqlite"];
if (sqlite3_open([writableDBPath UTF8String], &database) == SQLITE_OK) {
[database executeNonQuery:#"DELETE FROM test;"];
}
[database release];
}
Assuming
sqlite3 *database;
somewhere all up ins, it should be noted that sqlite3_open() doesn't create an Objective-C object; it creates an sqlite3 database handle, which is, if memory serves, a struct packed in a pointer. It can, in other words, not receive Objective-C messages. * does not an object make.