I am unable to delete the tables from sqlite database using DROP TABLE query. Have tried all possible solutions such as [database openCloseResultSet], [resultSet close] and so on. But adding these lines results in out of memory error and if i dont write these lines then my program just stops at the drop table statement. There is no warning or error given too.Even if i put the code in debug, my debug point just goes away once this line is executed.I am using FMDatabase library while working with process related to sqlite.I am unable to find out the cause of this issue.
Have tried these links too but they are not working in my case.
1)FMDB executeUpdate DROP command does halt the app
2)How to remove all data from table using FMDB
Here is my code where the issue prevails.
+ (NSString *) deleteTable:(NSInteger) index{
NSString *returnFlag = #"success";
FMDatabase *database = nil;
#try {
NSString *query = #"select name from sqlite_master where type = 'table'";
database = [FMDatabase databaseWithPath:[DBOperator getDataBasePath:DATABASENAME]];
if(database != nil && [database open])
{
FMResultSet *resultSet = [database executeQuery:query];
while ([resultSet next]) {
NSString *temp = [resultSet stringForColumnIndex: 0];
if (index == DELETE_TYPE_ONE &&
([temp equalsIgnoreCase: TBUPW] ||
[temp equalsIgnoreCase: TBCVR] ||
[temp equalsIgnoreCase: TBCNTRLNO])) {
[database executeUpdate:[NSString stringWithFormat:#"DROP TABLE %#", temp]];
}else if(index == DELETE_TYPE_TWO && [temp hasPrefix:#"txn"]){
[database executeUpdate:[NSString stringWithFormat:#"DROP TABLE %#", temp]];
}else if(index == DELETE_TYPE_THREE &&
([temp hasPrefix:#"t"] ||
[temp hasPrefix:#"T"] ||
[temp hasPrefix:#"ob"] ||
[temp hasPrefix:#"fb"] ||
[temp hasPrefix:#"cp"])){
NSlog("This is printed in console");
[database executeUpdate:[NSString stringWithFormat:#"DROP TABLE %#", temp]];
NSLog("This is not printed in console");
}else if(index == DELETE_TYPE_FOUR && [temp equalsIgnoreCase:#"TBPLAN"]){
[database executeUpdate:[NSString stringWithFormat:#"DROP TABLE %#", temp]];
}
}
}
}
#catch (NSException *exception) {
returnFlag = #"error";
}
#finally {
[database close];
}
return returnFlag;
}
you can use this query.
DROP TABLE YOUR_TABLE_NAME;
or you can use this
DELETE FROM YOUR_TABLE_NAME;
As for me following code works, maybe it'll give you a hint:
#property (nonatomic, strong, readonly) FMDatabaseQueue *database;
__block BOOL finishedSuccessfully = YES;
[database inTransaction:^(FMDatabase *db, BOOL *rollback) {
// firstly let's remove the table:
[db closeOpenResultSets];
FMResultSet *deleteResultSet = [db executeQuery:#"DROP TABLE myTableName"];
if ([deleteResultSet next]) {}
[deleteResultSet close];
finishedSuccessfully = !db.lastErrorCode && finishedSuccessfully; // breakpoint after this line
// then let's perform anything on the db:
FMResultSet *select = [db executeQuery:#"SELECT row FROM myTableName WHERE anotherRow = ?", #{2}];
finishedSuccessfully = !db.lastErrorCode && finishedSuccessfully; // breakpoint after this line
}
I don't have an error after the first part, but second part returns something like "there is no such table as myTableName".
Related
I've added FMDB/SQLCipher (2.7.5) to my app by cocoapods.
use_frameworks!
pod 'FMDB/SQLCipher'
And perform the code bellow:
- (void)decryptDBAtPath:(NSString *)path withKey:(NSString *)key {
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
[queue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
BOOL result = [db setKey:key];
NSLog(#"decrypt db %#", result ? #"success" : #"failed");
//it always return YES.
NSString *sql = #"SELECT * FROM PTypeImage";
FMResultSet *rs = [db executeQuery:sql];
NSDictionary *dic = [rs resultDictionary];
NSLog(#"query test with result : %#", dic);
//query can not by executed. 'file is not a database'.
}];
}
It's always return decrypt success, but query failed.
Any wrong in my code?
I also tryed encryption by FMDB. It seems failed. Returns encrypt success, but can be open without key.
- (void)enryptDBAtPath:(NSString *)path withKey:(NSString *)key {
FMDatabase *db = [FMDatabase databaseWithPath:path];
if ([db open]) {
BOOL result = [db rekey:key];
//always return YES.
NSLog(#"encrypt db %#", result ? #"success" : #"failed");
[db close];
}
}
Here is the code which I'm using to insert a record into a sqlite table
FMDatabase *dataBase = [self openDatabase];
[dataBase open];
if ([dataBase open] != YES) {
NSLog(#"DB Error %d: %#", [dataBase lastErrorCode], [dataBase lastErrorMessage]);
//VERY IMPORTANT
}
BOOL success= [dataBase executeUpdate:#"Insert into CrewUnits (pkCrewUnits,fkUnits,fkAgencyVehicles,fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, PrimaryUnit) values (?, ?, ?, ?, ?, ?);", pkCrewUnits, fkUnits, fkAgencyVehicle, fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, [NSNumber numberWithInt:1]];
NSLog(success ?#"YES" :#"NO");
NSLog(#"Error %d: %#", [dataBase lastErrorCode], [dataBase lastErrorMessage]);
FMResultSet*resultSet= [dataBase executeQuery:#"select * from CrewUnits"];
NSLog(#"ResultSet : %#", [resultSet resultDictionary]);
[dataBase close];
Database Path
- (FMDatabase *)openDatabase
{
NSLog(#"Open Database");
NSString *documents_dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *db_path = [documents_dir stringByAppendingPathComponent:[NSString stringWithFormat:#"HPSix_05BD.db"]]; // DatabasePath
FMDatabase *db = [FMDatabase databaseWithPath:db_path];
if (![db open])
NSLog(#"Failed to open database!!!!!");
return db;
}
I'm using the same logic to fetch data from table that works fine for me. But I can't insert a record. I don't know what I'm doing wrong here.
Two problems:
You are calling open three times. Once in openDatabase and twice in the code that called it.
So, have your open routine open the database if it can, but return nil if it can't:
- (FMDatabase *)openDatabase
{
NSLog(#"Open Database");
NSString *documents_dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *db_path = [documents_dir stringByAppendingPathComponent:[NSString stringWithFormat:#"HPSix_05BD.db"]]; // DatabasePath
FMDatabase *db = [FMDatabase databaseWithPath:db_path];
if (![db open]) {
NSLog(#"Failed to open database!!!!!");
return nil;
}
return db;
}
Then check that result:
FMDatabase *dataBase = [self openDatabase];
if (!dataBase) {
// quit; note, no point in checking error message as it only returns meaningful messages if you have an open database
}
After calling executeQuery, you have to call next.
FMResultSet *resultSet = [dataBase executeQuery:#"select * from CrewUnits"];
if ([resultSet next]) {
NSLog(#"ResultSet : %#", [resultSet resultDictionary]);
} else {
NSLog(#"No data found");
}
I think I see the problem. You are committing after running the SELECT query.
You have to commit right after the UPDATE query. When you do it like you have now when selecting, the UPDATE query has not been committed and thus will not be returned.
[dataBase beginTransaction];
BOOL success= [dataBase executeUpdate:#"Insert into CrewUnits (pkCrewUnits,fkUnits,fkAgencyVehicles,fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, PrimaryUnit) values (?, ?, ?, ?, ?, ?);", pkCrewUnits, fkUnits, fkAgencyVehicle, fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, [NSNumber numberWithInt:1]];
[dataBase commit]; // commit the query
NSLog(success ?#"YES" :#"NO");
NSLog(#"Error %d: %#", [dataBase lastErrorCode], [dataBase lastErrorMessage]);
// now at this point the transaction has been committed and can be selected
FMResultSet*resultSet= [dataBase executeQuery:#"select * from CrewUnits"];
NSLog(#"ResultSet : %#", [resultSet resultDictionary]);
Also according to FMDB docs:
The parameters must start with a colon. SQLite itself supports other
characters, but internally the Dictionary keys are prefixed with a
colon, do not include the colon in your dictionary keys.
Thus this line of code must be rewritten to:
BOOL success= [dataBase executeUpdate:#"Insert into CrewUnits (pkCrewUnits,fkUnits,fkAgencyVehicles,fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, PrimaryUnit) values (:pkCrewUnits,:fkUnits,:fkAgencyVehicles,:fkLookupCodes_PrimaryRole, :fkLookupCodes_LevelOfCare, :PrimaryUnit);", pkCrewUnits, fkUnits, fkAgencyVehicle, fkLookupCodes_PrimaryRole, fkLookupCodes_LevelOfCare, [NSNumber numberWithInt:1]];
Lastly according to the docs you use next for looping through the results:
while ([resultSet next]) {
//retrieve values for each record
}
my problem is that i am trying to connect my database to sqlite . it always with an error "table not found".. what should i do now .. plz help
here is my code for opendatabaseconnectivity....
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK) {
// Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
sqlite3_stmt *compiledStatement;
// Load all data from database to memory.
BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
if(prepareStatementResult == SQLITE_OK) {
// Check if the query is non-executable.
if (!queryExecutable){
// In this case data must be loaded from the database.
// Declare an array to keep the data for each fetched row.
NSMutableArray *arrDataRow;
// Loop through the results and add them to the results array row by row.
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Initialize the mutable array that will contain the data of a fetched row.
arrDataRow = [[NSMutableArray alloc] init];
// Get the total number of columns.
int totalColumns = sqlite3_column_count(compiledStatement);
// Go through all columns and fetch each column data.
for (int i=0; i<totalColumns; i++){
// Convert the column data to text (characters).
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
// If there are contents in the currenct column (field) then add them to the current row array.
if (dbDataAsChars != NULL) {
// Convert the characters to string.
[arrDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
// Keep the current column name.
if (self.arrColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
// Store each fetched data row in the results array, but first check if there is actually data.
if (arrDataRow.count > 0) {
[self.arrResults addObject:arrDataRow];
}
}
}
else {
// This is the case of an executable query (insert, update, ...).
// Execute the query.
BOOL executeQueryResults = sqlite3_step(compiledStatement);
if (executeQueryResults == true) {
// Keep the affected rows.
self.affectedRows = sqlite3_changes(sqlite3Database);
// Keep the last inserted row ID.
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
}
else {
// If could not execute the query show the error message on the debugger.
NSLog(#"DB Error: %s", sqlite3_errmsg(sqlite3Database));
}
}
}
else {
// In the database cannot be opened then show the error message on the debugger.
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
// Release the compiled statement from memory.
sqlite3_finalize(compiledStatement);
}
// Close the database.
sqlite3_close(sqlite3Database);
}
Before accessing your database, have you copied it into document directory ?
Like this :
static sqlite3 *database = nil;
+ (void)openDatabase
{
[self copyDatabaseIfNeeded];
(sqlite3_open([[self getDBPath] UTF8String],&database));
}
+ (NSString *)getDBPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSLog(#"%#",documentsDir);
return [documentsDir stringByAppendingPathComponent:#"databaseName.sqlite"];
}
+ (void)copyDatabaseIfNeeded
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
NSLog(#"dbpath=%#",dbPath);
if(!success)
{
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databaseName.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message \"%#\".", [error localizedDescription]);
}
}
Also check that the table which you are going to access is created in database before use.
This the my code
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
// [self.dbManager executeQuery:query1];
// -(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable
NSLog(#"q1--%#",query1);
BOOL recordExist = [self.dbManager recordExistOrNot:query1];
NSLog(#"------%d",recordExist);
if (!recordExist)
{
NSString *query;
if (self.recordIDToEdit == -1) {
query = [NSString stringWithFormat:#"insert into c values(null,'%#','%d','%d',%d)",item_name.text,a,p,c];
NSLog(#"query---%#",query);
}
// Execute the query.
[self.dbManager executeQuery:query];
// If the query was successfully executed then pop the view controller.
if (self.dbManager.affectedRows != 0) {
NSLog(#"Query was executed successfully. Affected rows = %d", self.dbManager.affectedRows);
// UIAlertView *alert=[[UIAlertView alloc]initWithTitle:Nil message:#"Successfully Added to The Cart" delegate:Nil cancelButtonTitle:#"ok" otherButtonTitles:Nil, nil];
// [alert show];
[self loadData];
}
else{
NSLog(#"Could not execute the query.");
}
}
else
{
NSLog(#"item already exits....");
}
- (BOOL)recordExistOrNot:(NSString *)query1{
sqlite3 *sqlite3Database;
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
sqlite3_stmt *compiledStatement;
BOOL recordExist=NO;
if(sqlite3_open([databasePath UTF8String], &sqlite3Database) == SQLITE_OK)
{
// sqlite3_stmt *statement;
if (sqlite3_prepare_v2(sqlite3Database,[query1 UTF8String], -1, &compiledStatement, NULL)==SQLITE_OK)
{
if (sqlite3_step(compiledStatement)==SQLITE_ROW)
{
recordExist=YES;
}
else
{
//////NSLog(#"%s,",sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
sqlite3_close(sqlite3Database);
}
}
return recordExist;
}
actually i want to be check string value in the table like "select * from table name where item_name=tea"
but this code is checking integer value but i want check string value.please help me
You are missing the single quotes in you select statement. first line.
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name=%#",trimmedString];
to
NSString *query1 =[NSString stringWithFormat:#"select * from table name where item_name='%#'",trimmedString];
i'll assume that item_name is unique then you might be better served with doing insert or ignore.
i.e.
insert or ignore into tablename (item_name) values ('something')
thsi will ignore doing the insert if that value for your key exists
I have one method which accepts va_list like this:
+(NSUInteger) addObjectToDB:(NSString*)dbFilePath withSQL:(NSString*)sql, ... {
va_list args;
va_start(args, sql);
FMDatabaseQueue* dbQ = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];
__block NSUInteger result = -1;
[dbQ inDatabase:^(FMDatabase *db) {
[db open];
if ([db executeUpdate:sql, args]) {
result = (NSUInteger) [db lastInsertRowId];
}
[db close];
}];
va_end(args);
return result;
}
EDIT1:
I want to pass va_list(args) to the 'executeUpdate:' method of FMDatabase like this:
NSString* sql = [NSString stringWithFormat:#"Insert Into Table_Name Values (NULL, '%#', ?, ?)", #"string"];
[CXDBHelper addObjectToDB:self.dbFilePath withSQL:sql, NSData, NSData];
but the execution stopped in the method (FMDatabase.m) :
- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt {
if ((!obj) || ((NSNull *)obj == [NSNull null])) {
sqlite3_bind_null(pStmt, idx);
}
// FIXME - someday check the return codes on these binds.
else if ([obj isKindOfClass:[NSData class]]) {
at the last line without error message.
EDIT 2:
Thanks to #rmaddy's tips, I check the code executeUpdate:, it is defined as:
- (BOOL)executeUpdate:(NSString*)sql, ...
I realize that the problem is I cannot pass a va_list to it.
EDIT 3:
At last, I use another method which accept va_list: executeUpdate: withVAList: and everything is OK now.