I tried to update an entry in my table like this:
NSFileManager *fileMgr=[NSFileManager defaultManager];
NSString *dbPath=[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"quizDB.sqlite"];
if ([fileMgr fileExistsAtPath:dbPath]) {
NSLog(#"DB does exist!");//displayed
}
const char *dbpath = [dbPath UTF8String];
sqlite3_stmt *updateStmt;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSLog(#"%i",id_quiz);//displayed, in a test case it display 1 which is a quiz ID in the table
NSString *querySql=[NSString stringWithFormat:#"Update quiz set etat=1 where id=\"%i\"",id_quiz];
const char*sql=[querySql UTF8String];
sqlite3_prepare_v2(contactDB, sql, -1, &updateStmt, NULL);
if(SQLITE_DONE != sqlite3_step(updateStmt))
{
NSAssert1(0, #"Error while updating. '%s'", sqlite3_errmsg(contactDB));
}
else{
sqlite3_reset(updateStmt);
NSLog(#"Update done successfully!");//this is also displayed, i guess everything is ok then and the entry is updated
}
sqlite3_finalize(updateStmt);
sqlite3_close(contactDB);
}
In the log, i got the message: Update done successfully! so i assumed that everything is, however when i check the database within SQLite Manager in Mozilla Firefox, the entry is not updated. Am i missing something? thanx for help
first copy your database from resource to document dir:
- (void) checkAndCreateDatabase
{
NSString *database_Name =#"quizDB.sqlite"
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *database_Path = [documentsDir stringByAppendingPathComponent:database_Name];
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:database_Path])
{
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:database_Name];
[fileManager removeItemAtPath:database_Path error:nil];
[fileManager copyItemAtPath:databasePathFromApp toPath:database_Path error:nil];
}
else
{
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:database_Name];
[fileManager copyItemAtPath:databasePathFromApp toPath:database_Path error:nil];
}
}
and after you update your database:
- (void) UpdateDatabase
{
sqlite3 *contactDB;
sqlite3_stmt *updateStmt;
NSString *database_Name =#"quizDB.sqlite"
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *dbpath = [documentsDir stringByAppendingPathComponent:database_Name];
if(sqlite3_open([dbpath UTF8String], &contactDB) == SQLITE_OK)
{
NSString *querySql=[NSString stringWithFormat:#"Update quiz set etat=1 where id=\"%i\"",id_quiz];
const char*sql=[querySql UTF8String];
if(sqlite3_prepare_v2(contactDB,sql, -1, &updateStmt, NULL) == SQLITE_OK)
{
if(SQLITE_DONE != sqlite3_step(updateStmt))
{
NSAssert1(0, #"Error while updating. '%s'", sqlite3_errmsg(contactDB));
}
else{
sqlite3_reset(updateStmt);
NSLog(#"Update done successfully!");
}
}
sqlite3_finalize(updateStmt);
}
sqlite3_close(contactDB);
}
and check your database which save in documentdir not in resource
Related
I'm saving an image in the document directory and then I save its path inside a SQLite DB. After the process finishes I try to retrieve the image path from the db but I can't get it working and I really have no Idea why. On the simulator the code works but on a real device it doesn't.
This is the code I've used to save the img path and to retrieve the img path and display the image inside an UIImageView
This is the code to save the image:
NSString *stringURL = #"http://addons.cdn.mozilla.net/user-media/addon_icons/80/80205-64.png?modified=1317416463";
NSURL *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
NSString *filePath;
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory,#"test.png"];
[urlData writeToFile:filePath atomically:YES];
}
NSLog(#"path:%#",filePath);
[self saveImgPath:filePath];
This is the saveImgPath method:
-(void) saveImgPath:(NSString*)path{
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &ImgDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO ImgPath (path) VALUES (\"%#\")",path];
const char *insert_stmt = [insertSQL UTF8String];
if(sqlite3_prepare_v2(ImgDB, insert_stmt, -1, &statement, NULL) == SQLITE_OK)
{
sqlite3_step(statement);
}
sqlite3_finalize(statement);
sqlite3_close(ImgDB);
}
[self performSegueWithIdentifier:#"sfondo" sender:self];
}
And this is how I retrieve it:
-(NSString*)getImgPath{
NSString* imgPath;
const char *dbpath = [[self GetDatabasePath] UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &ImgDB) == SQLITE_OK)
{
NSString *checkSQL = [NSString stringWithFormat: #"SELECT * FROM ImgPath"];
const char *insert_stmt = [checkSQL UTF8String];
sqlite3_prepare_v2(ImgDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ERROR)
NSAssert1(0,#"Errore %s",sqlite3_errmsg(ImgDB));
else
sqlite3_step(statement);
sqlite3_finalize(statement);
sqlite3_close(ImgDB);
}
return imgPath;
}
The DB is initialized correctly and the NSLog of the paths are correct but I get 0 results when I try to retrieve the image path
the first view is word list view controller and it has a word table containing word_id,word meaning and sentence and this data i need to pass on the other view having 1 text field which i add to display the word and two text views to display meaning and sentence.
Here is the code-
- (void)getListData
{
//tableData = [[NSMutableArray alloc]init];
sqlite3_stmt *statement;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"dexternotedb.sqlite"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
WordListViewController *temp = APP_DELEGATE.wordListViewController;
NSLog(#"word id %ld",(long)[temp.wordId integerValue]);
NSString *sql=[NSString stringWithFormat:#"SELECT word_id, word ,meaning,sentence FROM words WHERE word_id=\"%#\"",APP_DELEGATE.wordListViewController.wordId];
const char *read_stmt = [sql UTF8String];
NSLog(#"select query%#",sql);
if(sqlite3_prepare_v2(database, read_stmt, -1, &statement, NULL) == SQLITE_OK){
//sqlite3_bind_int(statement, 1, [temp.wordId integerValue]);
while(sqlite3_step(statement) == SQLITE_ROW) {
NSString *word1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
word.text = word1;
NSString *meaning1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
meaning.text = meaning1;
NSString *sentence1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 3)];
Sentence.text = sentence1;
}
sqlite3_finalize(statement);
} else
{
sqlite3_close(database);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
}
}
Simply Store Value in NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:#"String" forKey:#"KeyName"];
[[NSUserDefaults standardUserDefaults] synchronize];
and whenever data is required fetch data from NSUserDefaults in entire app
NSString *str= [[NSUserDefaults standardUserDefaults] valueForKey:#"KeyName"];
Everything in this function seems to work as expected, just no record actually shows up in the database table. If I enter the sql directly through the Firefox sqlite manager plugin, the record appears just fine. Probably something frustratingly stupid, any ideas?
- (IBAction)buttonInsertRecord:(id)sender
{
// initializing db file access
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"KJV.sqlite"];
// testing to see if database was found
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
// database not found
labelStatus.text = #"database not found";
}
else
{
// database not found
labelStatus.text = #"database found";
}
sqlite3_stmt *statement;
sqlite3 *dbPointer;
if (sqlite3_open(dbPath.UTF8String, &dbPointer) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO users (user_name, user_id) VALUES ('testuser', null);"];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(dbPointer, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
labelStatus.text = #"added";
}
else
{
labelStatus.text = #"failed";
}
sqlite3_finalize(statement);
sqlite3_close(dbPointer);
}
}
//your database is not writable because its in the bundle.
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"KJV.sqlite"];
if you want a readable/writable database, you can do this:
- (void) createEditableCopyOfDatabaseIfNeeded
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"databasename.sqlite"];
NSLog(#"writableDBPath == %#",writableDBPath);
if ([fileManager fileExistsAtPath:writableDBPath])
{
NSLog(#"Database already exist");
}
else
{
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databasename.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success)
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
and heres how you add your data
- (void) addToDatabase
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"databasename.sqlite"];
if(sqlite3_open([databasePath UTF8String], &mDatabase_update) == SQLITE_OK)
{
NSString *sqlQuery = [NSString stringWithFormat: #"Insert into table
.
.
.
.
I'm trying to add new row to TableView with edit mode. Used this tutorial. But after dismissing my edit mode view my table view is not reloaded. My addItem: method
- (IBAction)addItem:(id)sender {
BIDAppDelegate *appDelegate = (BIDAppDelegate *)[[UIApplication sharedApplication] delegate];
sqlite3 *database;
NSString *databaseName;
NSString *databasePath;
databaseName = #"TestProjectDatabase.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:databasePath];
if(!success) {
databasePath = [[NSBundle mainBundle] pathForResource:databaseName ofType:nil];
}
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"insert into \"MyItems\" ( \"MyItemName\", \"MyItemDescription\") values ( '%#', '%#');", _nameTextField.text, _descriptionTextField.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, insert_stmt, -1, &compiledStatement, NULL) != SQLITE_OK)
{
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}else{
if (sqlite3_step(compiledStatement) == SQLITE_DONE)
{
// NSLog(#"All ok");
} else {
// NSLog(#"FAIL");
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
MyItems *itemsToDatabase = [[MyItems alloc] initWithItemName:_nameTextField.text andItemDescription:_descriptionTextField.text];
[appDelegate.myItems addObject:itemsToDatabase];
[self dismissModalViewControllerAnimated:YES];
}
SQL insertion is OK because where is new row after restarting my project. Any suggestions how to fix it?
Assuming the table data source reads from appDelegate.myItems, you just need to reload the table itself [tableView reloadData];.
EDIT: SOLVED! answer below first code box
When i try to connect with a sqlite database (with a table TblTest). In debug mode in my app, the error is:
* Assertion failure in -[QueryClass getTestData:],
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cant build SQL to read item [no such table: TblTest]'
In release mode (simulator), it does not give an error but it will not read the database.
The code behaves like it can connect to the db, but can NOT read the TblTest?
I already reset the simulator and used clean and build.
Sorry for the long code:
#implementation QueryClass
#synthesize databaseName;
#synthesize databaseLite;
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
self.databaseName = databaseNameP;
self.databaseLite = [self getNewDBConnection];
}
return self;
}
- (void)createEditableCopyOfDatabaseIfNeeded {
NSLog(#"Creating editable copy of database");
// 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:self.databaseName];
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:self.databaseName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message ‘%#’.", [error localizedDescription]);
}
}
- (sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:self.databaseName];
// 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;
}
-(NSMutableArray *)getTestData:(NSInteger) testId{
(NSMutableArray *testArray = [[NSMutableArray alloc]init];
int ret;
sqlite3_stmt *selStmt = nil;
const char *sql = "SELECT testId, name, FROM TblTest WHERE testId = ?";
if (!selStmt)
{ // build update statement
if (sqlite3_prepare_v2(self.databaseLite, sql, -1, &selStmt, NULL)!=SQLITE_OK)
{
selStmt = nil;
}
}
sqlite3_bind_int(selStmt, 1, testId);
if(!selStmt){
NSAssert1(0, #"Cant build SQL to read item [%s]", sqlite3_errmsg(self.databaseLite));
}
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{ // get the fields from the record set and assign to item
Test *test = [[Test alloc]init];
NSNumber *testId = [NSNumber numberWithInt: (int) sqlite3_column_int(selStmt, 0)];
NSString *name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(selStmt, 1)];
test.testId =testId;
test.name =name;
[testArray addObject:pill];
[test release];
}
sqlite3_reset(selStmt);
return [testArray autorelease];
}
//in my function i do:
qc = [[QueryClass alloc]initWithDatabase:#"databaseLite.sql"];
[qc getTestData:0];
I rewrote my code using this tutorial and it works like a charm. :)
Thanks
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];
}
return self;
}
// Creates a writable copy of the bundled default database in the application Documents directory.
- (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:#"databaseLite4.sqlite"];
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:#"databaseLite4.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
// The database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.path = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
}
When you solve your own problems, you should provide your solution as an answer rather than updating your question. It is possible (and recommended in this situation) to answer your own question and accept it as your answer. You will not gain any reputation for accepting your own answer, but the question will be correctly listed as solved.
Below is the answer I extracted from your question. Feel free to accept it.
I rewrote my code using this tutorial and it works like a charm. :)
Here's my solution:
-(id)initWithDatabase:(NSString *)databaseNameP{
if(self = [super init]){
[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];
}
return self;
}
// Creates a writable copy of the bundled default database in the application Documents directory.
- (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:#"databaseLite4.sqlite"];
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:#"databaseLite4.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
// The database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.path = [documentsDirectory stringByAppendingPathComponent:#"databaseLite4.sqlite"];
}