I'm curious in the differences that I've come across in using both an iOS Simulator/Device and the sqlite3 command line app that comes packaged with Mac OSX.
On a different machine (my Windows box), I created a sqlite database out of a text file. Here's the create statement for the SQLite file.
CREATE TABLE IF NOT EXISTS GeocodeData (ZipCode TEXT, City TEXT COLLATE NOCASE, State TEXT COLLATE NOCASE, Latitude REAL, Longitude REAL, PRIMARY KEY(ZipCode, City, State) ON CONFLICT INGORE);
I'm using the COLLATE NOCASE
as I found on this SO question to have case insensitive searches.
When I move the DB to my Mac, running the sqlite3
app in the terminal, I can run the following query:
SELECT * FROM GeocodeData WHERE City = 'elyria' AND State = 'oh'
.
44035|Elyria|OH|41.3724|-82.1051
44036|Elyria|OH|41.4015|-82.0771
Running this statement returns 2 results from my database. Awesome.
Moving to the iPad app I'm creating, I'm using FMDatabase to wrap access to the Sqlite database.
Here's the code that accesses it.
+(CLLocationCoordinate2D)getCoordinateForFilter:(GeocodingFilter *)filter
{
__block CLLocationCoordinate2D coordinate;
FMDatabaseQueue *queue = [self databaseQueue];
[queue inDatabase:^(FMDatabase *db)
{
//Determine if we're using zipcode or city/state.
NSMutableString *query = [[NSMutableString alloc] initWithString:SELECT_STATEMENT];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
if(![NSString isNilOrWhitespace:filter.zipCode])//Zipcode logic
{
[query appendFormat:WHERE_CLAUSE, @"ZipCode = :zipCode "];
params[@"zipCode"] = filter.zipCode;
}
else
{
NSString *clause = nil;
if(![NSString isNilOrWhitespace:filter.city])
{
clause = [NSString stringWithFormat:WHERE_CLAUSE, @"City = :city"];
params[@"city"] = filter.city;
}
if (![NSString isNilOrWhitespace:filter.state])
{
if(clause)
clause = [NSString stringWithFormat:@"%@ AND", clause];
clause = [NSString stringWithFormat:@"%@ State = :state", clause];
params[@"state"] = filter.state;
}
[query appendString:clause];
}
FMResultSet *set = [db executeQuery:query withParameterDictionary:params];
NSMutableArray *results = [NSMutableArray array];
while ([set next])
{
double latitude = [set doubleForColumn:@"Latitude"];
double longitude = [set doubleForColumn:@"Longitude"];
[results addObject:[[CLLocation alloc] initWithLatitude:latitude longitude:longitude]];
}
[set close];
[db close];
__block double avgLat = 0.;
__block double avgLong = 0.;
[results enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CLLocation *loc = obj;
avgLat += loc.coordinate.latitude;
avgLong += loc.coordinate.longitude;
}];
coordinate = CLLocationCoordinate2DMake(avgLat/(double)results.count, avgLong/(double)results.count);
}];
return coordinate;
}
This runs the exact same query that I used in the sqlite3 command line, yet returns 0 results every time.
Now, I can fix the issue by changing these 4 lines of code.
clause = [NSString stringWithFormat:WHERE_CLAUSE, @"City LIKE :city"];
params[@"city"] = [NSString stringWithFormat:@"%%%@%%", filter.city];
and
clause = [NSString stringWithFormat:@"%@ State LIKE :state", clause];
params[@"state"] = [NSString stringWithFormat:@"%%%@%%", filter.state];
but I explicitly created the table to use COLLATE NOCASE
in the create statement. Why doesn't this work?
EDIT: Apparently I need to re-iterate the problem. The problem is NOT the LIKE
query!
I want to know why this query: SELECT * FROM GeocodeData WHERE City = 'elyria' AND State = 'oh'
on the command line returns 2 results, while running THIS EXACT SAME QUERY in an iOS environment with FMDatabase return 0 results.