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).
Related
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.
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;
}
}
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];
:-)
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)]];
I am a newbie and working on code below. As a result of creating NSMutableDictionary from CSV file I am passing the value to DatabaseManager class and there is a method which receives the values and trying to insert it to the database.
1. How can I insert those values to DB?
2. Is is efficient way to make little dictionary Application on iOS? (I have approx 40000 records and size is about 3MB)
MAIN CLASS
...
NSString *filePath= [[NSBundle mainBundle] pathForResource:#"Test" ofType:#"csv"];
NSString *content = [[NSString alloc]initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//NSString *path1=[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"JapMon" ofType:#"csv"] encoding:NSUTF8StringEncoding error:nil];
NSArray *messArr=[content componentsSeparatedByString:#"\n"];
if(messArr)
{
NSLog(#"%d", [messArr count]);
for(int i=1;i<=[messArr count]-2;i++)
{
NSMutableDictionary *d=[[NSMutableDictionary alloc] init];
NSString *StrValue=[NSString stringWithFormat:#"%#",[messArr objectAtIndex:i]];
StrValue=[StrValue stringByReplacingOccurrencesOfString:#"\"" withString:#""];
StrValue=[StrValue stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// Here give whatever saperator you need to saperate data
NSArray *arr=[StrValue componentsSeparatedByString:#","];
//NSLog(#"%#", [arr objectAtIndex:2]);
[d setValue:[arr objectAtIndex:0] forKey:#"word"];
[d setValue:[arr objectAtIndex:1] forKey:#"hansa"];
[d setValue:[arr objectAtIndex:2] forKey:#"def"];
//Here add logic to insert row in your database table
[[DatabaseManager getSharedInstance]insertInitialDataToDb:d];
//NSLog(#"%#", d);
//Add this dictionary "d" into database
[d release]; //Cleanup.
}
}
//[content release];
...
2.DATABASEMANAGER CLASS
-(BOOL) insertInitialDataToDb:(NSMutableDictionary*)initialData
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:#"insert into japmon (word, hansa, def) values (\"%#\")", initialData];
NSLog(#"ok");
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
return TRUE;
}
else {
return FALSE;
}
sqlite3_reset(statement);
}
return TRUE;
From your query you would like to insert values to three column. But you are passing only dictionary.
NSString *insertSQL = [NSString stringWithFormat:#"insert into japmon (word, hansa, def) values (\"%#\")", initialData];
you need to change you stringWithFormat with this
NSString *insertSQL = [NSString stringWithFormat:#"insert into japmon (word, hansa, def) values (\"%#\",\"%#\",\"%#\"), WORD_COL_VALUE,HANSA_COL_VALUE,DEF_COM_VALUE];
Finally I solved my question on my own. The best way was prepared FTS sqlite database not importing after creation of "core data" database. As a result my app autocomplete/suggestion performance is at most 3.2MB CPU usage # more than 50.000 records in UTF-8 format on simulator like a windspeed.