Sqlite result set contain a null value - ios

I get a result set from sqlite which looks something like this:
Null, 23, 34, 45 (being (say) 4 items returned)
The null value is correct - however when I try to add it to an array in objective-c with the following code I get an error - Null cstring - here's my code:
[array addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]];
I tried unsuccessfully testing for the null before adding it to the array and replacing it with a zero but so far no luck.
Could someone please help me to handle the null value so I can add maybe a zero into the array.
Thanks for any help.

As Hot Licks said, check the return value and either add a string created from that, or add [NSNull null].
const unsigned char *column0 = sqlite3_column_text(statement, 0);
if (column0)
[array addObject:[NSString stringWithUTF8String:(const char *)column0]];
else
[array addObject:[NSNull null]];

Handling null as suggested is a good option.
You can also modify queries to force column to always be TEXT using CAST(column_name AS TEXT), or force NULLs to empty strings using COALESCE(column_name, '').

Related

Sort numbers inside an array of custom objects

i tried this, this and this link
I have an array (Say personObjectArray) which contains objects of class Person.
Class Person having 2 variables say,
NSString *name, NSString *age.
Here age has type of nsstring.
Now when i sort like below,
personObjectArray = [[personObjectArray sortedArrayUsingComparator:^NSComparisonResult(Person *p1, Person *p2){
return [p1.age compare:p2.age];
}] mutableCopy];
It sorts like this,
1,
11,
123
2,
23,
3... It sorts like alphabetical order not considering it as an number.
So i change my code like this,
personObjectArray = [[personObjectArray sortedArrayUsingComparator:^NSComparisonResult(Person *p1, Person *p2){
return [[p1.age intValue] compare:[p2.age intValue] ];
}] mutableCopy];
And it says, Bad receiver type 'int'
How can i sort now ?
Please don't tell me to change the datatype of age in Person class. I can't change it. Any help appreciated (: , Thanks for the time.
You were using compare on a primitive (Not Object) type int , hence it won't work.
Try this
return [#([p1.age intValue]) compare:#([p2.age intValue])];
Here, we are using NSNumber (Which is an object type) to compare the int values
#() is a NSNumber's literal
Hope this will help you.. (:
Try this :
personObjectArray = [[personObjectArray sortedArrayUsingComparator:^NSComparisonResult(Person *p1, Person *p2){
return [p1.age compare:p2.age options:NSNumericSearch];
}] mutableCopy];

String matching in iOS returning 0x00000001?

i have a simple string checking code, which will check NSString which coming from my server to the NSString which i hard coded in my xcode.
Please check the code
if([[array valueForKey:#"type"] isEqualToString:#"type"] ) {
//Failed
}
input values are these
[array valueForKey:#"type"] is a string from server 'type'
When i did this in xcode console
po [[array valueForKey:#"type"] isEqualToString:#"type"]
i got output as
0x00000001
Both strings are same but then what is this 0x00000001??
What are you doing now in printing the result of the comparison, to check the value of string you have to print [array valueForKey:#"type"] value alone, or print value of the all items of the array just to be sure.
Hope that helps.
[array valueForKey:#"type"] is going to return a value most likely different than a string. Assuming array is a NSDictionary filled with NSIntegers then the integer for key "type" is not going to be equal to the string "type".
I thought you got a hexadecimal value. All hexadecimal values start from 0x. You got value equals to 1. In if statement 1 equals to true. So your compared strings are equal. This 0x0000000000000001 value comes from a compiler and that way compiler designed.
Here, [array valueForKey:#"type"]
array must be NSDictionary... because array don't have "valueForKey:" method..
Better you first save in some var and then do comparison.

SQLite Go through each column in Row

I have a sqlite statement that provides me with a selected single row and 20 columns.
Up to now I've been using this while loop:
while(sqlite3_step(statement) == SQLITE_ROW) {
NSString *name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, an_incrementing_int)];
...
}
However the problem with this is as there is only one row it will naturally only return the 1st column.
So is there something like while.. == SQLITE_COLUMN ?
Thanks
To get number of column a query returns, use sqlite3_column_count.
Function to return column data, sqlite3_column_... all accept an 2nd argument which is int column index.
NSString coldata;
int i;
while(sqlite3_step(statement) == SQLITE_ROW) {
for (i=0; i<sqlite3_column_count(statement); ++i) {
coldata= [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, i)];
}
}
Note also: take care using data pointer to column values!
The pointers returned are valid until a type conversion occurs as
described above, or until sqlite3_step() or sqlite3_reset() or
sqlite3_finalize() is called. The memory space used to hold strings
and BLOBs is freed automatically. Do not pass the pointers returned
from sqlite3_column_blob(), sqlite3_column_text(), etc. into
sqlite3_free().

Obfuscating a number(in a string) Objective C

I'm using the following code to obfuscate a passcode for a test app of mine.
- (NSString *)obfuscate:(NSString *)string withKey:(NSString *)key
{
// Create data object from the string
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// Get pointer to data to obfuscate
char *dataPtr = (char *) [data bytes];
// Get pointer to key data
char *keyData = (char *) [[key dataUsingEncoding:NSUTF8StringEncoding] bytes];
// Points to each char in sequence in the key
char *keyPtr = keyData;
int keyIndex = 0;
// For each character in data, xor with current value in key
for (int x = 0; x < [data length]; x++)
{
// Replace current character in data with
// current character xor'd with current key value.
// Bump each pointer to the next character
*dataPtr = *dataPtr++ ^ *keyPtr++;
// If at end of key data, reset count and
// set key pointer back to start of key value
if (++keyIndex == [key length])
keyIndex = 0, keyPtr = keyData;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
This works like a charm with all strings, but i've ran into a bit of a problem comparing the following results
NSLog([[self obfuscate:#"0000", #"maki"]); //Returns 0]<W
NSLog([[self obfuscate:#"0809", #"maki"]); //Returns 0]<W
As you can see, the two strings with numbers in, while different, return the same result! Whats gone wrong in the code i've attached to result in the same result for these two numbers?
Another example:
NSLog([self obfuscate:#"8000" withKey:#"maki"]); //Returns 8U4_
NSLog([self obfuscate:#"8290" withKey:#"maki"]); //Returns 8U4_ as well
I may be misunderstanding the concept of obfuscation, but I was under the impression that each unique string returns a unique obfuscated string!
Please help me fix this bug/glitch
Source of Code: http://iosdevelopertips.com/cocoa/obfuscation-encryption-of-string-nsstring.html
The problem is your last line. You create the new string with the original, unmodified data object.
You need to create a new NSData object from the modified dataPtr bytes.
NSData *newData = [NSData dataWithBytes:dataPtr length:data.length];
return [[NSString alloc] initWithData:newData encoding:NSUTF8StringEncoding];
But you have some bigger issues.
The calls to bytes returns a constant, read-only reference to the bytes in the NSData object. You should NOT be modifying that data.
The result of your XOR on the character data could, in theory, result in a byte stream that is no longer a valid UTF-8 encoded string.
The obfuscation algorithm that you have selected is based on XORing the data and the "key" values together. Generally, this is not very strong. Moreover, since XOR is symmetric, the results are very prone to producing duplicates.
Although your implementation is currently broken, fixing it would not be of much help in preventing the algorithm from producing identical results for different data: it is relatively straightforward to construct key/data pairs that produce the same obfuscated string - for example,
[self obfuscate:#"0123" withKey:#"vwxy"]
[self obfuscate:#"pqrs" withKey:#"6789"]
will produce identical results "FFJJ", even though both the strings and the keys look sufficiently different.
If you would like to "obfuscate" your strings in a cryptographically strong way, use a salted secure hash algorithm: it will produce very different results for even slightly different strings.

sqlite3_column_text returns only 255 bytes even though there is data in db

Ladies and Gents,
I'm using FMDB in an iOS application. I have some text in columns which exceeds 255 bytes. I use BASE and browse the database file, and I can query the length of the data in the columns... So I know my data is there and that it is longer than 255...
YET, when trying to pull out data from these columns, I always get a C string of exactly 255 bytes, and I have no clue whatsoever why.
Here's some piece of code (basically from - (NSString*)stringForColumnIndex:(int)columnIdx {
of FMDB FMResultSet.m, and I can trap the error already there.
- (NSString*)stringForColumnIndex:(int)columnIdx {
if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
return nil;
}
const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx);
int xx = strlen(c); //added by me, already here it is only 255 bytes
if (!c) {
// null row.
return nil;
}
return [NSString stringWithUTF8String:c];
}
What am I missing? I'm using the standard supplied libsqlite3.dylib, FMDB includes sqlite.h. I tried to google similar problems to no avail for hours now.
This is neither a FMDB nor SQLite limitation. I use FMDB to return strings longer than 255 characters from my SQLite database all the time. I just checked:
FMResultSet *rs = [fmdb executeQuery:#"select personnel_description from personnel where personnel_id=297"];
[rs next];
NSString *test2 = [rs stringForColumnIndex:0];
NSLog(#"%s len=%d string=%#", __FUNCTION__, [test2 length], test2);
[rs close];
and I got my 8429 character string, same length that BASE told me it was going to be.
This makes me wonder if there's something strange about your data (e.g. binary data instead of characters, DBCS, etc.). Have you tried returning as an object rather than a string and examining that? Perhaps confirm that it is a NSString and not a NSData result set, e.g.:
id test3 = [rs objectForColumnIndex:0];
if ([test3 isKindOfClass:[NSString class]])
NSLog(#"It's a string");
else
NSLog(#"It's not");
If you really think this is a FMDB issue, you could try posting this question at the FMDB discussion. Also, I'd make sure you have the latest FMDB code, which you can retrieve from that same site.

Resources