I created a sqlite3 database, created tables and insert some data. I can retrieve using select query by using terminal application.
But when i add this database to my iPhone application resources and try to access data programatically I get error as "no such table: table name"
Why does this happen?
sqlite3_open() creates an empty database for you if the database path does not exist. So, it is possible that the path you gave it does not lead you to the intended file. With an empty database, you get "no such table" a lot.
The DB file is probably not reachable by the iPhone. Try creating the DB from the iPhone app itself.
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES
);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [
documentsDirectory stringByAppendingPathComponent:#"yourdbname.sql"
];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &db_handle) != SQLITE_OK) {
// Even though the open failed,
// call close to properly clean up resources.
sqlite3_close(db_handle);
NSAssert1(0,
#"Failed to open database with message '%s'.",
sqlite3_errmsg(db_handle)
);
}
And the perform your query again. Also, it helps if you check for potential errors on every step of your DB access code.
I had the same error with sqlite3X C++ wrapper.
I use this library in my IE-plugin.
The problem was in unavailability .sqlite base.
Current directory for IE(not plugin) is "C:\Documents and Settings\UserName\desktop\".
When I put my base in this location - problem was solved.
Related
I have a situation where I'm presenting data in a UITableView using NSJSONSerialization from an external source. I also have to show this data if the device is in offline mode. What is the best approach to doing this? Do I need an internal db to store the data, check for wifi and if it's unavailable present the local data?
thanks for any help or tutorials you may know of.
I have a similar requirement for an app I am working on. I am pulling the data from parse.com (remote objects) and put the data into core data (local objects). When presenting a table view, I run the parse.com query in the background, which pulls the data and puts it into core data. The table views use NSFetchedResultsController so when changes occur to the core data (local) objects, the table view is updated as the data is retrieved. If off line, nothing is retrieved, so the table view does not update, but is presenting the last update of the objects.
Yes . You can make local database to do that thing.
You can check the wifi status. If net connection is available than display data from the external source and if net connection is not available than display data from the local database.
When you retrieve data from external source when you are online store it locally.
Next time when your app is launched:
Check for network connection
If network connection is available retrieve data and re-write the old content
If network connection is not available use the locally stored data
Data can be stored in plist, database file or as an text file.
You can use a CoreData database i.e. and update the data every time you connect. If you cannot connect, just show the old data.
How to use and how to check WiFi connection SO is offering more than enought content ;)
you can store the data in plist if it is not too much.
-(void)Writetoplist:(NSMutableDictionary*)LoginDetails
{
{
//////// This is used to delete the plist file if exist //////
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
plistPath = [documentsDirectory stringByAppendingPathComponent:#"LoginDetails.plist"];
NSError *error;
if(![[NSFileManager defaultManager] removeItemAtPath:plistPath error:&error])
{
//TODO: Handle/Log error
}
/// to write the SP Details in plist file
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
// get the path to our plist ("Documents/foo.plist")
plistPath = [documentsDirectory stringByAppendingPathComponent:#"LoginDetails.plist"];
[LoginDetails writeToFile:plistPath atomically:YES];
}
}
I'm having some difficulty with my sqlite prepare statement. I get an error saying my table does not exist, although I've checked in multiple places for it, and it does exist, so I'm confuzzled.
The file is in the correct iPhone Simulator Application folder
The file is added to my project and viewable in the project navigator
It is also in my build phases- Copy Bundle Resources area.
I've cleaned and started running again.
The database exists and running my sql statement gets me just the
results I expected.
- (NSMutableArray *) getMyWorkout{
NSMutableArray *workoutArray = [[NSMutableArray alloc] init];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"IOSDB.sqlite"];
NSLog(#"Db path is %#",dbPath);
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)){
sqlite3_close(db);
NSLog(#"Failed to open database with message '%s'.", sqlite3_errmsg(db));
}
const char *sql = "SELECT Id, type, difficulty, duration, description FROM workoutTbl";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK){
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
} //...
When I run it, I get the file path and the following error
2013-02-01 18:07:08.060 TriShake[9251:c07] -[MyWorkoutList getMyWorkout] Prepare failure 'no such table: workoutTbl' (1)
I've checked out these other questions, but have been unable to find a solution
Sqlite Prepare Failed: no such table<tablename>
Sqlite3 gives "no such table" error on iPhone
I understand sqlite3_open() creates an empty database for you if the database path does not exist, but i know it exists, so frustration ensues. Any help or guidance you could give me would be much appreciated.
In terms of your immediate problem, it's going to be something simple.
You say you've "cleaned and built again", but have you actually removed the old app from your simulator? Either remove the app manually, or, easier, just reset the simulator entirely by choosing "reset content and settings" from the "iOS Simulator" menu. Sometimes Xcode is not good about knowing what files to copy over (particularly in a case like this where your running it on the device may be changing the timestamp of the file in the simulator's bundle!)
Run the app again.
If the app doesn't work as expected, open up the database in the simulator folder from the Mac and check out the database to make sure the table is there and precisely as you expected it to be. So navigate to the app, open the bundle (you may have to choose the "show package contents" option), confirm the existence of the database, but just as importantly, open it up this particular copy of the database in your favorite Mac sqlite3 tool of choice and confirm the existence of the table there.
Let us know what you find. Again, it's got to be something simple such as:
Perhaps the process of rebuilding the app was not reinstalling everything; I've occasionally had problems where Xcode elected to not re-copy something during the install on my simulator;
Perhaps your database in your project was accidentally put in a subdirectory, worse, you might have two copies sitting in different directories;
Perhaps the database in your Xcode project is missing (or has a typo or (esp in the case of the device) has incorrect filename capitalization) in the name of the table or file;
Etc.
For a lot of these errors, you won't notice the problem until you completely reset the simulator itself. There are a million little things it could be, but hopefully completely resetting the simulator and starting over will help you find the issue. It's always something simple when it comes to these sorts of issues.
Some other minor observations:
You probably should not be opening databases from the bundle. Programmatically copy it from the bundle to the Documents folder, and open the database from there. I know it seems unnecessary, but it's important for a myriad of reasons (if db changes during operation of the app, if db accidentally gets created on you, don't let Xcode get confused about things that changed (even if only file timestamps) in the bundle changing behind Xcode's back, etc.)
You should, if you need the database to be there, use sqlite3_open_v2, using either SQLITE_OPEN_READWRITE or SQLITE_OPEN_READONLY for flags (but do not include SQLITE_OPEN_CREATE). It causes headaches to ever give sqlite a chance to create a blank database for you, or otherwise modify it, so never give it an opportunity to so.
I have encounter the same problem as yours. If the IOS can not find the designated database file, defaultly it will create one for you instead of throwing an error. So you must open the database file IOS created for you which is blank so it off course contain the table you expected.
what I deal with it :
1 you have to bundle the resource file named *.sqlite3 into your project
2 Then You have to use [NSBundle mainBundle] pathFordirectory...... function to search your proper database file.
then you can open the database file you expected and can operate it properly
Best regards,
Not enough rep to comment on Jack's post, but that helped me.
In my case, I had mistyped my path for resource extension:
// Wrong
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"productList"
ofType:#"sqlite3"];
// Should have been (added db ext)
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"productList"
ofType:#"db"];
I would always get past the:
if (sqlite3_open([sqLiteDb UTF8String], &_database) == SQLITE_OK))
because it was automatically creating a db file for me.
I have to add an existent DB into my iphone app
I' ve tried to put it into the project's folder and used this init function
-(id) initDatabase{
databaseName = #"mydatabase.sqlite";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
[databasePath retain];
return self;
}
and then i used this function
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK){ //inserting methods
but I have an error: the table 'nametable' does not exists, I am sure that this table exists and I think that these methods create a new db file into the device path.
You can't have any files in the documents folder to start. Everything that comes with the app has to be included in the app bundle. The first time the app runs, the documents folder is always empty.
You need to locate the file inside the app bundle using NSBundle's pathForResource:ofType:.
If the DB is readonly, you can just leave it there. If it is readwrite, you need to copy the file into the documents or library folder the first time the app launches.
Update:
could you make an example about using
'NSBundle's pathForResource:ofType:'
please?I'm sorry but I'm new to iphone
sdk
It's just:
NSString *path=[[NSBundle mainBundle] pathForResource:#"myDatabase" ofType:#"sqlite"];
In the sidebar, check "Targets" => (Your Target) => "Copy Bundle Resources". I think your database file might not have been copied because Xcode has no idea what file type that is.
I am using Sqlite database in my iphone app.
Here in my app i initially used a absolute path like #"/Users/macos/Documents/appdatabase.sql
Now here I want to run the app on the device. It requires the relative path.
What needs to be done to get that path for the database ?
Here I am getting this error when i try to run with the absolute path on the device.
Sqlite Prepare Failed: No such table
I have checked that table already exist in my database.
What should I do to get the relative path for the database?
Please Help and Suggest.
Thanks
You can get the database path using this -
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"mydb.sqlite"];
also delete your app from simulator or device and run/install it again.
So I have been working on this project for a short while now. I have no problems with reading data from the DB, and formatting it into UITableViews and what not. But now I am wanting also to write to the DB as well. The problem is I keep getting a "Database is Locked" error from sqlite. After messing around with the original version I had the face-palm moment by realizing my database was in the bundle and therefore not writable. So I relocated the DB to the Apps Documents folder, which is writeable. But now I still get the same "Database is Locked" sql error. I only open and close the DB when necessary. And as far as I can tell, I don't leave it open anywhere. Below is the code where I am wanting to do updates. Any thoughts?
- (BOOL) loanBookTo:(NSString *)newborrower{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"books.sqlite"];
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
NSLog(#"File Exists at: %#", path);
}
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
NSString *mySQL = #"UPDATE BOOKS SET LOANED = 1, BORROWER = \"<BORROWER>\" where ISBN = \"<ISBN>\"";
mySQL = [mySQL stringByReplacingOccurrencesOfString:#"<ISBN>" withString:self.isbn];
mySQL = [mySQL stringByReplacingOccurrencesOfString:#"<BORROWER>" withString:newborrower];
const char *sql = [mySQL UTF8String];
char* errmsg;
sqlite3_exec(database, sql, NULL, NULL, &errmsg);
// Q. Database is locked. Why?
// A. Because it is in the Bundle and is ReadOnly.
// Need to write a copy to the Doc folder.
// Database is Locked error gets spit out here.
printf(errmsg);
sqlite3_close(database);
}
return NO;
}
Open the database once at the start of your app, then close it in applicationWillTerminate of the AppDelegate.
After every exec you will want to do a reset to clear the connection state.
Take a look at the SQLiteBooks sample app, it is coded this way.
How do you move the DB to the documents folder from the bundle? You need to check that it is there, and if not copy it. I get the feeling that either you have copied it some other way, but retained a read-only attribute, or more likely, you are still referencing the original in the bundle.
For details see
Where would you place your SQLite database file in an iPhone app?
or as joshperry says, the SQLiteBooks sample has all the code you need.
How are you getting to loanBookTo? If the database is open and then you call loanBookTo, it may not throw an error of the open, however the database is holding the state from where you came.
Also, at times, the database retains the locked state upon closing and exiting the application, so you could be 'inheriting' a locked state from your previous failures. Deleting the app from the simulator should give you a clean copy.