How to use function parameter in sql query? - objective-c

I am trying to create a sql query in Objective-C. But in where clause I want to use a parameter that comes from a function. I couldn't append it to query.
The query must be char type. My parameter is integer. I tried to convert them into string to use stringFormat: and appendString: options but it didn't work.
I am trying to concentrate two chars, but I couldn't.
Here is the code;
(NSMutableArray*)getSomething:(NSInteger)some_id
{
NSMutableArray *something = [[[NSMutableArray alloc] init] autorelease];
// const char *sql = "SELECT * FROM t_something WHERE some_id = ";
I want to use some_id parameter in the query.

check this example code
NSString *stmt=[NSString stringWithFormat:#"SELECT * FROM person where word like '%#%% order by name asc",name];
const char *sql=(const char *) [stmt UTF8String];

Related

FMDB avoid sql injection

I am working on a project that is built on raw sqlite, and I have changed it to FMDB.
All the queries are parametrized.
Here is one such an example:
NSString* sqlQuery = [NSString stringWithFormat:#"SELECT COUNT(*) FROM Contacts WHERE FirstName='%#' AND LastName='%#'", fName,lName];
and I pass it to my helper class:
NSInteger count = [[[DB sharedManager] executeSQL:sqlQuery] integerValue];
Helper class:
- (NSString*)executeSQL:(NSString *)sql
{
__block NSString *resultString = #"";
[_secureQueue inDatabase:^(FMDatabase *db) {
FMResultSet *results = [db executeQuery:sql];
while([results next]) {
resultString= [results stringForColumnIndex:0];
}
}];
return resultString;
}
I can make a workaround something like:
sql = #"SELECT COUNT(*) FROM Contacts WHERE FirstName=? AND LastName=?"
[db executeQuery:sql,firstParam, secondParam]
But I do not want to change the helper method, I need to pass the changed/updated sql query to my helper method.
How can I change this:
NSString* sqlQuery = [NSString stringWithFormat:#"SELECT COUNT(*) FROM Contacts WHERE FirstName='%#' AND LastName='%#'", fName,lName];
to something like:
NSString* sqlQuery = [NSString stringWithFormat:#"SELECT COUNT(*) FROM Contacts WHERE FirstName=? AND LastName=?", fName,lName];
If you want to avoid SQL Injection problems, then you must never build a query using stringWithFormat. You must properly bind variables into the query. Period. End of discussion.
So you have no choice but to change your helper. Have it take two parameters instead of one. The first being the query with the proper use of ? and the second being an array of values that get bound into the query but the helper method.

why does my sqlite sql return no results?

The follow is my db function:
+(NSArray*)searchWithKey:(NSString*)_key{
NSMutableArray* tmpArray = [NSMutableArray array];
static Statement* stmt = nil;
char* sql = "select * from Bookmarks where BMUrl like '%?%'";
if (stmt == nil) {
stmt = [DBConnection statementWithQuery:sql];
[stmt retain];
}
[stmt bindString:_key forIndex:1];
while ([stmt step] == SQLITE_ROW) {
BookMark* tmpBM = [[BookMark alloc] initWithStatement:stmt];
NSLog(#"tmpBM = %#",tmpBM);
[tmpArray addObject:tmpBM];
[tmpBM release];
}
[stmt reset];
return tmpArray;}
The keyword of sql is "like" which I use.But there are no results that the sqlite return.Anyone could tell me why?
I change the sql into "select * from Bookmarks where BMUrl like '%h%'",there are some results which are returned.So , I guess the mistake is the function "bindString:forIndex",the code is
- (void)bindString:(NSString*)value forIndex:(int)index{
sqlite3_bind_text(stmt, index, [value UTF8String], -1, SQLITE_TRANSIENT);}
which is the correct sqlite3 api that i will use? thank u!
Bindings aren't interpolated like that. If you put a quotation mark in a string, as in '%?%', it will be interpreted as a literal question mark.
You should instead modify your input _key:
Escape any instances of % and _ with a \
Add %s at the beginning and end
This prepares it to be used with a LIKE operator.
You also need to modify your SQL so that the ? represents a standalone parameter: ... where BMUrl like ?.
Here's an example for how to escape special characters and add %s at the beginning and end of _key:
NSString *escapedKey = [_key stringByReplacingOccurencesOfString:#"%"
withString:#"\\%"];
escapedKey = [escapedKey stringByReplacingOccurencesOfString:#"_"
withString:#"\\_"];
NSString *keyForLike = [NSString stringWithFormat:#"%%%#%%", escapedKey];
[stmt bindString:keyForLike forIndex:1];

FMDatabase query works with ? but fails with literal

This is an odd problem. I've found a workaround that works, but I'd like to understand why, because I suspect it will come up again later in my code. Here's the method that's giving my the problem:
FMDatabase *cardDatabase // initialized elsewhere
NSString *cleanChar; // this is the sanitized query string
NSString *cardQueryString;
int cardID;
switch ([self studyLanguage])
{
case CSStudyLanguageMandarinTraditional:
cardQueryString = #"SELECT rowid, * FROM trad_char WHERE search = ";
break;
// [...other cases...]
}
cardQueryString = [cardQueryString stringByAppendingString:cleanChar];
[cardDatabase open];
FMResultSet* cardSet = [cardDatabase executeQuery:cardQueryString];
BOOL foundCard = NO;
while ([cardSet next])
{
foundCard = YES;
cardID = [cardSet intForColumn:#"rowid"];
}
[cardDatabase close];
This code gives a database error:
DB Error 1: no such column: 意
where "意" is the character sequence I'm passing in cleanChar, which is apparently being treated as a column rather than a value somehow. However...if I add the search character in the query step, like so:
cardQueryString = #"SELECT rowid, * FROM trad_char WHERE search = ?";
FMResultSet* cardSet = [cardDatabase executeQuery:cardQueryString, cleanChar];
everything works just fine.
So I've actually solved the problem...but I want to know why, because it affects the way I'd like to do some more complicated queries with multiple joins down the road, where it'll be harder to just plug in variables at the end.
So: Is this a bug in FMDatabase? Do I just not understand how to use FMDatabase? Or is there some other problem with the code?
Your query is failing because you haven't wrapped your search string in single quotes (used to designate literals). So you need to replace this line
cardQueryString = [cardQueryString stringByAppendingString:cleanChar];
with this:
cardQueryString = [NSString stringWithFormat:#"%#'%#'", cardQueryString cleanChar];
However, that's bad practice, to compose the query by using NSString methods to combine the query string and query argument. It's problematic for several reasons, such as if the argument contains reserved characters or words, or escape sequences that open you up to SQL injection issues.
You should instead provide argument via the binding mechanisms of SQLite, which are wrapped up nicely in the FMDB methods. So, your "workaround" is actually the best method:
cardQueryString = #"SELECT rowid, * FROM trad_char WHERE search = ?";
FMResultSet* cardSet = [cardDatabase executeQuery:cardQueryString, cleanChar];
or send one or more arguments in an array:
cardQueryString = #"SELECT rowid, * FROM trad_char WHERE search = ?";
FMResultSet* cardSet = [cardDatabase executeQuery:cardQueryString arguments:#[cleanChar]];
Tom
BareFeetWare

How do I get JSON back from a Sqlite text field?

I've managed to store some JSON to a field in my sqlite database, the length of the TEXT (in the sqlite docs theres no limit on a text field size) field is 1337.
I've even tried varchar, but again my app crashes with SGABRT. I don't get any other error details.
Looking at the record in a sqlite utility the data is complete and fine and my query shown below works.
I've even substituted why query and the code does work with a record in another table.
I know I should be using Core Data but this is an existing app and I can't convert it at this time.
No sure how to proceed ?
NSString *ret = #"";
const char *sql = "select value from MyTable where item = 'json'";
sqlite3 *database;
int result = sqlite3_open(... db path function ...], &database);
... snip in not db and error code ...
sqlite3_stmt *statementTMP;
sqlite3_prepare_v2(database, sql, -1, &statementTMP, NULL);
if (sqlite3_step(statementTMP) == SQLITE_ROW) {
ret = [[NSString alloc] initWithUTF8String:
(char *)sqlite3_column_text(statementTMP, 1)]; << Fails here
}
sqlite3_finalize(statementTMP);
sqlite3_close(database);
EDIT
Start of my JSON data
{"lowestday":"31","pfAppAdvAcSel":-1,"styleselec
Further EDIT
char *test = (char *)sqlite3_column_text(statementTMP, 1);
NSLog(#"value = %s", test); << (NULL)
The problem is that you are calling sqlite3_column_text() incorrectly. Since you are selecting only a single column (value), there is only one column from which you can extract text. In SQLite3, column numbers begin with 0, rather than 1. Therefore, you should change the second argument of your call to sqlite3_column_text with 0 instead of 1.

How to convert NSString to C string?

I know that this question is a possible duplicate, but even after looking at some Google tutorials and questions even on this forum none of them gives me a decent answer about this subject.
I have:
NSString *str = #"text";
And I would like to do something like:
char cstring [512] = str;
(this only shows what I want to do, after looking at Apple's NSString Class Ref I didn't even think about using it).
Up to now I have:
char command [512] = [[NSString stringWithFormat:#"text"] cStringUsingEncoding:NSUTF8StringEncoding];
Still, with that I get errors.
Any solution?
try const char *command = [str UTF8String];
A c string is returned as a pointer, not as an array of characters. To use it, you can change your variable to a pointer.
const char *command = [theString cStringUsingEncoding:NSUTF8StringEncoding];
Since you want the UTF8 encoding, you can use the UTF8String convenience method.
const char *command = [theString UTF8String];
If you need the data to be stored in a character array, you can use the getCString:maxLength:encoding: method, passing the array as the buffer. This will allow you to store the string directly to the buffer, and will tell you if the buffer is too small.
char command[512];
if(![theString getCString:command maxLength:sizeof(command)/sizeof(*command) encoding:NSUTF8StringEncoding]) {
NSLog(#"Command buffer too small");
}