Database Application not work properly - iphone

In my application i open the database many time in one loop and then again i open the database it will not execute if (sqlite3_open([[self getDBPath] UTF8String], &database) == SQLITE_OK) this statement so my application doesnt work....
-(NSString *)getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"BasicGreetings.sqlite"];
}
-(void) fillimage:(NSInteger)imgno
{
testAppDelegate *appDelg = (testAppDelegate *)[[UIApplication sharedApplication]delegate];
sqlite3 *database= nil;
if (sqlite3_open([[self getDBPath] UTF8String], &database) == SQLITE_OK)
{
const char *sql = "select setflag from Tblsetflag where imgNo = ?";
sqlite3_stmt *selectStmt = nil;
if (sqlite3_prepare_v2(database, sql, -1, &selectStmt, NULL) == SQLITE_OK)
{
sqlite3_bind_int(selectStmt, 1,imgno);
while (sqlite3_step(selectStmt) == SQLITE_ROW)
{
appDelg.a = sqlite3_column_int(selectStmt, 0);
NSLog(#"%d",appDelg.a);
}
}
}
sqlite3_close(database);
}

Can you post the code to getDBPath, I suspect it can't find the file... check that value you return from that method (run in the simulator) and browse the simulator documents directory in Finder and verify the file exists.

Don't open and close your database on every pass through your -fillimage: method. You really should open it once at the start of your application (or when your application has become active from the background) and close it when your application exits or goes to the background.
You also never finalize your prepared statement, which may be leading to the sqlite3_close() failing. Again, you may want to create a prepared statement once, then reset it every time you run that method and finalize it before the SQLite database is closed.

Related

Sqlite3 database Table cannot open in XCode 4.2

I am creating and iphone app using XCode 4.2. And I am using sqlite3 database for the app. I created and ran the app successfully on iPhone 3GS and with XCode 3.2.5, when I am having a problem with the XCode 4.2. The db file cannot open, here is the sample code code for opening the Table. And when I opened the same db file using SQlite manager, I could see the table. I don't understand what the error is.
static sqlite3 *database = nil;
static sqlite3_stmt *selectStmt = nil;
+ (void) getInitialDataToDisplay:(NSString *)dbPath {
NSLog(#"Path: %#",dbPath);
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *sqlStr = #"select * from Space";
const char *sql = [sqlStr UTF8String];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
SpaceClass *spaceObj = [[SpaceClass alloc] initWithPrimaryKey:primaryKey];
spaceObj.spacePK = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
spaceObj.spName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)];
spaceObj.spDescrptn = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)];
[appDelegate.spaceArray addObject:spaceObj];
[spaceObj release];
}
}else
NSLog(#"not ok");
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
Please help, thanks
You put the close method in the wrong place I think. I have been using SQLite3 in iOS for 2 weeks and I had that problem. I solved it by putting the SQLite3_close method in the last line of the if(open == ok).
Your code should look like:
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
while(sqlite3_step(selectstmt) == SQLITE_ROW)
{
}
}
else
{
NSLog(#"not ok");
}
//here you should close database, before exit from if open block
sqlite3_close(database);
}
else
{
//here is not needed because of database open failure
//sqlite3_close(database);
NSLog(#"not ok");
}
This should solve your problem because now you're going to close the database each time you open it. But in your code you open it time after time without close it!

How to insert only one username and password in SQLite database?

I have an application where I have two textfields and a button. In the first textfield I am entering the username of the user and in the second textfield I am entering the password of the user. When the user enters the username and password and click on create user button a backend api is called which will register the username and password of the user and at the time I want to enter the username and password of the user in local SQLite databse in encrypted format.
When a user is registered the username of that particular user should get displayed in the first textfield and it should not be editable and password field should be editable. Only one user is allowed to be registered for the entire application.
Don't use a sqlite dbs to store user credentials. With reverse engineering it is fairly simple to get to the data. This because you probably have some value in your program you use to encrypt/decrypt the password. For security purposes, please use the keychain. There are several projects on github which makes it very easy to use the keychain. There is no more secure way for saving credentials then the keychain, so please use that to store your credentials!!!
If I understood your requirement correctly, You can follow the below guideline.
Before inserting the data to the table, You can check if any record is added to the table.
If the count is 0, you can proceed to insert the record, else you can prompt the error.
I think this will be the simplest way to do this.
First step is to check the database exist in resource folder and create database:-
1)
-(void)checkAndCreateDatabase{
databaseName = #"databasename.sql";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
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];
}
2) call the function to retrieve the data:-
-(NSMutableArray *) readFromDatabase:(NSString *)query{
// Setup the database object
sqlite3 *database;
// Init the animals Array
returnArray = [[NSMutableArray alloc] init];
NSString *readCommand= query;
// 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 = [readCommand 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
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
[returnArray addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)]];
[returnArray addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return returnArray;
}
3) check for the retrun array is empty or nil then call the insert function defined at step
4) Insert into the database
-(void)insertIntoDatabase:(NSString *)username:(NSString *)password{
// 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
NSString *insertCommand=#"Insert into tableName values(username,password)";
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
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {}
sqlite3_finalize(compiledStatement);
}
// Release the compiled statement from memory
}
sqlite3_close(database);
}
You can use NSUserDefaults saving locally it. following code is for saving data.
perf = [NSUserDefaults standardUserDefaults];
[perf setObject:#"1" forKey:#"remember"];
[perf setObject:emailAddresTextField.text forKey:#"email"];
[perf setObject:passwordTextField.text forKey:#"password"];
[perf synchronize];
And for retrieving data use following code
perf=[NSUserDefaults standardUserDefaults];
NSString *remString = [perf stringForKey:#"remember"];
if ([remString isEqualToString:#"1"]) {
emailAddresTextField.text=[perf stringForKey:#"email"];
passwordTextField.text = [perf stringForKey:#"password"];
[rememberBtn setTag:1];
[rememberBtn setImage:[UIImage imageNamed:#"on_radioButton.png"] forState:0];
}

Sqlite3 in iPhone gives Database Locked Exception

I am newbiee in iphone and sqlite and doing some tutorials.
I have created one method which stores some temperory informartion into my database.
Now when i am on firstView controller of my Application i called that method twice. It stores the data twice into the particular table. Now i went to SecondViewController and in there i have a new sqlite3 object in the header file and i again copy paste that method into the SecondViewController. Now when i call that method on Second ViewController it gives me following error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while inserting data. 'database is locked''
my Code is:
-(void)storeTemp
{
SchoolFocusIPadAppDelegate *delegate = (SchoolFocusIPadAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"sfocusDB.sqlite"];
if(sqlite3_open([path UTF8String], &databases) == SQLITE_OK){
//const char *sql = "select * from animal";
const char *sql = "insert into groups(id, groupid, name, desc , createdon,createdby) Values(?,?,?,?,?,?)";
sqlite3_stmt *add;
if(sqlite3_prepare_v2(databases, sql, -1, &add, NULL) == SQLITE_OK){
NSLog(#"Connection Successful");
NSLog(#"***Storing START on Database ***");
sqlite3_bind_text(add, 2, [[NSString stringWithFormat:#"Temp Group Dont Open"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 3, [[NSString stringWithFormat:#"kjhasd"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 4, [[NSString stringWithFormat:#"asdas"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 5, [[NSString stringWithFormat:#"asdsa"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(add, 6, [[NSString stringWithFormat:#""] UTF8String], -1, SQLITE_TRANSIENT);
NSLog(#"***Storing END on Database ***");
if(SQLITE_DONE != sqlite3_step(add))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(databases));
else {
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
}
sqlite3_finalize(add);
}
sqlite3_close(databases);
}
Please Help me friends. M really stucked.
Thanks alot
here lots of chances to kill
1.if your id is not null in DB it will kill with constraint failed error
if you don't want to insert any value to id remove from list
like
const char *sql = "insert into groups( groupid, name, desc , createdon,createdby) Values(?,?,?,?,?)";
and change that number 1-5 instead of 2-6
I've had some problems with sqlite3_close following an if/else (not sure why) but when I also put the finalize and close calls inside the if, it'd work out. I started following every open and close with an NSLog of the same (numbered so I knew which one was which) and you can then see which step left the DB open (and therefore locked)
Have you copied the database to the writable doc-dir?
Your prepare-call needs a little change:
From if(sqlite3_prepare_v2(databases, sql, -1, &add, NULL) == SQLITE_OK){
To if(sqlite3_prepare_v2(databases, [sql UTF8String], -1, &add, NULL) == SQLITE_OK){
(but that's nit the reason for the database locked).

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?

SQLite Out of Memory when preparing insert statement

I have a problem with my app it opens this database and selects rows from it ok,
Then when I want to add new rows using the following code and I always get the following problem at the execution of the prepare_V2.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while creating add statement. 'out of memory''
code is .....
static sqlite3 *database = nil;
static sqlite3_stmt *addStmt = nil;
- (BOOL)addUserprofile {
addStmt = nil; // set to force open for testing
database = nil; // set to force creation of addstmt for testing
if (database == nil) { // first time then open database
NSString *databaseName = #"UserProfile.db";
// Use editable database paths
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"path = %#",databasePath);
NSLog(#"opening Database");
sqlite3 *database;
// Open the database from the users filessytem
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"Database Open");
}
else {
NSLog(#"Database did not open");
}
}
if(addStmt == nil) {
NSLog(#"Creating add stmt");
const char *sql = "INSERT INTO Profile (ProfileName) VALUES(?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK) {
NSAssert1(0, #"** Error while creating add statement. '%s'", sqlite3_errmsg(database));
success = NO;
return success;
}
}
sqlite3_bind_text(addStmt, 1, [ProfileName UTF8String], -1, SQLITE_TRANSIENT);
Sometime, your database is being SQLITE_BUSY or SQLITE_LOCKED.
You can refer this framework to know how to do:
https://github.com/ccgus/fmdb
Good luck!:)