| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- import Foundation
- import SQLite3
- public class FMDatabaseQueue : NSObject {
-
-
- enum FMDBTransaction : Int32 {
- case FMDBTransactionExclusive = 1,
- FMDBTransactionDeferred = 2,
- FMDBTransactionImmediate = 3
- }
-
-
-
- var _databasePath : String?
- var _openFlags : Int32 = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
- var _vfsName : String?
- private var _db : FMDatabase?
-
- static var savePointIdx : CUnsignedLong = 0
-
- public let queue = DispatchQueue(label: "fmdb.\(String(describing: self))")
-
- private let queueKey = DispatchSpecificKey<FMDatabaseQueue>()
-
- public override init() {
- super.init()
-
- queue.setSpecific(key:queueKey, value:self)
-
- print(queue)
- }
-
- deinit {
-
- if let _db = _db {
- queue.sync {
- if (!_db.close()) {
- print("Could not close database")
- }
- }
- }
-
-
- }
-
- public func interrupt() {
- _db?.interrupt()
- }
-
- // FIXME: What would the swift version of this be?
- /*
- + (Class)databaseClass {
- return [FMDatabase class];
- }
- */
-
-
-
-
-
-
- static func queue(with filePath : String) -> FMDatabaseQueue {
-
- let q = FMDatabaseQueue()
-
- q._databasePath = filePath
-
- return q
- }
-
- static func queue(with fileURL : URL) -> FMDatabaseQueue {
- return FMDatabaseQueue.queue(with: fileURL.path)
- }
-
- func database() -> FMDatabase? {
-
- if (_db == nil || !(_db!._isOpen)) {
-
- if (_db == nil) {
-
- _db = FMDatabase.database(with: _databasePath!)
-
- }
-
- do {
- try _db?.openWithFlags(flags: _openFlags, vfsName: _vfsName)
- }
- catch {
- print(error)
- abort()
- }
- }
-
- return _db
-
- }
-
- func inDatabase(_ f: (FMDatabase) -> ()) {
-
- /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue
- * and then check it against self to make sure we're not about to deadlock. */
-
- let currentSyncQueue = queue.getSpecific(key: queueKey)
- assert(currentSyncQueue != self, "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock")
-
- queue.sync {
-
- let db = database()
-
- f(db!)
-
-
- if (db!.hasOpenResultSets()) {
- print("Warning: there is at least one open result set around after performing FMDatabaseQueue.inDatabase()")
- }
- }
- }
-
-
- func beginTransaction(transaction: FMDBTransaction, f: (FMDatabase, inout Bool) -> ()) {
-
-
- queue.sync {
-
- if let db = database() {
-
- var shouldRollback = false
-
- do {
-
- switch (transaction) {
-
- case .FMDBTransactionExclusive:
- try db.beginExclusiveTransaction()
- break
-
- case .FMDBTransactionDeferred:
- try db.beginDeferredTransaction()
- break
-
- case .FMDBTransactionImmediate:
- try db.beginImmediateTransaction()
- break
-
- }
-
- f(db, &shouldRollback)
-
- if (shouldRollback) {
- try db.rollback();
- }
- else {
- try db.commit();
- }
- }
- catch {
- print(error)
- }
- }
- }
-
- }
-
-
- func inTransaction(_ f: (FMDatabase, inout Bool) -> ()) {
- beginTransaction(transaction: .FMDBTransactionExclusive, f: f)
- }
-
- func inDeferredTransaction(_ f: (FMDatabase, inout Bool) -> ()) {
- beginTransaction(transaction: .FMDBTransactionDeferred, f: f)
- }
-
- func inExclusiveTransaction(_ f: (FMDatabase, inout Bool) -> ()) {
- beginTransaction(transaction: .FMDBTransactionExclusive, f: f)
- }
-
- func inImmediateTransaction(_ f: (FMDatabase, inout Bool) -> ()) {
- beginTransaction(transaction: .FMDBTransactionImmediate, f: f)
- }
-
-
- func inSavePoint(_ f: (FMDatabase, inout Bool) -> ()) {
-
-
- queue.sync {
-
- #warning("Need to implement startSavePointWithName in FMDatabase before the Queue can do inSavePoint:")
- FMDatabaseQueue.savePointIdx = FMDatabaseQueue.savePointIdx + 1
-
- // let name = "savePoint\(FMDatabaseQueue.savePointIdx)"
- // var shouldRollback = false
- //
- }
-
- }
-
-
- /*
-
- - (NSError*)inSavePoint:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block {
- #if SQLITE_VERSION_NUMBER >= 3007000
- static unsigned long savePointIdx = 0;
- __block NSError *err = 0x00;
- FMDBRetain(self);
- dispatch_sync(_queue, ^() {
-
- NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
-
- BOOL shouldRollback = NO;
-
- if ([[self database] startSavePointWithName:name error:&err]) {
-
- block([self database], &shouldRollback);
-
- if (shouldRollback) {
- // We need to rollback and release this savepoint to remove it
- [[self database] rollbackToSavePointWithName:name error:&err];
- }
- [[self database] releaseSavePointWithName:name error:&err];
-
- }
- });
- FMDBRelease(self);
- return err;
- #else
- NSString *errorMessage = NSLocalizedStringFromTable(@"Save point functions require SQLite 3.7", @"FMDB", nil);
- if (_db.logsErrors) NSLog(@"%@", errorMessage);
- return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
- #endif
- }
- - (BOOL)checkpoint:(FMDBCheckpointMode)mode error:(NSError * __autoreleasing *)error
- {
- return [self checkpoint:mode name:nil logFrameCount:NULL checkpointCount:NULL error:error];
- }
- - (BOOL)checkpoint:(FMDBCheckpointMode)mode name:(NSString *)name error:(NSError * __autoreleasing *)error
- {
- return [self checkpoint:mode name:name logFrameCount:NULL checkpointCount:NULL error:error];
- }
- - (BOOL)checkpoint:(FMDBCheckpointMode)mode name:(NSString *)name logFrameCount:(int * _Nullable)logFrameCount checkpointCount:(int * _Nullable)checkpointCount error:(NSError * __autoreleasing _Nullable * _Nullable)error
- {
- __block BOOL result;
- FMDBRetain(self);
- dispatch_sync(_queue, ^() {
- result = [self.database checkpoint:mode name:name logFrameCount:logFrameCount checkpointCount:checkpointCount error:error];
- });
- FMDBRelease(self);
-
- return result;
- }
- */
-
- }
|