cannot fetch value from sqlite in IOS - ios

Table values:
ID=1 CUSTOMERID=1 NAME=John EMAIL=email USERNAME=usernaeme
I am using this code to fetch customerId from Usertable with this code
#try {
//CustomerIdField=#"admin";
// customerUsername=#"admin";
NSLog(#"the value of customerusername is %#",customerUsername);
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSLog(#"inside function");
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"EBook.db" ]];
const char *dbpath;
#try {
dbpath = [databasePath UTF8String];
NSLog(#"the const char is %s",dbpath);
}
#catch (NSException *exception) {
NSLog(#"the exception3 is %#",exception);
}
if (sqlite3_open(dbpath, &Ebookreaderdb) == SQLITE_OK)
{
NSString *selectSQL = [NSString stringWithFormat: #"SELECT CUSTOMERID FROM Usertable WHERE EMAIL=\"%#\"",customerUsername];
sqlite3_stmt *selstatement;
const char *select_stmt = [selectSQL UTF8String];
//NSMutableArray *resultArray = [[NSMutableArray alloc]init];
if (sqlite3_prepare_v2(Ebookreaderdb,
select_stmt, -1, &selstatement, NULL ) == SQLITE_OK)
{
NSLog(#"inside sqlite OK"); //this prints in log
if (sqlite3_step(selstatement) == SQLITE_ROW)
{
NSLog(#"inside sqlite ROW"); // this is also printing in log
NSString *userInfoStr = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selstatement,1)];
NSLog(#"val is %#",userInfoStr);
char *tmp = sqlite3_column_text(selstatement,1);
if (tmp == NULL)
CustomerIdField = nil;
else
CustomerIdField = [[NSString alloc] initWithUTF8String:tmp];
CustomerIdField = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selstatement,1)];
NSLog(#"inside customer is %#",CustomerIdField);
// [resultArray addObject:name];
}
else{
NSLog(#"Not found");
// return nil;
}
sqlite3_reset(selstatement);
}
But i am getting this exception Newpjtonfriday[2165:84017] the exception is 2 *** +[NSString stringWithUTF8String:]: NULL cString
I googled with the above result and everywhere it is saying that the value is null that is why the exception occurs. but in my case the value is there.
Because the code
NSLog(#"inside sqlite ROW");
is coming in log meaning that a row exists in table. But cannot fetch it.
Please help

I think it's a typo:
#"SELECT CUSTOMERID FROM Usertable WHERE EMAIL=\"%#\"",customerUsername;
You are passing the username instead of the e-mail? Or maybe you meant to SELECT ... WHERE USERNAME=?
Also there is no need for any of those #try/#catch blocks as I cannot see how an Objective-C exception can be thrown by that code.
One last thing; in order to avoid SQL Injection attacks you should bind the values into your statements, rather than formatting them as a string, as you have done here.

Little advise if you are just starting to develop on iOS, try to use some library(FMDB to easy work with SQLite) to make some task more straight forward.
Answer to your Question
Try the "SELECT * FROM Usertable" if it has any row in your table.
Second you should check if the value in your row is not NULL.
To get easy solution use something like Datum SQLite Free(Mac os X) OR you could use SELECT COUNT to ensure you have any rows in table.
Try your select and if the app return the rows but there is no value in your column that's mean you have problems with write to DB logic but not in read logic and you are trying to fetch row with have null value on column you want.That's why this method is not working:
[NSString stringWithUTF8String:]: NULL cString
its thrown an exception because you have no string and trying to send NULL to method.

The sqlite3_column_text index number is zero-based, not one-based. Thus, this line:
char *tmp = sqlite3_column_text(selstatement, 1);
Should be:
char *tmp = sqlite3_column_text(selstatement, 0);
By the way, your handling of this tmp variable is a prudent way of checking to make sure it's not NULL before you use it. Unfortunately, elsewhere in this same routine you use sqlite3_column_text value directly (which is why your app crashed, rather than gracefully reporting the error). You have several redundant calls to sqlite3_column_text here. I would suggest employing the pattern you used with this tmp variable.

Let me give you my suggestion I tried what you just did and I also got the error. Then I did some googling and found this link
http://www.raywenderlich.com/913/sqlite-tutorial-for-ios-making-our-app
just modify you codes from these
char *tmp = sqlite3_column_text(selstatement,1);
if (tmp == NULL)
CustomerIdField = nil;
else
CustomerIdField = [[NSString alloc] initWithUTF8String:tmp];
CustomerIdField = [[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(selstatement,1)];
NSLog(#"inside customer is %#",CustomerIdField);
to
int tmp = sqlite3_column_int(selstatement,0);// my case it is int
char *nameChars = (char *) sqlite3_column_text(selstatement, 1);// here is the change occuring please refer this
NSString *name = [[NSString alloc] initWithUTF8String:nameChars]; // there are two steps first fetch as char, then change to String
NSLog(#"customerid is %d",tmp);
NSLog(#"customer name is %#",name);
Try this, It worked for me..
I think the problem is that you are fetching the coustomerId as String directly
In you case just try this
char *custId = (char *) sqlite3_column_text(selstatement, 0);
NSString *customerId = [[NSString alloc] initWithUTF8String:custId];
:-)

Related

How to get data from Sqlite database?

I have create sqlite db Table as below
NSString * sqlStmt =#"CREATE TABLE IF NOT EXISTS SONGS (ID INTEGER PRIMARY KEY AUTOINCREMENT, SONGNAME TEXT UNIQUE NOT NULL,ALBUMNAME TEXT ,ARTIST TEXT ,SIZE FLOAT ,IMAGE BLOB)";
when i am trying to get data from this table getting nothing
NSString *sqlQuery = [NSString stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE SONGNAME=kannulada"];
but iam getting data when iam trying to get data by id.
NSString *sqlQuery = [NSString stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE id=1"];
when i debugging it not excuting prepare loop
-(NSMutableArray*)retrieveDataArrayWHICHISequql
{
[dataArray removeAllObjects];
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &_SQliteDB) == SQLITE_OK)
{
const char * selectQuery =[sqlQuery UTF8String];
if (sqlite3_prepare_v2(_SQliteDB, selectQuery, -1, &statement, NULL)== SQLITE_OK)
{
while (sqlite3_step(statement)== SQLITE_ROW)
{
NSString * addressStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 0)];
NSString * phNumStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 1)];
// NSString * nameStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 2)];
NSMutableDictionary * dataDict = [[NSMutableDictionary alloc]init];
[dataDict setObject:addressStr forKey:#"getaddress"];
[dataDict setObject:phNumStr forKey:#"getphone"];
// [dataDict setObject:nameStr forKey:#"getname"];
[dataArray addObject:dataDict];
}
sqlite3_finalize(statement);
sqlite3_close(_SQliteDB);
}
}
return dataArray;
NSString *sqlQuery = [NSString
stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE SONGNAME='kannulada'"]
;
kannulada is string , so you must use single quote
The problem is that if you have an error in sqlite3_prepare_v2 (it didn't return SQLITE_OK). So, if that happens, you should look at what sqlite3_errmsg returned, and it will tell you precisely why it failed. If you don't look at the meaningful error message that SQLite returns, you're flying blind.
if (sqlite3_prepare_v2(_SQliteDB, selectQuery, -1, &statement, NULL)== SQLITE_OK)
{
...
} else {
NSLog(#"SQL Error: %s", sqlite3_errmsg(_SQliteDB));
}
Regarding why it's failing, it's because you have to either quote the string literal, 'kannulada', or, better, use a SQL placeholder, ?, and then use sqlite3_bind_text.

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.

Store accented word into Sqlite - iOS

I coulnd not find a solution.
I store data into a local SQLITE DB. Everything works except for accented words.
As in the figure.
However, if I try to store accented word by using SqliteManager (Firefox plugin) everything works. In conclusion: when I store accented word by using my app, strange chars appear.
I use the following code to write data (same for read). Basically, all strings are UTF8 encoded.
-(NSInteger)writeData:(NSDictionary* )data table:(NSString* )table
{
sqlite3_stmt *sqlStatement;
NSMutableArray *columns = [[NSMutableArray alloc] init];
NSMutableArray *values = [[NSMutableArray alloc] init];
NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithDictionary:data];
#try {
assert([data count] != 0);
if ([[data allKeys] count] == 0) return 1;
[temp removeObjectForKey:#"id"];
[columns addObjectsFromArray:[temp allKeys]];
NSString *cols = [columns componentsJoinedByString:#","];
NSMutableString *colNames = [[NSMutableString alloc] initWithString:
[NSString stringWithFormat:#"INSERT INTO %s (",[table UTF8String]]];
[colNames appendString:cols];
[colNames appendString:#")"];
// VALUES FOR INSERT
[values addObjectsFromArray:[temp allValues] ];
NSMutableString *s = [[NSMutableString alloc] init];
for(int i = 0; i < [values count]; i++)
{
[s setString:[NSString stringWithFormat:#"%#",[values objectAtIndex:i]]];
const char* currentValue = [s UTF8String];
[values setObject:[NSString stringWithFormat:#"\"%s\"",currentValue] atIndexedSubscript:i];
}
NSString *vals = [values componentsJoinedByString:#","];
NSMutableString *valNames = [[NSMutableString alloc] initWithString:#" VALUES ("];
[valNames appendString:vals];
[valNames appendString:#")"];
[colNames appendString:valNames];
const char *sql = [colNames UTF8String];
#ifdef DEBUG
NSLog(#"avvDB writeDATA insert string %#",colNames);
#endif
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement write %s",sqlite3_errmsg(db));
return 0;
}
if (sqlite3_exec(db, sql, NULL, NULL, NULL) == SQLITE_OK)
{
// NSLog(#"Last id %llu %s",sqlite3_last_insert_rowid(db),sqlite3_errmsg(db));
}
}// end try
#catch(NSException* e)
{
NSLog(#"Eccezione in write %#",[e reason]);
}
#finally {
sqlite3_reset(sqlStatement);
sqlite3_finalize(sqlStatement);
sqlStatement = nil;
return sqlite3_last_insert_rowid(db);
}
}
The %s operator does not support unicode characters. As the String Format Specifiers of the String Programming Guide says, it is "Null-terminated array of 8-bit unsigned characters."
Frankly, for other reasons, you shouldn't be using stringWithFormat anyway (what if one of the strings had a quotation mark in it ... your SQL statement would fail; you're even exposed to SQL injection attacks). You should be using a ? placeholder instead (with no quotation marks), and then call sqlite3_bind_text for each of the parameters you want to bind to the respective question mark (note, sqlite3_bind_xxx functions use a 1-based index, unlike sqlite3_column_xxx which use a 0-based index).

sql and UIPickerView

I need to develop a sql statement based on values picked on a UIPickerView. If you need a visual idea, here's a link to the screenshot (sorry not enough reputation to post pics yet) . I haven't been able to find any documentation on this and want to make sure I'm on the right track before I dig into it.
Each component (kTypeComponent, kDifficultyComponent, kDescriptionComponent) has three rows to select from (ex. kTypeComponent row1=bike, row2=run, row3=swim)
My thought would be that the sql statement would look something like this
sqlite3_stmt *pickerStatement;
//This would give back a string of the row selected (i.e bike, run, swim)
NSInteger getTypeSelected = [pickerView selectedRowInComponent:kTypeComponent];
NSString typeSQL = [rowOneItems objectAtIndex:getTypeSelected];
const char *pickerSQL = "SELECT description FROM workoutTbl WHERE (type = typeSQL) AND ...
Is this possible to do with a sql statement? I'm only familiar with basic SQL, so I'm not sure
Would the SQL statement go in the action (button) or where I set up my NSMutableArray and open the database? Should it go into a different class?
Edit - Solution
In case anyone comes around with the same problem, here is the solution to it
- (NSArray *)getWorkoutListwithType:(NSString *)workoutType withDifficulty:(NSString *)difficulty withLength:(NSString *)length {
NSMutableArray *workouts;
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"workoutList.sqlite"];
// NSLog(#"Db path is %#",dbPath);
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if (!success){
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK)) {
NSLog(#"error with message '%s'.", sqlite3_errmsg(db));
}
// only alloc/init the array if the SQL database opens properly
workouts = [[NSMutableArray alloc] init];
sqlite3_stmt *sqlStatement;
// add "%%" as a wildcard so the query will say "difficulty LIKE '>30%' and match >30 MINS, >30 HOURS, etc.
NSString *sqlString = [NSString stringWithFormat: #"SELECT description FROM workoutTbl WHERE type LIKE '%#%%' AND difficulty LIKE '%#%%' AND duration LIKE '%#%%'", workoutType, difficulty, length];
NSLog(#"query: %#", sqlString);
const char *sql = [sqlString UTF8String];
if (sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK) {
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
}
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
[workouts addObject:[NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)]];
}
sqlite3_finalize(sqlStatement);
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally {
sqlite3_close(db);
}
// Pass back an immutable copy of the array. if the array is nil, then the database never opened and there will be an error
return [workouts copy];
}
What do you mean by 'three rows to select'? Do you mean 'three fields (columns) to select'? If you want to specify field values, then a statement should like
NSString* sqlStatement = [NSString stringWithFormat:#"SELECT * FROM workoutTbl WHERE type = '%#' AND id = '%i'", typeSQL,idNumber];

App crashes when trying to load from SQLite

Well, I am making an update to an app I made, but I am having some runtime issues. People said they wanted to be able to save data they entered, so I am implementing an SQLite database. I got the app to check if database exists and create everything needed, if the database or database table does not exist. However, I am having troubles retrieving data from SQLite. When I press a button that should load data, the app crashes. I tried using both NSLog and UIAlertView to figure out what is going on, but I cannot retrieve results. However, when performing a test run in SQLite, the query I am issuing is correct, so there must be something else.
the following is the code I am using to retrieve data:
- (IBAction)loadData
{
NSDateFormatter* bf = [[NSDateFormatter alloc] init];
[bf setDateFormat:#"MM/dd/yyyy"];
NSDate* sdate;
NSString* birthDate;
NSString* balance;
NSString* dyear;
sqlite3_stmt *stmt;
// get document directory
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
// build path to database
dbpath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"mrd.db"]];
const char *dpath = [dbpath UTF8String];
if (sqlite3_open(dpath, &mrdDB) == SQLITE_OK)
{
NSString* query = [NSString stringWithFormat:#"SELECT date(birth), bal, year FROM rmd LIMIT 1"];
const char* query_statement = [query UTF8String];
if (sqlite3_prepare_v2(mrdDB, query_statement, -1, &stmt, NULL) == SQLITE_OK)
{
if (sqlite3_step(stmt) == SQLITE_ROW)
{
birthDate = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(stmt, 1)];
balance = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(stmt, 2)];
dyear = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(stmt, 3)];
sdate = [bf dateFromString:birthDate];
self.birth.text = [bf stringFromDate:sdate];
[birthDate release];
[bf release];
self.bal.text = balance;
[balance release];
self.year.text = dyear;
[dyear release];
self.status.text = #"data loaded sucessfully";
} else {
self.status.text = #"Cannot find/retrieve saved data";
}
sqlite3_finalize(stmt);
}
sqlite3_close(mrdDB);
}
}
The app is able to save data to the database, as the app displays a "save successful" message, which I added for the user's sake as well as seeing if things were done right, so I am not too sure what is going on.
I found my problem, after finding where the simulator saves databases. My problem was not with the loading the data, but how it was saved. Thanks for the help.

Resources