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];
27 [columnNameToIndexMap release];
28 columnNameToIndexMap = nil;
39 // we don't need this anymore... (i think)
40 //[parentDB setInUse:NO];
44 - (void) setupColumnNames {
46 if (!columnNameToIndexMap) {
47 [self setColumnNameToIndexMap:[NSMutableDictionary dictionary]];
50 int columnCount = sqlite3_column_count(statement.statement);
53 for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
54 [columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
55 forKey:[[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)] lowercaseString]];
57 columnNamesSetup = YES;
60 - (void) kvcMagic:(id)object {
63 int columnCount = sqlite3_column_count(statement.statement);
66 for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
69 const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
71 // check for a null row
73 NSString *s = [NSString stringWithUTF8String:c];
75 [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)]];
84 int numberOfRetries = 0;
88 rc = sqlite3_step(statement.statement);
90 if (SQLITE_BUSY == rc) {
91 // this will happen if the db is locked, like if we are doing an update or insert.
92 // in that case, retry the step... and maybe wait just 10 milliseconds.
96 if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {
98 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
99 NSLog(@"Database busy");
103 else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
104 // all is well, let's return.
106 else if (SQLITE_ERROR == rc) {
107 NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
110 else if (SQLITE_MISUSE == rc) {
112 NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
117 NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
124 if (rc != SQLITE_ROW) {
128 return (rc == SQLITE_ROW);
131 - (int) columnIndexForName:(NSString*)columnName {
133 if (!columnNamesSetup) {
134 [self setupColumnNames];
137 columnName = [columnName lowercaseString];
139 NSNumber *n = [columnNameToIndexMap objectForKey:columnName];
145 NSLog(@"Warning: I could not find the column named '%@'.", columnName);
152 - (int) intForColumn:(NSString*)columnName {
154 if (!columnNamesSetup) {
155 [self setupColumnNames];
158 int columnIdx = [self columnIndexForName:columnName];
160 if (columnIdx == -1) {
164 return sqlite3_column_int(statement.statement, columnIdx);
166 - (int) intForColumnIndex:(int)columnIdx {
167 return sqlite3_column_int(statement.statement, columnIdx);
170 - (long) longForColumn:(NSString*)columnName {
172 if (!columnNamesSetup) {
173 [self setupColumnNames];
176 int columnIdx = [self columnIndexForName:columnName];
178 if (columnIdx == -1) {
182 return (long)sqlite3_column_int64(statement.statement, columnIdx);
185 - (long) longForColumnIndex:(int)columnIdx {
186 return (long)sqlite3_column_int64(statement.statement, columnIdx);
189 - (long long int) longLongIntForColumn:(NSString*)columnName {
191 if (!columnNamesSetup) {
192 [self setupColumnNames];
195 int columnIdx = [self columnIndexForName:columnName];
197 if (columnIdx == -1) {
201 return sqlite3_column_int64(statement.statement, columnIdx);
204 - (long long int) longLongIntForColumnIndex:(int)columnIdx {
205 return sqlite3_column_int64(statement.statement, columnIdx);
208 - (BOOL) boolForColumn:(NSString*)columnName {
209 return ([self intForColumn:columnName] != 0);
212 - (BOOL) boolForColumnIndex:(int)columnIdx {
213 return ([self intForColumnIndex:columnIdx] != 0);
216 - (double) doubleForColumn:(NSString*)columnName {
218 if (!columnNamesSetup) {
219 [self setupColumnNames];
222 int columnIdx = [self columnIndexForName:columnName];
224 if (columnIdx == -1) {
228 return sqlite3_column_double(statement.statement, columnIdx);
231 - (double) doubleForColumnIndex:(int)columnIdx {
232 return sqlite3_column_double(statement.statement, columnIdx);
236 #pragma mark string functions
238 - (NSString*) stringForColumnIndex:(int)columnIdx {
240 const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
247 return [NSString stringWithUTF8String:c];
250 - (NSString*) stringForColumn:(NSString*)columnName {
252 if (!columnNamesSetup) {
253 [self setupColumnNames];
256 int columnIdx = [self columnIndexForName:columnName];
258 if (columnIdx == -1) {
262 return [self stringForColumnIndex:columnIdx];
268 - (NSDate*) dateForColumn:(NSString*)columnName {
270 if (!columnNamesSetup) {
271 [self setupColumnNames];
274 int columnIdx = [self columnIndexForName:columnName];
276 if (columnIdx == -1) {
280 return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumn:columnName]];
283 - (NSDate*) dateForColumnIndex:(int)columnIdx {
284 return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
288 - (NSData*) dataForColumn:(NSString*)columnName {
290 if (!columnNamesSetup) {
291 [self setupColumnNames];
294 int columnIdx = [self columnIndexForName:columnName];
296 if (columnIdx == -1) {
301 return [self dataForColumnIndex:columnIdx];
304 - (NSData*) dataForColumnIndex:(int)columnIdx {
306 int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
308 NSMutableData *data = [NSMutableData dataWithLength:dataSize];
310 memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
316 - (NSData*) dataNoCopyForColumn:(NSString*)columnName {
318 if (!columnNamesSetup) {
319 [self setupColumnNames];
322 int columnIdx = [self columnIndexForName:columnName];
324 if (columnIdx == -1) {
329 return [self dataNoCopyForColumnIndex:columnIdx];
332 - (NSData*) dataNoCopyForColumnIndex:(int)columnIdx {
334 int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
336 NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob(statement.statement, columnIdx) length:dataSize freeWhenDone:NO];
345 - (void)setParentDB:(FMDatabase *)newDb {
350 - (NSString *)query {
354 - (void)setQuery:(NSString *)value {
360 - (NSMutableDictionary *)columnNameToIndexMap {
361 return columnNameToIndexMap;
364 - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value {
366 [columnNameToIndexMap release];
367 columnNameToIndexMap = value;
370 - (FMStatement *) statement {
374 - (void)setStatement:(FMStatement *)value {
375 if (statement != value) {
377 statement = [value retain];