1 #import "FMResultSet.h"
4 @interface FMResultSet (Private)
5 - (NSMutableDictionary *)columnNameToIndexMap;
6 - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value;
9 @implementation FMResultSet
11 + (id) resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
13 FMResultSet *rs = [[FMResultSet alloc] init];
15 [rs setStatement:statement];
18 return [rs autorelease];
24 [self setColumnNameToIndexMap:[NSMutableDictionary dictionary]];
37 [columnNameToIndexMap release];
38 columnNameToIndexMap = nil;
49 [parentDB setInUse:NO];
52 - (void) setupColumnNames {
54 int columnCount = sqlite3_column_count(statement.statement);
57 for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
58 [columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
59 forKey:[[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)] lowercaseString]];
61 columnNamesSetup = YES;
64 - (void) kvcMagic:(id)object {
67 int columnCount = sqlite3_column_count(statement.statement);
70 for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
73 const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
75 // check for a null row
77 NSString *s = [NSString stringWithUTF8String:c];
79 [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)]];
88 int numberOfRetries = 0;
92 rc = sqlite3_step(statement.statement);
94 if (SQLITE_BUSY == rc) {
95 // this will happen if the db is locked, like if we are doing an update or insert.
96 // in that case, retry the step... and maybe wait just 10 milliseconds.
100 if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {
102 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
103 NSLog(@"Database busy");
107 else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
108 // all is well, let's return.
110 else if (SQLITE_ERROR == rc) {
111 NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
114 else if (SQLITE_MISUSE == rc) {
116 NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
121 NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
128 if (rc != SQLITE_ROW) {
132 return (rc == SQLITE_ROW);
135 - (int) columnIndexForName:(NSString*)columnName {
137 if (!columnNamesSetup) {
138 [self setupColumnNames];
141 columnName = [columnName lowercaseString];
143 NSNumber *n = [columnNameToIndexMap objectForKey:columnName];
149 NSLog(@"Warning: I could not find the column named '%@'.", columnName);
156 - (int) intForColumn:(NSString*)columnName {
158 if (!columnNamesSetup) {
159 [self setupColumnNames];
162 int columnIdx = [self columnIndexForName:columnName];
164 if (columnIdx == -1) {
168 return sqlite3_column_int(statement.statement, columnIdx);
170 - (int) intForColumnIndex:(int)columnIdx {
171 return sqlite3_column_int(statement.statement, columnIdx);
174 - (long) longForColumn:(NSString*)columnName {
176 if (!columnNamesSetup) {
177 [self setupColumnNames];
180 int columnIdx = [self columnIndexForName:columnName];
182 if (columnIdx == -1) {
186 return sqlite3_column_int64(statement.statement, columnIdx);
189 - (long) longForColumnIndex:(int)columnIdx {
190 return sqlite3_column_int64(statement.statement, columnIdx);
193 - (BOOL) boolForColumn:(NSString*)columnName {
194 return ([self intForColumn:columnName] != 0);
197 - (BOOL) boolForColumnIndex:(int)columnIdx {
198 return ([self intForColumnIndex:columnIdx] != 0);
201 - (double) doubleForColumn:(NSString*)columnName {
203 if (!columnNamesSetup) {
204 [self setupColumnNames];
207 int columnIdx = [self columnIndexForName:columnName];
209 if (columnIdx == -1) {
213 return sqlite3_column_double(statement.statement, columnIdx);
216 - (double) doubleForColumnIndex:(int)columnIdx {
217 return sqlite3_column_double(statement.statement, columnIdx);
221 #pragma mark string functions
223 - (NSString*) stringForColumnIndex:(int)columnIdx {
225 const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
232 return [NSString stringWithUTF8String:c];
235 - (NSString*) stringForColumn:(NSString*)columnName {
237 if (!columnNamesSetup) {
238 [self setupColumnNames];
241 int columnIdx = [self columnIndexForName:columnName];
243 if (columnIdx == -1) {
247 return [self stringForColumnIndex:columnIdx];
253 - (NSDate*) dateForColumn:(NSString*)columnName {
255 if (!columnNamesSetup) {
256 [self setupColumnNames];
259 int columnIdx = [self columnIndexForName:columnName];
261 if (columnIdx == -1) {
265 return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumn:columnName]];
268 - (NSDate*) dateForColumnIndex:(int)columnIdx {
269 return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
273 - (NSData*) dataForColumn:(NSString*)columnName {
275 if (!columnNamesSetup) {
276 [self setupColumnNames];
279 int columnIdx = [self columnIndexForName:columnName];
281 if (columnIdx == -1) {
285 int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
287 NSMutableData *data = [NSMutableData dataWithLength:dataSize];
289 memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
294 - (NSData*) dataForColumnIndex:(int)columnIdx {
296 int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
298 NSMutableData *data = [NSMutableData dataWithLength:dataSize];
300 memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
306 - (void)setParentDB:(FMDatabase *)newDb {
311 - (NSString *)query {
315 - (void)setQuery:(NSString *)value {
321 - (NSMutableDictionary *)columnNameToIndexMap {
322 return columnNameToIndexMap;
325 - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value {
327 [columnNameToIndexMap release];
328 columnNameToIndexMap = value;
331 - (FMStatement *) statement {
335 - (void)setStatement:(FMStatement *)value {
336 if (statement != value) {
338 statement = [value retain];