i am trying to extract data from sqlite database.I added "libsqlite3.0.dylib" file and copied created sqlite DB into my app folder. I have created two method in appdelegate file. They are
//To copy DB
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"DB File %# does not exists", dbPath);
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"tms.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
NSLog(#"Successfully copied db file to path %#", dbPath);
if (!success)
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
} else {
NSLog(#"DB File %# already exists", dbPath);
}
}
//To get DB path
-(NSString *)getDBPath{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir=[paths objectAtIndex:0];
return [documentDir stringByAppendingPathComponent:#"sampleDB.sqlite"];
}
i have called copyDatabaseIfNeeded() in didFinishLaunchingWithOptions and i have added one method in ViewController.m file. That is
-(void)Display
{
SqlitAppDelegate *appDelegate=(SqlitAppDelegate *)[UIApplication sharedApplication].delegate;
NSString *dbPath=[appDelegate getDBPath];
if (sqlite3_open([dbPath UTF8String], &myDB) == SQLITE_OK)
{
NSLog(#"Database opned successflly");
const char *sql = "select * from sampleTable";
NSLog(#"%s",sql);
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(myDB, sql, -1, &selectstmt, NULL) == SQLITE_OK)
NSLog(#"Prepared successfully");
else
{
NSLog(#"Preparation failed");
NSLog(#"%s",sqlite3_errmsg(myDB));
NSLog(#"%d",sqlite3_errcode(myDB));
}
}
else
NSLog(#"Couldn't open database");
}
i called this method in didViewLoad method.
I get the follwing output:
2013-03-20 12:02:24.026 SqliteSample2[951:11303] Database opned successflly
2013-03-20 12:02:24.027 SqliteSample2[951:11303] select * from sampleTable
2013-03-20 12:02:24.028 SqliteSample2[951:11303] Preparation failed
2013-03-20 12:02:24.029 SqliteSample2[951:11303] no such table: sampleTable
2013-03-20 12:02:24.029 SqliteSample2[951:11303] 1
Anybody tell what i do??????
Thanks in advance...........
Import SqlitAppDelegate in your view controller and make Object like SqlitAppDelegate *app after #implementation ViewController
In viewDidLoad write
app= (SqlitAppDelegate *)[[UIApplication sharedApplication]delegate];
databasepath = [app getDBPath];
if(sqlite3_open([databasepath UTF8String], &dbAssessor) == SQLITE_OK)
{
NSString *sql = [NSString stringWithFormat:#"select * from SampleTable ;"];
sqlite3_stmt *selectstmt;
const char *sel_query=[sql UTF8String];
if(sqlite3_prepare(dbAssessor, sel_query, -1, &selectstmt, NULL) == SQLITE_OK)
{
while(sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSLog(#"Prepared Successfully...");
}
}
sqlite3_finalize(selectstmt);
}
else
sqlite3_close(dbAssessor);
Please try this code and pass me the result. Enjoy !!!
Related
I am using SqliteDatabase in my project.I am calling a function for data manuplation.
-(void)updateInspectionMapData2:(NSString *)clientid : (NSString *)inspectionid : (NSString *)status
{
NSLog(#"EIGHT");
NSLog(#"inside update data");
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSArray *checkVal = [self getSubClientDataByInspectionId:inspectionid :clientid];
NSLog(#"check is %#",checkVal);
if(checkVal == nil || [checkVal count] == 0)
{
NSString *querySql=[NSString stringWithFormat:
#"UPDATE inspectioninspectormap SET status=\"%#\" where inspectionid = \"%#\" and clientid =\"%#\" and (status = \"1\" or status = \"2\")",status,inspectionid,clientid];
NSLog(#"sql is %#",querySql);
const char *sql=[querySql UTF8String];
if(sqlite3_prepare_v2(database,sql, -1, &statement, NULL) == SQLITE_OK)
{
if(SQLITE_DONE != sqlite3_step(statement))
{
NSLog(#"Error while updating. '%s'", sqlite3_errmsg(database));
}
else
{
sqlite3_reset(statement);
NSLog(#"Update done successfully!");
}
}
sqlite3_finalize(statement);
}
}
sqlite3_close(database);
}
Please tell me is this the right way to close sqlite database.I am not sure i am right because later i get error unable to open database.?
There are many problems with your code. Here's what I see after just a quick glance:
You try to close the database even if it doesn't open.
You try to finalize the prepared statement even if the statement can't be prepared.
You needlessly call sqlite3_reset on the prepared statement.
You build your query using stringWithFormat: instead of properly binding values into the prepared statement.
You are using sqlite3_open instead of sqlite3_open_v2.
You don't log an error if sqlite3_open or sqlite3_prepare_v2 fail.
There is an issue in your code:
This code:
}
sqlite3_finalize(statement);
}
}
sqlite3_close(database);
should be changed to:
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
Closing the sqlite should happen right after you finish your work with database, and also within the open connection if loop, but not after the open connection!!!!
When using sqlite, opening and closing should be taken care, else it could lead to lock the database. The problem occurs when you try to open another connection to sqlite without closing the previous one, then your database will be locked .To avoid this, you need make sure that every open connection should have the close connection at the end.
You can try FMDB which is an sqlite wrapper. By using the FMDB,you can simply create the sqlite database using:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"database.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
and you can open the database connection by:
[database open];
and close it by:
[database close];
and to execute a simple statement:
[database executeUpdate:#"create table user(name text primary key, age int)"];
There is a good tutorial out there:
+ (NSString*)setupDatabase
{
NSError *error;
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *dbFilePath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", DATABASENAME, DATABASETYPE]];
if (! [[NSFileManager defaultManager] fileExistsAtPath:dbFilePath])
{
// if installing the application very first time didn't find db, need to copy
NSString *backupDbPath = [[NSBundle mainBundle] pathForResource:DATABASENAME
ofType:DATABASETYPE];
BOOL copiedBackupDb = [[NSFileManager defaultManager] copyItemAtPath:backupDbPath
toPath:dbFilePath
error:&error];
if (! copiedBackupDb)
{
// copying backup db failed
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
return nil;
}
}
return dbFilePath;
}
+ (NSString *)getDataBaseFilePath
{
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbFilePath = [cachePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", DATABASENAME, DATABASETYPE]];
return dbFilePath;
}
+(NSString*)selectItem:(NSString*)itemID
{
NSString *name=nil;
NSString* _dataBasePath = [self getDataBaseFilePath];
sqlite3 *database;
if (sqlite3_open([_dataBasePath UTF8String], &database) == SQLITE_OK) {
NSString *query;
query= [NSString stringWithFormat:#"select ITEM_id from Table where IF ITEM_id='%#' ",itemID];
const char *sql=[query UTF8String];
sqlite3_stmt *selectstmt;
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL)==SQLITE_OK) {
while (sqlite3_step(selectstmt)==SQLITE_ROW) {
if (sqlite3_column_text(selectstmt, 0))
name=[NSString stringWithUTF8String:(char*) sqlite3_column_text(selectstmt, 0)];
}
sqlite3_finalize(selectstmt);
}
}
sqlite3_close(database);
return (name) ;
}
+(BOOL)updateITEM:(ItemObj*)itemObj;
{
NSString* _dataBasePath = [self getDataBaseFilePath];
sqlite3 *database;
if (sqlite3_open([_dataBasePath UTF8String], &database) == SQLITE_OK) {
NSString *qs=[NSString stringWithFormat:#"UPDATE ITEM set User_ID = '%#',User_Name = '%#',Item_id = '%#',User_Status = '%#' WHERE Item_id = '%#'", itemObj.usersid, itemObj.user_name, itemObj.user_id, itemObj.user_status, itemObj.user_id];
const char *sql=[qs UTF8String];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) != SQLITE_OK)
return FALSE;
int result = sqlite3_step(selectstmt);
if(result != SQLITE_DONE) return FALSE;
sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
return TRUE;
}
I guess this should be fairly simple, since I an new to Xcode, Objective-C and SQLite, and I am just trying to get a simple tutorial to work.
I copied the "sampled.sql" file to the directory and this is the code that connects:
-(NSMutableArray *) authorList {
theauthors = [[NSMutableArray alloc] initWithCapacity:10];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"sampledb.sql"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured: %s", sqlite3_errmsg(db));
}
const char *sql = "SELECT * FROM verb";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement 1: %s", sqlite3_errmsg(db));
} else {
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
Author * author = [[Author alloc] init];
author.verb_nutid = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
//author.title = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
[theauthors addObject:author];
}
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"Problem with prepare statement 2: %s", sqlite3_errmsg(db));
}
#finally {
sqlite3_close(db);
return theauthors;
}
}
DATABASE FILE:
BEGIN TRANSACTION
CREATE TABLE "verb" ('ID' INTEGER PRIMARY KEY AUTOINCREMENT, 'verba' TEXT, 'verbb' TEXT);
INSERT INTO 'verb' VALUES …
And so on...
But I get the error:
Problem with prepare statement 1: file is encrypted or is not a database
Help would be much appreciated! (-:
Try to write your sampledb.sql into the documents directory instead of the bundle directory :
// Getting the documents directory path
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Getting your db's path
NSString *dbPath = [docsDir stringByAppendingPathComponent:#"sampledb.sql"];
There's no way to write into the bundle directory because it's code signed with SSL certificate. But the documents directory's not.
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 SQLite database for my app. To retrieve the entities from the db I use this method:
- (sqlite3*) openDatabaseNamed:(NSString*)databaseName
{
if(![databaseName isEqualToString:kTopInternationalDatabaseName] &&
![databaseName isEqualToString:kTop500RODatabaseName]){
NSAssert(nil, #"Database does not exist!");
}
sqlite3 * dataBase;
NSString * path;
path = [[NSBundle mainBundle] pathForResource:databaseName ofType:#"sqlite3"];
if (sqlite3_open([path UTF8String], &dataBase) != SQLITE_OK) {
NSString * errorString = [NSString stringWithFormat:#"[SQLITE] Unable to open database <%#> ",databaseName];
NSAssert(nil,errorString);
}
return dataBase;
}
- (NSArray *) getAllEntitiesForDatabaseNamed:(NSString*)databaseName
{
(...)
sqlite3 * database = [self openDatabaseNamed:databaseName];
NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM %#",databaseName];
NSArray *properties = [entityClass classProperties];
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
for (int i=2; i<countLimit; i++){
chars = (char *) sqlite3_column_text(statement,i+1);
if(chars != NULL)
{
containerString = [NSString stringWithUTF8String:chars];
if(containerString && containerString.length>0){
[entityModel setValue:containerString forKey:properties[i]];
}
}
}
[retval addObject:entityModel];
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return retval.copy;
}
Everything works as expected. For setting a custom field for an entity to a specific value in the database I use this method:
- (void)setEntity:(EntityModel *)entity favorite:(BOOL)favorite
{
NSString *query = [NSString stringWithFormat:#"UPDATE %# SET favorite = %i WHERE position = '%i';",kDatabaseName,favorite?1:0,entity.positionInTop];
sqlite3_stmt *statement;
sqlite3 * database = [self openDatabaseNamed:kTop500RODatabaseName];
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK) {
sqlite3_step(statement);
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
What is happening is a little weird. If I use the update method and in the same lifecycle of the app query for all entities using getAllEntitiesForDatabaseNamed the changes I did with setEntity:Favorite: persist. On the other hand, if I use the update method, then turn off the app and restart it, the changes I did using setEntity:Favorite: are lost. Any idea on why is that?
PS: I also tried using sqlite3_exec and still the results are the same:
if (sqlite3_exec(database, [query UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
// deal with error...
NSLog(#" -- ERROR!");
}
The problem is that you're opening the database in the bundle, which is read only (on a device, at least). You should, instead, check to see if the database exists in your Documents folder, if not, copy it there from the bundle, and then open the database from the Documents folder.
Thus, you might do something like:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:databaseName ofType:#"sqlite"];
NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *documentsPath = [[documentsFolder stringByAppendingPathComponent:databaseName] stringByAppendingPathExtension:#"sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:documentsPath]) {
NSError *error = nil;
BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error];
NSAssert(success, #"%s: copyItemAtPath failed: %#", __FUNCTION__, error);
}
Having done that, you can now proceed to open the database at documentsPath.