I have a problem in my app and I don't know where it comes from ...
So I add my file to my project The on highlighted !
But when I want to init and select in my table I have an error :
no such table
I'm pretty sure the table is here beceause in my terminal I got this :
And I do the same request in my code :
tableData = [sqlManager getList:#"SELECT name_fr FROM info_max"];
sqlManager works with the 3 other files ..
I use this to init
-(id)initDatabase:(NSString*)dbName {
if (self = [super init]) {
//Nom de la base de données
databaseName = dbName;
//Obtention du chemin complet de la base de données
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
}
return self;
}
EDIT
And my query is executed like this :
-(NSMutableDictionary *)getList:(NSString*)typeOfRequest{
sqlite3 *database;
const char *sqlStatement = [typeOfRequest UTF8String];
NSMutableDictionary *aromaArray = [[NSMutableDictionary alloc] init];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
sqlite3_stmt *compiledStatement;
//Compilation de la requete et verification du succes
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
NSDictionary *dictionary = [self indexByColumnName:compiledStatement]; // Creation d'un dictionnaire des noms de colonnes
NSMutableArray *array = [[NSMutableArray alloc] init];
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
char *tab = (char*)sqlite3_column_text(compiledStatement, [[dictionary objectForKey:nil] intValue]);
NSString *finalUpperCase = [[NSString stringWithUTF8String:tab] capitalizedString];
if (finalUpperCase != nil && finalUpperCase.length >0 && !([finalUpperCase isEqualToString:#"Null"])) {
[array addObject:finalUpperCase];
}
}
aromaArray = [self getDictionnary:array];
}
else {
NSAssert1(0, #"Erreur :. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement); // Finalise la requete et libere le statement
}
else {
NSAssert(0, #"Erreur d'ouverture de la base de donnees");
}
sqlite3_close(database);
return aromaArray;
}
Sometimes Xcode its a mess and it's Derived Data keep references of files, so sometimes you need to clear the Product and Run it again.
Quit XCode
Go to derived data's folder, delete them (also from trash).
Open XCode clean project and try to build it again
For insert and Update queries that is not enough:
Insert and Update Queries
When you copy this file to bundle (target) you have this file only read-only. To make it readable and be able to make insert queries follow the solution below:
This code creates a writable copy of the bundled default database in the application Documents directory. Put it on application didFinishLaunchingWithOptions on appDelegate and now you will be able to test your queries:
// 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:#"info_max.sqlite3"];
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:#"info_max.sqlite3"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
You must have to also try move that Database(sqlite) file to out of project directory and add it again and clear all cache data.
it is work for me.
Related
Ok so I have a database in my iPhone simulator documents. And I now know for sure it's in the applications sandbox. Something is funky in the code I have. So I first get the DB path:
-(NSString *)getsynDbPath
{
NSString* dataBAse = [[NSBundle mainBundle] pathForResource:#"ddd"ofType:#"sqlite"];
return dataBAse;
}
Then I test the path:
NSString *testData;
testData = [self getsynDbPath];
NSFileManager * fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:testData];
if (success) {
NSLog(#"Oh no! There was a big problem!");
} else {
//Successfully opened
if(sqlite3_open([testData UTF8String], &db)==SQLITE_OK){
NSLog(#"Raise the roof!");
//Calling method to loop through columns
[self listOfCols];
}
}
I then go to a custom method where I loop through the columns inside the database:
-(NSArray *)listOfCols{
NSMutableArray *retval = [[[NSMutableArray alloc]init]autorelease];
NSString *query = #"SELECT KEY_ID FROM CON_DETAIL";
sqlite3_stmt *statement;
//Does not execute
if (sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, nil)==SQLITE_OK) {
while (sqlite3_step(statement)==SQLITE_ROW) {
int key_id = sqlite3_column_int(statement, 0);
NSLog(#"Key ID: %d", key_id);
char *nameChars = (char *) sqlite3_column_text(statement, 1);
NSLog(#"chars %s", nameChars);
char *cityChars = (char *) sqlite3_column_text(statement, 2);
NSLog(#"chars %s", cityChars);
}
}
NSLog(#"%s Why '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
return retval;
}
So here's my question. After I successfully opened the database, why the heck am I getting a log error that says: no such table: CON_DETAIL ? Any help is appreciated.
I think you have to copy your db in your document directory and then try to fetch. Copy it with following functions.
-(void) dbconnect{
self.databaseName = #”yourdbname.sqlite”;
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
self.databasePath = [documentsDir stringByAppendingPathComponent:self.databaseName];
// Execute the “checkAndCreateDatabase” function
[self checkAndCreateDatabase];
}
-(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:self.databasePath error:nil];
[fileManager release];
}
NOTE: If you are not getting db in your app’s document directory do the following.
Go to : Target -> “Build Phases” -> “copy bundle Resources” Then add that particular file here.
After that call your "listOfCols" method.
I am trying to update just one cell in row but I can`t get it work. Method for updating:
- (void) UpdateQuestionShownParameter:(int)QuestionId :(BOOL)QuestionShown{
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"Milionar.sqlite"];
const char *sql = "UPDATE Questions set Show = ? WHERE id = ?";
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)
{
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) == SQLITE_OK)
{
NSInteger shownInteger = (QuestionShown ? 1 : 0);
sqlite3_bind_int(sqlStatement, 1, shownInteger);
sqlite3_bind_int(sqlStatement, 2, QuestionId);
if (sqlite3_step(sqlStatement) != SQLITE_DONE)
{
NSLog(#"Error while updating. '%s'", sqlite3_errmsg(db));
}
sqlite3_finalize(sqlStatement);
}
else
{
NSLog(#"Problem with prepare statement");
}
}
else
{
NSLog(#"An error has occured while opening database.");
}
sqlite3_close(db);
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
}
Trying in ViewDidLoad:
- (void)viewDidLoad
{
ListOfQuestions *listQuestions =[[ListOfQuestions alloc] init];
self.Questions = [listQuestions getQuestions];
Question *generatedQuestion = (Question *) [self.Questions objectAtIndex:0];
[listQuestions UpdateQuestionShownParameter:generatedQuestion.id :TRUE];
[self.Description setText:(generatedQuestion.Description)];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Everytime when I tried to run app I get 0 in Shown column. But I don`t have any errors. So am I doing something wrong or everytime when I tried to run app in emulator I get recreate database from project database?
Thanks
You are opening the database in the bundle, which is read-only. You should be copying the database from bundle to Documents folder if the database doesn't already exist in Documents folder:
NSString *filename = #"Milionar.sqlite";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:filename];
NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *documentsPath = [documentsFolder stringByAppendingPathComponent:filename];
if (![fileManager fileExistsAtPath:documentsPath]) {
NSError *error = nil;
BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error];
NSAssert(success, #"Unable to copy database: %#", error);
}
if (sqlite3_open([documentsPath UTF8String], &db) != SQLITE_OK) {
NSLog(#"Open failed");
} else {
// ...
}
For more information about where documents belong, see the File System Programming Guide.
By the way, if you're looking for the Documents folder for your simulator, that's located in ~/Library/Application Support/iPhone Simulator (in Xcode 6, this is now ~/Library/Developer/CoreSimulator/Devices). If you don't see the "Library" folder, you can unhide it by typing the following command into your Terminal command line interface:
chflags nohidden ~/Library
I'm creating an app for my school project that has to write data to my sqlite database. It works, as long as the app is running active but as soon as the app closes, my added data is gone and when I want to read this data this will not work off course. I included both my loadData and saveData methods. The two database paths are the same in both functions so it's not that I'm writing my data elsewhere. I really can't find the solution or the problem. I even get the insert success in my output, so the insert is successful.
- (void) saveData:(id)sender{
NSString *sqldb = [[NSBundle mainBundle] pathForResource:#"PXLate" ofType:#"sqlite3"];
sqlite3_stmt *stmt;
NSString *queryInsert = #"INSERT INTO assignments (name, lesson, dueDate, notification, start, at) VALUES ('abc','abc', 'abc', 1, 'abc', 'abc')";
NSLog(#"%#",sqldb);
NSLog(#"%#",queryInsert);
if(sqlite3_open([sqldb UTF8String], &_PXLate) == SQLITE_OK)
{
sqlite3_prepare_v2(_PXLate, [queryInsert UTF8String], -1, &stmt, NULL);
if(sqlite3_step(stmt)==SQLITE_DONE)
{
NSLog(#"insert success");
}
else
{
NSLog(#"insert un success");
NSAssert1(0, #"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(_PXLate));
}
int success=sqlite3_step(stmt);
if (success == SQLITE_ERROR)
{
NSAssert1(0, #"Error: failed to insert into the database with message '%s'.", sqlite3_errmsg(_PXLate));
//[_PXLate save:&error];
} sqlite3_finalize(stmt);
}
sqlite3_close(_PXLate);
}
and my loadData function
- (void) loadData:(id)sender
{
//path for database
NSString *sqldb = [[NSBundle mainBundle] pathForResource:#"PXLate" ofType:#"sqlite3"];
//check if present
NSFileManager*fm=[NSFileManager defaultManager];
NSLog(#"path: %#", sqldb);
const char *dbpath = [sqldb UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_PXLate) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT * FROM assignments WHERE name='abc'", _label.text];
const char *query_stmt = [querySQL UTF8String];
NSLog(#"name");
NSLog(querySQL);
int response = sqlite3_prepare_v2(_PXLate, query_stmt, -1, &statement, NULL);
NSLog(#"response %d", response);
if (response == SQLITE_OK)
{
NSLog(#"name");
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *namefield = [[NSString alloc]
initWithUTF8String:
(const char *) sqlite3_column_text(
statement, 0)];
NSLog(#"name:%#", namefield);
_label.text = namefield;
} else {
_label.text = #"Match not found";
}
sqlite3_finalize(statement);
}
sqlite3_close(_PXLate);
}
}
You have to copy your sqlite to the documents directory and then work with that. Example:
self.databaseName = #"databasename.sqlite";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
self.databasePath = [[NSString alloc]init];
self.databasePath = [documentsDir stringByAppendingPathComponent:self.databaseName];
[self checkAndCreateDatabase];
And the create method:
-(void)checkAndCreateDatabase
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:self.databasePath error:nil];
}
A couple of observations:
As Retterdesdialogs said, you should
Check for existence of database in Documents;
If not there, copy from bundle to Documents; and
Open database from Documents.
You should not open database from bundle, because on the device that folder is read-only.
In your INSERT statement you are not checking the response of sqlite3_prepare_v2, which is a very common source of errors. If this is not SQLITE_OK, you should immediately log sqlite3_errmsg, before you call sqlite3_step.
You are performing sqlite3_step twice in the INSERT statement.
In loadData, you are not logging sqlite3_errmsg if sqlite3_prepare_v2 failed. Always look at sqlite3_errmsg upon any error.
I have an already made .sqlite file, I can use the mozilla plugin and see all the fields and edit/add etc. I want to read this file into an iphone application. How do I approach reading the file and saving each entry into a new NSObject?
All I can find on stackoverflow when I search for this question is people saying to use the mozilla plugin but not actually talk about the objective-c side of things.
Thanks in advance,
Oli
To achieve this , you'll need a class that creates the database by copying the database from your project resource to the actual directory that app use.
So, create a Objective C class called DataController like this. In DataController.h do like this
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface DataController : NSObject
{
sqlite3 *databaseHandler ;
}
-(void)initDatabase;
-(NSArray*)getBooks;
-(NSString*)getChapter:(NSString*) bible:(NSString*) book:(NSString*) chapter;
#end
In it's implementation do like this. Assume, your database is bible.sqlite . What it basically do is , it checks the document directory that if the database exists , if not it copies your already created database from your project resource to actual directory. Here's the codes.
#import "DataController.h"
#import <sqlite3.h>
#implementation DataController
-(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:#"Bibles.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], &databaseHandler) == SQLITE_OK)
{
// Create the database if it doesn't yet exists in the file system
if (!databaseAlreadyExists)
{
NSLog(#"Database doesn't Exists");
BOOL success = NO ;
NSFileManager *filemngr = [NSFileManager defaultManager];
NSError *error;
NSString *defaultDbPath = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:#"Bibles.sqlite"];
NSLog(#"Size : %lld" , [[[NSFileManager defaultManager] attributesOfItemAtPath:defaultDbPath error:nil] fileSize]);
[filemngr removeItemAtPath:databasePath error:&error];
success = [filemngr copyItemAtPath:defaultDbPath toPath:databasePath error:&error];
if (!success){
NSLog(#"Error : %#" , [error localizedDescription]);
} else{
NSLog(#"Copy Successful");
NSLog(#"Size : %lld" , [[[NSFileManager defaultManager] attributesOfItemAtPath:databasePath error:nil] fileSize]);
}
} else{
NSLog(#"Database already Exists of Size : %lld" , [[[NSFileManager defaultManager] attributesOfItemAtPath:databasePath error:nil] fileSize]);
}
}
}
- (void)dealloc {
sqlite3_close(databaseHandler);
}
-(NSArray*)getBooks
{
NSMutableArray *Books = [[NSMutableArray alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT Name FROM Book ORDER BY ID"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(databaseHandler, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString *bookName = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
[Books addObject:bookName];
NSLog(#"Book : %#" , bookName);
}
sqlite3_finalize(statement);
} else{
NSLog(#"Error : %s",sqlite3_errmsg(databaseHandler));
}
return Books ;
}
-(NSString*)getChapter:(NSString*) bible:(NSString*) book:(NSString*) chapter{
NSString *verse = [[NSString alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT Text FROM %# WHERE BookID = %# AND Chapter = %#" , bible , book , chapter];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(databaseHandler, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString *temp = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
verse = [[NSString alloc]initWithFormat:#"%#\n\n%#",verse ,temp];
// NSLog(#"Book : %#" , verse);
}
sqlite3_finalize(statement);
}
return verse ;
}
#end
Ok...I have created 2 methods for you to show how to use it.
Firstly , in Appdelegate.m , you have to init the database by doing this
DataController *c = [[DataController alloc]init];
[c initDatabase];
Now , let's use it. It's very simple. Just take an instance of DataController and call the method that runs SQL within the database like the last 2 methods I have written. Hope it solves your problem.
I had the same issue a couple of months ago, I found the solution in youtube.
You have to copy your sqlite file to your bundle, import all the link libraries then write some small pieces of code mainly.
Here's a video, you don't need to watch it all, its kinda long.
https://www.youtube.com/watch?v=SVMorX_2Ymk
If you just need the codes let me know ;D
I am trying to execute a simple hard-coded insert statement for a SqLite database. The code works and I get a success message from my own NSLog, however, no records are added to the database. Can anyone help? THx! Viv
-(void)addFavorites{
const char *sqlInsert = "insert into rivers (stat_ID, stat_Name, state) values ('03186500','WILLIAMS RIVER','WA')";
sqlite3_stmt *statement;
sqlite3_prepare_v2(_database, sqlInsert, -1, &statement, NULL);
if(sqlite3_step(statement) == SQLITE_DONE){
NSLog(#"RECORD ADDED!");
} else {
NSLog(#"RECORD NOT ADDED!");
}
sqlite3_finalize(statement);
}
Do you have code like this in your app delegate to copy the database out of the bundle to your NSDocuments directory? Be sure to copy the database to there, then point to there when you're running your sqlite3_open, not to the bundle. The NSDocument directory will be saved when the device is synced to iTunes or iCloud, so it's the place you want your database to be for maintaining data.
NSString *databaseName = #"MyDatabase.sqlite";
NSArray *systemPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *libraryDirectory = [systemPaths objectAtIndex:0];
NSString *databaseFullPath = [libraryDirectory stringByAppendingFormat:#"%#%#",#"/",databaseName];
//copy the database to the file system if it hasn't been done yet.
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL exists = [fileManager fileExistsAtPath:databaseFullPath];
if(exists == NO)
{
NSString *dbPathInBundle = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:dbPathInBundle toPath:databaseFullPath error:nil];
}