memory leaks when opening sqlite database in iOS? [closed] - iphone

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I have been getting constant memory leak at this line
> if (sqlite3_open([databasePath UTF8String], &databaseHandle) != SQLITE_OK)
. What could be the reason ?? I have even closed the database after opening it . But its of no avail.
My whole method is
-(void)copyCustomDatabase{
/** done - #todo Copy db file from app resources */
#try {
NGMobileCaptureSingleton * singleton = [NGMobileCaptureSingleton getSharedInstance];
NSString *documentsDirectory = [singleton getAppDocumentDirectory];
NSString *apkIdStr = [NSString stringWithFormat:#"%d", [NGMobileCaptureSingleton getSharedInstance].apkId];
NSString *databaseName = [[[[#"ngcapcust_" stringByAppendingString:apkIdStr] stringByAppendingString:#"_"] stringByAppendingString:[NSString stringWithFormat:#"%d", formId]] stringByAppendingString:#".db"];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:databaseName];
// NSLog(#"copyCustomDatabase Custom Database Path %#", databasePath);
bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
if (!databaseAlreadyExists)
{
NSError *error;
NSFileManager *fileManager = [[NSFileManager defaultManager] init];
NSString *srcPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:srcPath toPath:databasePath error:&error];
}
if (sqlite3_open([databasePath UTF8String], &databaseHandle) != SQLITE_OK)
{
[self closeDatabase];
NSLog(#"NGDefaultCustomHelper copyCustomDatabase Error in creating database handle");
// } else {
// NSLog(#"NGDefaultCustomHelper copyCustomDatabase Database handle created successfully");
}
} #catch (NSException *exception) {
NSLog(#"NGDefaultCustomHelper copyCustomDatabase exception : %#", exception);
}
}
- (void)closeDatabase
{
sqlite3_close(databaseHandle);
databaseHandle = NULL;
tableMap = NULL;
tableIdMap = NULL;
}

sqlite3_open([databasePath UTF8String], &databaseHandle) returns databaseHandle, which (according to the docs) "Whether or not an error occurs when it is opened, resources associated with the database connection handle should be released by passing it to sqlite3_close() when it is no longer required".

The reason is you don't close the database with sqlite_close().

U forgot to add sqlite_close()

Related

sqlite 3 opening issue

I'm getting my data ,with several similar methods, from sqlite3 file like in following code:
-(NSMutableArray *) getCountersByID:(NSString *) championID{
NSMutableArray *arrayOfCounters;
arrayOfCounters = [[NSMutableArray alloc] init];
#try {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *databasePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"DatabaseCounters.sqlite"];
BOOL success = [fileManager fileExistsAtPath:databasePath];
if (!success) {
NSLog(#"cannot connect to Database! at filepath %#",databasePath);
}
else{
NSLog (#"SUCCESS getCountersByID!!");
}
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK){
NSString *tempString = [NSString stringWithFormat:#"SELECT COUNTER_ID FROM COUNTERS WHERE CHAMPION_ID = %#",championID];
const char *sql = [tempString cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *sqlStatement;
int ret = sqlite3_prepare(database, sql, -1, &sqlStatement, NULL);
if (ret != SQLITE_OK) {
NSLog(#"Error calling sqlite3_prepare: %d", ret);
}
if(sqlite3_prepare_v2(database, sql, -1, &sqlStatement, NULL) == SQLITE_OK){
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
counterList *CounterList = [[counterList alloc]init];
CounterList.counterID = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)];
[arrayOfCounters addObject:CounterList];
}
}
else{
NSLog(#"problem with database prepare");
}
sqlite3_finalize(sqlStatement);
}
else{
NSLog(#"problem with database openning %s",sqlite3_errmsg(database));
}
}
#catch (NSException *exception){
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally{
sqlite3_close(database);
return arrayOfCounters;
}
//end
}
then i'm getting access to data with this and other similar lines of code:
myCounterList *MyCounterList = [[myCounterList alloc] init];
countersTempArray = [MyCounterList getCountersByID:"2"];
[countersArray addObject:[NSString stringWithFormat:#"%#",(((counterList *) [countersTempArray objectAtIndex:i]).counterID)]];
I'm getting a lot of data like image name and showing combination of them that depends on users input with such code:
UIImage *tempImage = [UIImage imageNamed:[NSString stringWithFormat:#"%#_0.jpg",[countersArray objectAtIndex:0]]];
[championSelection setBackgroundImage:tempImage forState:UIControlStateNormal];
My problem:
When i'm run my app for some time and get a lot of data it throws error: " problem with database openning unable to open database file - error = 24 (Too many open files)"
My guess is that i'm opening my database every time when getCountersByID is called but not closing it.
My question:
Am i using right approach to open and close database that i use?
Similar questions that did not helped me to solve this problem:
unable to open database
Sqlite Opening Error : Unable to open database
UPDATE:
I made assumption that error is showing up because i use this lines of code too much:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *databasePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"DatabaseCounters.sqlite"];
BOOL success = [fileManager fileExistsAtPath:databasePath];
and ending up with error 24.
So i made them global but sqlite3_errmsg shows same err 24, but app runs much faster now
You should open your DB only once basically when you are in the initialization phase but not when you are requesting some info to your DB. Your code shouldn't failed though since you seems to open then close the DB after each request. Make sure this is happening by either logging those events or debugging through your code.
The code you've shown does close the database, so it's likely that you forget to close it in some other place, or that some other file is opened repeatedly but never closed.

Fetch different data types values from string and separate them [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am using QR code and after scanning getting username, eventtitle and ticketcode. I need to get these values separately in three different strings, so that i can save them in sqlite. I want to know only how to do this separation, saving is i can do.
Thanks in advance.
- (void)saveData {
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO CONTACTS (name, address, phone) VALUES (\"%#\", \"%#\", \"%#\")", #"NameString", #"Address", #"Phone"];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"Success");
} else {
NSLog(#"Failed");
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
Note
If you post what type of string you are getting, i will add how exactly you have to split it.
Below is example how you can split
NSArray arrResult = [str componentsSeparatedByString:#"-"];
Or By Character set
NSString* str = #"A string with newlines in it";
NSArray *arrTemp = [str componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
you can use componentsSeparatedByString
NSString *str = #"userName:Password:etc";
NSArray* parts1 = [str componentsSeparatedByString:#":"];
NSLog(#" [[parts1 objectAtIndex:0] integerValue]=%d", [[parts1 objectAtIndex:0] integerValue]);
//the output will be: username for index 0, and so on

iPhone - Trying to Copy sqlite Database to Documents Directory - copies blank version

I have an sqlite database called 'ProductDatabase.sql', which I have copied into my applications project directory:
/Users/jacknutkins/Documents/TabbedDietApp/TabbedDietApp/ProductDatabase.sql
In the applications app delegate class I have this piece of code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Set-up some globals
m_DatabaseName = #"ProductDatabase.sql";
//Get the path to the documents directory and append the databaseName
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
m_DatabasePath = [documentsDirectory stringByAppendingPathComponent:#"ProductDatabase.sql"];
//Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase];
//Query the databse for all animal records and construct the "animals" array
[self readProductsFromDatabase];
....
At this point:
m_DatabasePath = '/Users/jacknutkins/Library/Application Support/iPhone Simulator/5.0/Applications/6D5BBE3A-BC9A-4C44-B089-FABA27CFFF4B/Library/ProductDatabase.sql'
Here is the code for the other 2 methods:
- (void) checkAndCreateDatabase {
NSError * error;
//Check if the database has been saved to the users phone, if not then copy it over
BOOL l_Success;
//Create a file manager object, we will use this to check the status
//of the databse and to copy it over if required
NSFileManager *l_FileManager = [NSFileManager defaultManager];
//Check if the database has already been created in the users filesystem
l_Success = [l_FileManager fileExistsAtPath:m_DatabasePath];
//If the database already exists then return without doing anything
if(l_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 *l_DatabasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:m_DatabaseName];
//Copy the database from the package to the usrrs filesystem
[l_FileManager copyItemAtPath:l_DatabasePathFromApp toPath:m_DatabasePath error:&error];
}
If I perform some NSLogs here:
l_DatabasePathFromApp = /Users/jacknutkins/Library/Application Support/iPhone Simulator/5.0/Applications/6D5BBE3A-BC9A-4C44-B089-FABA27CFFF4B/TabbedDietApp.app/ProductDatabase.sql
and:
error = Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0x6b6d060 {NSFilePath=/Users/jacknutkins/Library/Application Support/iPhone Simulator/5.0/Applications/6D5BBE3A-BC9A-4C44-B089-FABA27CFFF4B/TabbedDietApp.app/ProductDatabase.sql, NSUnderlyingError=0x6b6cfa0 "The operation couldn’t be completed. No such file or directory"}
I'm not sure what file it is it can't find here..
- (void) readProductsFromDatabase {
//Init the products array
m_Products = [[NSMutableArray alloc] init];
NSLog(#"%#", m_DatabasePath);
//Open the database from the users filessystem
if(sqlite3_open([m_DatabasePath UTF8String], &database) == SQLITE_OK) {
//Set-up the SQL statement and compile it for faster access
const char *sqlStatement = "select * from products";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#"Success..");
//Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
//Read the data from the results row
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aCategory = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aCalories = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSString *aFat = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
NSString *aSaturates = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
NSString *aSugar = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
NSString *aFibre = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
NSString *aSalt = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 8)];
NSString *aImageURL = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 9)];
NSLog(#"Delegate");
NSString *aNote = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 10)];
NSUInteger myInt = sqlite3_column_int(compiledStatement, 11);
NSString *aServes = [NSString stringWithFormat:#"%d", myInt];
//Create a new animal object with the data from the database
Product *l_Product = [[Product alloc] initWithName:aName category:aCategory calories:aCalories fat:aFat saturates:aSaturates sugar:aSugar fibre:aFibre salt:aSalt imageURL:aImageURL note:aNote serves:aServes];
//Add the animal object to the animals array
[m_Products addObject:l_Product];
}
}
//Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
database is declared in the .h file as follows:
//Setup the database object
sqlite3 *database;
In the above method, the line:
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
does not evaluate to SQLITE_OK, because the database I try to copy to the documents directory is blank.
I have tried cleaning and building, deleting the blank copy of the database and re-running etc but it continues to copy a blank database every time.
I've googled this several times and I've tried everything I can find with no success..
Any help would be hugely appreciated.
Jack
EDIT
If I perform 'select * from products' from the terminal window on the database in the project directory I return the expected results.
I had forgotten to include the database file in the target membership by clicking on the check box in the file inspector tab.

initialization from incompatible pointer type

-(void)initializeTableData
{
sqlite3 *db=[DatabaseTestAppDelegate getNewDBConnection];
sqlite3_stmt *statement=nil;
const char *sql="select * from WhereTo";
if (sqlite3_prepare_v2(db, sql, -1, &statement, NULL)!=SQLITE_OK)
NSAssert1(0,#"error in preparing staement",sqlite3_errmsg(db));
else {
while(sqlite3_step(statement)==SQLITE_ROW)
[tableData addObject:[NSString stringWithFormat:#"%s",(char*)sqlite3_column_text(statement,1)]];
}
sqlite3_finalize(statement);
}
at sqlite3 *db=[DatabaseTestAppDelegate getNewDBConnection]; <--- it says, DatabaseTestAppDelegate may not respond to '+getNewDbConnection'
and here is my getNewDbConnection
+(sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Malacca-lah.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;
}
im new to XCode and also SQLite... been learning this for the past few weeks now, trying to get a hang on it... anyways, pls help me out with this problem. I understand the whole code but i dont understand why the inheritance has an issue.
Thanks in advance
If it says that a class may not respond to a selector, it means that it can not able to find the method declaration of the selector. Have you declared the method +(sqlite3 *)getNewDBConnection in DatabaseTestAppDelegate's header(".h") file?

how to create a sqlite

how to create a sqlite file when the application starts (didFinishLaunchingWithOptions) the test if it already or not exsist otherwise create the file sqlite
Like this... the sqlPath variable is the path to the pre-made sql database on your ressource
- (void) checkAndCreateSQL
{
if (![[NSFileManager defaultManager] fileExistsAtPath:[documentPath stringByAppendingString:#"/database.sql"]]) {
[[NSFileManager defaultManager] createFileAtPath:[documentPath stringByAppendingString:#"/database.sql"]
contents:[NSData dataWithContentsOfFile:sqlPath]
attributes:nil];
}
}
EDIT 1:
You can create the database on your mac using this command line :
sqlite3 database.sql < DATABASE_CREATION.txt
in the DATABASE_CREATION.txt something like this :
CREATE TABLE IF NOT EXISTS `group` (
`id` integer PRIMARY KEY,
`name` text,
`position` integer
);
Then put directly the database.sql file into your project resource. (like an image)
You'd probably want to use the default Core Data libraries instead of manually creating and handling a single sqlite file. Please check the official Apple Core Data Programming Guide. It will automatically handle the creation and update of the inner database in the app.
sqlite3 *reference2Database() {
if (_database == nil) {
// First, test for existence.
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"my.sqlite"];
if ([fileManager fileExistsAtPath:writableDBPath] == NO) {
// Database file doesnt exists. Copy the database at writable path (documents directory).
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"my.sqlite"];
[fileManager removeItemAtPath:writableDBPath error:nil];
BOOL databaseCopied = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!databaseCopied) {
// Handle the error...
}
}else {
// Open the database. The database was prepared outside the application.
if (sqlite3_open([writableDBPath UTF8String], &_database) != SQLITE_OK) {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(_database);
_database = nil;
// Additional error handling, as appropriate...
}
}
}
return _database;
}
// Sample usage.
-(void) someDatabaseFunction {
sqlite3 *database = reference2Database();
// Do something with "database"...
}
// Close the database. This should be called when the application terminates.
void closeDatabase() {
if (_database == nil) return;
// Close the database.
if (sqlite3_close(_database) != SQLITE_OK) {
// Handle the error...
}
_database = nil;
}
NOTE: At the top of the file, you should have: static sqlite3 *_database = nil;
I use Matteo Bertozzi's SQLite Wrapper to create my sqlite database with the following code:
-(void)checkDatabase
{
if([[NSFileManager defaultManager] fileExistsAtPath:DBPATH] == NO)
{
sqlite = [[Sqlite alloc] init];
if (![sqlite open:DBPATH]) return;
[sqlite executeNonQuery:#"DROP TABLE yourtable"];
[sqlite executeNonQuery:#"CREATE TABLE yourtable (record1 TEXT NOT NULL,
record2 TEXT NOT NULL,
record3 TEXT NOT NULL,
record4 TEXT NOT NULL);"];
NSArray *results = [sqlite executeQuery:#"SELECT * FROM yourtable;"];
for (NSDictionary *dictionary in results) {
for (NSString *key in [dictionary keyEnumerator])
NSLog(#" - %# %#", key, [dictionary objectForKey:key]);
}
[results release];
[sqlite release];
}
}