I have written a delete query in method applicationDidEnterBackground of AppDelegate class. But when i stop the simulator it does not delete the database table. I want to delete the database tables when the app enters in the background or when the app terminates. Here is my applicationDidEnterBackground method for delete table query.
- (void)applicationDidEnterBackground:(UIApplication *)application {
sqlite3 *database;
NSArray * dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* docsDir = [dirPaths objectAtIndex:0];
NSString * databasePath = [docsDir stringByAppendingPathComponent:#"sssw.sqlite"];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSString *sqlStatement_userInfo =[NSString stringWithFormat:#"DELETE * from SHOPDATA"];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement_userInfo UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#"table deleted");
}
else
{
NSLog(#"Unable to delete table");
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
please tell me what should i do and what am i doing wrong here.
Any help will be appreciated.
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 am trying to delete the data from my table view.The data is coming from the database.
if (editingStyle == UITableViewCellEditingStyleDelete) {
DetailData *datatoDelete;//=[DetailData new];
datatoDelete= dataArray[indexPath.row];
NSLog(#"ID at selected row is %#",datatoDelete.ID);
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc]
initWithString: [docsDir stringByAppendingPathComponent:
#"MYDat.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &myDatabase) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"DELETE FROM ABC WHERE ID=%#",datatoDelete.ID];
// i tried ID='%#' too
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(myDatabase, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSLog(#"statement deleted successfully"); // i am seeing this statement when i click delete
}
sqlite3_finalize(statement);
sqlite3_close(myDatabase);
}
// [dataArray removeObjectAtIndex:indexPath.row];
[tableView reloadData];
}
Here when I click on delete, i am getting "the statement data deleted successfully" but,when I check the database file after the delete operation, the data still exists there.Could anyone tell me whats wrong in here?
The sqlite3_prepare_v2 only prepares a statement, you need to use sqlite3_step for executing it.
if (sqlite3_prepare_v2(myDatabase, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if(sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"statement deleted successfully");
}
}
For referece:
sqlite_step
Evaluate An SQL Statement
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.
hi i'm getting stuck with some code. i have a file catalog.db and a class that let me work with it. When i try to retrieve datas from the db it seems like it's empty. With several nslog i can see that it connect and enter the database, i can see it enter in it but then it won't get any value from it.
i tried to see if the query was wrong with an external DB manager software and the query works fine...
this is my class
#import "DBAccess.h"
sqlite3* database;
#implementation DBAccess
-(id)init{
self = [super init];
if (self){
[self initializeDatabase];
}
return self;
}
-(void)initializeDatabase{
NSString *path = [[NSBundle mainBundle]pathForResource:#"catalog" ofType:#"db"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) { NSLog(#"Opening Database"); }
else {
sqlite3_close(database);
NSAssert1(0, #"FAILED to open database '%s'", sqlite3_errmsg(database));
}
}
-(void)closeDatabase{
if (sqlite3_close(database) != SQLITE_OK){
NSAssert1(0, #"ERROR to close databse: '%s'", sqlite3_errmsg(database));
}
}
-(NSMutableArray *)getAllProduct{
NSMutableArray *products = [[NSMutableArray alloc]init];
const char *sql = "SELECT product.ID,product.Name, Manufacturer.name, product.details,product.price, product.quantityOnHand,country.country,product.image FROM product,manufacturer,country WHERE manufacturer.manufacturerID = product.manufacturerID and product.countryOfOriginID = country.countryID";
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
NSLog(#"sqlResult: %d", sqlResult);
if (sqlResult == SQLITE_OK){
NSLog(#"sql step statement: %d",sqlite3_step(statement));
NSLog(#"QUERY DONE");
while (sqlite3_step(statement) == SQLITE_ROW){
NSLog(#"TEST");
Product *product = [[Product alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSLog(#"n %s",name);
char *manufacturer = (char *)sqlite3_column_text(statement, 2);
NSLog(#"m %s", manufacturer);
char *details = (char *)sqlite3_column_text(statement, 3);
NSLog(#"d %s", details);
char *countryoforigin = (char *)sqlite3_column_text(statement, 6);
NSLog(#"%s", countryoforigin);
char *image = (char *)sqlite3_column_text(statement, 7);
NSLog(#"%s", image);
product.ID = sqlite3_column_text(statement, 0);
product.name = (name)?[NSString stringWithUTF8String:name]:#"";
product.manufacturer = (manufacturer)?[NSString stringWithUTF8String:manufacturer]:#"";
product.details = (details)?[NSString stringWithUTF8String:details]:#"";
product.price = sqlite3_column_double (statement, 4);
product.quantity = sqlite3_column_int(statement, 5);
product.countryOfOrigin = (countryoforigin)?[NSString stringWithUTF8String:countryoforigin]:#"";
product.image = (image)?[NSString stringWithUTF8String:image]:#"";
[products addObject:product];
}
sqlite3_finalize(statement);
}
else {
NSLog(#"Problem with database %d",sqlResult);
}
return products;
}
#end
this is what i get in my console
2013-08-14 12:38:58.505 Catalog[1642:c07] Opening Database
2013-08-14 12:38:58.508 Catalog[1642:c07] sqlResult: 0
2013-08-14 12:38:58.509 Catalog[1642:c07] sql step statement: 101
2013-08-14 12:38:58.509 Catalog[1642:c07] QUERY DONE
2013-08-14 12:38:58.510 Catalog[1642:c07] ()
what can be my problem? thanks
Here
NSLog(#"sql step statement: %d",sqlite3_step(statement));
you fetch already the first row (without using the result).
1)Copy the database to your documents directory...
-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
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:#"test.sqlite"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
2)Then talk to database in this way.
-(void)sqliteTransaction
{
sqlite3 *database;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
// Init the animals Array
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from me";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSLog(#"%#",aName);
// Create a new animal object with the data from the database
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
Try like this, before going to SELECT make sure the table is properly connected for selection with the open query like this
sqlite3_open(dbpath, &ProDB)
After that execute your selection. See this below sample code. Hope it will help
ex:
NSMutableArray *sessionDetails = [NSMutableArray array];
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"cPro.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &ProDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT * FROM USER_SESSION_INFO"];
NSLog(#"query: %#",querySQL);
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(ProDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
// Your functionality.
}
}
}
i tried the method you guys suggested but i still get the same problem.
i think i found out what's causing it.
i changed my query with this:
const char *sql = "SELECT product.ID,product.Name, product.details,product.price, product.quantityOnHand,product.image FROM Product";
and this way it works... so it looks like i have trouble reading other tables...
the moment i add another table it stop working. but that's weird cause with external db manager software the query works just fine
I have an SQLite database, I can open it with SQLite browser, execute queries to it etc. But I can't get any data from it in my Xcode project.
NSString *databaseName = #"dbFile.db";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"db is ok"); // works just fine
const char *sqlStatement = "SELECT table.column FROM table";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
NSLog(#"OK"); // nothing happens
}
sqlite3_close(database);
}
The very same query executed from SQLite browser for Mac works just fine.
sqlite3_open doesn't report all errors until you start accessing the data. For example just about any filename and path will pass without errors.
Are you sure the database is in the Documents folder? It's not there by default.
Perhaps it's in the main bundle?
Try
NSString *databaseName = [[NSBundle mainBundle] pathForResource:#"dbFile" ofType:#"db"];