I am using sqlite3 in my project.
I am getting error after couple(50-60) of transaction that "unable to open
database file",So check my database file path but path is correct and
file is there.
I tried each and every solution discussed on stack overflow, but with no
luck.
I check my "DocumentDirectory" path, done all necessary step before to close database. Like:
sqlite3_finalize(selectStatement);
sqlite3_close(database);
I don't know how to tackle this problem.can I check that my sqlite3 database is open or not.
====================== 1============================
+(NSMutableArray*)executeDataSet:(NSString*)query
{
NSMutableArray *arryResult = [[NSMutableArray alloc] initWithCapacity:0];
const char *sql = [query UTF8String];
sqlite3_stmt *selectStatement;
sqlite3 *database = [DataBaseClass openDataBase];
//prepare the select statement
int returnValue = sqlite3_prepare_v2(database, sql, -1, &selectStatement, NULL);
if(returnValue == SQLITE_OK)
{
//my code
}
}
//sqlite3_reset(selectStatement);
// NILOBJECT(selectStatement);
// NILOBJECT(selectStatement);
sqlite3_finalize(selectStatement);
sqlite3_close(database);
return arryResult;
}
==================== 2 =================================
+(sqlite3 *) openDataBase {
sqlite3 * edenAdultDatabase;
NSString * databasePath =[DataBaseClass pathForDatabase];
if(sqlite3_open([databasePath UTF8String], &edenAdultDatabase) == SQLITE_OK) {
NSLog(#"Yes database is open");
return edenAdultDatabase;
}
else
{
NSLog(#"do something %s",sqlite3_errmsg(edenAdultDatabase));
}
return edenAdultDatabase;
}
====================== 3 ===========================
+(NSString *) pathForDatabase {
NSString *libraryDir = [FileManager pathForPrivateDocumentsFolder];
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSError *error;
NSString *privateFolderPath = [libraryDir stringByAppendingPathComponent:#"DataBase"];
if (![fileMgr fileExistsAtPath:privateFolderPath])
{
[fileMgr createDirectoryAtPath:privateFolderPath withIntermediateDirectories:NO attributes:nil error:&error];
}
/*
// My database in library private folder ..this is just for test.
// I copied databae to document dir but no luck.
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
privateFolderPath = [documentsDir stringByAppendingPathComponent:kDatabaseName];
*/
privateFolderPath = [privateFolderPath stringByAppendingPathComponent:kDatabaseName];
return privateFolderPath;
}
There is a weird issue in database connectivity, sometime it does not connect. Therefore it is recommended by people that your application should open a database once (during in initialisation phase) and close the connection when application is terminating.
Reference: Sqlite opening issue
Regarding checking database connectivity, Sqlite3 does not provide any method to check that either database is open or not.
By using Shared instance of database manager, you can achieve it. Define a boolean at class level and set it's value when you open the database:
// .h file
BOOL isDatabaseOpen;
// .m file
-(void) openDatabase
{
if(![self isDatabaseExist])
{
// copy database to library
[self copyDatabaseFile];
}
NSString *sqLiteDb = [self getDatabaseLibraryPath];
if (sqlite3_open([sqLiteDb UTF8String], &_databaseHandler) != SQLITE_OK) {
NSLog(#"Database --> Failed to open");
isDatabaseOpen = NO;
}
else
{
isDatabaseOpen = YES;
}
}
and then you can use the following method to check is database opened or not.
-(BOOL) isDatabaseOpen
{
return isDatabaseOpen;
}
Let me know if it worked :).
check out this kind of solution
first of all create function like below:
-(void)checkDBAndCopy{
NSArray *dirPath=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *connectionPath=[dirPath objectAtIndex:0];
strDBPath=[connectionPath stringByAppendingPathComponent:#"database.sqlite"];
NSLog(#"%#",strDBPath);
NSFileManager *filemanager=[[NSFileManager alloc]init];
if (![filemanager fileExistsAtPath:strDBPath]) {
NSString *databasePathFromApp=[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"database.sqlite"];
[filemanager copyItemAtPath:databasePathFromApp toPath:strDBPath error:nil];
}
}
and call this function like below method:-
-(NSMutableArray *)RetriveSharedspots:(NSString *)Query{
[self checkDBAndCopy];
if (sqlite3_open([strDBPath UTF8String], &contactDB)==SQLITE_OK) {
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(contactDB, [Query UTF8String],-1,&statement,NULL)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW) {
// Your code
}
}
sqlite3_finalize(statement);
}
sqlite3_close(databaseName);
return array;
}
Above this worked for me great. try this.
Just sharing my case with this issue.
I have a project that uses databaseFile1.sqlite and I am not sure if there was a build of it installed on my simulator.
Then I changed the database file, say databaseFile2.sqlite different contents, different filename. Then this issue came up. As I read the solutions and comments, I realized that the issue shouldn't be so biggie.
Welp, I deleted the build and restarted Xcode. Voila. It's okay now. Later on, I will revert back to databaseFile1.sqlite the database, and I'll see if this issue can be reproduced.
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 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];
}
I am really new in ios development. What I try to do now is open an existing sqlite database and select data from there. I debug my source and see that I open the database success (I think I success since the *database pointer is not nil). but when I use sqlite3_prepare_v2() to initialize the select query, I always receive the error: "No such table People". I have checked at the path:
~/Library/Application Support/iphone simulator/6.0/Application//.
The database was copied successful, I can open it a see the data there.
Here is my code to copy the database and open it:
- (NSString*) getDatabasePath{
//Search for standard documents using NSSearchPathForDirectoriesInDomains
//First Param = Searching the documents directory
//Second Param = Searching the Users directory and not the System
//Expand any tildes and identify home directories.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"data.sqlite"];
}
- (void)copyDatabaseToDocument {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDatabasePath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"data.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
- (sqlite3*)openDatabaseConnection {
sqlite3 *database;
NSString * path = [self getDatabasePath];
if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
}
return database;
}
And here is my code to select data. The error occurs at line: sqlite3_prepare_v2(database, query, -1, &selectStatement, NULL)
- (People*) getPeople{
sqlite3 *database = [[[DBConnector alloc] init] openDatabaseConnection];
if(database == nil)
return nil;
sqlite3_stmt *selectStatement;
NSString *rawquery = #"select * from people";
const char *query = [rawquery UTF8String];
NSMutableArray* result = [[NSMutableArray alloc] init];
if (sqlite3_prepare_v2(database, query, -1, &selectStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(selectStatement) == SQLITE_ROW) {
//Parse the data by calling a private method:
People *people = [self parsePeopleWithStatement:selectStatement];
[result addObject:people];
}
}else{
NSAssert1(0, #"Error: '%s'.", sqlite3_errmsg(database));
}
sqlite3_finalize(selectStatement);
return result;
}
Please tell me if you know what the mistake I have.
Thanks.
I have resolved the problem by myself. When I debug the app, I see that It didn't call applicationDidFinishLaunching method, It calls applicationDidFinishLaunchingWithOptions method. I just place the code to call the copyDatabaseToDocument at the applicationDidFinishLaunchingWithOptions method and It works.
Here is the code of my Delegate class:
//THIS METHOD WAS NOT CALLED
- (void)applicationDidFinishLaunching:(UIApplication *)application{
DBConnector *connector = [[DBConnector alloc] init];
[connector copyDatabaseToDocument];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//SHOW MY SCREEN
(...)
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
By the way, I think this is not a real answer sync I don't know why my App didn't start at the applicationDidFinishLaunching(). If you know, please give me a description.
Thanks.
I working on an app that takes input from a text field and puts it into a string. I have a table with a field in it that I want to check the value of the string from the input against the value in the field in the database. I'm new to iOS and fairly new to SQLite.
Code:
-(IBAction)setInput:(id)sender
{
NSString *strStoreNumber;
NSString *strRegNumber;
strStoreNumber = StoreNumber.text;
strRegNumber = RegNumber.text;
lblStoreNumber.text = strStoreNumber;
lblRegNumber.text = strRegNumber;
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths lastObject];
// NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:#"tblStore.sqlite"];
NSString* databasePath = [[NSBundle mainBundle] pathForResource:#"tblStore" ofType:#"sqlite"];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"Opened sqlite database at %#", databasePath);
//...stuff
}
else
{
NSLog(#"Failed to open database at %# with error %s", databasePath, sqlite3_errmsg(database));
sqlite3_close (database);
}
NSString *querystring;
// create your statement
querystring = [NSString stringWithFormat:#"SELECT strStore FROM tblStore WHERE strStore = %#;", strStoreNumber];
const char *sql = [querystring UTF8String];
NSString *szStore = nil;
NSString *szReg = nil;
if (sqlite3_prepare_v2(database, sql, -1, &databasePath, NULL)!=SQLITE_OK) //queryString = Statement
{
NSLog(#"sql problem occured with: %s", sql);
NSLog(#"%s", sqlite3_errmsg(database));
}
else
{
// you could handle multiple rows here
while (sqlite3_step(databasePath) == SQLITE_ROW) // queryString = statement
{
szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(databasePath, 0)];
szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(databasePath, 1)];
} // while
}
sqlite3_finalize(databasePath);
// Do something with data...
}
It gets to the line "NSLog(#"Opened sqlite database at %#", databasePath);", so it appears as though it has access to the database. However, when I run the app, I get the "NSLog(#"sql problem occured with: %s", sql);" error, which I can see in the console. Additionally, in the console, it says "No such table: tblStore".
I created the table using the Firefox add-on SQLite Manager. I added the sqlite3 library to the project. I dragged and dropped the database table I created in SQLite manager into my project, above my two AppDelegate files and my two ViewController files.
Any help or input would be greatly appreciated. Thanks!
EDIT: I have properly added the file to the project, and it appears as though the table is found now. Now I have some strange warnings, though:
"Incompatible pointer types passing 'const char *' to parameter of type 'sqlite3_stmt *' (aka 'struct sqlite3_stmt *')"
This warning appears on the following lines of code:
if (sqlite3_prepare_v2(database, sql, -1, &databasePath, NULL)!=SQLITE_OK)
while (sqlite3_step(sql) == SQLITE_ROW)
szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(sql, 0)];
szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(sql, 1)];
sqlite3_finalize(sql);
It's got something to do with "sql", but I'm unsure of what. Any suggestions?
Your code seems ok - did you copy the db to the ressource folder of your project?
EDIT
Make sure you access your db file with something like that:
- (void) initializeDB {
// Get the database from the application bundle
NSString* path = [[NSBundle mainBundle] pathForResource:#"tblStore" ofType:#"sqlite"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
NSLog(#"Opening Database");
}
else
{
// Call close to properly clean up
sqlite3_close(database);
NSAssert1(0, #"Error: failed to open database: '%s'.",
sqlite3_errmsg(database));
}
}
The database file you add to the project will be embedded in the main NSBundle (see [NSBundle mainBundle]).
In order to do what you want, you need to copy the database from the main bundle to the documents folder before trying to access it. Otherwise, as you are experiencing, you will not be able to find the SQLite DB on the document's folder.
You can copy your database, click finder and write this address(/Users/administrator/Library/Application Support/iPhone Simulator/6.1/Applications/) in finder click ok.
You will get documentary path.
Open your project document file and paste your database....