PageRenderTime 131ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/fmdb/FMResultSet.m

http://github.com/petewarden/iPhoneTracker
Objective C | 405 lines | 281 code | 113 blank | 11 comment | 68 complexity | a6d5b7f2ec57522ef802908647bbdfb5 MD5 | raw file
  1. #import "FMResultSet.h"
  2. #import "FMDatabase.h"
  3. #import "unistd.h"
  4. @interface FMDatabase ()
  5. - (void)resultSetDidClose:(FMResultSet *)resultSet;
  6. @end
  7. @interface FMResultSet (Private)
  8. - (NSMutableDictionary *)columnNameToIndexMap;
  9. - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value;
  10. @end
  11. @implementation FMResultSet
  12. + (id)resultSetWithStatement:(FMStatement *)statement usingParentDatabase:(FMDatabase*)aDB {
  13. FMResultSet *rs = [[FMResultSet alloc] init];
  14. [rs setStatement:statement];
  15. [rs setParentDB:aDB];
  16. return [rs autorelease];
  17. }
  18. - (void)finalize {
  19. [self close];
  20. [super finalize];
  21. }
  22. - (void)dealloc {
  23. [self close];
  24. [query release];
  25. query = nil;
  26. [columnNameToIndexMap release];
  27. columnNameToIndexMap = nil;
  28. [super dealloc];
  29. }
  30. - (void)close {
  31. [statement reset];
  32. [statement release];
  33. statement = nil;
  34. // we don't need this anymore... (i think)
  35. //[parentDB setInUse:NO];
  36. [parentDB resultSetDidClose:self];
  37. parentDB = nil;
  38. }
  39. - (void)setupColumnNames {
  40. if (!columnNameToIndexMap) {
  41. [self setColumnNameToIndexMap:[NSMutableDictionary dictionary]];
  42. }
  43. int columnCount = sqlite3_column_count(statement.statement);
  44. int columnIdx = 0;
  45. for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
  46. [columnNameToIndexMap setObject:[NSNumber numberWithInt:columnIdx]
  47. forKey:[[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)] lowercaseString]];
  48. }
  49. columnNamesSetup = YES;
  50. }
  51. - (void)kvcMagic:(id)object {
  52. int columnCount = sqlite3_column_count(statement.statement);
  53. int columnIdx = 0;
  54. for (columnIdx = 0; columnIdx < columnCount; columnIdx++) {
  55. const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
  56. // check for a null row
  57. if (c) {
  58. NSString *s = [NSString stringWithUTF8String:c];
  59. [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name(statement.statement, columnIdx)]];
  60. }
  61. }
  62. }
  63. - (NSDictionary *)resultDict {
  64. int num_cols = sqlite3_data_count(statement.statement);
  65. if (num_cols > 0) {
  66. NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols];
  67. if (!columnNamesSetup) {
  68. [self setupColumnNames];
  69. }
  70. NSEnumerator *columnNames = [columnNameToIndexMap keyEnumerator];
  71. NSString *columnName = nil;
  72. while ((columnName = [columnNames nextObject])) {
  73. id objectValue = [self objectForColumnName:columnName];
  74. [dict setObject:objectValue forKey:columnName];
  75. }
  76. return [[dict copy] autorelease];
  77. }
  78. else {
  79. NSLog(@"Warning: There seem to be no columns in this set.");
  80. }
  81. return nil;
  82. }
  83. - (BOOL)next {
  84. int rc;
  85. BOOL retry;
  86. int numberOfRetries = 0;
  87. do {
  88. retry = NO;
  89. rc = sqlite3_step(statement.statement);
  90. if (SQLITE_BUSY == rc || SQLITE_LOCKED == 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. if (SQLITE_LOCKED == rc) {
  95. rc = sqlite3_reset(statement.statement);
  96. if (rc != SQLITE_LOCKED) {
  97. NSLog(@"Unexpected result from sqlite3_reset (%d) rs", rc);
  98. }
  99. }
  100. usleep(20);
  101. if ([parentDB busyRetryTimeout] && (numberOfRetries++ > [parentDB busyRetryTimeout])) {
  102. NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [parentDB databasePath]);
  103. NSLog(@"Database busy");
  104. break;
  105. }
  106. }
  107. else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
  108. // all is well, let's return.
  109. }
  110. else if (SQLITE_ERROR == rc) {
  111. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  112. break;
  113. }
  114. else if (SQLITE_MISUSE == rc) {
  115. // uh oh.
  116. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  117. break;
  118. }
  119. else {
  120. // wtf?
  121. NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([parentDB sqliteHandle]));
  122. break;
  123. }
  124. } while (retry);
  125. if (rc != SQLITE_ROW) {
  126. [self close];
  127. }
  128. return (rc == SQLITE_ROW);
  129. }
  130. - (BOOL)hasAnotherRow {
  131. return sqlite3_errcode([parentDB sqliteHandle]) == SQLITE_ROW;
  132. }
  133. - (int)columnIndexForName:(NSString*)columnName {
  134. if (!columnNamesSetup) {
  135. [self setupColumnNames];
  136. }
  137. columnName = [columnName lowercaseString];
  138. NSNumber *n = [columnNameToIndexMap objectForKey:columnName];
  139. if (n) {
  140. return [n intValue];
  141. }
  142. NSLog(@"Warning: I could not find the column named '%@'.", columnName);
  143. return -1;
  144. }
  145. - (int)intForColumn:(NSString*)columnName {
  146. return [self intForColumnIndex:[self columnIndexForName:columnName]];
  147. }
  148. - (int)intForColumnIndex:(int)columnIdx {
  149. return sqlite3_column_int(statement.statement, columnIdx);
  150. }
  151. - (long)longForColumn:(NSString*)columnName {
  152. return [self longForColumnIndex:[self columnIndexForName:columnName]];
  153. }
  154. - (long)longForColumnIndex:(int)columnIdx {
  155. return (long)sqlite3_column_int64(statement.statement, columnIdx);
  156. }
  157. - (long long int)longLongIntForColumn:(NSString*)columnName {
  158. return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]];
  159. }
  160. - (long long int)longLongIntForColumnIndex:(int)columnIdx {
  161. return sqlite3_column_int64(statement.statement, columnIdx);
  162. }
  163. - (BOOL)boolForColumn:(NSString*)columnName {
  164. return [self boolForColumnIndex:[self columnIndexForName:columnName]];
  165. }
  166. - (BOOL)boolForColumnIndex:(int)columnIdx {
  167. return ([self intForColumnIndex:columnIdx] != 0);
  168. }
  169. - (double)doubleForColumn:(NSString*)columnName {
  170. return [self doubleForColumnIndex:[self columnIndexForName:columnName]];
  171. }
  172. - (double)doubleForColumnIndex:(int)columnIdx {
  173. return sqlite3_column_double(statement.statement, columnIdx);
  174. }
  175. - (NSString*)stringForColumnIndex:(int)columnIdx {
  176. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  177. return nil;
  178. }
  179. const char *c = (const char *)sqlite3_column_text(statement.statement, columnIdx);
  180. if (!c) {
  181. // null row.
  182. return nil;
  183. }
  184. return [NSString stringWithUTF8String:c];
  185. }
  186. - (NSString*)stringForColumn:(NSString*)columnName {
  187. return [self stringForColumnIndex:[self columnIndexForName:columnName]];
  188. }
  189. - (NSDate*)dateForColumn:(NSString*)columnName {
  190. return [self dateForColumnIndex:[self columnIndexForName:columnName]];
  191. }
  192. - (NSDate*)dateForColumnIndex:(int)columnIdx {
  193. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  194. return nil;
  195. }
  196. return [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]];
  197. }
  198. - (NSData*)dataForColumn:(NSString*)columnName {
  199. return [self dataForColumnIndex:[self columnIndexForName:columnName]];
  200. }
  201. - (NSData*)dataForColumnIndex:(int)columnIdx {
  202. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  203. return nil;
  204. }
  205. int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
  206. NSMutableData *data = [NSMutableData dataWithLength:dataSize];
  207. memcpy([data mutableBytes], sqlite3_column_blob(statement.statement, columnIdx), dataSize);
  208. return data;
  209. }
  210. - (NSData*)dataNoCopyForColumn:(NSString*)columnName {
  211. return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]];
  212. }
  213. - (NSData*)dataNoCopyForColumnIndex:(int)columnIdx {
  214. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  215. return nil;
  216. }
  217. int dataSize = sqlite3_column_bytes(statement.statement, columnIdx);
  218. NSData *data = [NSData dataWithBytesNoCopy:(void *)sqlite3_column_blob(statement.statement, columnIdx) length:dataSize freeWhenDone:NO];
  219. return data;
  220. }
  221. - (BOOL)columnIndexIsNull:(int)columnIdx {
  222. return sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL;
  223. }
  224. - (BOOL)columnIsNull:(NSString*)columnName {
  225. return [self columnIndexIsNull:[self columnIndexForName:columnName]];
  226. }
  227. - (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx {
  228. if (sqlite3_column_type(statement.statement, columnIdx) == SQLITE_NULL || (columnIdx < 0)) {
  229. return nil;
  230. }
  231. return sqlite3_column_text(statement.statement, columnIdx);
  232. }
  233. - (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName {
  234. return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]];
  235. }
  236. - (id)objectForColumnIndex:(int)columnIdx {
  237. int columnType = sqlite3_column_type(statement.statement, columnIdx);
  238. id returnValue = nil;
  239. if (columnType == SQLITE_INTEGER) {
  240. returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]];
  241. }
  242. else if (columnType == SQLITE_FLOAT) {
  243. returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]];
  244. }
  245. else if (columnType == SQLITE_BLOB) {
  246. returnValue = [self dataForColumnIndex:columnIdx];
  247. }
  248. else {
  249. //default to a string for everything else
  250. returnValue = [self stringForColumnIndex:columnIdx];
  251. }
  252. if (returnValue == nil) {
  253. returnValue = [NSNull null];
  254. }
  255. return returnValue;
  256. }
  257. - (id)objectForColumnName:(NSString*)columnName {
  258. return [self objectForColumnIndex:[self columnIndexForName:columnName]];
  259. }
  260. // returns autoreleased NSString containing the name of the column in the result set
  261. - (NSString*)columnNameForIndex:(int)columnIdx {
  262. return [NSString stringWithUTF8String: sqlite3_column_name(statement.statement, columnIdx)];
  263. }
  264. - (void)setParentDB:(FMDatabase *)newDb {
  265. parentDB = newDb;
  266. }
  267. - (NSString *)query {
  268. return query;
  269. }
  270. - (void)setQuery:(NSString *)value {
  271. [value retain];
  272. [query release];
  273. query = value;
  274. }
  275. - (NSMutableDictionary *)columnNameToIndexMap {
  276. return columnNameToIndexMap;
  277. }
  278. - (void)setColumnNameToIndexMap:(NSMutableDictionary *)value {
  279. [value retain];
  280. [columnNameToIndexMap release];
  281. columnNameToIndexMap = value;
  282. }
  283. - (FMStatement *)statement {
  284. return statement;
  285. }
  286. - (void)setStatement:(FMStatement *)value {
  287. if (statement != value) {
  288. [statement release];
  289. statement = [value retain];
  290. }
  291. }
  292. @end