Thursday, April 12, 2012

Converting sqllite error to NSError – bridging the Gap

sqllite and Cocoa represent two distinct worlds with different error handling idioms. In order to bridge that semantic gap in my code, I came up with the following helper code:
@implementation DbHelper
+ (void)handleSqlError:(sqlite3 *)db error:(NSError **)error
    NSLog(@"Error while executing sql statement. '%s'", sqlite3_errmsg(db));
    NSError *underlyingError = [[[NSError alloc] initWithDomain:@"db"
                                                           code:sqlite3_errcode(db) userInfo:nil]autorelease];
    // Make and return custom domain error.
    NSArray *objArray = [NSArray arrayWithObjects:[NSString stringWithFormat:@"sqlite error:%s", sqlite3_errmsg(db)], underlyingError, nil];
    NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey,
                         NSUnderlyingErrorKey, nil];
    NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray
    *error = [[[NSError alloc] initWithDomain:@""
                                         code:1 userInfo:eDict] autorelease];
Usage in the code would be (“select” is “aselect” on purpose):
sqlite3_stmt *checkStmt;
const char *sql = "aselect count(*) from sqlite_master where type='table' AND name=?";
if(sqlite3_prepare_v2(db, sql, -1, &checkStmt, NULL) == SQLITE_OK)
            [DbHelper handleSqlError:db error:error];
            return false;
Unit test to see what it would return in case of a simulated error:
- (void) test_when_invalidstatement_should_return_error
    NSError *error = nil;
    bool exists = [SchemaUpdater tableExistsWithName:@"note" error:&error];
    STAssertFalse(exists, @"When statement is invalid, exists should be false!");
    STAssertNotNil(error, @"For this test case error should not be nil!");
    NSLog(@"%@", error);
Where mine SchemaUpdater is just a simple class with snippet shown above having error in sql statement and calling that handleSqlError method.
The output of NSLog is:
Error Domain= Code=1 
"sqlite error:near "aselect": syntax error" 
{NSUnderlyingError=0xbd28b40 "The operation couldn’t be completed. ( error 1.)", 
NSLocalizedDescription=sqlite error:near "aselect": syntax error}
This is it for a moment. You might be also interested in a follow up post: Check if sqllite table exists
Or wait! Here are some links that enlightened me on NSError idioms: (definitely take a look if your way of checking for error is error!=nil) (probably the most comprehensive one)
Stackoverflow nn risk of the NULL dereference
Using and Creating Erorr objects

No comments: