Nesting of Sql Statements - ios

Hi i have made a function in my app delegate to remove the redundancy of my database , I am not sure do i have coded right as i have to perform nesting of SQL statements to find out the error in DB.
Can any body suggest me where i am wrong because the application is running well in simulator and crashing in Device.
I am even Not Sure where to Put finalize and sqlite3_close . Kindly help
-(void) removeRedundancy2
{
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
dbPathString = [[docPaths objectAtIndex:0] stringByAppendingPathComponent:#"turfnutritiontool_ver_99.db"];
sqlite3_stmt *selectStmt;
sqlite3_stmt *selectStmt1;
BOOL isMyFileThere = [[NSFileManager defaultManager] fileExistsAtPath:dbPathString];
if (isMyFileThere)
{
if (sqlite3_open([dbPathString UTF8String], &database1)==SQLITE_OK)
{
// TO REMOVE FROM from tnt_scenario_product when NO ProductID Found
NSString *querySql2= [NSString stringWithFormat:#"SELECT productid from tnt_scenarioproduct"];
const char* query_sql2 = [querySql2 UTF8String];
if(sqlite3_prepare_v2(database1, query_sql2, -1, &selectStmt, NULL) == SQLITE_OK)
{
while (sqlite3_step(selectStmt) == SQLITE_ROW)
{
int productid = sqlite3_column_int(selectStmt, 0);
// NSLog(#"ProductId1 =%d",productid);
NSString *querySql21= [NSString stringWithFormat:#"SELECT productid from tnt_productcontent WHERE productid = %d",productid];
const char* query_sql21 = [querySql21 UTF8String];
if(sqlite3_prepare_v2(database1, query_sql21, -1, &selectStmt1, NULL) == SQLITE_OK)
{
if (sqlite3_step(selectStmt1) == SQLITE_ROW)
{
// DO NOTHING
}
else
{ // to delete scenario without product id
NSLog(#"Delete this Product from TPC 2 %d",productid);
NSString *querydelete2= [NSString stringWithFormat:#"DELETE from tnt_scenarioproduct WHERE productid = %d",productid];
const char* query_delete2 = [querydelete2 UTF8String];
char *error;
sqlite3_exec(database1, query_delete2, NULL, NULL, &error);
NSLog(#"error=%s ",error);
sqlite3_finalize(selectStmt1);
}
}
sqlite3_finalize(selectStmt1);
sqlite3_close(database1);
}
sqlite3_finalize(selectStmt);
}
sqlite3_close(database1);
}
sqlite3_close(database1);
}
}

After calling sqlite3_open, you must call sqlite3_close for that connection exactly once.
After calling sqlite3_prepare_v2, you must call sqlite3_finalize for that statement exactly once.
if (sqlite3_open([dbPathString UTF8String], &database1)==SQLITE_OK)
{
...
if(sqlite3_prepare_v2(database1, query_sql21, -1, &selectStmt1, NULL) == SQLITE_OK)
{
...
}
sqlite3_finalize(selectStmt);
....
}
sqlite3_close(database1);
Furthermore, you should not reuse the same variable (selectStmt) for two different queries to prevent confusion about its lifetime.

Related

while (sqlite3_step(statement) == SQLITE_ROW) Loop is not working

I had debugged code but don't know why While statement is not executing . After putting NSlog I came to know it's mismatching the result. 101 and SQLITE_ROW is equal to 100.
But query has result. If I fetch Select * from table name its returning me result and while statement executes. If I fetch result
sql_stmt = [NSString stringWithFormat:#"SELECT * FROM DeviceType WHERE upper(TypeName) = upper('%#')", deviceType];
While statement never execute so please help. don't know where is the problem.
Here is the code:
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:#"ClientDB.sqlite"];
NSString* sql_stmt = [self searchStringForLocalData];
BOOL found = NO;
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
const char* sql1 = [sql_stmt UTF8String];
sqlite3_stmt *statement;
NSNumber *typeCount;
typeCount = 0;
if (sqlite3_prepare_v2(database, sql1, -1, &statement, NULL) == SQLITE_OK)
{
NSLog(#" %d, %d ",sqlite3_step(statement),SQLITE_ROW);
while (sqlite3_step(statement) == SQLITE_ROW) {
// The second parameter indicates the column index into the result set.
int primaryKey1 = sqlite3_column_int(statement, 0);
NSNumber *typeId = [[NSNumber alloc] initWithInt:primaryKey1];
NSString *typeName =[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
NSString* sql_stmt1 = [NSString stringWithFormat:#"SELECT COUNT(*) FROM Devices WHERE DeviceTypeId =%d",primaryKey1];
const char *sql1 = [sql_stmt1 UTF8String];
sqlite3_stmt *statement;
NSNumber *typeCount;
typeCount = 0;
As already mentioned in a comment, the code calls sqlite3_step once for the NSLog, and then a second time in the condition of the while loop.
If your query returns exactly one record, the first sqlite3_step call will step to that record, and the second sqlite3_step call will then report (correctly) that no further results are available.
Just remove that NSLog call.
Alternatively, call sqlite3_step only once, and use the same return value for both the logging and the loop:
int rc;
...
while (1) {
rc = sqlite3_step(statement);
NSLog(#" %d, %d ", rc, SQLITE_ROW);
if (rc != SQLITE_ROW)
break;
...
}
if (rc != SQLITE_DONE)
NSLog(#"error: %s", sqlite3_errmsg(database));
Try to use the following syntax
while(sqlite3_step(stmt)!=SQLITE_DONE)
{
//do ur processing
for(i=0;i<NO_OF_COLS;i++)
{
char * tmp1=sqlite3_column_text(stmt,i);
if(tmp1!=NULL)
{
//use the value
}
else
{
//use a default
}
}
}
It shows that your table is totally empty. You may want to check your insert whether it works correctly. If you're using sqlite3_prepare_v2 to prepare your statement with some ? marks, remember to execute your query after all. Simply like this:
if(sqlite3_step(stmt) == SQLITE_DONE) NSLog(#"INSERTED");
else NSLog(#"NO INSERTED");
Note: It will display error only if your query is wrong, but not your prepared statement was executed or not.

Communication of the database

I am working with the communication of sqlite database from one viewcontroller to another, but some how i am not getting the database on the second view controller. Bellow is the code which i am using for it.:-
On First View controller
//Creating a table of MOtivational Thoughts
dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPath objectAtIndex:0];
Second.databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent:#"S.H.E.D_DB"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([ filemgr fileExistsAtPath: Second.databasePath] == NO) {
const char *dbpath = [Second.databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt =
"CREATE TABLE IF NOT EXISTS THOUGHTS (ID integer ,Motivation_Thaought TEXT)";
if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table");
}
else
{
NSLog(#" created table");
}
sqlite3_close(contactDB);
} else {
}
}
// Fetching Data from table of MOtivational Thoughts
if(sqlite3_open([Second.databasePath UTF8String], &contactDB) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
int randomNumber = [self getRandomNumberBetween:0 to:6];
NSString *queryString = [NSString stringWithFormat:#"Select * FROM THOUGHTS where ID= '%d'",randomNumber];
const char* sql = [queryString UTF8String];
NSLog(#"path value : %#", Second.databasePath);
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(contactDB, sql, -1, &compiledStatement, nil)==SQLITE_OK) {
// Loop through the results and add them to the feeds array
NSLog(#"Ready to enter while loop");
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSLog(#"reading");
NSString *aid = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
motivationView.text = aid;
NSLog(#"Thought of the day %#", aid);
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(contactDB);
// Do any additional setup after loading the view from its nib.
}
On Second View Controller
NSLog(#"path value : %#", databasePath);
if(sqlite3_open([databasePath UTF8String], &contactDB) == SQLITE_OK){
char *errMsg;
const char *sql_stmt =
"CREATE TABLE IF NOT EXISTS SHEDSLIST (SHED_ID integer ,SHED_Name TEXT ,SHED_Description TEXT, SHED_TIME DATETIME)";
if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table");
}
else
{
NSLog(#" created table");
}
sqlite3_close(contactDB);
} else {
}
PLease locate my error and give me sutable solution.
May be you should access the database path as self.databasePath in SecondViewController because I believe you have created a property for that. Instead of that you are trying to access some instance variable databasePath. Look at your following code in FirstViewController:
Second.databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent:#"S.H.E.D_DB"]];

Issue in deleting raw from table sqlite

this is what i am doing in header
static sqlite3 *database = nil;
static sqlite3_stmt *deleteStmt = nil;
#implementation SQLAppDelegate
#synthesize window;
#synthesize navigationController;
#synthesize coffeeArray;
this is what i am using for deleting raw
- (void) removeCoffee:(NSNumber *)coffeeObj {
NSLog(#"coffeeObj%#",coffeeObj);
int myInteger = [coffeeObj integerValue];
NSLog(#"myInteger%d",myInteger);
// print this myInteger0
NSLog(#"%#",coffeeArray);
//print object
if (sqlite3_open([self getDBPath], &database) == SQLITE_OK)
{
NSLog(#"myInteger%#",[self getDBPath]);
NSString *sql = [NSString stringWithFormat: #"delete from Coffee where CoffeeID =%d",myInteger];
const char *del_stmt = [sql UTF8String];
NSLog(#"%#",del_stmt); // getting print
// print this delete from Coffee where CoffeeID =0.
sqlite3_prepare_v2(database, del_stmt, -1, & deleteStmt, NULL);
NSLog(#"sqlite3_step(deleteStmt) == SQLITE_DONE%#",sqlite3_step(deleteStmt) == SQLITE_DONE);
// this print null
if (sqlite3_step(deleteStmt) == SQLITE_DONE)
{
//NSLog(#"hi") this is not getting print
} else {
//NSLog(#"hi") this is getting print
}
sqlite3_finalize(deleteStmt);
sqlite3_close(database);
[coffeeArray removeObjectAtIndex:myInteger];
NSLog(#"%#",coffeeArray);
// object is deleted
}
}
my table is like below
table name = Coffee
CoffeeID(INTEGER)=0
CoffeeName(VARCHAR)=Latte
Price(REAL)=2.99
where thing runs perfectly object get deleted from array and thats why its not appearing on table cell. but its not getting deleted from database table thats why it when i launch app again then it shows again please help what i am doing wrong.
Before start deleting the object just conform once the database is opened properly or not. Just try like this.
//Setting path
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"database.db"]];
const char *dbpath=[databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *sql = [NSString stringWithFormat: #"delete from Coffee where CoffeeID =%d",myInteger];
const char *del_stmt = [sql UTF8String];
sqlite3_prepare_v2(database, del_stmt, -1, & deleteStmt, NULL);
if (sqlite3_step(deleteStmt) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(deleteStmt);
sqlite3_close(database);
[coffeeArray removeObjectAtIndex:myInteger];
NSLog(#"%#",coffeeArray);
// object is deleted
}
if(sqlite3_open([[self filepath] UTF8String], &db) == SQLITE_OK)
{
Deletestatement = nil;
if(Deletestatement == nil)
{
const char *sql = "delete from Sqlitemanager2;";
if(sqlite3_prepare_v2(db, sql, -1, &Deletestatement, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating delete statement. '%s'", sqlite3_errmsg(db));
}
if (SQLITE_DONE != sqlite3_step(Deletestatement)) //prathibha for problem in if
NSAssert1(0, #"Error while deleting. '%s'", sqlite3_errmsg(db));
sqlite3_finalize(Deletestatement);
}
I hope this will help you.

SQLite3 library routine called out of sequence

the following code give me an library routine called out of sequence error, but I can't explain me where is the problem. Any ideas ?
- (BOOL)insertProduct:(Product *)product inOrder:(Order *)order withAmount:(int)amount
{
BOOL ok = NO;
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_database) == SQLITE_OK)
{
NSString * insertSQL;
int amount = [self getAmountForProduct:product inOrder:order];
NSLog(#"%i", amount);
if (amount != -1)
{
insertSQL = [NSString stringWithFormat: #"UPDATE ARTICOLIPERORDINE SET quantita = %i WHERE ordine = %i AND articolo = '%#'", amount, order.idOrdine, product.codice];
}
else
{
insertSQL = [NSString stringWithFormat: #"INSERT INTO ARTICOLIPERORDINE (ordine, articolo, quantita) VALUES(%i, '%#', %i)",order.idOrdine, product.codice, 1];
}
NSLog(#"%#", insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
if (sqlite3_prepare_v2(_database, insert_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_DONE)
{
ok = YES;
}
else
{
ok = NO;
NSLog(#"sqlite3 ERROR %s: %#",sqlite3_errmsg(_database), insertSQL);
}
sqlite3_finalize(statement);
sqlite3_close(_database);
}
else
{
NSLog(#"Error prepare = %s", sqlite3_errmsg(_database));
}
}
return ok;
}
The log print Error prepare = library routine called out of sequence
I have one approach.
Before this make sure that you have completed all your sql queries like connection open, close, finalize etc.
Before run your query actual into your code, execute that query into any database browser, You will see what is missing in your query.
As in my case I wrongly put the column name in query and run the code and I got the error multiple times. I review all the code carefully and execute the query into database browser and I found my mistake.

what does if exist return

I am using sqlite3 as my database for ios project and would like to execute if exist statement to see whether the object exists and if does, update or else insert.
I am using this function to query the database
-(void)updateStatus:(NSString *)queryString {
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
m_singleton = [Singleton sharedSingleton];
strDatabasePath = [NSString stringWithString:[docsDir stringByAppendingPathComponent:#"BorneoMotors.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: strDatabasePath] == YES)
{
const char *dbpath = [strDatabasePath UTF8String];
if (sqlite3_open(dbpath, &sqlDatabase) == SQLITE_OK)
{
const char* beginString = "BEGIN;";
sqlite3_stmt *compiledstatement;
sqlite3_prepare_v2(sqlDatabase, beginString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
NSLog(#"QUERY : %#",queryString);
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &compiledstatement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
const char* endString="END;";
sqlite3_prepare_v2(sqlDatabase, endString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
sqlite3_close(sqlDatabase);
}
else NSLog(#"Failed to open table");
}
}
The problem i have is that what this if exists will return and how do i move upon that.
NSString *checkstring = [NSString stringWithFormat:#"IF EXISTS (SELECT * FROM DATABASE WHERE id = %#",cars.ID];
DB *accessdb = [[DB alloc] init];
[accessdb updateStatus:checkstring];
if (??){
NSString *queryString = [NSString stringWithFormat: #"UPDATE DATABASE SET STATUS='%#' WHERE \"DATABASEID\" = '%#'", cars.status,cars.ID];
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &statement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(statement);
}else{
insert}
How do i check whether the existence of the object? What does the if exists return? Need some guidance...
SQLite does not have an IF statement.
To check whether some record exist, just execute a query like
SELECT 1 FROM database WHERE ID = ?
and test in your app whether or not you get back a record.
For your update/insert problem: If you have a unique index on the key colum, you could use the INSERT OR REPLACE command which automatically deletes the old record if the new one would create a duplicate.

Resources