Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ccgus/fmdb.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAugust Mueller <gus@flyingmeat.com>2021-12-24 04:07:33 +0300
committerAugust Mueller <gus@flyingmeat.com>2021-12-24 04:07:33 +0300
commit589c05e7848e75675450b5121531d11b79a06098 (patch)
tree7627c9f67edb0c33f054e0539fe82e8b817777e0
parent7f0098b2a28e2e90aad502819262a34dd1ae3189 (diff)
Fleshing out some more of the queueFMDB4-Swift
-rw-r--r--FMDBSwift/Sources/FMDB/FMDatabase.swift6
-rw-r--r--FMDBSwift/Sources/FMDB/FMDatabaseQueue.swift252
-rw-r--r--FMDBSwift/Tests/FMDBTests/FMDatabaseQueueTests.swift57
3 files changed, 312 insertions, 3 deletions
diff --git a/FMDBSwift/Sources/FMDB/FMDatabase.swift b/FMDBSwift/Sources/FMDB/FMDatabase.swift
index 116340b..385398a 100644
--- a/FMDBSwift/Sources/FMDB/FMDatabase.swift
+++ b/FMDBSwift/Sources/FMDB/FMDatabase.swift
@@ -35,7 +35,7 @@ public class FMDatabase : NSObject {
private var _db : OpaquePointer?
var _databasePath : String?
- private var _isOpen : Bool
+ internal var _isOpen : Bool
private var _maxBusyRetryTimeInterval : TimeInterval = 2
private var _startBusyRetryTime : TimeInterval = 0
public var logsErrors : Bool
@@ -207,7 +207,7 @@ public class FMDatabase : NSObject {
}
- public func openWithFlags(flags : Int32, vfsName : String?) throws -> Bool {
+ @discardableResult public func openWithFlags(flags : Int32, vfsName : String?) throws -> Bool {
if (_isOpen) {
return true
@@ -823,7 +823,7 @@ public class FMDatabase : NSObject {
_isInTransaction
}
- func interrupt() -> Bool {
+ @discardableResult func interrupt() -> Bool {
if (_db != nil) {
sqlite3_interrupt(_db);
return true;
diff --git a/FMDBSwift/Sources/FMDB/FMDatabaseQueue.swift b/FMDBSwift/Sources/FMDB/FMDatabaseQueue.swift
index 9ed432c..96aec5a 100644
--- a/FMDBSwift/Sources/FMDB/FMDatabaseQueue.swift
+++ b/FMDBSwift/Sources/FMDB/FMDatabaseQueue.swift
@@ -4,4 +4,256 @@ 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;
+ }
+
+ */
+
}
diff --git a/FMDBSwift/Tests/FMDBTests/FMDatabaseQueueTests.swift b/FMDBSwift/Tests/FMDBTests/FMDatabaseQueueTests.swift
new file mode 100644
index 0000000..2a66a93
--- /dev/null
+++ b/FMDBSwift/Tests/FMDBTests/FMDatabaseQueueTests.swift
@@ -0,0 +1,57 @@
+import XCTest
+import SQLite3
+@testable import FMDB
+
+final class FMDatabaseQueueTests: FMDBTempDBTests {
+
+ let tempPath = "/tmp/FMDatabaseQueueTests.db"
+
+ override func setUp() {
+
+ }
+
+ /*
+ func testURLOpenNoPath() throws {
+
+ do {
+ let q = FMDatabaseQueue()
+ XCTAssert(q != nil, "Database queue should be returned")
+ }
+
+ catch {
+ print(error)
+ XCTAssert(false)
+ }
+ }*/
+
+ func testSimpleSelect() throws {
+
+ let q = FMDatabaseQueue.queue(with: tempPath)
+
+ var worked = false
+
+ q.inDatabase({ db in
+
+ do {
+ let rs = try db.executeQuery("select 'hello'")
+ try rs.next()
+
+ XCTAssertTrue(rs.string(0) == "hello")
+ rs.close()
+ worked = true
+ }
+
+ catch {
+ print(error)
+ XCTAssert(false)
+ }
+
+ })
+
+ XCTAssert(worked)
+ }
+
+
+
+
+}