FMDatabaseQueue.m 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
  29. self = [super init];
  30. if (self != nil) {
  31. _db = [FMDatabase databaseWithPath:aPath];
  32. FMDBRetain(_db);
  33. #if SQLITE_VERSION_NUMBER >= 3005000
  34. if (![_db openWithFlags:openFlags]) {
  35. #else
  36. if (![_db open]) {
  37. #endif
  38. NSLog(@"Could not create database queue for path %@", aPath);
  39. FMDBRelease(self);
  40. return 0x00;
  41. }
  42. _path = FMDBReturnRetained(aPath);
  43. _queue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
  44. _openFlags = openFlags;
  45. }
  46. return self;
  47. }
  48. - (instancetype)initWithPath:(NSString*)aPath {
  49. // default flags for sqlite3_open
  50. return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
  51. }
  52. - (instancetype)init {
  53. return [self initWithPath:nil];
  54. }
  55. - (void)dealloc {
  56. FMDBRelease(_db);
  57. FMDBRelease(_path);
  58. if (_queue) {
  59. FMDBDispatchQueueRelease(_queue);
  60. _queue = 0x00;
  61. }
  62. #if ! __has_feature(objc_arc)
  63. [super dealloc];
  64. #endif
  65. }
  66. - (void)close {
  67. FMDBRetain(self);
  68. dispatch_sync(_queue, ^() {
  69. [_db close];
  70. FMDBRelease(_db);
  71. _db = 0x00;
  72. });
  73. FMDBRelease(self);
  74. }
  75. - (FMDatabase*)database {
  76. if (!_db) {
  77. _db = FMDBReturnRetained([FMDatabase databaseWithPath:_path]);
  78. #if SQLITE_VERSION_NUMBER >= 3005000
  79. if (![_db openWithFlags:_openFlags]) {
  80. #else
  81. if (![db open]) {
  82. #endif
  83. NSLog(@"FMDatabaseQueue could not reopen database for path %@", _path);
  84. FMDBRelease(_db);
  85. _db = 0x00;
  86. return 0x00;
  87. }
  88. }
  89. return _db;
  90. }
  91. - (void)inDatabase:(void (^)(FMDatabase *db))block {
  92. FMDBRetain(self);
  93. dispatch_sync(_queue, ^() {
  94. FMDatabase *db = [self database];
  95. block(db);
  96. if ([db hasOpenResultSets]) {
  97. NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
  98. }
  99. });
  100. FMDBRelease(self);
  101. }
  102. - (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
  103. FMDBRetain(self);
  104. dispatch_sync(_queue, ^() {
  105. BOOL shouldRollback = NO;
  106. if (useDeferred) {
  107. [[self database] beginDeferredTransaction];
  108. }
  109. else {
  110. [[self database] beginTransaction];
  111. }
  112. block([self database], &shouldRollback);
  113. if (shouldRollback) {
  114. [[self database] rollback];
  115. }
  116. else {
  117. [[self database] commit];
  118. }
  119. });
  120. FMDBRelease(self);
  121. }
  122. - (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
  123. [self beginTransaction:YES withBlock:block];
  124. }
  125. - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
  126. [self beginTransaction:NO withBlock:block];
  127. }
  128. #if SQLITE_VERSION_NUMBER >= 3007000
  129. - (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
  130. static unsigned long savePointIdx = 0;
  131. __block NSError *err = 0x00;
  132. FMDBRetain(self);
  133. dispatch_sync(_queue, ^() {
  134. NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
  135. BOOL shouldRollback = NO;
  136. if ([[self database] startSavePointWithName:name error:&err]) {
  137. block([self database], &shouldRollback);
  138. if (shouldRollback) {
  139. // We need to rollback and release this savepoint to remove it
  140. [[self database] rollbackToSavePointWithName:name error:&err];
  141. }
  142. [[self database] releaseSavePointWithName:name error:&err];
  143. }
  144. });
  145. FMDBRelease(self);
  146. return err;
  147. }
  148. #endif
  149. @end