SQLite Problem - Database path - iphone

I'm trying to select data from the database and I have the following code in place:
Code:
// Setup the database object
sqlite3 *database;
// Init the animals Array
list = [[NSMutableArray alloc] init];
NSLog(#"documents path: ", documentsDir);
NSLog(#"database path: ", databasePath);
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select route_name from Route";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
// Read the data from the result row
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
// Add the animal object to the animals Array
//[list addObject:animal];
[list addObject:aName];
//[animal release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
I'm getting EXC_BAD_ACCESS error at the first IF statement. Anyone any thoughts.
Also in the NSLOG documentsDir and databasePath are blank.
I have the following code in ViewDidLoad:
-(void)viewDidLoad
{
// Setup some globals
databaseName = #"xxxxxxCoreData.sqlite";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
// NSString *documentsDir = [documentPaths objectAtIndex:0];
documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];

It looks like databasePath is not retained, so between the time that the view loads and your database code is run, it's already been released. If you want to keep those variables around, you need to change the last two lines to this:
documentsDir = [[documentPaths objectAtIndex:0] retain];
databasePath = [[documentsDir stringByAppendingPathComponent:databaseName] retain];
And since you're doing this in viewDidLoad you should release them in viewDidUnload (set to nil in this method as well) and dealloc.

Related

how can i update sqlite database

I want to update records from several textfiels in detail viewcontroller, but when I cliCk on update button, its goes to failed to update database. pls suggest me.
-(IBAction)updateQuery:(id)sender
{
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &Information) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat: #"update CONTACTS set address=\"%#\",phone=\"%#\",imageUrl=\"%#\" WHERE name=\"%#\"",daddress.text,dphone.text,durl.text,dname.text];
const char *update_stmt = [updateSQL UTF8String];
sqlite3_prepare_v2(Information, update_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
dstatuslabel.text=#"updated successfully";
}
else
{
dstatuslabel.text = #"Failed to update contact";
}
sqlite3_finalize(statement);
sqlite3_close(Information);
}
}
NSString *updateSQL = [NSString stringWithFormat: #"update CONTACTS set address='%#',phone='%#',imageUrl='%#' WHERE name='%#'",daddress.text,dphone.text,durl.text,dname.text];
In my method i use following way its working :
-(BOOL)updateProfileFromCreatorId:(int)creatorProfileId{
char *st,*errorMsg;
NSLog(#"profile.creatorProfileId:%d",creatorProfileId);
st = sqlite3_mprintf("UPDATE Profile SET `CreatorID`=%d WHERE `CreatorID`= 1"
,creatorProfileId //username
);
NSLog(#"updateQUERY: %#",[NSString stringWithUTF8String:st]);
int ret = sqlite3_exec(rlraDb, st, NULL, NULL, &errorMsg);
if (ret != SQLITE_OK) {
sqlite3_free(errorMsg);
sqlite3_free(st);
return NO;
}
sqlite3_free(st);
return YES;
}
Add the Sqlite DB like any other file in your application bundle
Copy it to documents directory via code and use it (Method :checkAndCreateDatabase ) .The purpose of this is that updating content in sqlite is possible in Documents directory only
-(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:_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:_databasePath error:nil];
}
- (id)init {
if ((self = [super init]))
{
_databaseName = DB_NAME;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
_databasePath = [documentsDir stringByAppendingPathComponent:_databaseName];
if (sqlite3_open([[self dbPath] UTF8String], &_database) != SQLITE_OK)
{
[[[UIAlertView alloc]initWithTitle:#"Missing"
message:#"Database file not found"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil]show];
}
}
return self;
}
Try this...It should work...
1) Please make sure you are copying the db from your bundle to documents directory before updating the db...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"YOUR DBNAME.sqlite"];
// 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:filePath];
// 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:_databasePath error:nil];
}
2)Step 2: Update
sqlite3 *database;
sqlite3_stmt *updateStmt=nil;
const char *dbpath = [filePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat: #"update CONTACTS set address=\"%#\",phone=\"%#\",imageUrl=\"%#\" WHERE name=\"%#\"",daddress.text,dphone.text,durl.text,dname.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &updateStmt, NULL);
if (sqlite3_step(updateStmt) == SQLITE_DONE)
{
NSLog(#"updated");
}
}

Potential Leak of an object

I am facing Potential leak of an object allocated. So how can I release my custom class object in loop . I am enclosing my code below herewith.
- (ProfileClass *) getUserProfile
{
NSString *query = [NSString stringWithFormat:#"SELECT * FROM Profile"];
NSLog(#"query %#",query);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"MOFAdb.sqlite"];
ProfileClass *profile = nil;
// Open the database. The database was prepared outside the application.
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
sqlite3_stmt *Statement1;
//int i=0;
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &Statement1, NULL) == SQLITE_OK) {
//int returnValue = sqlite3_prepare_v2(database, sql, -1, &Statement1, NULL);
if (sqlite3_step(Statement1) == SQLITE_ROW) {
// The second parameter indicates the column index into the result set.
NSString *userName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 0)];
NSString *userEmail = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 1)];
NSString *phoneNum = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 2)];
//int phone = sqlite3_column_int(Statement1, 2);
//NSLog(#"%d",phone);
//RecipeClass *rc = [[RecipeClass alloc] getRecipe:recipeName withRecipeIng:recipeIng withRecipeInst:recipeInstru withRecipeTips:recipeTips withRecipeDesc:recipeDesc];
if (profile)
[profile release];
profile = [[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum];
//NSLog(#"%#",fact);
//NSLog(#"%d",i);
//i++;
}
}
//Release the select statement memory.
sqlite3_finalize(Statement1);
//}
}
else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
return profile;
}
If I autorelease my profile = [[[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum] autorelease]; so my application crashes later. So I m release on if check but build and Analyze shows it as a warning.
You can also autorelease like that:
return [profile autorelease];
and retain the object of ProfileClass where you used it,
Ex- ProfileClass *objProfile=[[database getUserProfile] retain];
and release objProfile when you used it.
Your method: - (ProfileClass *) getUserProfile is not an instance method or a copy you should return an object that is autoreleased. But you should do it on the last line, since you have a if/else structure and if you only autorelease it on line profile = [[[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum] autorelease]; it will not get autoreleased if it fails the if statement and goes to else. So just do this:
return [profile autorelease];
Why don't you do:
return [profile autorelease];
And there is no need for the
if (profile)
check. Just release unconditionally. If profile is nil, it won't have any negative effect.
FWIW: I don't quite understand what your getProfile:etc... method does. I assume it is an initializer and nothing more (like the many initXYZ: methods in Cocoa). If so, you should probably call it initWithUserName:email:phone: to go with the convention. Could you post the method?
using an array you can solve this issue before calling this method
NSMutableArray *ProfileArray=[[NSMutableArray alloc] initWithArray:[ClassObj getUserProfile]];
ProfileClass *profileObj=[[ProfileArray objectAtIndex:0] retain];
[ProfileArray release];
// now you can use profile object anywhere... I hope memory issue is also solved
- (NSMutableArray *) getUserProfile
{
NSMutableArray *array=[[NSMutableArray alloc] init];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM Profile"];
NSLog(#"query %#",query);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"MOFAdb.sqlite"];
ProfileClass *profile = nil;
// Open the database. The database was prepared outside the application.
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
sqlite3_stmt *Statement1;
//int i=0;
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &Statement1, NULL) == SQLITE_OK) {
//int returnValue = sqlite3_prepare_v2(database, sql, -1, &Statement1, NULL);
if (sqlite3_step(Statement1) == SQLITE_ROW) {
// The second parameter indicates the column index into the result set.
NSString *userName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 0)];
NSString *userEmail = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 1)];
NSString *phoneNum = [NSString stringWithUTF8String:(char *)sqlite3_column_text(Statement1, 2)];
//int phone = sqlite3_column_int(Statement1, 2);
//NSLog(#"%d",phone);
//RecipeClass *rc = [[RecipeClass alloc] getRecipe:recipeName withRecipeIng:recipeIng withRecipeInst:recipeInstru withRecipeTips:recipeTips withRecipeDesc:recipeDesc];
if (profile)
[profile release];
profile = [[ProfileClass alloc] getProfileInfo:userName withEmail:userEmail withPhone:phoneNum];
[array addObject:profile];
[profile release];
}
}
//Release the select statement memory.
sqlite3_finalize(Statement1);
//}
}
else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
return [array autorelease];
}
I hope it will be helpful to you
cheers

unable to insert in sqlite database for iphone when app is terminated and started again

-(void)checkAndCreateDatabase{
NSLog(#"hello");
databaseName = #"EMAP234.sql";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"database path %#",databasePath);
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: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:databasePath error:nil];
[fileManager release];
}
-(void)insertIntoDatabase:(NSString *)insertCommand{
// Setup the database object
sqlite3 *database;
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = [insertCommand UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
NSLog(#"inserted");
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
the app works fine for the first time but when i restart it , it can read the earlier values but cannot insert new ones ... pls help
here is how I am calling this....
DatabaseOperations *obj=[[DatabaseOperations alloc]init];
[obj checkAndCreateDatabase];
NSLog(#"patient ID %d",[obj readMaxPatientIDFromDatabase]);
patientID= [NSString stringWithFormat:#"HCI%d", ([obj readMaxPatientIDFromDatabase]+1)];
NSLog(#"patient ID %#",patientID);
[self generatePatientInsertCommand];
[obj insertIntoDatabase:patientInsertCommand];
[self generateCarrierInsertCommand];
[obj insertIntoDatabase:carrierInsertCommand];
[self generateSyncTableInsertCommand];
[obj insertIntoDatabase:syncTableInsertCommand];
NSString *msg=#"your PatientID is";
[obj release];
msg=[msg stringByAppendingString:patientID];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"REGISTERED" message:msg delegate:self cancelButtonTitle:#"ok" otherButtonTitles: nil];
[alert show];
[alert release];
Hello Ankit I used your code and called
[self checkAndCreateDatabase];
[self insertIntoDatabase:[NSString stringWithFormat:#"INSERT INTO User (uId,userName,userBirthday) VALUES (\"%d\", \"%#\", \"%#\" )",3,#"Admin",#"2010-12-01"]];
The only thing I changed is using a different database file which I choose in checkAndCreateDatabase function by
-(void)checkAndCreateDatabase{
NSLog(#"hello");
databaseName = #"MasterDB.sqlite";
....
}
The code worked fine for every insert with a new uId. Please check your read Function and If Possible then paste the code for read function along with the above code and the way you call these two viz read and insert functions.

Update Database Sqlite

I can't update my database: I connect to it and then I use this function but it must execute but no update:
- (BOOL) updatePoint:(NSString *) word {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"master.sqlite"];
sqlite3_stmt *statement;
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
int newPoint = point + 1;
NSString *sql = [NSString stringWithFormat:#"UPDATE %# SET Point='%d' WHERE Parola=?",
dictionaries1[[[word substringWithRange:NSMakeRange(0,1)] intValue]-1],newPoint];
if(sqlite3_prepare_v2(database, [sql UTF8String], -1, &statement, NULL)==SQLITE_OK)
sqlite3_bind_text(statement,1,[word UTF8String] ,-1, SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
//sqlite3_reset(statement);
sqlite3_close(database);
return YES;
} else
return NO;
}
What's wrong?
you can look at this, the update code above seems fine but the only problem that might come may be due to database being overwritten or it might not be present at the specified location.
Problem with inserting data into a table
You can replace the insert code with your update statements

how can i retrieve the text data from sqlite datadase in objective-c?

i am using this
-(void) Data
{
databaseName = #"List.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath =[documentsDir stringByAppendingPathComponent:databaseName];
[self checkAndCreateDatabase];
sqlite3 *database;
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
if(detailStmt == nil)
{
const char *sql = "Select item from list";
if(sqlite3_prepare_v2(database, sql, -1, &detailStmt, NULL) == SQLITE_OK)
{
NSLog(#"Hiiiiiii");
while(sqlite3_step(detailStmt) == SQLITE_ROW)
{
NSLog(#"Helllloooooo");
NSString *item= [NSString stringWithUTF8String:(char *)sqlite3_column_text(detailStmt, 0)];
//item1=item;
NSLog(#"%#",item);
}
sqlite3_reset(detailStmt);
}
sqlite3_finalize(detailStmt);
sqlite3_clear_bindings(detailStmt);
}
}
detailStmt = nil;
sqlite3_close(database);
}
You should have a look at this tutorial. It always helped me when I used sqlite in ios. For me it looks like you should structure your code a little bit, you shouldn't load any path's inside a query method.
Maybe the problem occurs because of
sqlite3_reset(detailStmt);
sqlite3_clear_bindings(detailStmt);