getting a problem while retrieving data from database - iphone

i am trying to validate username and password entered by the user with the sqlite database.if the username and password are present in the database the user need not to log in.But if his username and password does not match he need to login. i have added the following code in my appdelegate first:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
databaseName =#"journeymapper.db3";
NSArray *documentsPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentsPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
[self checkAndCreateDatabase];
}
-(void)checkAndCreateDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if (success)
return;
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
-(void)readLoginFromDatabase{
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK){
const char *sqlStatement = "Select Username,Password from UserInformation";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK){
NSString *aUserName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aPassword = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
Initially i have checked if database is present .If not i have created one.Then i have read from database.
Then in my login controller's login action i have added the following code:
-(IBAction)login:(id)sender{
journey = (JourneyAppDelegate *)[[UIApplication sharedApplication]delegate];
if ([mUserName.text isEqualToString:#"shardulprabhu"] && [mPassword.text isEqualToString:#"password"]) {
[journey readLoginFromDatabase];
NSLog(#"journey read");
}
else{
[self signUp];
}
}
this code checks if myusername and password is equaltostring specified the one in database and if it is equal it should read from database.else it should signup.But when i run my app my app loads and when i enter username and password and click login button the app crashes.
i am having a warning on login action that JourneyAppDelegate may not respond to-readLoginFromDatabase
What may be the problem
thanks

At first, if it crashes, you need to post crash log here too.
Second thing - do not use sqllite for username / password storage. Do use keychain.
Third thing - if you do want to use sqllite to store something, why not via CoreData?
About your warning - it seems that you forgot to add your readLoginFromDatabase method to header file too.

If you want to remove the warning add this code to your JourneyAppDelegate.h
-(void)readLoginFromDatabase;

Related

Can't copy sqlite database from app's mainbundle to users documents

I can't copy my sqlite database to the users documents folder, the database has always 0 byte but should have 322 kb.
I have also checked that the database is included in the target membership.
The Problem is that i can't copy the database correctly.
Here is my code:
-(void)initDatabase
{
// Create a string containing the full path to the sqlite.db inside the documents folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"wine.sqlite"];
// Check to see if the database file already exists
bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
// Open the database and store the handle as a data member
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
{
// Create the database if it doesn't yet exists in the file system
if (!databaseAlreadyExists)
{
// Get the path to the database in the application package
NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:#"wine" ofType:#"sqlite"];
//NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"wine.sqlite"];
// Copy the database from the package to the users filesystem
[[NSFileManager defaultManager] copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
NSLog(#"Database created");
}
}
}
There is a logic error, you check for databaseAlreadyExists inside the
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK) { ... }
block.
What you probably meant is
// Check to see if the database file already exists
bool databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
// Create the database if it doesn't yet exists in the file system
if (!databaseAlreadyExists)
{
// Get the path to the database in the application package
NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:#"wine" ofType:#"sqlite"];
// Copy the database from the package to the users filesystem
[[NSFileManager defaultManager] copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
NSLog(#"Database created");
}
// Open the database and store the handle as a data member
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
{
...
}
you open a DB (making a new 0 byte one if it isnt there using sqlite3_open and THEN copy the shipped one right where the new DB should be..
you check if DB_docs is there
but then you open DB_docs with sqlite no matter what
and THEN you try copy it from the bundle into the OPENED File path
-(void)initDatabase
{
// Create a string containing the full path to the sqlite.db inside the documents folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"wine.sqlite"];
// Check to see if the database file already exists
BOOL databaseAlreadyExists = [[NSFileManager defaultManager] fileExistsAtPath:databasePath];
// Create the database if it doesn't yet exists in the file system
if (!databaseAlreadyExists)
{
// Get the path to the database in the application package
NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:#"wine" ofType:#"sqlite"];
// Copy the database from the package to the users filesystem
[[NSFileManager defaultManager] copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
NSLog(#"Database created");
}
// Open the database and store the handle as a data member
if (sqlite3_open([databasePath UTF8String], &databaseHandle) == SQLITE_OK)
{
NSLog(#"db opened");
}
}
I just use the following method written in AppDelegate,
(It seems like the method body is huge, but it's actually not. Just remove all the comments and see for the clarity after you read the comments):
#pragma mark - SQLite DB
// SQLite Copy the Database.
-( void ) checkAndCreateDatabase
{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
NSString *databasePath = [LIBRARY_DIR_PATH stringByAppendingPathComponent:DATABASE_NAME];
NSLog(#"%#",databasePath);
// 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;
NSLog(#"DB WASN'T THERE! SO GONNA COPY IT!");
// 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:DATABASE_NAME];
success = [fileManager fileExistsAtPath:databasePathFromApp];
if (success) {
NSLog(#"SIMULATOR FOUND DB FROM APP, GONNA COPY IT");
} else {
NSLog(#"SIMULATOR COULDN'T FIND DB\nIT SHOULD BE IN : %#\nPlease check if you have added the DB file and selected its target", databasePathFromApp);
}
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
And call that method within
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
As follows:
//Copy the SQLite3 DB File
[self checkAndCreateDatabase];
Hint: Keep in mind that you need to add the SQLite DB file to your correct target membership when you drag and drop the db file to the XCode Project.

Sqlite Database Load Fails - Issue with sqlite prepare statement - iPhone - xCode 4.3.1

I am having issues with the following code which loads an SQLite database.
- (NSArray *)getDatabase {
NSLog(#"Get Database Called");
NSMutableArray *retval = [[[NSMutableArray alloc] init] autorelease];
NSString *query = #"SELECT Description, UniqueID, HexCoords, NoHexCoords, NoAnnots, AnnotText, DescriptionFormatting, HexCoordsPortrait FROM MainTable";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *nameChars = (char *) sqlite3_column_text(statement, 0);
char *desChars = (char *) sqlite3_column_text(statement, 1);
int uniqueID = sqlite3_column_int(statement, 2);
From using breakpoints I can see that the problem is with the if statement and that the code never gets past this if statement. Can anyone spot what might be wrong ? The code was working a few months ago and I have recently upgraded to xCode 4.3 so might this be the problem ?
Thank in advance.
Yeah i agree With Joachim. there is a problem sometimes the DB doesnot really connect. what i do is a couple of things. First i add following Code in my Application App Delegate.
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"MyDB.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Call This Function in ApplicationDidFinishLaunching.
Now remove the data base that is in ur bundle currently. (MAKE SURE U HAD BACKUP OF IT). And (if Possible Delete All the project From Iphone Simulator Folder) Coz sometimes the previous Database is attached.
Clean Your project, Add the Data Base in ur bundle. Compile it..
Let Me know if it worked
the Get Path Function
- (NSString *) getDBPath {
//Search for standard documents using NSSearchPathForDirectoriesInDomains
//First Param = Searching the documents directory
//Second Param = Searching the Users directory and not the System
//Expand any tildes and identify home directories.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"MYDB.sqlite"];
}

Cannot add to sqlite database even though there are no errors

I'm making a iphone app for a final project at school and I'm having some trouble. I have it connected to a sqlite database, but even though I'm not getting any errors in xcode and when I've stepped through the code with the debugger it indicates that it is working - but its not actually updating. I saw a few other threads with similar problems on the net but I was unable to solve the problem by looking at them. Here is the relevant code but if you think you need to see more I'd be happy to post it all:
first the createAndCheckCode method is called followed by the addRecipe method. I just through in a generic string until I can figure out how to get it working. i can view the database contents from a different program.
(void) addToDatabase
{
databaseName = #"recipeappdatabase.sqlite";
// 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];
// 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)
{
// 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];
}
// 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 = "insert into Recipes (title) VALUES ('toor')";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement, 1, sqlStatement, -1, SQLITE_TRANSIENT);
}
//if (sqlite3_step(compiledStatement) != SQLITE_DONE)
//NSAssert1(0, #"Error updating table: %s", errorMsg);
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
Edit/Delete Message

SQLite3 on iPhone - insert returns error code 8 attempt to write a readonly database

So, I have been beating my head against the wall on this for about a week now.
I'm writing an iPhone app that has an sqlite database in it. I'm able to open the database and read from it (I put some test data in there through via the command line / terminal), select specific data, etc. But, what I cannot do is insert into the database from the phone. When I execute sqlite3_exec(...) it returns error code 8 "attempt to write a readonly database."
I had read other questions on here saying that I was using the Main Bundle's database and not the users database, and that the simulator will often times just "let you do it" while on a live device you'll get an error. Well, that's not what's happening in my case - I'm getting this error while running on the simulator. And from what I can tell my code to check the database is exactly as a lot of others recommend it to be.
Here is the code I use to verify the database exists, and if it doesn't I copy it:
// initialize db (if not already)
+(void) checkDatabase {
// setup some variables
Boolean success;
dbName = #"daarma.sqlite";
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDirectory, YES);
// I have tried this with both NSUserDirectory and NSUserDomainMask, desn't seem to make a difference
NSString *documentsDir = [documentPath objectAtIndex:0];
dbPath = [documentsDir stringByAppendingPathComponent:dbName];
// dbPath = [[NSBundle mainBundle] pathForResource:#"daarma" ofType:#"sqlite"];
// check to see if the database already exists
NSFileManager *fm = [NSFileManager defaultManager];
success = [fm fileExistsAtPath:dbPath];
if(success) {
NSLog(#"Database exists, returning.");
return;
}
// if not, we create it
NSLog(#"Creating database in user profile...");
NSString *dbPathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName];
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:nil];
[fm release];
[documentPath release];
[documentsDir release];
}
When I go to insert data using this:
sqlite3 *db;
int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL);
if(open == 0) {
NSLog(#"open, inserting");
NSString *sql = [NSString stringWithFormat:#"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"];
int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL);
NSLog(#"exec = %d",exec);
}
sqlite3_close(db);
exec returns with the above mentioned error code 8: ""attempt to write a readonly database."
I've also tried the usual restarts, cleaning the project, resetting the simulator data. I even went in to my Simulator directory and deleted all the application data out manually. When I tried to go back in, it recognized the database wasn't there and copied it over, but I still get that error.
EDIT:
I've just noticed that if I do this in the checkDatabase method:
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(#"error = %#",error);
it causes the simulator to crash the first go around (after doing a content reset), but each time after that it resumes the above error with no crashes. So maybe I am doing something wrong with my checkDatabase method. ?? :( It never tells me the output of the error message.
try to change the open function to this
sqlite3_open_v2([dbPath UTF8String], &db, SQLITE_OPEN_READWRITE , NULL);
or basically use the trivial open function
Sqlite3_open([dbPath UTF8String],&db);// this should do the job
hope that helps :)
I tried your code, and it failed with open = 21 (SQLITE_MISUSE) in the following line:
int open = sqlite3_open_v2([dbPath UTF8String], &db, -1, NULL);
Because you pass -1 to flags parameter. It should be SQLITE_OPEN_READWRITE.
I have some more comments.
[fm release];
[documentPath release];
[documentsDir release];
These release's are not necessary, because you don't alloc/init, retain, or copy them.
NSString *sql = [NSString stringWithFormat:#"insert into affiliates values('1','2','3','4','5','6','7','8','9','10','11','12')"];
int exec = sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL);
You should use sqlite3_prepare_v2 and bind parameters instead of stringWithFormat: for SQL.
if(open == 0) { ... }
Whenever possible, you should use symbolic constant (SQLITE_OK) instead of magic number (0).
NSError *error;
[fm copyItemAtPath:dbPathFromApp toPath:dbPath error:&error];
NSLog(#"error = %#",error);
You should initialize error = nil before calling copyItemAtPath: because error is not changed when the copy operation succeeds.

Xcode Sqlite persistence problem

I have a persistence problem in my application. I'm using sqlite database. when some insert queries executed results temporary added to the database. After restarting application the new values vanish! I think new values stored on RAM do not save on hard-disk.
-(IBAction)add:(id)sender
{
NSString *myDB;
NSString *query;
myDB=[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Ssozluk.sql"];
database =[[Sqlite alloc] init];
[database open:myDB];
query=[NSString stringWithFormat:#"INSERT INTO words(col_1,col_2) VALUES('asd','asd2');"];
[database executeNonQuery:query];
[database commit];
[database close];
}
-(IBAction)show:(id)sender
{
NSString *myDB;
NSString *query;
NSArray *asdasd;
NSString *asd;
myDB=[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Ssozluk.sql"];
database =[[Sqlite alloc] init];
[database open:myDB];
query=[NSString stringWithFormat:#"Select col_2,col_1 FROM words"];
asdasd=[database executeQuery:query];
for(NSDictionary *row in kelimeler)
{
asd=[row valueForKey:#"col_2"];
olabel1.text=asd;
}
[database commit];
[database close];
}
You need programmatically copy your database to Documents dir of application, and work with writable copy. Resources in bundle is readonly.
I use the following code to copy my database to the documents folder and than get the writable part:
- (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"];
//NSLog(writableDBPath);
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]);
}
}
- (void)initializeDatabase {
// The database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"db.sqlite"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
//Add initial sql statements here
} 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...
}
}
- (sqlite3*) getDB{
return database;
}
Insert the calls to your applicationDidFinishLaunching method
As far as I remember, when you use path to db the way you do, it should be added to project.
Sometimes, and especially with databases, just cleaning doesn't work!!!
Go to the dir: /Users/qjsi/Library/Application Support/iPhone Simulator/4.3/Applications
There, you'll find all the projects you've run. Find the folder containing the project your working on, and delete it. Then clean your project through Xcode, then run. The folder in that dir will be recreated, and so will the database.
NOTE: The database will be removed as well! If you have it saved in your bundle and copy it to an editable directory, please note that the database will be the same as the one in your bundle (so, without altered records made in the iPhone Simulator).