FMDatabaseQueue.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //
  2. // FMDatabaseQueue.m
  3. // fmdb
  4. //
  5. // Created by August Mueller on 6/22/11.
  6. // Copyright 2011 Flying Meat Inc. All rights reserved.
  7. //
  8. #import "FMDatabaseQueue.h"
  9. #import "FMDatabase.h"
  10. /*
  11. Note: we call [self retain]; before using dispatch_sync, just incase
  12. FMDatabaseQueue is released on another thread and we're in the middle of doing
  13. something in dispatch_sync
  14. */
  15. @implementation FMDatabaseQueue
  16. @synthesize path = _path;
  17. @synthesize openFlags = _openFlags;
  18. + (instancetype)databaseQueueWithPath:(NSString*)aPath {
  19. FMDatabaseQueue *q = [[self alloc] initWithPath:aPath];
  20. FMDBAutorelease(q);
  21. return q;
  22. }
  23. + (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags {
  24. FMDatabaseQueue *q = [[self alloc] initWithPath:aPath flags:openFlags];
  25. FMDBAutorelease(q);
  26. return q;
  27. }
  28. + (Class)databaseClass {
  29. return [FMDatabase class];
  30. }
  31. - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
  32. self = [super init];
  33. if (self != nil) {
  34. _db = [[[self class] databaseClass] databaseWithPath:aPath];
  35. FMDBRetain(_db);
  36. #if SQLITE_VERSION_NUMBER >= 3005000
  37. BOOL success = [_db openWithFlags:openFlags];
  38. #else
  39. BOOL success = [_db open];
  40. #endif
  41. if (!success) {
  42. NSLog(@"Could not create database queue for path %@", aPath);
  43. FMDBRelease(self);
  44. return 0x00;
  45. }
  46. _path = FMDBReturnRetained(aPath);
  47. _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
  48. _openFlags = openFlags;
  49. }
  50. return self;
  51. }
  52. - (instancetype)initWithPath:(NSString*)aPath {
  53. // default flags for sqlite3_open
  54. return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
  55. }
  56. - (instancetype)init {
  57. return [self initWithPath:nil];
  58. }
  59. - (void)dealloc {
  60. FMDBRelease(_db);
  61. FMDBRelease(_path);
  62. if (_queue) {
  63. FMDBDispatchQueueRelease(_queue);
  64. _queue = 0x00;
  65. }
  66. #if ! __has_feature(objc_arc)
  67. [super dealloc];
  68. #endif
  69. }
  70. - (void)close {
  71. FMDBRetain(self);
  72. dispatch_sync(_queue, ^() {
  73. [_db close];
  74. FMDBRelease(_db);
  75. _db = 0x00;
  76. });
  77. FMDBRelease(self);
  78. }
  79. - (FMDatabase*)database {
  80. if (!_db) {
  81. _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]);
  82. #if SQLITE_VERSION_NUMBER >= 3005000
  83. BOOL success = [_db openWithFlags:_openFlags];
  84. #else
  85. BOOL success = [db open];
  86. #endif
  87. if (!success) {
  88. NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path);
  89. FMDBRelease(_db);
  90. _db = 0x00;
  91. return 0x00;
  92. }
  93. }
  94. return _db;
  95. }
  96. - (void)inDatabase:(void (^)(FMDatabase *db))block {
  97. FMDBRetain(self);
  98. dispatch_sync(_queue, ^() {
  99. FMDatabase *db = [self database];
  100. block(db);
  101. if ([db hasOpenResultSets]) {
  102. NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
  103. #ifdef DEBUG
  104. NSSet *openSetCopy = FMDBReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]);
  105. for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
  106. FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
  107. NSLog(@"query: '%@'", [rs query]);
  108. }
  109. #endif
  110. }
  111. });
  112. FMDBRelease(self);
  113. }
  114. - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
  115. FMDBRetain(self);
  116. dispatch_sync(_queue, ^() {
  117. BOOL shouldRollback = NO;
  118. if (useDeferred) {
  119. [[self database] beginDeferredTransaction];
  120. }
  121. else {
  122. [[self database] beginTransaction];
  123. }
  124. block([self database], &shouldRollback);
  125. if (shouldRollback) {
  126. [[self database] rollback];
  127. }
  128. else {
  129. [[self database] commit];
  130. }
  131. });
  132. FMDBRelease(self);
  133. }
  134. - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
  135. [self beginTransaction:YES withBlock:block];
  136. }
  137. - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
  138. [self beginTransaction:NO withBlock:block];
  139. }
  140. #if SQLITE_VERSION_NUMBER >= 3007000
  141. - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
  142. static unsigned long savePointIdx = 0;
  143. __block NSError *err = 0x00;
  144. FMDBRetain(self);
  145. dispatch_sync(_queue, ^() {
  146. NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
  147. BOOL shouldRollback = NO;
  148. if ([[self database] startSavePointWithName:name error:&err]) {
  149. block([self database], &shouldRollback);
  150. if (shouldRollback) {
  151. // We need to rollback and release this savepoint to remove it
  152. [[self database] rollbackToSavePointWithName:name error:&err];
  153. }
  154. [[self database] releaseSavePointWithName:name error:&err];
  155. }
  156. });
  157. FMDBRelease(self);
  158. return err;
  159. }
  160. #endif
  161. @end