Am making an iOS apps with an embedded SQLite database. So I make my DB in a SQLite administrator and drag it to my Xcode project, like in the tutorial says.
When I try open my DataBase, I get this error: "out of memory". Dont know if it is a SQLite bug or something, but my file is really small to get a memory problem.
This is my code to init my DataBase:
- (id)initWithPath:(NSString *)path {
if (self = [super init]) {
BOOL success;
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"SoundLib_DB.sqlite"];
if ([fileManager fileExistsAtPath:dbPath] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"SoundLib_DB" ofType:#"sqlite"];
[fileManager copyItemAtPath:resourcePath toPath:dbPath error:&error];
}
success = [fileManager fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
sqlite3 *dbConnection;
//Here is when I get the error, at trying to open the DB
if (sqlite3_open_v2("SoundLib", &dbConnection, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
NSLog(#"[SQLITE] Unable to open database!");
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
return nil;
}
database = dbConnection;
}
return self;
}
Error may be because you need to pass databasepath as UTF8String. I see you are passing "SoundLib". You can not directly pass like that.
if (sqlite3_open([dbPath UTF8String], &databaseHandle) == SQLITE_OK)
{
//dbPath is your full database path you getting above
}
P.S. Also have dbpath as const char
const char *dbpath
Change your opening process so that it looks like this... It works for me ;)
I guess your main mistake is that you forgot the UTF8String....
sqlite3 *database;
int result = sqlite3_open([dbPath UTF8String], &database);
if (result != SQLITE_OK) {
sqlite3_close(database);
NSLog(#"Error opening databse");
return;
}
Related
When I test my app on the simulator everything works. But when I test the app on my iPhone, it doesn't load from the db.sqlite3 data base.
I tried every solution from the internet. I cleaned the app. I added the database to the build phrases - copy bundle resources etc.
Can you help me? Is there any fails in my coding?
-(void)openDataBase{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
dbPath = [documentsDirectory stringByAppendingString:#"db.sqlite3"];
//load it
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *pathInRessource = [[NSBundle mainBundle] pathForResource:#"db" ofType:#"sqlite3"];
//exist it?
if (![fileManager fileExistsAtPath:dbPath]) {
[fileManager copyItemAtPath:pathInRessource toPath:dbPath error:nil];
}
//open database
int result = sqlite3_open([dbPath UTF8String], &db);
if (result != SQLITE_OK) {
sqlite3_close(db);
return;
}
//if ok
NSLog(#"Data base opened");
}
At the time of opening database you can call this with its else case to get the issue.
if (sqlite3_open([getDBPath UTF8String], &sqlhandle) == SQLITE_OK)
{
NSLog(#"Database Open!");
}
else
{
NSLog(#"Select err: %s",sqlite3_errmsg(sqlhandle));
}
You will be able to get proper error message using this
I am wondring where you getting stuck, I am doing same way and its working fine to me.
BTW I have updated your code, how I am handling, please check let me know if find and trouble in this.
//My DB variable
static sqlite3 *database;
-(void)openDataBase{
if (database == NULL)
sqlite3 *mDatabse;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
dbPath = [documentsDirectory stringByAppendingString:#"db.sqlite3"];
//load it
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *pathInRessource = [[NSBundle mainBundle] pathForResource:#"db" ofType:#"sqlite3"];
//exist it?
if (![fileManager fileExistsAtPath:dbPath]) {
[fileManager copyItemAtPath:pathInRessource toPath:dbPath error:nil];
}
if (sqlite3_open([path UTF8String], &mDatabse) == SQLITE_OK) {
NSLog(#"Database Successfully Opened");
database = mDatabse;
} else {
NSLog(#"Error in opening database");
mDatabse = NULL;
}
}
I want to update my table.This code work on simulator but does not work on device. I found that I can't write to any files in my app bundle but I do not how change it to work. Please help me.
-(NSString *)filePath
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir=[paths objectAtIndex:0];
NSError *error;
bool success;
NSString *writablePath = [documentsDir stringByAppendingPathComponent:#"Test.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:writablePath];
if(!success)
{
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Test.sqlite"];
success = [fileManager copyItemAtPath:defaultPath toPath:writablePath error:&error];
}
NSLog(#"%#",writablePath);
return writablePath;
}
And Then:
- (IBAction)addToFavorite:(id)sender
{
[self filePath];
sqlite3_stmt *updateStatement=nil;
NSString *sql=[[NSString alloc]initWithFormat:#"UPDATE A SET favorite=? WHERE x='%#' ",mystring];
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &updateStatement, nil)==SQLITE_OK)
{
sqlite3_bind_text(updateStatement, 1, [#"1" UTF8String], -1, SQLITE_TRANSIENT);
}
if (sqlite3_step(updateStatement)!=SQLITE_DONE)
{
NSAssert(0,#"Error While Creating Update Statement. '%s'",sqlite3_errmsg(db));
}
sqlite3_reset(updateStatement);
}
I thing you have made changes in simulator, but on device new database have not been updated.
Just delete your app from device and re-run it i.e.
CLEAN INSTALL
I m using below code to for sqlite DB, but I can not insert values with Execute query can any one tell me where i m wrong ?
- (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:DATABASE_NAME];
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:DATABASE_NAME];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Initialize Database
- (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:DATABASE_NAME];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
//TRUE
}
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...
}
}
Execute Sql Method
-(void)ExecuteSQL:(NSString*)SQL
{
#synchronized(self)
{
sqlite3_stmt *select_statement=nil;
if (sqlite3_prepare_v2(database, [SQL UTF8String], -1, &select_statement, NULL) != SQLITE_OK) {
NSString *errString = [NSString stringWithFormat:#"%#",
[NSLocalizedString(#"statementPrepareFailedKey",#"")
stringByReplacingOccurrencesOfString:#"#" withString:[NSString
stringWithCString:sqlite3_errmsg(database) encoding:NSUTF8StringEncoding] ]];
NSAssert1(0, #"%#", errString);
}
//int columncount=sqlite3_column_count(select_statement);
//NSMutableDictionary* dic;
if(sqlite3_step(select_statement) == SQLITE_DONE)
{
NSLog(#"Execute sql");
}
sqlite3_finalize(select_statement);
}
}
Thanks.
Hopefully this makes sense. I have a sqlite database in my documents folder. I also have a function that checks to see if that file exists in the directory, and if it doesn't, it is moved there from the main bundle. So I know that the database is in the correct place to access. However, when I run my app, I get the error: no such table: databaseName. Could the problem have to do with read write access of the sqlite database? If so, how to I check this and rectify the problem?
#define kFilename #"foods.sqlite"
- (NSString *)dataFilePath {
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* sqliteFile = [documentsPath stringByAppendingPathComponent:kFilename];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:sqliteFile];
if(fileExists)
return sqliteFile;
else {
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:kFilename];
NSString *folderPath = [documentsPath stringByAppendingPathComponent:kFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:folderPath
error:&error];
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
}
return [documentsPath stringByAppendingPathComponent:kFilename];
}
-(void) viewWillAppear:(BOOL)animated{
sqlite3 *database;
if (sqlite3_open([[self dataFilePath] UTF8String], &database)
!= SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
sqlite3_stmt *statement;
//why is this if statement failing?
if (sqlite3_prepare_v2(database, [sqlStatement UTF8String],
-1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
//int row = sqlite3_column_int(statement, 0);
char *rowData = (char *)sqlite3_column_text(statement, 1);
foodName = [[NSString alloc] initWithUTF8String:rowData];
[foodArray addObject:foodName];
}
sqlite3_finalize(statement);
}
else {
NSLog(#"%i", sqlite3_prepare_v2(database, [sqlStatement UTF8String],
-1, &statement, nil));
NSLog(#"Statement: %s", sqlite3_errmsg(database));
}
sqlite3_close(database);
}
Use this way instead. skip the intermediate directory steps, and talk right to the db.
- (void)checkAndCreateDB {
NSString *dbPath = [[[NSBundle mainBundle] bundlePath]stringByAppendingPathComponent:#"../Documents/yourDB.sqlite"];
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Check if the database has already been created in the users filesystem
success = [[NSFileManager defaultManager] fileExistsAtPath:dbPath];
if(!success) {
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"yourDB.sqlite"];
[fileManager copyItemAtPath:databasePathFromApp toPath:dbPath error:nil];
NSLog(#"readandwrite is available");
}
if(!(sqlite3_open([dbPath UTF8String], &dB) == SQLITE_OK))
{
NSLog(#"An error has occurred.");
}
}
The error that you are getting says that the table 'databaseName' does not exist in your database file.
You are not getting an error that the database can not be opened, so that isn't the problem.
It looks like your sqlStatement is wrong.
I have a problem with sqlite database integration in my app.
My app uses a translator style function, whereby a users text entry is converted into another way of wording the same word, the word alternatives are listed in a SQLite database.
Basically the code is designed to take text, split it into individual words, and search for them on the database, and return the result for each word, however, the application ends up not returning results and I get the error "error: no such table: dictionary" Even though a query on terminal returns results successfully.
Can anyone give me a hand in identifying what's been done wrong? Thanks
This is the code I used:
-(void)translate{
//take input and break into an array
NSString *clearText = [[NSString alloc] init];
clearText=inputBox.text;
NSArray *words = [[NSArray alloc] init];
words= [clearText componentsSeparatedByString:#" "];
numOfWords=words.count;
NSString *newText=#"";
//open database
sqlite3 *db = [self getNewDBConnection];
//loop through array
for(i=0;i<numOfWords;i++){
sqlite3_stmt *resultStatement= nil;
NSString *res = [NSString stringWithFormat:#"select * from dictionary where plain='%#'",[words objectAtIndex:i]];
if((sqlite3_prepare_v2(db, [res UTF8String], -1, &resultStatement, nil))!=SQLITE_OK){
NSLog(#"Error getting result, maybe word not found\n");
//NSLog(#"tried query:%#",res);
NSLog(#"error: %s", sqlite3_errmsg(db));
}
else{
if(sqlite3_step(resultStatement)==SQLITE_ROW){
//in the line below, 1 is the column number of the replacement word
NSString *add = [[NSString alloc] initWithUTF8String: (char*)sqlite3_column_text(resultStatement,1)];
newText=[newText stringByAppendingString:add];
[add release];
}
}
sqlite3_finalize(resultStatement);
}
//output result
outputBox.text=newText;
sqlite3_close(db);
}
-(sqlite3 *) getNewDBConnection{
sqlite3 *newDBconnection;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data9.sqlite"];
if (sqlite3_open([path UTF8String], &newDBconnection) == SQLITE_OK) {
NSLog(#"Database Successfully Opened");
} else {
NSLog(#"Error in opening database");
}
return newDBconnection;
}
This is the code used to copy the database:
- (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:#"data9.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:#"data9.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Based on the missing table, it looks like it is creating a new database at the path. So either the path is wrong, or it is possible that you might not have copied the master database to that location. The SQLite file is usually in the bundle and needs to be copied first.
Major issues from my perspective.
I went so far as to delete the entire database capability and then ran the app and it still opened the database.
I have this code in applicationDidFinishLaunchingWithOption in the appDelegate. It is designed for start-up to check a valid database is avaailable, so mostly it is never executed. I removed the conditional statement around the copy, and inserted a removeItemAtPath statement to delete the file. Ran it once, and my problem all went away (or at least those with the database, by biggest problem is still user error :-))
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"languageDB.sqlite"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
NSError *error;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"language.sqlite"];
NSString *writableDBPath = [docsDir stringByAppendingPathComponent:#"languageDB.sqlite"];
if ([filemgr fileExistsAtPath: databasePath ] == NO){
[filemgr copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
NSLog(#"copy error %#",error);
}
Something else you might want to make sure of if you're adding a table to an existing database and then trying to re-add it to your project is that you delete the copy of the database in the location where Xcode is copying it prior to loading your app in the simulator. For instance, when I was having this problem, I had to go into /Users/<user>/Library/Application Support/iPhone Simulator/6.0/Applications/1234DFE1-5AA9-4CFF-0235-3D98961E9281/Documents/ to delete the database there. When I cleaned and re-ran the simulator, it found my new table just fine.