Added dataNoCopyForColumn: and dataNoCopyForColumnIndex: to FMResultSet.
[fmdb.git] / src / FMResultSet.m
blob4670963d98f8479c07d2f9263f8e642a9687a617
1 #import "FMResultSet.h"
2 #import "FMDatabase.h"
4 @interface FMResultSet (Private)
5 - (NSMutableDictionary *)columnNameToIndexMap;
6 - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value;
7 @end
9 @implementation FMResultSet
11 + (id) resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
12     
13     FMResultSet *rs = [[FMResultSet alloc] init];
14     
15     [rs setStatement:statement];
16     [rs setParentDB:aDB];
17     
18     return [rs autorelease];
21 - (void)dealloc {
22     [self close];
23     
24     [query release];
25     query = nil;
26     
27     [columnNameToIndexMap release];
28     columnNameToIndexMap = nil;
29     
30         [super dealloc];
33 - (void) close {
34     
35     [statement reset];
36     [statement release];
37     statement = nil;
38     
39     // we don't need this anymore... (i think)
40     //[parentDB setInUse:NO];
41     parentDB = nil;
44 - (void) setupColumnNames {
45     
46     if (!columnNameToIndexMap) {
47         [self setColumnNameToIndexMap:[NSMutableDictionary dictionary]];
48     }   
49     
50     int columnCount = sqlite3_column_count(statement.statement);
51     
52     int columnIdx = 0;
53     for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
54         [columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
55                                  forKey:[[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)] lowercaseString]];
56     }
57     columnNamesSetup = YES;
60 - (void) kvcMagic:(id)object {
61     
62     
63     int columnCount = sqlite3_column_count(statement.statement);
64     
65     int columnIdx = 0;
66     for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
67         
68         
69         const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
70         
71         // check for a null row
72         if (c) {
73             NSString *s = [NSString stringWithUTF8String:c];
74             
75             [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)]];
76         }
77     }
80 - (BOOL) next {
81     
82     int rc;
83     BOOL retry;
84     int numberOfRetries = 0;
85     do {
86         retry = NO;
87         
88         rc = sqlite3_step(statement.statement);
89         
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.
93             retry = YES;
94             usleep(20);
95             
96             if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {
97                 
98                 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
99                 NSLog(@"Database busy");
100                 break;
101             }
102         }
103         else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
104             // all is well, let's return.
105         }
106         else if (SQLITE_ERROR == rc) {
107             NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
108             break;
109         } 
110         else if (SQLITE_MISUSE == rc) {
111             // uh oh.
112             NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
113             break;
114         }
115         else {
116             // wtf?
117             NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
118             break;
119         }
120         
121     } while (retry);
122     
123     
124     if (rc != SQLITE_ROW) {
125         [self close];
126     }
127     
128     return (rc == SQLITE_ROW);
131 - (int) columnIndexForName:(NSString*)columnName {
132     
133     if (!columnNamesSetup) {
134         [self setupColumnNames];
135     }
136     
137     columnName = [columnName lowercaseString];
138     
139     NSNumber *n = [columnNameToIndexMap objectForKey:columnName];
140     
141     if (n) {
142         return [n intValue];
143     }
144     
145     NSLog(@"Warning: I could not find the column named '%@'.", columnName);
146     
147     return -1;
152 - (int) intForColumn:(NSString*)columnName {
153     
154     if (!columnNamesSetup) {
155         [self setupColumnNames];
156     }
157     
158     int columnIdx = [self columnIndexForName:columnName];
159     
160     if (columnIdx == -1) {
161         return 0;
162     }
163     
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 {
171     
172     if (!columnNamesSetup) {
173         [self setupColumnNames];
174     }
175     
176     int columnIdx = [self columnIndexForName:columnName];
177     
178     if (columnIdx == -1) {
179         return 0;
180     }
181     
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 {
190     
191     if (!columnNamesSetup) {
192         [self setupColumnNames];
193     }
194     
195     int columnIdx = [self columnIndexForName:columnName];
196     
197     if (columnIdx == -1) {
198         return 0;
199     }
200     
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 {
217     
218     if (!columnNamesSetup) {
219         [self setupColumnNames];
220     }
221     
222     int columnIdx = [self columnIndexForName:columnName];
223     
224     if (columnIdx == -1) {
225         return 0;
226     }
227     
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 {
239     
240     const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
241     
242     if (!c) {
243         // null row.
244         return nil;
245     }
246     
247     return [NSString stringWithUTF8String:c];
250 - (NSString*) stringForColumn:(NSString*)columnName {
251     
252     if (!columnNamesSetup) {
253         [self setupColumnNames];
254     }
255     
256     int columnIdx = [self columnIndexForName:columnName];
257     
258     if (columnIdx == -1) {
259         return nil;
260     }
261     
262     return [self stringForColumnIndex:columnIdx];
268 - (NSDate*) dateForColumn:(NSString*)columnName {
269     
270     if (!columnNamesSetup) {
271         [self setupColumnNames];
272     }
273     
274     int columnIdx = [self columnIndexForName:columnName];
275     
276     if (columnIdx == -1) {
277         return nil;
278     }
279     
280     return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumn:columnName]];
283 - (NSDate*) dateForColumnIndex:(int)columnIdx {
284     return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
288 - (NSData*) dataForColumn:(NSString*)columnName {
289     
290     if (!columnNamesSetup) {
291         [self setupColumnNames];
292     }
293     
294     int columnIdx = [self columnIndexForName:columnName];
295     
296     if (columnIdx == -1) {
297         return nil;
298     }
299     
300     
301     return [self dataForColumnIndex:columnIdx];
304 - (NSData*) dataForColumnIndex:(int)columnIdx {
305     
306     int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
307     
308     NSMutableData *data = [NSMutableData dataWithLength:dataSize];
309     
310     memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
311     
312     return data;
316 - (NSData*) dataNoCopyForColumn:(NSString*)columnName {
317     
318     if (!columnNamesSetup) {
319         [self setupColumnNames];
320     }
321     
322     int columnIdx = [self columnIndexForName:columnName];
323     
324     if (columnIdx == -1) {
325         return nil;
326     }
327     
328     
329     return [self dataNoCopyForColumnIndex:columnIdx];
332 - (NSData*) dataNoCopyForColumnIndex:(int)columnIdx {
333     
334     int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
335     
336     NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob(statement.statement, columnIdx) length:dataSize freeWhenDone:NO];
337     
338     return data;
345 - (void)setParentDB:(FMDatabase *)newDb {
346     parentDB = newDb;
350 - (NSString *)query {
351     return query;
354 - (void)setQuery:(NSString *)value {
355     [value retain];
356     [query release];
357     query = value;
360 - (NSMutableDictionary *)columnNameToIndexMap {
361     return columnNameToIndexMap;
364 - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value {
365     [value retain];
366     [columnNameToIndexMap release];
367     columnNameToIndexMap = value;
370 - (FMStatement *) statement {
371     return statement;
374 - (void)setStatement:(FMStatement *)value {
375     if (statement != value) {
376         [statement release];
377         statement = [value retain];
378     }
383 @end