sqlite select method implement issue for iOS - ios

I am trying to retrieve some data from my sqlite table base on a date, but I am getting EXC_BAD_ACCESS(code=EXC_1386_GPFLT) error. Here is my method to fetch data-
-(NSMutableArray*)fetchDataFromTable:(NSString*)tableName whenDate:(NSString*)activeDate{
NSMutableArray *resultArray=[[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"select * from %# where ActiveDate = \"%#\"", tableName, activeDate];
if ([self canOpenDatabase]) { //checks if database can be openned
sqlite3_stmt *statement=nil;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
NSMutableArray *fetchedResults=[[NSMutableArray alloc]init];
int numberOfColumns = sqlite3_column_count(statement);
for (int i=0; i< numberOfColumns; i++){
char *dataAsChars = (char *)sqlite3_column_text(statement, i);
if (dataAsChars != NULL) {
NSString *dataString = [[NSString alloc] initWithUTF8String:dataAsChars];
[fetchedResults addObject:dataString];
}
}
[resultArray addObject:fetchedResults];
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
else{
NSLog(#"Data can not be retrived");
}
return resultArray;
}
else{
return resultArray;
}
}
I also trying printing the query. It shows
select * from Time_table where ActiveDate = "2016-01-01"
Please Help me out.

There are several issues.
Pair the call to sqlite3_close with the success of opening the database.
Pair the call to sqlite_finalize with the success of preparing the statement.
Don't close the database or finalize the statement inside the loop.
Don't build queries using stringWithFormat. Properly bind values into the prepared statement.

The issue was very obvious yet very intuitive. I am glad that I faced this issue. At least I won't do it again. So, here is the simple fix and the reason behind it-
In case of database object fetching, EXC_BAD_ACCESS normally happens when -
An object is not initialised or
An object is already released untimely
So, in case, I were never to use the prepared statement or completely done working with the statement, I should use sqlite_finalize. In may method, I used the statement after I finalised the statement.
So the easy fix was to finalise after the while statement-
-(NSMutableArray*)fetchDataFromTable:(NSString*)tableName whenDate:(NSString*)activeDate{
NSMutableArray *resultArray=[[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"select * from %# where ActiveDate = \"%#\"", tableName, activeDate];
if ([self canOpenDatabase]) {
sqlite3_stmt *statement=nil;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
NSMutableArray *fetchedResults=[[NSMutableArray alloc]init];
int numberOfColumns = sqlite3_column_count(statement);
for (int i=0; i< numberOfColumns; i++){
char *dataAsChars = (char *)sqlite3_column_text(statement, i);
if (dataAsChars != NULL) {
NSString *dataString = [[NSString alloc] initWithUTF8String:dataAsChars];
[fetchedResults addObject:dataString];
}
}
[resultArray addObject: fetchedResults];
}
sqlite3_finalize(statement);
}
else{
NSLog(#"Data can not be retrived");
}
sqlite3_close(database);
return resultArray;
}
else{
return resultArray;
}
}

Related

Retrieve data from sqlite

I try to retrieve data from sqlite. Unfortunately the table is filled with null values.
The console shows FIRST ID RECUPERÉ : (null). Can you give me your opinions please?
This is the code:
NSString * statementID = [NSString stringWithFormat:#"SELECT id_message FROM messages;"];
const char * sql_stmt_id = [statementID UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(contactDB, sql_stmt_id, -1, &compiledStatement, NULL) == SQLITE_OK)
{
[tableauMsgReceived removeAllObjects];
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
[tableauMsgReceived addObject:[NSString stringWithFormat:#"%s",(char *) sqlite3_column_text(compiledStatement, 0)]];
NSLog(#"First ID : %#", [tableauMsgReceived objectAtIndex:0]);
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(contactDB);
The only way that the NSLog statement will give that result given your code is if tableauMsgReceived is nil.
Somewhere you need to do:
tableauMsgReceived = [[NSMutableArray alloc] init];
First of all, make sure you have done something like
tableauMsgReceived = [[NSMutableArray alloc] init];
Then, check whether database opened successfully
if (sqlite3_open([YourDBPath UTF8String], &yourDatabase) == SQLITE_OK){}
Last thing, maybe you can try
[tableauMsgReceived addObject:[NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 0)]];

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.

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

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...

Resources