/MapView/Map/FMDB/FMResultSet.m

http://github.com/route-me/route-me · Objective C · 332 lines · 224 code · 98 blank · 10 comment · 47 complexity · dad3fba684cbe9235acf5ba47ade3b6a MD5 · raw file

  1. #import "FMResultSet.h"
  2. #import "FMDatabase.h"
  3. #import "unistd.h"
  4. @interface FMResultSet (Private)
  5. - (NSMutableDictionary *)columnNameToIndexMap;
  6. - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value;
  7. @end
  8. @implementation FMResultSet
  9. + (id) resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
  10. FMResultSet *rs = [[FMResultSet alloc] init];
  11. [rs setStatement:statement];
  12. [rs setParentDB:aDB];
  13. return [rs autorelease];
  14. }
  15. - (void)dealloc {
  16. [self close];
  17. [query release];
  18. query = nil;
  19. [columnNameToIndexMap release];
  20. columnNameToIndexMap = nil;
  21. [super dealloc];
  22. }
  23. - (void) close {
  24. [statement reset];
  25. [statement release];
  26. statement = nil;
  27. // we don't need this anymore... (i think)
  28. //[parentDB setInUse:NO];
  29. parentDB = nil;
  30. }
  31. - (void) setupColumnNames {
  32. if (!columnNameToIndexMap) {
  33. [self setColumnNameToIndexMap:[NSMutableDictionary dictionary]];
  34. }
  35. int columnCount = sqlite3_column_count(statement.statement);
  36. int columnIdx = 0;
  37. for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
  38. [columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
  39. forKey:[[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)] lowercaseString]];
  40. }
  41. columnNamesSetup = YES;
  42. }
  43. - (void) kvcMagic:(id)object {
  44. int columnCount = sqlite3_column_count(statement.statement);
  45. int columnIdx = 0;
  46. for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
  47. const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
  48. // check for a null row
  49. if (c) {
  50. NSString *s = [NSString stringWithUTF8String:c];
  51. [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)]];
  52. }
  53. }
  54. }
  55. - (BOOL) next {
  56. int rc;
  57. BOOL retry;
  58. int numberOfRetries = 0;
  59. do {
  60. retry = NO;
  61. rc = sqlite3_step(statement.statement);
  62. if (SQLITE_BUSY == rc) {
  63. // this will happen if the db is locked, like if we are doing an update or insert.
  64. // in that case, retry the step... and maybe wait just 10 milliseconds.
  65. retry = YES;
  66. usleep(20);
  67. if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {
  68. NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
  69. NSLog(@"Database busy");
  70. break;
  71. }
  72. }
  73. else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
  74. // all is well, let's return.
  75. }
  76. else if (SQLITE_ERROR == rc) {
  77. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  78. break;
  79. }
  80. else if (SQLITE_MISUSE == rc) {
  81. // uh oh.
  82. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  83. break;
  84. }
  85. else {
  86. // wtf?
  87. NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  88. break;
  89. }
  90. } while (retry);
  91. if (rc != SQLITE_ROW) {
  92. [self close];
  93. }
  94. return (rc == SQLITE_ROW);
  95. }
  96. - (BOOL) hasAnotherRow {
  97. return sqlite3_errcode([parentDB sqliteHandle]) == SQLITE_ROW;
  98. }
  99. - (int) columnIndexForName:(NSString*)columnName {
  100. if (!columnNamesSetup) {
  101. [self setupColumnNames];
  102. }
  103. columnName = [columnName lowercaseString];
  104. NSNumber *n = [columnNameToIndexMap objectForKey:columnName];
  105. if (n) {
  106. return [n intValue];
  107. }
  108. NSLog(@"Warning: I could not find the column named '%@'.", columnName);
  109. return -1;
  110. }
  111. - (int) intForColumn:(NSString*)columnName {
  112. return [self intForColumnIndex:[self columnIndexForName:columnName]];
  113. }
  114. - (int) intForColumnIndex:(int)columnIdx {
  115. return sqlite3_column_int(statement.statement, columnIdx);
  116. }
  117. - (long) longForColumn:(NSString*)columnName {
  118. return [self longForColumnIndex:[self columnIndexForName:columnName]];
  119. }
  120. - (long) longForColumnIndex:(int)columnIdx {
  121. return (long)sqlite3_column_int64(statement.statement, columnIdx);
  122. }
  123. - (long long int) longLongIntForColumn:(NSString*)columnName {
  124. return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]];
  125. }
  126. - (long long int) longLongIntForColumnIndex:(int)columnIdx {
  127. return sqlite3_column_int64(statement.statement, columnIdx);
  128. }
  129. - (BOOL) boolForColumn:(NSString*)columnName {
  130. return [self boolForColumnIndex:[self columnIndexForName:columnName]];
  131. }
  132. - (BOOL) boolForColumnIndex:(int)columnIdx {
  133. return ([self intForColumnIndex:columnIdx] != 0);
  134. }
  135. - (double) doubleForColumn:(NSString*)columnName {
  136. return [self doubleForColumnIndex:[self columnIndexForName:columnName]];
  137. }
  138. - (double) doubleForColumnIndex:(int)columnIdx {
  139. return sqlite3_column_double(statement.statement, columnIdx);
  140. }
  141. - (NSString*) stringForColumnIndex:(int)columnIdx {
  142. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  143. return nil;
  144. }
  145. const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
  146. if (!c) {
  147. // null row.
  148. return nil;
  149. }
  150. return [NSString stringWithUTF8String:c];
  151. }
  152. - (NSString*) stringForColumn:(NSString*)columnName {
  153. return [self stringForColumnIndex:[self columnIndexForName:columnName]];
  154. }
  155. - (NSDate*) dateForColumn:(NSString*)columnName {
  156. return [self dateForColumnIndex:[self columnIndexForName:columnName]];
  157. }
  158. - (NSDate*) dateForColumnIndex:(int)columnIdx {
  159. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  160. return nil;
  161. }
  162. return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
  163. }
  164. - (NSData*) dataForColumn:(NSString*)columnName {
  165. return [self dataForColumnIndex:[self columnIndexForName:columnName]];
  166. }
  167. - (NSData*) dataForColumnIndex:(int)columnIdx {
  168. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  169. return nil;
  170. }
  171. int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
  172. NSMutableData *data = [NSMutableData dataWithLength:dataSize];
  173. memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
  174. return data;
  175. }
  176. - (NSData*) dataNoCopyForColumn:(NSString*)columnName {
  177. return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]];
  178. }
  179. - (NSData*) dataNoCopyForColumnIndex:(int)columnIdx {
  180. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  181. return nil;
  182. }
  183. int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
  184. NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob(statement.statement, columnIdx) length:dataSize freeWhenDone:NO];
  185. return data;
  186. }
  187. - (BOOL) columnIndexIsNull:(int)columnIdx {
  188. return sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL;
  189. }
  190. - (BOOL) columnIsNull:(NSString*)columnName {
  191. return [self columnIndexIsNull:[self columnIndexForName:columnName]];
  192. }
  193. - (const unsigned char *) UTF8StringForColumnIndex:(int)columnIdx {
  194. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  195. return nil;
  196. }
  197. return sqlite3_column_text(statement.statement, columnIdx);
  198. }
  199. - (const unsigned char *) UTF8StringForColumnName:(NSString*)columnName {
  200. return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]];
  201. }
  202. // returns autoreleased NSString containing the name of the column in the result set
  203. - (NSString*) columnNameForIndex:(int)columnIdx {
  204. return [NSString stringWithUTF8String: sqlite3_column_name(statement.statement, columnIdx)];
  205. }
  206. - (void)setParentDB:(FMDatabase *)newDb {
  207. parentDB = newDb;
  208. }
  209. - (NSString *)query {
  210. return query;
  211. }
  212. - (void)setQuery:(NSString *)value {
  213. [value retain];
  214. [query release];
  215. query = value;
  216. }
  217. - (NSMutableDictionary *)columnNameToIndexMap {
  218. return columnNameToIndexMap;
  219. }
  220. - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value {
  221. [value retain];
  222. [columnNameToIndexMap release];
  223. columnNameToIndexMap = value;
  224. }
  225. - (FMStatement *) statement {
  226. return statement;
  227. }
  228. - (void)setStatement:(FMStatement *)value {
  229. if (statement != value) {
  230. [statement release];
  231. statement = [value retain];
  232. }
  233. }
  234. @end