PageRenderTime 56ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/source/FTS/Classes/FMDB/FMResultSet.m

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