After some research in sqlite documentation, I found sqlite3_get_table method (http://www.sqlite.org/c3ref/free_table.html), which I used in the following way:
+ (NSMutableArray*) executeQuery: (const char *) sql
{
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
char** azResult = NULL;
int nRows = 0;
int nColumns = 0;
char* errorMsg; //= malloc(255); // this is not required as sqlite do it itself
sqlite3_get_table(
[appDelegate getdb], /* An open database */
sql, /* SQL to be evaluated */
&azResult, /* Results of the query */
&nRows, /* Number of result rows written here */
&nColumns, /* Number of result columns written here */
&errorMsg /* Error msg written here */
);
if(azResult != NULL)
{
NSMutableArray* dataTable = [[[NSMutableArray alloc] init] autorelease];
nRows++; //because the header row is not account for in nRows
for (int i = 1; i < nRows; i++)
{
NSMutableDictionary* row = [NSMutableDictionary dictionaryWithCapacity:nColumns];
for(int j = 0; j < nColumns; j++)
{
NSString* key = [NSString stringWithUTF8String:azResult[j]];
NSString* value = [NSString stringWithUTF8String:azResult[(i*nColumns)+j]];
[row setValue:value forKey:key] ;
}
[dataTable addObject:row];
}
//free(errorMsg); // no need to free, sqlite somehow doing it
sqlite3_free_table(azResult);
return dataTable;
}
else
{
NSAssert1(0,@"Failed to execute query with message '%s'.",errorMsg);
return nil;
}
}
Above code is capable of accepting any 'select' query and generate results in a standard data structure consist of NSMutableArray and NSMutableDictionary. Each element in the array represent a row, while each key-value pair in dictionary represent a column name and its value. Column name would be same as given in the query or as altered by 'as' keyword.
Using this method one can totally separate DB layer and application layer, and even in DB layer the method would be very short. Here is an example:
Related Links
NSString* sql = [NSString stringWithFormat:@"select ID, aText, aFloat, aFloat2, "
"aText2 as myText2, aText3, 'aStringConstant' as myStringConstant "
"from myTable where afloat<=%1.6f and afloat2>=%1.6f Order by aText",
floatVariable, floatVariable2];
return [self executeQuery:[sql UTF8String]];
SQLite Version 3 C/C++ API Reference
Convenience Routines For Running Queries
1 comments:
Sorry there is a small bug in this code, we don't need to malloc memory for errormsg, it is done by sqlite and somehow (it amazing) it free it as well. So if we malloc it and free it (thinking we are freeing our allocation), it actually got leaked.
Fix: just comment out malloc and free statements.
Post a Comment