I am working on iPhone app and calling following code on my button click, its updating my Database table only on first click. When I click it second time it gives me success message but database table is not getting updated.
Code is :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Games.sqlite"];
NSMutableArray *arrayRandomLevel = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
for (int i = 0; i< 5; i++)
{
NSUInteger randomIndex = arc4random() % 5;
[arrayRandomLevel exchangeObjectAtIndex:i withObjectAtIndex:randomIndex];
//firstObject +=1;
}
NSLog(#"arrayRandomLevel = %#",arrayRandomLevel);
for (int level = 0; level < 5; level++)
{
NSString *strLevel = [#"" stringByAppendingFormat:#"%d",level+1];
int finalLevel = [[arrayRandomLevel objectAtIndex:level] intValue];
NSLog(#"Static level = %#, Changed level = %d",strLevel,finalLevel);
sqlite3 *database;
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
NSString *cmd = [NSString stringWithFormat:#"UPDATE zquestionsdata SET zdifficultylevel = %d WHERE zanswertype = '%#' AND zquestiontype = '%#';",finalLevel,strLevel,#"Geni"];
const char * sql = [cmd UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sql, -1, &compiledStatement, NULL) == SQLITE_OK)
{
sqlite3_step(compiledStatement); // Here is the added step.
NSLog(#"update SUCCESS - executed command %#",cmd);
}
else {
NSLog(#"update FAILED - failed to execute command %#",cmd);
}
sqlite3_finalize(compiledStatement);
}
else {
NSLog(#"pdateContact FAILED - failed to open database");
}
sqlite3_close(database);
}
Please help me on this or provide any other solution to update table each time.
Thanks in advance.
The Updating process will happen at
if(sqlite3_step(statement) == SQLITE_DONE)
There the values assigned will go and store in the database the statement look like the above.
code from Prepare statement is given below
if(sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if(sqlite3_step(statement) == SQLITE_DONE)
{
//assign new values here
}
}
Related
I have database, but when i tried to remove data from the database nothing happens, what should i do to make sure it works? Because when i pressed delete the dta is still in the database
This is the code:
/file path to database
-(NSString*)filePath {
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0]stringByAppendingPathComponent:#"bp.sql"];
}
//open database
-(void)openDB {
if(sqlite3_open([[self filePath]UTF8String], &db) !=SQLITE_OK) {
sqlite3_close(db);
NSAssert(0, #"Databese failed to open");
}
else {
NSLog(#"database opemed");
}
}
- (IBAction)del:(id)sender {
NSString*sql = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
const char* query_stmt = [sql UTF8String];
sqlite3_stmt*statement;
sqlite3_prepare_v2(db, query_stmt, -1, & statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSAssert(0, #"database object delete failed");
} else {
NSLog(#"No error");
}
sqlite3_finalize(statement);
sqlite3_close(db)
You can't delete specific column values using the DELETE query. It's for removing the entire row.
The problem is with the following query:
NSString*sql = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
Change it to:
NSString*sql = [NSString stringWithFormat:#"DELETE FROM summary WHERE key=\"%#\"",customerName];
If you need to remove particular column value of a row use the UPDATE query.
Please check the sqlite documentation for the details
All the functions that you wrote like checking filepath, opendb should occur in the same function(maybe inside your del function).
This is how I will do it:
-(void)updateStatus:(NSString *)queryString {
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
strDatabasePath = [NSString stringWithString:[docsDir stringByAppendingPathComponent:#"bp.sql"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: strDatabasePath] == YES)
{
const char *dbpath = [strDatabasePath UTF8String];
if (sqlite3_open(dbpath, &sqlDatabase) == SQLITE_OK)
{
const char* beginString = "BEGIN;";
sqlite3_stmt *compiledstatement;
sqlite3_prepare_v2(sqlDatabase, beginString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
DLog(#"QUERY : %#",queryString);
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &compiledstatement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
const char* endString="END;";
sqlite3_prepare_v2(sqlDatabase, endString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
sqlite3_close(sqlDatabase);
}
else DLog(#"Failed to open table");
}
}
NSString *queryString;
queryString = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
[self updateStatus:queryString];
Hope this helps...
-(BOOL)DeleteWishList:(int)rowno
{
NSString *queryString=[NSString stringWithFormat:#"delete from wishtable where _id=%d",rowno];
[self openDB];
char *err;
if (sqlite3_exec(dBObject, [queryString UTF8String], NULL,NULL, &err)!= SQLITE_OK)
{
sqlite3_close(dBObject);
return NO;
}
else
{
return YES;
}
}
I am new to Objective - C and Sqlite database.So I don't understand what is the mistake in my code. I am doing a simple Todo List. In the first page, I want to display all the tasks and in the header, there is one add button.When we click on that button, it will move to the second storyboard.In that, we can enter the main task and subtask. I have created a new page named TodolistView1Controller and in that I have created the database and inserted the data into the db. But my problem is When we come back to the main page, it will not show the new task which we entered now. I will paste the code below :-
In TodolistView1Controller.m
-(void)viewDidLoad
{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"todo.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &todoDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS TODO (ID INTEGER PRIMARY KEY AUTOINCREMENT, MYTASK TEXT, SUBTASK TEXT)";
if (sqlite3_exec(todoDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
status.text = #"Failed to create table";
}
status.text = #"Created the database";
sqlite3_close(todoDB);
} else {
status.text = #"Failed to open/create database";
}
} - (IBAction)save:(id)sender {
[myTask resignFirstResponder];
[subTask resignFirstResponder];
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &todoDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO TODO (MYTASK, SUBTASK) VALUES (\"%#\", \"%#\")", myTask.text, subTask.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(todoDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
status.text = #"Contact added";
myTask.text = #"";
subTask.text = #"";
} else {
status.text = #"Failed to add contact";
}
NSLog(#"7");
sqlite3_finalize(statement);
sqlite3_close(todoDB);
}
And in Main ViewController.m
-(void)viewDidLoad
{
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
NSLog(#"Display1");
if (sqlite3_open(dbpath, &todoDB) == SQLITE_OK)
{
NSLog(#"Display2");
NSString *querySQL = [NSString stringWithFormat:
#"SELECT MYTASK, SUBTASK FROM TODO "];
NSLog(#"Display3");
const char *query_stmt = [querySQL UTF8String];
NSLog(#"Display4");
if (sqlite3_prepare_v2(todoDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSLog(#"Display5");
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"Display6");
NSLog(#"Data is displayed");
} else {
NSLog(#"Display7");
NSLog(#"Data cannot be displayed");
}
sqlite3_finalize(statement);
}
sqlite3_close(todoDB);
}
So whenever i run this, I am getting the output Display1, Display2, Display3 and Display4 in the console . Can anyone please tell me why i am not getting the output display5 and display6.
Thanks in advance.
When you first displayed your list of to-do task, they are rendered to screen.
Subsequent inserts into the database are stored into the database but you have not yet told the app to re-fetch the list of to-do task from the database when you returned to your main page.
In the "viewWillAppear" or "viewDidAppear" of your to-do list page, write a method to fetch all your to do list. Make sure when you fetch the records, you store them in your array which you will use to render them into the table view.
Then after you have fetched your list of to-do from the SQL database, execute this method
[myTableView reloadData];
That will essentially reload your table and display any new records which are contained in your array of to-do.
The ATTACH DATABASE command is useful for transferring rows between sqlite database files and allows you to join rows from tables across databases
e.g.
$ sqlite3 BookLoansDB.sqlite
sqlite> ATTACH DATABASE '/Users/.../Documents/BooksDB.sqlite' AS books_db;
sqlite> select B.BookName, B.Pages, BL.LentTo from main.tblBookLoan BL inner join books_db.tblBook B on B.BookID = BL.BookID;
The Client|512|Jenny
The Pelican Brief|432|Mike
How can I do the same from objective-c on the iPhone. I've had no success with this kind of code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
const char *booksDBPath = [[documentDirectory stringByAppendingPathComponent:#"BooksDB.sqlite"] UTF8String];
const char *bookLoansDBPath = [[documentDirectory stringByAppendingPathComponent:#"BookLoansDB.sqlite"] UTF8String];
sqlite3 *bookLoansDB;
int result = sqlite3_open(bookLoansDBPath, &bookLoansDB);
sqlite3_stmt *attachStmt;
NSString *attachSQL = [NSString stringWithFormat: #"ATTACH DATABASE \'%s\' AS books_db", bookLoansDBPath];
result = sqlite3_prepare_v2(bookLoansDB, [attachSQL UTF8String] , -1, &attachStmt, nil);
char *errorMessage;
result = sqlite3_exec(bookLoansDB, [attachSQL UTF8String], NULL, NULL, &errorMessage);
sqlite3_stmt *selectStmt;
NSString *selectSQL = #"select * from main.tblBookLoan BL inner join books_db.tblBook B on B.BookID = BL.BookID";
result = sqlite3_prepare_v2(bookLoansDB, [selectSQL UTF8String] , -1, &selectStmt, nil);
// result == 1
result = sqlite3_step(selectStmt) ;
// result == 21
if (result == SQLITE_ROW)
{
//do something
}
Can it even be done?
I've got the example working (had my database names mixed up in the "attach database" SQL). So yes it can be done. Thanks for pointing me in the right direction Deepmist
As such examples are rather hard to find, I've pasted the working version below.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
const char *booksDBPath = [[documentDirectory stringByAppendingPathComponent:#"BooksDB.sqlite"] UTF8String];
const char *bookLoansDBPath = [[documentDirectory stringByAppendingPathComponent:#"BookLoansDB.sqlite"] UTF8String];
sqlite3 *bookLoansDB;
if (sqlite3_open(bookLoansDBPath, &bookLoansDB) == SQLITE_OK) {
NSString *attachSQL = [NSString stringWithFormat: #"ATTACH DATABASE \'%s\' AS books_db", booksDBPath];
char *errorMessage;
if (sqlite3_exec(bookLoansDB, [attachSQL UTF8String], NULL, NULL, &errorMessage) == SQLITE_OK) {
sqlite3_stmt *selectStmt;
NSString *selectSQL = #"select * from main.tblBookLoan BL inner join books_db.tblBook B on B.BookID = BL.BookID";
if (sqlite3_prepare_v2(bookLoansDB, [selectSQL UTF8String] , -1, &selectStmt, nil) == SQLITE_OK) {
int n=0;
while (sqlite3_step(selectStmt) == SQLITE_ROW) {
//do something
}
}
else {
NSLog(#"Error while creating select statement: '%s'", sqlite3_errmsg(bookLoansDB));
}
}
else {
NSLog(#"Error while attaching databases: '%s'", errorMessage);
}
}
else {
NSLog(#"Failed to open database at %# with error %s", booksDBPath, sqlite3_errmsg(bookLoansDB));
sqlite3_close(bookLoansDB);
}
You can attach databases in sqlite on the iPhone. It's hard to say what's going on with your code but it should help if it looks a little more like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
const char *booksDBPath = [[documentDirectory stringByAppendingPathComponent:#"BooksDB.sqlite"] UTF8String];
const char *bookLoansDBPath = [[documentDirectory stringByAppendingPathComponent:#"BookLoansDB.sqlite"] UTF8String];
sqlite3 *bookLoansDB;
if (sqlite3_open(bookLoansDBPath, &bookLoansDB) == SQLITE_OK) {
NSString *attachSQL = [NSString stringWithFormat: #"ATTACH DATABASE \'%s\' AS books_db", bookLoansDBPath];
char *errorMessage;
if (sqlite3_exec(bookLoansDB, [attachSQL UTF8String], NULL, NULL, &errorMessage) == SQLITE_OK && errorMessage == nil) {
sqlite3_stmt *selectStmt;
NSString *selectSQL = #"select * from main.tblBookLoan BL inner join books_db.tblBook B on B.BookID = BL.BookID";
if (sqlite3_prepare_v2(bookLoansDB, [selectSQL UTF8String] , -1, &selectStmt, nil) == SQLITE_OK) {
while (sqlite3_step(selectStmt) == SQLITE_ROW) {
//process row
}
}
else {
NSLog(#"Error while creating select statement: '%s'", sqlite3_errmsg(bookLoansDB));
}
}
else {
NSLog(#"Error while attaching databases: '%s'", errorMessage);
}
}
else {
NSLog(#"Failed to open database at %# with error %s", booksDBPath, sqlite3_errmsg(bookLoansDB));
sqlite3_close(bookLoansDB);
}
I haven't tested this code, just modified yours, so it might require fixes.
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!:)
i've been trying to figure out wh. sqy my object allocation keeps rigth up every time i call this function, Instruments reports no leaks but I get a heck of a lot of object coming from
sqlite3_exec --> sqlite3Prepare --> sqlite3Parser --> yy_reduce --> malloc & also a whole bunch from
& from
sqlite3Step --> sqlite3VdbeExec --> sqlite3BtreeInsert --> malloc
I tried solving it by following the suggestions posted here: http://www.iphonedevsdk.com/forum/iphone-sdk-development/7092-sqlite3-database-gobbling-up-memory.html but haven't been able to fix it
ANY HELP is appreciated, my code is below
+(void)getDesignationsInLibrary:(NSString *)library
{
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
NSString *dbName = #"s8.sqlite";
NSArray *documentPaths = \
NSSearchPathForDirectoriesInDomains \
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = \
[documentPaths objectAtIndex:0];
NSString *databasePath = \
[documentsDir stringByAppendingPathComponent:dbName];
[[DT sharedDT].designationsInLibrary removeAllObjects];
NSString *sqlString;
for(int i=0;i<[[DT sharedDT].typesInLibrary count];i++)
{
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
NSMutableString *lib=[NSMutableString stringWithString:library];
[lib appendString:#"-"];
[lib appendString:[[DT sharedDT].typesInLibrary objectAtIndex:i]];
if([DT sharedDT].sortedBy==#"AISC Default")
{
sqlString = [NSString stringWithFormat:#"select DESIGNATION from \"%#\";",lib];
}
else
{
sqlString = [NSString stringWithFormat:#"select DESIGNATION from \"%#\" order by cast(%# as numeric) %#;",lib, [DT sharedDT].sortedBy, [DT sharedDT].sortAscDesc];
}
const char *sql = [sqlString cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(db,sql,-1,&selectstmt, NULL)==SQLITE_OK)
{
while(sqlite3_step(selectstmt)==SQLITE_ROW)
{
[[DT sharedDT].designationsInLibrary addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,0)]];
}
sqlite3_finalize(selectstmt);
selectstmt=nil;
}
}
}
sqlite3_close(db);
[localPool release];
}
It seems, that you're opening db on every loop cycle, but close only once, before function exit
So try to change:
}
sqlite3_close(db);
[localPool release];
}
to
sqlite3_close(db);
}
[localPool release];
}
Or even better change:
for(int i=0;i [[DT sharedDT].typesInLibrary count];i++)
{
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
to:
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
for(int i=0;i [[DT sharedDT].typesInLibrary count];i++)
{
...
because you're always open the same database
Try invoking sqlite3_exec with:
pragma cache_size=1
Sqlite seems to gobble up memory for caching.