while(sqlite3_step(statement) == SQLITE_ROW) loops never execute - ipad

hi all
i have some problem in using sqlite in IOS. i have select data from database, and then i want to save that data in a variable. But when i use while(sqlite3_step(statement) == SQLITE_ROW) loop, the code never execute.
here is my code :
-(void)retrieveProjectNameFromDb:(NSString *)segmenId{
NSString *query;
NSString *nameProjectStr;
NSString *dbPath = [[NSBundle mainBundle] pathForResource:#"database" ofType:#"sqlite"];
if (sqlite3_open([dbPath UTF8String], &db) != SQLITE_OK) {
sqlite3_close(db);
NSAssert(0, #"Database failed to open.");
}else {
query = [NSString stringWithFormat:#"SELECT remote_projectname, remote_base_uri FROM REMOTE_SETTING WHERE remote_settingid = '%#' ORDER BY remote_projectname", segmenId];
NSLog(#"query : %#", query);
}
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, nil)==SQLITE_OK){
NSLog(#"sqlite row : %d", SQLITE_ROW);
NSLog(#"sqlite 3 : %d", sqlite3_step(statement));
while (sqlite3_step(statement) == SQLITE_ROW) {
char *nameProject = (char *)sqlite3_column_text(statement, 0);
if (nameProject == nil) {
NSLog(#"UNNAMED");
}else {
NSLog(#"else");
nameProjectStr = [NSString stringWithUTF8String:nameProject];
}
projectName.text = nameProjectStr;
nameProject = nil;
}
NSLog(#"project name : %#", projectName.text);
sqlite3_close(db);
}
}
when i nslog the value, sqlite3_step(statement) always show 101 and sqlite_row always show 100. Why it can happen??
can somebody help me, please?
thank you
Regards
-risma-

As you mentioned sqlite3_step(statement) always show 101 which means sqlite3_step has finished executions hence it means your sql query is not returning any rows from database. I would recommend you to first check in database if any record exists in table REMOTE_SETTING for remote_settingid which you are referring.
For your reference I took following constant snippet from sqlite.org
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */

Remove the NSLog entry in which you are having sqlite3_step(). Since you have your NSLog statement executing sqlite3_step(), the record is already stepped through here. Hence, your while loop won't execute as there are no more rows to step through.
I think this will surely help you. :)

From your description of the logging output I would guess that your query is returning an empty row set. However I can see two other problems here:
You discard the result of your first call to sqlite3_step, because you log it then immediately call sqlite3_step again. That means you will miss the first row.
You probably should not be closing the database after a single query. You should finalize the statement after the query, but only close the database when your app shuts down.
Try:
if(sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, nil)==SQLITE_OK){
NSLog(#"sqlite row : %d", SQLITE_ROW);
int stepResult = sqlite3_step(statement);
NSLog(#"sqlite 3 : %d", stepResult);
while (stepResult == SQLITE_ROW) {
char *nameProject = (char *)sqlite3_column_text(statement, 0);
if (nameProject == nil) {
NSLog(#"UNNAMED");
}else {
NSLog(#"else");
nameProjectStr = [NSString stringWithUTF8String:nameProject];
}
projectName.text = nameProjectStr;
nameProject = nil;
stepResult = sqlite3_step(statement);
}
NSLog(#"project name : %#", projectName.text);
sqlite3_finalize(&statement);
}

Try with something like this..
sqlite3 *database1;
NSString *sqlStatement1 = #"";
if(sqlite3_open([databasePath UTF8String], &database1) == SQLITE_OK)
{
sqlStatement1 = [NSString stringWithString:#"SELECT uniqueid from shortlisted"];
sqlite3_stmt *compiledStatement1;
if(sqlite3_prepare_v2(database1, [sqlStatement1 cStringUsingEncoding:NSUTF8StringEncoding], -1, &compiledStatement1, NULL) == SQLITE_OK)
{
while(sqlite3_step(compiledStatement1) == SQLITE_ROW)
{
NSString * str = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
}
}
sqlite3_finalize(compiledStatement1);
sqlite3_close(database1);
}
Also close database instance whenever you open them.. if you are not closing an instance then that can cause issues..
Sorry I am pasting this from my project.. but actually I am in a bit hurry... I'll modify this answer when I reach home...

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.

How to retrieve value from SQLite database

I'm trying to get data from my DB but I have some problem.
Here is my code:
NSString *action=[[NSString alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol];
// Prepare the query for execution
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
// Create a new address from the found row
while (sqlite3_step(statement) == SQLITE_ROW) {
action = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)]; // fails on this line
}
sqlite3_finalize(statement);
return action;
}
(the parameter symbol come from outside)
When I run this, it fails at the line with the call to stringWithUTF8String with sqlite3_column_text results.
You probably want to collect the results in an NSMutableArray:
NSMutableArray *action = [[NSMutableArray alloc] init];
...
while (sqlite3_step(statement) == SQLITE_ROW) {
[action addObject:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)]];
}
...
You can then see what was collected later:
for (NSString *s in action) {
NSLog(#"%#", s);
}
EDIT As pointed out in #Rob's answer, the first column is 0, not 1.
In your call to sqlite3_column_text, you're using the index 1, but it takes a zero-based index. Use 0 instead of 1. See the SQLite sqlite_column_XXX documentation, which says:
The leftmost column of the result set has the index 0.
By the way, since stringWithUTF8String throws an exception if you pass it a NULL value, it's often safer to check the result if sqlite3_column_text is not NULL before proceeding, and handle the error gracefully otherwise. Also, you might want to check for sqlite3_step and sqlite3_prepare_v2 errors, like so:
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol]; // note, it can be dangerous to use `stringWithFormat` to build SQL; better to use `?` placeholders in your SQL and then use `sqlite3_bind_text` to bind the `symbol` value with the `?` placeholder
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
int rc;
while ((rc = sqlite3_step(statement)) == SQLITE_ROW) {
const unsigned char *value = sqlite3_column_text(statement, 0); // use zero
if (value) {
NSString *action = [NSString stringWithUTF8String:(const char *)value];
// now do whatever you want with `action`, e.g. add it to an array or what
} else {
// handle the error (or NULL value) gracefully here
}
// make sure to check for errors in `sqlite3_step`
if (rc != SQLITE_DONE)
{
NSLog(#"%s: sqlite3_step failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
}
}
else
{
NSLog(#"%s: sqlite3_prepare_v2 failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
Incidentally, as the above illustrates, to correctly perform all of the error checking is a little cumbersome. This is where FMDB can be useful, simplifying the above to (where db is an FMDatabase object that has been opened):
FMResultSet *rs = [db executeQuery:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = ?", symbol];
if (!rs) {
NSLog(#"%s: executeQuery failed: %#", __FUNCTION__, [db lastErrorMessage]);
return;
}
while ([rs next]) {
NSString *action = [rs stringForColumnIndex:0];
// do whatever you want with `action` here
}
[rs close];
And if you use ? placeholders (rather than using stringWithFormat to build your SQL, which is dangerous) the benefits of using FMDB are even more compelling.

Delete from empty database in sqlite

I am deleting records from the database.and it is working fine .But it is crashing when there is no data in the database. The code is given Below
int noOfRecordsDeleted;
[self openDatabaseConnection];
// query = [NSString stringWithFormat:#"delete from %# where %#",query];
NSLog(#"del query=%#",query);
const char *sql = [query cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *statement = nil;
if(sqlite3_prepare_v2(dataBaseConnection,sql, -1, &statement, NULL)!= SQLITE_OK)
{
NSAssert1(0,#"error preparing statement",sqlite3_errmsg(dataBaseConnection));
}
else
{
int success = sqlite3_step(statement);
NSLog(#"%d",success);
}
sqlite3_finalize(statement);
noOfRecordsDeleted = sqlite3_changes(dataBaseConnection);
[self closeDatabaseConnection];
return noOfRecordsDeleted;
It is working fine. But if i am adding data i empty database it is crashing
[self openDatabaseConnection];
NSString *query;
query = [NSString stringWithFormat:#"insert into Userdetail(aboutMe,anniversary,areacode,birthdate,device_id,chat_id,emailid,gender ,image,last_login,latitute,longitude,Looking_For,mobilenumber,mobilenumber1 ,mobilenumber2,mood,name,password,place,profileviews,statusmessage) values ('%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#','%#')",aboutMe,anniversarydate,areacode,birthdate,
device_id,chat_id,email_id,gender,image,last_login,latitude,longitude,looking_for,mobilenumber,mobilenumber1,mobilenumber2,mood,name,password,place,profileviews,statusmessage];
NSLog(#"saveNewTemplateData query=%#",query);
const char *sql = [query cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *statement = nil;if(sqlite3_prepare_v2(dataBaseConnection,sql , -1, &statement, NULL)!= SQLITE_OK)
{
NSAssert1(0,#"error preparing statement",sqlite3_errmsg(dataBaseConnection));
}
else
{
sqlite3_step(statement);
}
sqlite3_finalize(statement);
[self closeDatabaseConnection];
above is the code
First of all check the Database is empty or not by using the following statement
if(sqlite3_column_text(statement, 0) != nil){//Data exists}
Then in the if method add the code to delete the dataBase.
It works fine.
query = [NSString stringWithFormat:#"delete from %# where %#",query];
what does this query means I think its the mistake of your query please doublecheck it
if the error persists programmatically check
by using if(sqlite3_column_text(statement, 0) != nil)
One issue I saw that you are calling sqlite3_finalize(statement); regardless the state of sqlite3_prepare_v2. You only need to call sqlite3_finalize if the sqlite3_prepare_v2 executed successfully.
Change that to:
if(sqlite3_prepare_v2(dataBaseConnection,sql, -1, &statement, NULL)!= SQLITE_OK)
{
NSAssert1(0,#"error preparing statement",sqlite3_errmsg(dataBaseConnection));
}
else
{
int success = sqlite3_step(statement);
NSLog(#"%d",success);
sqlite3_finalize(statement);
}
if (condition for check database empty (select * from table)){
}else{
//Perform Delete operation
}

Sqlite database cannot read column

I have a DBManager wich is fetching data from database (sqlite file). All other queries are fine, but this one seems to be somehow not working
-(NSArray *)readCountries{
NSLog(#"[DBManager] readCountries");
NSMutableArray *countriesArray = [[NSMutableArray alloc] init];
//open db from users filesystem
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char* sql = "SELECT DISTINCT country FROM aed ORDER BY rowid";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
//loop through results
while (sqlite3_step(statement) == SQLITE_ROW) {
//read data from record
NSString *_country;
char* tmpCountry = (char*)sqlite3_column_text(statement, 1);
NSLog(#"tmpCountry = %#", [NSString stringWithUTF8String:tmpCountry]);
if (tmpCountry != NULL) {
_country = [NSString stringWithUTF8String:tmpCountry];
}else{
_country = #"n/a";
}
NSLog(#"country = %#", _country);
[countriesArray addObject:_country];
}
}
//finalize statement
sqlite3_finalize(statement);
}
//close database
sqlite3_close(database);
NSLog(#"[DBManager] countriesArray has %d objects", [countriesArray count]);
return (NSArray*)countriesArray;
}
All I get from logs, that my array has 5 objects, which is fine - but it souldn't be only "n/a"... any idea? Other queries are good, they mostly use sqlite3_column_text so I don't get it, why it's not working here - maybe a fresh eye will help.
This is a confusing inconsistency with the sqlite C-api. When using the sqlite3_column_xxx functions, the column index is 0-based. But with the sqlite3_bind_xxx functions, the column index is 1-based.
Change this:
char* tmpCountry = (char*)sqlite3_column_text(statement, 1);
to:
char* tmpCountry = (char*)sqlite3_column_text(statement, 0);
BTW - you should add else statements to your sqlite3_open and sqlite3_prepare calls. If they fail you can log the error using the sqlite3_errmsg function.

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.

Resources